1316 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1316 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
 | |
|  *
 | |
|  * All Rights Reserved.
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining
 | |
|  * a copy of this software and associated documentation files (the
 | |
|  * "Software"), to deal in the Software without restriction, including
 | |
|  * without limitation on the rights to use, copy, modify, merge,
 | |
|  * publish, distribute, sublicense, and/or sell copies of the Software,
 | |
|  * and to permit persons to whom the Software is furnished to do so,
 | |
|  * subject to the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice (including the
 | |
|  * next paragraph) shall be included in all copies or substantial
 | |
|  * portions of the Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | |
|  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
|  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | |
|  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
 | |
|  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 | |
|  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | |
|  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | |
|  * SOFTWARE.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Authors:
 | |
|  *   Kevin E. Martin <kem@redhat.com>
 | |
|  *
 | |
|  */
 | |
| 
 | |
| /** \file
 | |
|  *  Provide support for the RENDER extension (version 0.8).
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_DMX_CONFIG_H
 | |
| #include <dmx-config.h>
 | |
| #endif
 | |
| 
 | |
| #include "dmx.h"
 | |
| #include "dmxsync.h"
 | |
| #include "dmxpict.h"
 | |
| #include "dmxwindow.h"
 | |
| #include "dmxpixmap.h"
 | |
| 
 | |
| #include "fb.h"
 | |
| #include "pixmapstr.h"
 | |
| #include "dixstruct.h"
 | |
| 
 | |
| #include <X11/extensions/render.h>
 | |
| #include <X11/extensions/renderproto.h>
 | |
| #include "picture.h"
 | |
| #include "picturestr.h"
 | |
| #include "mipict.h"
 | |
| #include "fbpict.h"
 | |
| 
 | |
| 
 | |
| extern int RenderErrBase;
 | |
| extern int (*ProcRenderVector[RenderNumberRequests])(ClientPtr);
 | |
| 
 | |
| static int (*dmxSaveRenderVector[RenderNumberRequests])(ClientPtr);
 | |
| 
 | |
| 
 | |
| static int dmxProcRenderCreateGlyphSet(ClientPtr client);
 | |
| static int dmxProcRenderFreeGlyphSet(ClientPtr client);
 | |
| static int dmxProcRenderAddGlyphs(ClientPtr client);
 | |
| static int dmxProcRenderFreeGlyphs(ClientPtr client);
 | |
| static int dmxProcRenderCompositeGlyphs(ClientPtr client);
 | |
| static int dmxProcRenderSetPictureTransform(ClientPtr client);
 | |
| static int dmxProcRenderSetPictureFilter(ClientPtr client);
 | |
| #if 0
 | |
| /* FIXME: Not (yet) supported */
 | |
| static int dmxProcRenderCreateCursor(ClientPtr client);
 | |
| static int dmxProcRenderCreateAnimCursor(ClientPtr client);
 | |
| #endif
 | |
| 
 | |
| /** Catch errors that might occur when allocating Glyph Sets.  Errors
 | |
|  *  are saved in dmxGlyphLastError for later handling. */
 | |
| static int dmxGlyphLastError;
 | |
| static int dmxGlyphErrorHandler(Display *dpy, XErrorEvent *ev)
 | |
| {
 | |
|     dmxGlyphLastError = ev->error_code;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /** Initialize the Proc Vector for the RENDER extension.  The functions
 | |
|  *  here cannot be handled by the mi layer RENDER hooks either because
 | |
|  *  the required information is no longer available when it reaches the
 | |
|  *  mi layer or no mi layer hooks exist.  This function is called from
 | |
|  *  InitOutput() since it should be initialized only once per server
 | |
|  *  generation. */
 | |
| void dmxInitRender(void)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < RenderNumberRequests; i++)
 | |
|         dmxSaveRenderVector[i] = ProcRenderVector[i];
 | |
| 
 | |
|     ProcRenderVector[X_RenderCreateGlyphSet]
 | |
| 	= dmxProcRenderCreateGlyphSet;
 | |
|     ProcRenderVector[X_RenderFreeGlyphSet]
 | |
| 	= dmxProcRenderFreeGlyphSet;
 | |
|     ProcRenderVector[X_RenderAddGlyphs]
 | |
| 	= dmxProcRenderAddGlyphs;
 | |
|     ProcRenderVector[X_RenderFreeGlyphs]
 | |
| 	= dmxProcRenderFreeGlyphs;
 | |
|     ProcRenderVector[X_RenderCompositeGlyphs8]
 | |
| 	= dmxProcRenderCompositeGlyphs;
 | |
|     ProcRenderVector[X_RenderCompositeGlyphs16]
 | |
| 	= dmxProcRenderCompositeGlyphs;
 | |
|     ProcRenderVector[X_RenderCompositeGlyphs32]
 | |
| 	= dmxProcRenderCompositeGlyphs;
 | |
|     ProcRenderVector[X_RenderSetPictureTransform]
 | |
| 	= dmxProcRenderSetPictureTransform;
 | |
|     ProcRenderVector[X_RenderSetPictureFilter]
 | |
| 	= dmxProcRenderSetPictureFilter;
 | |
| }
 | |
| 
 | |
| /** Reset the Proc Vector for the RENDER extension back to the original
 | |
|  *  functions.  This function is called from dmxCloseScreen() during the
 | |
|  *  server reset (only for screen #0). */
 | |
| void dmxResetRender(void)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < RenderNumberRequests; i++)
 | |
|         ProcRenderVector[i] = dmxSaveRenderVector[i];
 | |
| }
 | |
| 
 | |
| /** Initialize the RENDER extension, allocate the picture privates and
 | |
|  *  wrap mi function hooks.  If the shadow frame buffer is used, then
 | |
|  *  call the appropriate fb initialization function. */
 | |
| Bool dmxPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
 | |
| {
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps;
 | |
| 
 | |
|     /* The shadow framebuffer only relies on FB to be initialized */
 | |
|     if (dmxShadowFB) return fbPictureInit(pScreen, formats, nformats);
 | |
| 
 | |
|     if (!miPictureInit(pScreen, formats, nformats))
 | |
| 	return FALSE;
 | |
| 
 | |
|     if (!dixRequestPrivate(dmxPictPrivateKey, sizeof(dmxPictPrivRec)))
 | |
| 	return FALSE;
 | |
| 
 | |
|     ps = GetPictureScreen(pScreen);
 | |
| 
 | |
|     DMX_WRAP(CreatePicture,      dmxCreatePicture,      dmxScreen, ps);
 | |
|     DMX_WRAP(DestroyPicture,     dmxDestroyPicture,     dmxScreen, ps);
 | |
| 
 | |
|     DMX_WRAP(ChangePictureClip,  dmxChangePictureClip,  dmxScreen, ps);
 | |
|     DMX_WRAP(DestroyPictureClip, dmxDestroyPictureClip, dmxScreen, ps);
 | |
| 
 | |
|     DMX_WRAP(ChangePicture,      dmxChangePicture,      dmxScreen, ps);
 | |
|     DMX_WRAP(ValidatePicture,    dmxValidatePicture,    dmxScreen, ps);
 | |
| 
 | |
|     DMX_WRAP(Composite,          dmxComposite,          dmxScreen, ps);
 | |
|     DMX_WRAP(Glyphs,             dmxGlyphs,             dmxScreen, ps);
 | |
|     DMX_WRAP(CompositeRects,     dmxCompositeRects,     dmxScreen, ps);
 | |
| 
 | |
|     DMX_WRAP(Trapezoids,         dmxTrapezoids,         dmxScreen, ps);
 | |
|     DMX_WRAP(Triangles,          dmxTriangles,          dmxScreen, ps);
 | |
|     DMX_WRAP(TriStrip,           dmxTriStrip,           dmxScreen, ps);
 | |
|     DMX_WRAP(TriFan,             dmxTriFan,             dmxScreen, ps);
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /** Find the appropriate format on the requested screen given the
 | |
|  *  internal format requested.  The list of formats is searched
 | |
|  *  sequentially as the XRenderFindFormat() function does not always
 | |
|  *  find the appropriate format when a specific format is requested. */
 | |
| static XRenderPictFormat *dmxFindFormat(DMXScreenInfo *dmxScreen,
 | |
| 					PictFormatPtr pFmt)
 | |
| {
 | |
|     XRenderPictFormat *pFormat = NULL;
 | |
|     int                i       = 0;
 | |
| 
 | |
|     if (!pFmt || !dmxScreen->beDisplay) return pFormat;
 | |
| 
 | |
|     while (1) {
 | |
| 	pFormat = XRenderFindFormat(dmxScreen->beDisplay, 0, 0, i++);
 | |
| 	if (!pFormat) break;
 | |
| 
 | |
| 	if (pFormat->type             != pFmt->type)             continue;
 | |
| 	if (pFormat->depth            != pFmt->depth)            continue;
 | |
| 	if (pFormat->direct.red       != pFmt->direct.red)       continue;
 | |
| 	if (pFormat->direct.redMask   != pFmt->direct.redMask)   continue;
 | |
| 	if (pFormat->direct.green     != pFmt->direct.green)     continue;
 | |
| 	if (pFormat->direct.greenMask != pFmt->direct.greenMask) continue;
 | |
| 	if (pFormat->direct.blue      != pFmt->direct.blue)      continue;
 | |
| 	if (pFormat->direct.blueMask  != pFmt->direct.blueMask)  continue;
 | |
| 	if (pFormat->direct.alpha     != pFmt->direct.alpha)     continue;
 | |
| 	if (pFormat->direct.alphaMask != pFmt->direct.alphaMask) continue;
 | |
| 
 | |
| 	/* We have a match! */
 | |
| 	break;
 | |
|     }
 | |
| 
 | |
|     return pFormat;
 | |
| }
 | |
| 
 | |
| /** Free \a glyphSet on back-end screen number \a idx. */
 | |
| Bool dmxBEFreeGlyphSet(ScreenPtr pScreen, GlyphSetPtr glyphSet)
 | |
| {
 | |
|     dmxGlyphPrivPtr  glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
 | |
|     int              idx       = pScreen->myNum;
 | |
|     DMXScreenInfo   *dmxScreen = &dmxScreens[idx];
 | |
| 
 | |
|     if (glyphPriv->glyphSets[idx]) {
 | |
| 	XRenderFreeGlyphSet(dmxScreen->beDisplay, glyphPriv->glyphSets[idx]);
 | |
| 	glyphPriv->glyphSets[idx] = (GlyphSet)0;
 | |
| 	return TRUE;
 | |
|     }
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| /** Create \a glyphSet on the backend screen number \a idx. */
 | |
| int dmxBECreateGlyphSet(int idx, GlyphSetPtr glyphSet)
 | |
| {
 | |
|     XRenderPictFormat *pFormat;
 | |
|     DMXScreenInfo     *dmxScreen = &dmxScreens[idx];
 | |
|     dmxGlyphPrivPtr    glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
 | |
|     PictFormatPtr      pFmt      = glyphSet->format;
 | |
|     int              (*oldErrorHandler)(Display *, XErrorEvent *);
 | |
| 
 | |
|     pFormat = dmxFindFormat(dmxScreen, pFmt);
 | |
|     if (!pFormat) {
 | |
| 	return BadMatch;
 | |
|     }
 | |
| 
 | |
|     dmxGlyphLastError = 0;
 | |
|     oldErrorHandler = XSetErrorHandler(dmxGlyphErrorHandler);
 | |
| 
 | |
|     /* Catch when this fails */
 | |
|     glyphPriv->glyphSets[idx]
 | |
| 	= XRenderCreateGlyphSet(dmxScreen->beDisplay, pFormat);
 | |
| 
 | |
|     XSetErrorHandler(oldErrorHandler);
 | |
| 
 | |
|     if (dmxGlyphLastError) {
 | |
| 	return dmxGlyphLastError;
 | |
|     }
 | |
| 
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| /** Create a Glyph Set on each screen.  Save the glyphset ID from each
 | |
|  *  screen in the Glyph Set's private structure.  Fail if the format
 | |
|  *  requested is not available or if the Glyph Set cannot be created on
 | |
|  *  the screen. */
 | |
| static int dmxProcRenderCreateGlyphSet(ClientPtr client)
 | |
| {
 | |
|     int  ret;
 | |
|     REQUEST(xRenderCreateGlyphSetReq);
 | |
| 
 | |
|     ret = dmxSaveRenderVector[stuff->renderReqType](client);
 | |
| 
 | |
|     if (ret == Success) {
 | |
| 	GlyphSetPtr        glyphSet;
 | |
| 	dmxGlyphPrivPtr    glyphPriv;
 | |
| 	int                i;
 | |
| 
 | |
| 	/* Look up glyphSet that was just created ???? */
 | |
| 	/* Store glyphsets from backends in glyphSet->devPrivate ????? */
 | |
| 	/* Make sure we handle all errors here!! */
 | |
| 	
 | |
| 	glyphSet = SecurityLookupIDByType(client, stuff->gsid, GlyphSetType,
 | |
| 					  DixDestroyAccess);
 | |
| 	glyphPriv = xalloc(sizeof(dmxGlyphPrivRec));
 | |
| 	if (!glyphPriv) return BadAlloc;
 | |
|         glyphPriv->glyphSets = NULL;
 | |
|         MAXSCREENSALLOC_RETURN(glyphPriv->glyphSets, BadAlloc);
 | |
| 	DMX_SET_GLYPH_PRIV(glyphSet, glyphPriv);
 | |
| 
 | |
| 	for (i = 0; i < dmxNumScreens; i++) {
 | |
| 	    DMXScreenInfo *dmxScreen = &dmxScreens[i];
 | |
| 	    int beret;
 | |
| 
 | |
| 	    if (!dmxScreen->beDisplay) {
 | |
| 		glyphPriv->glyphSets[i] = 0;
 | |
| 		continue;
 | |
| 	    }
 | |
| 
 | |
| 	    if ((beret = dmxBECreateGlyphSet(i, glyphSet)) != Success) {
 | |
| 		int  j;
 | |
| 
 | |
| 		/* Free the glyph sets we've allocated thus far */
 | |
| 		for (j = 0; j < i; j++)
 | |
| 		    dmxBEFreeGlyphSet(screenInfo.screens[j], glyphSet);
 | |
| 
 | |
| 		/* Free the resource created by render */
 | |
| 		FreeResource(stuff->gsid, RT_NONE);
 | |
| 
 | |
| 		return beret;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /** Free the previously allocated Glyph Sets for each screen. */
 | |
| static int dmxProcRenderFreeGlyphSet(ClientPtr client)
 | |
| {
 | |
|     GlyphSetPtr  glyphSet;
 | |
|     REQUEST(xRenderFreeGlyphSetReq);
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xRenderFreeGlyphSetReq);
 | |
|     glyphSet = SecurityLookupIDByType(client, stuff->glyphset, GlyphSetType,
 | |
| 				      DixDestroyAccess);
 | |
| 
 | |
|     if (glyphSet && glyphSet->refcnt == 1) {
 | |
| 	dmxGlyphPrivPtr  glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
 | |
| 	int              i;
 | |
| 
 | |
| 	for (i = 0; i < dmxNumScreens; i++) {
 | |
| 	    DMXScreenInfo *dmxScreen = &dmxScreens[i];
 | |
| 	    
 | |
| 	    if (dmxScreen->beDisplay) {
 | |
| 		if (dmxBEFreeGlyphSet(screenInfo.screens[i], glyphSet))
 | |
| 		    dmxSync(dmxScreen, FALSE);
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
|         MAXSCREENSFREE(glyphPriv->glyphSets);
 | |
| 	xfree(glyphPriv);
 | |
| 	DMX_SET_GLYPH_PRIV(glyphSet, NULL);
 | |
|     }
 | |
| 
 | |
|     return dmxSaveRenderVector[stuff->renderReqType](client);
 | |
| }
 | |
| 
 | |
| /** Add glyphs to the Glyph Set on each screen. */
 | |
| static int dmxProcRenderAddGlyphs(ClientPtr client)
 | |
| {
 | |
|     int  ret;
 | |
|     REQUEST(xRenderAddGlyphsReq);
 | |
| 
 | |
|     ret = dmxSaveRenderVector[stuff->renderReqType](client);
 | |
| 
 | |
|     if (ret == Success) {
 | |
| 	GlyphSetPtr      glyphSet;
 | |
| 	dmxGlyphPrivPtr  glyphPriv;
 | |
| 	int              i;
 | |
| 	int              nglyphs;
 | |
| 	CARD32          *gids;
 | |
| 	Glyph           *gidsCopy;
 | |
| 	xGlyphInfo      *gi;
 | |
| 	CARD8           *bits;
 | |
| 	int              nbytes;
 | |
| 
 | |
| 	glyphSet = SecurityLookupIDByType(client, stuff->glyphset,
 | |
| 					  GlyphSetType, DixReadAccess);
 | |
| 	glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
 | |
| 
 | |
| 	nglyphs = stuff->nglyphs;
 | |
| 	gids = (CARD32 *)(stuff + 1);
 | |
| 	gi = (xGlyphInfo *)(gids + nglyphs);
 | |
| 	bits = (CARD8 *)(gi + nglyphs);
 | |
| 	nbytes = ((stuff->length << 2) -
 | |
| 		  sizeof(xRenderAddGlyphsReq) -
 | |
| 		  (sizeof(CARD32) + sizeof(xGlyphInfo)) * nglyphs);
 | |
| 
 | |
|         gidsCopy = xalloc(sizeof(*gidsCopy) * nglyphs);
 | |
|         for (i = 0; i < nglyphs; i++) gidsCopy[i] = gids[i];
 | |
| 
 | |
| 	/* FIXME: Will this ever fail? */
 | |
| 	for (i = 0; i < dmxNumScreens; i++) {
 | |
| 	    DMXScreenInfo *dmxScreen = &dmxScreens[i];
 | |
| 
 | |
| 	    if (dmxScreen->beDisplay) {
 | |
| 		XRenderAddGlyphs(dmxScreen->beDisplay,
 | |
| 				 glyphPriv->glyphSets[i],
 | |
| 				 gidsCopy,
 | |
| 				 (XGlyphInfo *)gi,
 | |
| 				 nglyphs,
 | |
| 				 (char *)bits,
 | |
| 				 nbytes);
 | |
| 		dmxSync(dmxScreen, FALSE);
 | |
| 	    }
 | |
| 	}
 | |
|         xfree(gidsCopy);
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /** Free glyphs from the Glyph Set for each screen. */
 | |
| static int dmxProcRenderFreeGlyphs(ClientPtr client)
 | |
| {
 | |
|     GlyphSetPtr  glyphSet;
 | |
|     REQUEST(xRenderFreeGlyphsReq);
 | |
| 
 | |
|     REQUEST_AT_LEAST_SIZE(xRenderFreeGlyphsReq);
 | |
|     glyphSet = SecurityLookupIDByType(client, stuff->glyphset, GlyphSetType,
 | |
| 				      DixWriteAccess);
 | |
| 
 | |
|     if (glyphSet) {
 | |
| 	dmxGlyphPrivPtr  glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
 | |
| 	int              i;
 | |
| 	int              nglyphs;
 | |
| 	Glyph           *gids;
 | |
| 
 | |
| 	nglyphs = ((client->req_len << 2) - sizeof(xRenderFreeGlyphsReq)) >> 2;
 | |
| 	if (nglyphs) {
 | |
|             gids    = xalloc(sizeof(*gids) * nglyphs);
 | |
|             for (i = 0; i < nglyphs; i++)
 | |
|                 gids[i] = ((CARD32 *)(stuff + 1))[i];
 | |
|             
 | |
| 	    for (i = 0; i < dmxNumScreens; i++) {
 | |
| 		DMXScreenInfo *dmxScreen = &dmxScreens[i];
 | |
| 
 | |
| 		if (dmxScreen->beDisplay) {
 | |
| 		    XRenderFreeGlyphs(dmxScreen->beDisplay,
 | |
| 				      glyphPriv->glyphSets[i], gids, nglyphs);
 | |
| 		    dmxSync(dmxScreen, FALSE);
 | |
| 		}
 | |
| 	    }
 | |
|             xfree(gids);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     return dmxSaveRenderVector[stuff->renderReqType](client);
 | |
| }
 | |
| 
 | |
| /** Composite glyphs on each screen into the requested picture.  If
 | |
|  *  either the src or dest picture has not been allocated due to lazy
 | |
|  *  window creation, this request will gracefully return. */
 | |
| static int dmxProcRenderCompositeGlyphs(ClientPtr client)
 | |
| {
 | |
|     int  ret;
 | |
|     REQUEST(xRenderCompositeGlyphsReq);
 | |
| 
 | |
|     ret = dmxSaveRenderVector[stuff->renderReqType](client);
 | |
| 
 | |
|     /* For the following to work with PanoramiX, it assumes that Render
 | |
|      * wraps the ProcRenderVector after dmxRenderInit has been called.
 | |
|      */
 | |
|     if (ret == Success) {
 | |
| 	PicturePtr         pSrc;
 | |
| 	dmxPictPrivPtr     pSrcPriv;
 | |
| 	PicturePtr         pDst;
 | |
| 	dmxPictPrivPtr     pDstPriv;
 | |
| 	PictFormatPtr      pFmt;
 | |
| 	XRenderPictFormat *pFormat;
 | |
| 	int                size;
 | |
| 
 | |
| 	int                scrnNum;
 | |
| 	DMXScreenInfo     *dmxScreen;
 | |
| 
 | |
| 	CARD8             *buffer;
 | |
| 	CARD8             *end;
 | |
| 	int                space;
 | |
| 
 | |
| 	int                nglyph;
 | |
| 	char              *glyphs;
 | |
| 	char              *curGlyph;
 | |
| 
 | |
| 	xGlyphElt         *elt;
 | |
| 	int                nelt;
 | |
| 	XGlyphElt8        *elts;
 | |
| 	XGlyphElt8        *curElt;
 | |
| 
 | |
| 	GlyphSetPtr        glyphSet;
 | |
| 	dmxGlyphPrivPtr    glyphPriv;
 | |
| 
 | |
| 	pSrc = SecurityLookupIDByType(client, stuff->src, PictureType,
 | |
| 				      DixReadAccess);
 | |
| 	pSrcPriv = DMX_GET_PICT_PRIV(pSrc);
 | |
| 	if (!pSrcPriv->pict)
 | |
| 	    return ret;
 | |
| 
 | |
| 	pDst = SecurityLookupIDByType(client, stuff->dst, PictureType,
 | |
| 				      DixWriteAccess);
 | |
| 	pDstPriv = DMX_GET_PICT_PRIV(pDst);
 | |
| 	if (!pDstPriv->pict)
 | |
| 	    return ret;
 | |
| 
 | |
| 	scrnNum = pDst->pDrawable->pScreen->myNum;
 | |
| 	dmxScreen = &dmxScreens[scrnNum];
 | |
| 
 | |
| 	/* Note: If the back-end display has been detached, then it
 | |
| 	 * should not be possible to reach here since the pSrcPriv->pict
 | |
| 	 * and pDstPriv->pict will have already been set to 0.
 | |
| 	 */
 | |
| 	if (!dmxScreen->beDisplay)
 | |
| 	    return ret;
 | |
| 
 | |
| 	if (stuff->maskFormat)
 | |
| 	    pFmt = SecurityLookupIDByType(client, stuff->maskFormat,
 | |
| 					  PictFormatType, DixReadAccess);
 | |
| 	else
 | |
| 	    pFmt = NULL;
 | |
| 
 | |
| 	pFormat = dmxFindFormat(dmxScreen, pFmt);
 | |
| 
 | |
| 	switch (stuff->renderReqType) {
 | |
| 	case X_RenderCompositeGlyphs8:  size = sizeof(CARD8);  break;
 | |
| 	case X_RenderCompositeGlyphs16: size = sizeof(CARD16); break;
 | |
| 	case X_RenderCompositeGlyphs32: size = sizeof(CARD32); break;
 | |
|         default:                        return BadPictOp; /* Can't happen */
 | |
| 	}
 | |
| 
 | |
| 	buffer = (CARD8 *)(stuff + 1);
 | |
| 	end = (CARD8 *)stuff + (stuff->length << 2);
 | |
| 	nelt = 0;
 | |
| 	nglyph = 0;
 | |
| 	while (buffer + sizeof(xGlyphElt) < end) {
 | |
| 	    elt = (xGlyphElt *)buffer;
 | |
| 	    buffer += sizeof(xGlyphElt);
 | |
| 
 | |
| 	    if (elt->len == 0xff) {
 | |
| 		buffer += 4;
 | |
| 	    } else {
 | |
| 		nelt++;
 | |
| 		nglyph += elt->len;
 | |
| 		space = size * elt->len;
 | |
| 		if (space & 3) space += 4 - (space & 3);
 | |
| 		buffer += space;
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
| 	/* The following only works for Render version > 0.2 */
 | |
| 
 | |
| 	/* All of the XGlyphElt* structure sizes are identical */
 | |
| 	elts = xalloc(nelt * sizeof(XGlyphElt8));
 | |
| 	if (!elts)
 | |
| 	    return BadAlloc;
 | |
| 
 | |
| 	glyphs = xalloc(nglyph * size);
 | |
| 	if (!glyphs) {
 | |
| 	    xfree(elts);
 | |
| 	    return BadAlloc;
 | |
| 	}
 | |
| 
 | |
| 	buffer = (CARD8 *)(stuff + 1);
 | |
| 	end = (CARD8 *)stuff + (stuff->length << 2);
 | |
| 	curGlyph = glyphs;
 | |
| 	curElt = elts;
 | |
| 
 | |
| 	glyphSet = SecurityLookupIDByType(client, stuff->glyphset,
 | |
| 					  GlyphSetType, DixReadAccess);
 | |
| 	glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
 | |
| 
 | |
| 	while (buffer + sizeof(xGlyphElt) < end) {
 | |
| 	    elt = (xGlyphElt *)buffer;
 | |
| 	    buffer += sizeof(xGlyphElt);
 | |
| 
 | |
| 	    if (elt->len == 0xff) {
 | |
| 		glyphSet = SecurityLookupIDByType(client,
 | |
| 						  *((CARD32 *)buffer),
 | |
| 						  GlyphSetType,
 | |
| 						  DixReadAccess);
 | |
| 		glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
 | |
| 		buffer += 4;
 | |
| 	    } else {
 | |
| 		curElt->glyphset = glyphPriv->glyphSets[scrnNum];
 | |
| 		curElt->xOff = elt->deltax;
 | |
| 		curElt->yOff = elt->deltay;
 | |
| 		curElt->nchars = elt->len;
 | |
| 		curElt->chars = curGlyph;
 | |
| 
 | |
| 		memcpy(curGlyph, buffer, size*elt->len);
 | |
| 		curGlyph += size * elt->len;
 | |
| 
 | |
| 		curElt++;
 | |
| 
 | |
| 		space = size * elt->len;
 | |
| 		if (space & 3) space += 4 - (space & 3);
 | |
| 		buffer += space;
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
| 	switch (stuff->renderReqType) {
 | |
| 	case X_RenderCompositeGlyphs8:
 | |
| 	    XRenderCompositeText8(dmxScreen->beDisplay, stuff->op,
 | |
| 				  pSrcPriv->pict, pDstPriv->pict,
 | |
| 				  pFormat,
 | |
| 				  stuff->xSrc, stuff->ySrc,
 | |
| 				  0, 0, elts, nelt);
 | |
| 	    break;
 | |
| 	case X_RenderCompositeGlyphs16:
 | |
| 	    XRenderCompositeText16(dmxScreen->beDisplay, stuff->op,
 | |
| 				   pSrcPriv->pict, pDstPriv->pict,
 | |
| 				   pFormat,
 | |
| 				   stuff->xSrc, stuff->ySrc,
 | |
| 				   0, 0, (XGlyphElt16 *)elts, nelt);
 | |
| 	    break;
 | |
| 	case X_RenderCompositeGlyphs32:
 | |
| 	    XRenderCompositeText32(dmxScreen->beDisplay, stuff->op,
 | |
| 				   pSrcPriv->pict, pDstPriv->pict,
 | |
| 				   pFormat,
 | |
| 				   stuff->xSrc, stuff->ySrc,
 | |
| 				   0, 0, (XGlyphElt32 *)elts, nelt);
 | |
| 	    break;
 | |
| 	}
 | |
| 
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
| 
 | |
| 	xfree(elts);
 | |
| 	xfree(glyphs);
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /** Set the picture transform on each screen. */
 | |
| static int dmxProcRenderSetPictureTransform(ClientPtr client)
 | |
| {
 | |
|     DMXScreenInfo  *dmxScreen;
 | |
|     PicturePtr      pPicture;
 | |
|     dmxPictPrivPtr  pPictPriv;
 | |
|     XTransform      xform;
 | |
|     REQUEST(xRenderSetPictureTransformReq);
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xRenderSetPictureTransformReq);
 | |
|     VERIFY_PICTURE(pPicture, stuff->picture, client, DixWriteAccess,
 | |
| 		   RenderErrBase + BadPicture);
 | |
| 
 | |
|     /* For the following to work with PanoramiX, it assumes that Render
 | |
|      * wraps the ProcRenderVector after dmxRenderInit has been called.
 | |
|      */
 | |
|     dmxScreen = &dmxScreens[pPicture->pDrawable->pScreen->myNum];
 | |
|     pPictPriv = DMX_GET_PICT_PRIV(pPicture);
 | |
| 
 | |
|     if (pPictPriv->pict) {
 | |
| 	xform.matrix[0][0] = stuff->transform.matrix11;
 | |
| 	xform.matrix[0][1] = stuff->transform.matrix12;
 | |
| 	xform.matrix[0][2] = stuff->transform.matrix13;
 | |
| 	xform.matrix[1][0] = stuff->transform.matrix21;
 | |
| 	xform.matrix[1][1] = stuff->transform.matrix22;
 | |
| 	xform.matrix[1][2] = stuff->transform.matrix23;
 | |
| 	xform.matrix[2][0] = stuff->transform.matrix31;
 | |
| 	xform.matrix[2][1] = stuff->transform.matrix32;
 | |
| 	xform.matrix[2][2] = stuff->transform.matrix33;
 | |
| 
 | |
| 	XRenderSetPictureTransform(dmxScreen->beDisplay,
 | |
| 				   pPictPriv->pict,
 | |
| 				   &xform);
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
|     }
 | |
| 
 | |
|     return dmxSaveRenderVector[stuff->renderReqType](client);
 | |
| }
 | |
| 
 | |
| /** Set the picture filter on each screen. */
 | |
| static int dmxProcRenderSetPictureFilter(ClientPtr client)
 | |
| {
 | |
|     DMXScreenInfo  *dmxScreen;
 | |
|     PicturePtr      pPicture;
 | |
|     dmxPictPrivPtr  pPictPriv;
 | |
|     char           *filter;
 | |
|     XFixed         *params;
 | |
|     int             nparams;
 | |
|     REQUEST(xRenderSetPictureFilterReq);
 | |
| 
 | |
|     REQUEST_AT_LEAST_SIZE(xRenderSetPictureFilterReq);
 | |
|     VERIFY_PICTURE(pPicture, stuff->picture, client, DixWriteAccess,
 | |
| 		   RenderErrBase + BadPicture);
 | |
| 
 | |
|     /* For the following to work with PanoramiX, it assumes that Render
 | |
|      * wraps the ProcRenderVector after dmxRenderInit has been called.
 | |
|      */
 | |
|     dmxScreen = &dmxScreens[pPicture->pDrawable->pScreen->myNum];
 | |
|     pPictPriv = DMX_GET_PICT_PRIV(pPicture);
 | |
| 
 | |
|     if (pPictPriv->pict) {
 | |
| 	filter  = (char *)(stuff + 1);
 | |
| 	params  = (XFixed *)(filter + ((stuff->nbytes + 3) & ~3));
 | |
| 	nparams = ((XFixed *)stuff + client->req_len) - params;
 | |
| 
 | |
| 	XRenderSetPictureFilter(dmxScreen->beDisplay,
 | |
| 				pPictPriv->pict,
 | |
| 				filter,
 | |
| 				params,
 | |
| 				nparams);
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
|     }
 | |
| 
 | |
|     return dmxSaveRenderVector[stuff->renderReqType](client);
 | |
| }
 | |
| 
 | |
| 
 | |
| /** Create a picture on the appropriate screen.  This is the actual
 | |
|  *  function that creates the picture.  However, if the associated
 | |
|  *  window has not yet been created due to lazy window creation, then
 | |
|  *  delay the picture creation until the window is mapped. */
 | |
| static Picture dmxDoCreatePicture(PicturePtr pPicture)
 | |
| {
 | |
|     DrawablePtr               pDraw     = pPicture->pDrawable;
 | |
|     ScreenPtr                 pScreen   = pDraw->pScreen;
 | |
|     DMXScreenInfo            *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     XRenderPictFormat        *pFormat;
 | |
|     Drawable                  draw;
 | |
| 
 | |
|     if (pPicture->pDrawable->type == DRAWABLE_WINDOW) {
 | |
| 	dmxWinPrivPtr  pWinPriv = DMX_GET_WINDOW_PRIV((WindowPtr)(pDraw));
 | |
| 
 | |
| 	if (!(draw = pWinPriv->window)) {
 | |
| 	    /* Window has not been created yet due to the window
 | |
| 	     * optimization.  Delay picture creation until window is
 | |
| 	     * mapped.
 | |
| 	     */
 | |
| 	    pWinPriv->hasPict = TRUE;
 | |
| 	    return 0;
 | |
| 	}
 | |
|     } else {
 | |
| 	dmxPixPrivPtr  pPixPriv = DMX_GET_PIXMAP_PRIV((PixmapPtr)(pDraw));
 | |
| 
 | |
| 	if (!(draw = pPixPriv->pixmap)) {
 | |
| 	    /* FIXME: Zero width/height pixmap?? */
 | |
| 	    return 0;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     /* This should not be reached if the back-end display has been
 | |
|      * detached because the pWinPriv->window or the pPixPriv->pixmap
 | |
|      * will be NULL; however, we add it here for completeness
 | |
|      */
 | |
|     if (!dmxScreen->beDisplay)
 | |
| 	return 0;
 | |
| 
 | |
|     pFormat = dmxFindFormat(dmxScreen, pPicture->pFormat);
 | |
| 
 | |
|     return XRenderCreatePicture(dmxScreen->beDisplay, draw, pFormat, 0, 0);
 | |
| }
 | |
| 
 | |
| /** Create a list of pictures.  This function is called by
 | |
|  *  dmxCreateAndRealizeWindow() during the lazy window creation
 | |
|  *  realization process.  It creates the entire list of pictures that
 | |
|  *  are associated with the given window. */
 | |
| void dmxCreatePictureList(WindowPtr pWindow)
 | |
| {
 | |
|     PicturePtr  pPicture = GetPictureWindow(pWindow);
 | |
| 
 | |
|     while (pPicture) {
 | |
| 	dmxPictPrivPtr  pPictPriv = DMX_GET_PICT_PRIV(pPicture);
 | |
| 
 | |
| 	/* Create the picture for this window */
 | |
| 	pPictPriv->pict = dmxDoCreatePicture(pPicture);
 | |
| 
 | |
| 	/* ValidatePicture takes care of the state changes */
 | |
| 
 | |
| 	pPicture = pPicture->pNext;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /** Create \a pPicture on the backend. */
 | |
| int dmxBECreatePicture(PicturePtr pPicture)
 | |
| {
 | |
|     dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pPicture);
 | |
| 
 | |
|     /* Create picutre on BE */
 | |
|     pPictPriv->pict = dmxDoCreatePicture(pPicture);
 | |
| 
 | |
|     /* Flush changes to the backend server */
 | |
|     dmxValidatePicture(pPicture, (1 << (CPLastBit+1)) - 1);
 | |
| 
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| /** Create a picture.  This function handles the CreatePicture
 | |
|  *  unwrapping/wrapping and calls dmxDoCreatePicture to actually create
 | |
|  *  the picture on the appropriate screen.  */
 | |
| int dmxCreatePicture(PicturePtr pPicture)
 | |
| {
 | |
|     ScreenPtr         pScreen   = pPicture->pDrawable->pScreen;
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps        = GetPictureScreen(pScreen);
 | |
|     dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pPicture);
 | |
|     int               ret       = Success;
 | |
| 
 | |
|     DMX_UNWRAP(CreatePicture, dmxScreen, ps);
 | |
| #if 1
 | |
|     if (ps->CreatePicture)
 | |
| 	ret = ps->CreatePicture(pPicture);
 | |
| #endif
 | |
| 
 | |
|     /* Create picture on back-end server */
 | |
|     pPictPriv->pict      = dmxDoCreatePicture(pPicture);
 | |
|     pPictPriv->savedMask = 0;
 | |
| 
 | |
|     DMX_WRAP(CreatePicture, dmxCreatePicture, dmxScreen, ps);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /** Destroy \a pPicture on the back-end server. */
 | |
| Bool dmxBEFreePicture(PicturePtr pPicture)
 | |
| {
 | |
|     ScreenPtr      pScreen   = pPicture->pDrawable->pScreen;
 | |
|     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture);
 | |
| 
 | |
|     if (pPictPriv->pict) {
 | |
| 	XRenderFreePicture(dmxScreen->beDisplay, pPictPriv->pict);
 | |
| 	pPictPriv->pict = (Picture)0;
 | |
| 	return TRUE;
 | |
|     }
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| /** Destroy a list of pictures that are associated with the window that
 | |
|  *  is being destroyed.  This function is called by #dmxDestroyWindow().
 | |
|  *  */
 | |
| Bool dmxDestroyPictureList(WindowPtr pWindow)
 | |
| {
 | |
|     PicturePtr  pPicture = GetPictureWindow(pWindow);
 | |
|     Bool        ret      = FALSE;
 | |
| 
 | |
|     while (pPicture) {
 | |
| 	ret |= dmxBEFreePicture(pPicture);
 | |
| 	pPicture = pPicture->pNext;
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /** Destroy a picture.  This function calls the wrapped function that
 | |
|  *  frees the resources in the DMX server associated with this
 | |
|  *  picture. */
 | |
| void dmxDestroyPicture(PicturePtr pPicture)
 | |
| {
 | |
|     ScreenPtr         pScreen   = pPicture->pDrawable->pScreen;
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps        = GetPictureScreen(pScreen);
 | |
| 
 | |
|     DMX_UNWRAP(DestroyPicture, dmxScreen, ps);
 | |
| 
 | |
|     /* Destroy picture on back-end server */
 | |
|     if (dmxBEFreePicture(pPicture))
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
| 
 | |
| #if 1
 | |
|     if (ps->DestroyPicture)
 | |
| 	ps->DestroyPicture(pPicture);
 | |
| #endif
 | |
|     DMX_WRAP(DestroyPicture, dmxDestroyPicture, dmxScreen, ps);
 | |
| }
 | |
| 
 | |
| /** Change the picture's list of clip rectangles. */
 | |
| int dmxChangePictureClip(PicturePtr pPicture, int clipType,
 | |
| 			 pointer value, int n)
 | |
| {
 | |
|     ScreenPtr         pScreen   = pPicture->pDrawable->pScreen;
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps        = GetPictureScreen(pScreen);
 | |
|     dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pPicture);
 | |
| 
 | |
|     DMX_UNWRAP(ChangePictureClip, dmxScreen, ps);
 | |
| #if 1
 | |
|     if (ps->ChangePictureClip)
 | |
| 	ps->ChangePictureClip(pPicture, clipType, value, n);
 | |
| #endif
 | |
| 
 | |
|     /* Change picture clip rects on back-end server */
 | |
|     if (pPictPriv->pict) {
 | |
| 	/* The clip has already been changed into a region by the mi
 | |
| 	 * routine called above.
 | |
| 	 */
 | |
| 	if (clipType == CT_NONE) {
 | |
| 	    /* Disable clipping, show all */
 | |
| 	    XFixesSetPictureClipRegion(dmxScreen->beDisplay,
 | |
| 				       pPictPriv->pict, 0, 0, None);
 | |
| 	} else if (pPicture->clientClip) {
 | |
| 	    RegionPtr   pClip = pPicture->clientClip;
 | |
| 	    BoxPtr      pBox  = REGION_RECTS(pClip);
 | |
| 	    int         nBox  = REGION_NUM_RECTS(pClip);
 | |
| 	    XRectangle *pRects;
 | |
| 	    XRectangle *pRect;
 | |
| 	    int         nRects;
 | |
| 
 | |
| 	    nRects = nBox;
 | |
| 	    pRects = pRect = xalloc(nRects * sizeof(*pRect));
 | |
| 
 | |
| 	    while (nBox--) {
 | |
| 		pRect->x      = pBox->x1;
 | |
| 		pRect->y      = pBox->y1;
 | |
| 		pRect->width  = pBox->x2 - pBox->x1;
 | |
| 		pRect->height = pBox->y2 - pBox->y1;
 | |
| 		pBox++;
 | |
| 		pRect++;
 | |
| 	    }
 | |
| 
 | |
| 	    XRenderSetPictureClipRectangles(dmxScreen->beDisplay,
 | |
| 					    pPictPriv->pict,
 | |
| 					    0, 0,
 | |
| 					    pRects,
 | |
| 					    nRects);
 | |
| 	    xfree(pRects);
 | |
| 	} else {
 | |
| 	    XRenderSetPictureClipRectangles(dmxScreen->beDisplay,
 | |
| 					    pPictPriv->pict,
 | |
| 					    0, 0, NULL, 0);
 | |
| 	}
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
|     } else {
 | |
| 	/* FIXME: Handle saving clip region when offscreen */
 | |
|     }
 | |
| 
 | |
|     DMX_WRAP(ChangePictureClip, dmxChangePictureClip, dmxScreen, ps);
 | |
|     
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| /** Destroy the picture's list of clip rectangles. */
 | |
| void dmxDestroyPictureClip(PicturePtr pPicture)
 | |
| {
 | |
|     ScreenPtr         pScreen   = pPicture->pDrawable->pScreen;
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps        = GetPictureScreen(pScreen);
 | |
|     dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pPicture);
 | |
| 
 | |
|     DMX_UNWRAP(DestroyPictureClip, dmxScreen, ps);
 | |
| #if 1
 | |
|     if (ps->DestroyPictureClip)
 | |
| 	ps->DestroyPictureClip(pPicture);
 | |
| #endif
 | |
| 
 | |
|     /* Destroy picture clip rects on back-end server */
 | |
|     if (pPictPriv->pict) {
 | |
| 	XRenderSetPictureClipRectangles(dmxScreen->beDisplay,
 | |
| 					pPictPriv->pict,
 | |
| 					0, 0, NULL, 0);
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
|     } else {
 | |
| 	/* FIXME: Handle destroying clip region when offscreen */
 | |
|     }
 | |
| 
 | |
|     DMX_WRAP(DestroyPictureClip, dmxDestroyPictureClip, dmxScreen, ps);
 | |
| }
 | |
| 
 | |
| /** Change the attributes of the pictures.  If the picture has not yet
 | |
|  *  been created due to lazy window creation, save the mask so that it
 | |
|  *  can be used to appropriately initialize the picture's attributes
 | |
|  *  when it is created later. */
 | |
| void dmxChangePicture(PicturePtr pPicture, Mask mask)
 | |
| {
 | |
|     ScreenPtr         pScreen   = pPicture->pDrawable->pScreen;
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps        = GetPictureScreen(pScreen);
 | |
|     dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pPicture);
 | |
| 
 | |
|     DMX_UNWRAP(ChangePicture, dmxScreen, ps);
 | |
| #if 1
 | |
|     if (ps->ChangePicture)
 | |
| 	ps->ChangePicture(pPicture, mask);
 | |
| #endif
 | |
| 
 | |
|     /* Picture attribute changes are handled in ValidatePicture */
 | |
|     pPictPriv->savedMask |= mask;
 | |
| 
 | |
|     DMX_WRAP(ChangePicture, dmxChangePicture, dmxScreen, ps);
 | |
| }
 | |
| 
 | |
| /** Validate the picture's attributes before rendering to it.  Update
 | |
|  *  any picture attributes that have been changed by one of the higher
 | |
|  *  layers. */
 | |
| void dmxValidatePicture(PicturePtr pPicture, Mask mask)
 | |
| {
 | |
|     ScreenPtr         pScreen   = pPicture->pDrawable->pScreen;
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps        = GetPictureScreen(pScreen);
 | |
|     dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pPicture);
 | |
| 
 | |
|     DMX_UNWRAP(ValidatePicture, dmxScreen, ps);
 | |
| 
 | |
|     /* Change picture attributes on back-end server */
 | |
|     if (pPictPriv->pict) {
 | |
| 	XRenderPictureAttributes  attribs;
 | |
| 
 | |
| 	if (mask & CPRepeat) {
 | |
| 	    attribs.repeat = pPicture->repeatType;
 | |
| 	}
 | |
| 	if (mask & CPAlphaMap) {
 | |
| 	    if (pPicture->alphaMap) {
 | |
| 		dmxPictPrivPtr  pAlphaPriv;
 | |
| 		pAlphaPriv = DMX_GET_PICT_PRIV(pPicture->alphaMap);
 | |
| 		if (pAlphaPriv->pict) {
 | |
| 		    attribs.alpha_map = pAlphaPriv->pict;
 | |
| 		} else {
 | |
| 		    /* FIXME: alpha picture drawable has not been created?? */
 | |
| 		    return; /* or should this be: attribs.alpha_map = None; */
 | |
| 		}
 | |
| 	    } else {
 | |
| 		attribs.alpha_map = None;
 | |
| 	    }
 | |
| 	}
 | |
| 	if (mask & CPAlphaXOrigin)
 | |
| 	    attribs.alpha_x_origin = pPicture->alphaOrigin.x;
 | |
| 	if (mask & CPAlphaYOrigin)
 | |
| 	    attribs.alpha_y_origin = pPicture->alphaOrigin.y;
 | |
| 	if (mask & CPClipXOrigin)
 | |
| 	    attribs.clip_x_origin = pPicture->clipOrigin.x;
 | |
| 	if (mask & CPClipYOrigin)
 | |
| 	    attribs.clip_y_origin = pPicture->clipOrigin.y;
 | |
| 	if (mask & CPClipMask)
 | |
| 	    mask &= ~CPClipMask; /* Handled in ChangePictureClip */
 | |
| 	if (mask & CPGraphicsExposure)
 | |
| 	    attribs.graphics_exposures = pPicture->graphicsExposures;
 | |
| 	if (mask & CPSubwindowMode)
 | |
| 	    attribs.subwindow_mode = pPicture->subWindowMode;
 | |
| 	if (mask & CPPolyEdge)
 | |
| 	    attribs.poly_edge = pPicture->polyEdge;
 | |
| 	if (mask & CPPolyMode)
 | |
| 	    attribs.poly_mode = pPicture->polyMode;
 | |
| 	if (mask & CPDither)
 | |
| 	    attribs.dither = pPicture->dither;
 | |
| 	if (mask & CPComponentAlpha)
 | |
| 	    attribs.component_alpha = pPicture->componentAlpha;
 | |
| 
 | |
| 	XRenderChangePicture(dmxScreen->beDisplay, pPictPriv->pict,
 | |
| 			     mask, &attribs);
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
|     } else {
 | |
| 	pPictPriv->savedMask |= mask;
 | |
|     }
 | |
| 
 | |
| #if 1
 | |
|     if (ps->ValidatePicture)
 | |
| 	ps->ValidatePicture(pPicture, mask);
 | |
| #endif
 | |
| 
 | |
|     DMX_WRAP(ValidatePicture, dmxValidatePicture, dmxScreen, ps);
 | |
| }
 | |
| 
 | |
| /** Composite a picture on the appropriate screen by combining the
 | |
|  *  specified rectangle of the transformed src and mask operands with
 | |
|  *  the specified rectangle of the dst using op as the compositing
 | |
|  *  operator.  For a complete description see the protocol document of
 | |
|  *  the RENDER library. */
 | |
| void dmxComposite(CARD8 op,
 | |
| 		  PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
 | |
| 		  INT16 xSrc, INT16 ySrc,
 | |
| 		  INT16 xMask, INT16 yMask,
 | |
| 		  INT16 xDst, INT16 yDst,
 | |
| 		  CARD16 width, CARD16 height)
 | |
| {
 | |
|     ScreenPtr         pScreen   = pDst->pDrawable->pScreen;
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps        = GetPictureScreen(pScreen);
 | |
|     dmxPictPrivPtr    pSrcPriv  = DMX_GET_PICT_PRIV(pSrc);
 | |
|     dmxPictPrivPtr    pMaskPriv = NULL;
 | |
|     dmxPictPrivPtr    pDstPriv  = DMX_GET_PICT_PRIV(pDst);
 | |
| 
 | |
|     if (pMask) pMaskPriv = DMX_GET_PICT_PRIV(pMask);
 | |
| 
 | |
|     DMX_UNWRAP(Composite, dmxScreen, ps);
 | |
| #if 0
 | |
|     if (ps->Composite)
 | |
| 	ps->Composite(op, pSrc, pMask, pDst,
 | |
| 		      xSrc, ySrc, xMask, yMask, xDst, yDst,
 | |
| 		      width, height);
 | |
| #endif
 | |
| 
 | |
|     /* Composite on back-end server */
 | |
|     if (pSrcPriv->pict && pDstPriv->pict &&
 | |
| 	((pMaskPriv && pMaskPriv->pict) || !pMaskPriv)) {
 | |
| 	XRenderComposite(dmxScreen->beDisplay,
 | |
| 			 op,
 | |
| 			 pSrcPriv->pict,
 | |
| 			 pMaskPriv ? pMaskPriv->pict : None,
 | |
| 			 pDstPriv->pict,
 | |
| 			 xSrc, ySrc,
 | |
| 			 xMask, yMask,
 | |
| 			 xDst, yDst,
 | |
| 			 width, height);
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     DMX_WRAP(Composite, dmxComposite, dmxScreen, ps);
 | |
| }
 | |
| 
 | |
| /** Null function to catch when/if RENDER calls lower level mi hooks.
 | |
|  *  Compositing glyphs is handled by dmxProcRenderCompositeGlyphs().
 | |
|  *  This function should never be called. */
 | |
| void dmxGlyphs(CARD8 op,
 | |
| 	       PicturePtr pSrc, PicturePtr pDst,
 | |
| 	       PictFormatPtr maskFormat,
 | |
| 	       INT16 xSrc, INT16 ySrc,
 | |
| 	       int nlists, GlyphListPtr lists, GlyphPtr *glyphs)
 | |
| {
 | |
|     /* This won't work, so we need to wrap ProcRenderCompositeGlyphs */
 | |
| }
 | |
| 
 | |
| /** Fill a rectangle on the appropriate screen by combining the color
 | |
|  *  with the dest picture in the area specified by the list of
 | |
|  *  rectangles.  For a complete description see the protocol document of
 | |
|  *  the RENDER library. */
 | |
| void dmxCompositeRects(CARD8 op,
 | |
| 		       PicturePtr pDst,
 | |
| 		       xRenderColor *color,
 | |
| 		       int nRect, xRectangle *rects)
 | |
| {
 | |
|     ScreenPtr         pScreen   = pDst->pDrawable->pScreen;
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps        = GetPictureScreen(pScreen);
 | |
|     dmxPictPrivPtr    pPictPriv = DMX_GET_PICT_PRIV(pDst);
 | |
| 
 | |
|     DMX_UNWRAP(CompositeRects, dmxScreen, ps);
 | |
| #if 0
 | |
|     if (ps->CompositeRects)
 | |
| 	ps->CompositeRects(op, pDst, color, nRect, rects);
 | |
| #endif
 | |
| 
 | |
|     /* CompositeRects on back-end server */
 | |
|     if (pPictPriv->pict) {
 | |
| 	XRenderFillRectangles(dmxScreen->beDisplay,
 | |
| 			      op,
 | |
| 			      pPictPriv->pict,
 | |
| 			      (XRenderColor *)color,
 | |
| 			      (XRectangle *)rects,
 | |
| 			      nRect);
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
|     }
 | |
| 
 | |
|     DMX_WRAP(CompositeRects, dmxCompositeRects, dmxScreen, ps);
 | |
| }
 | |
| 
 | |
| /** Indexed color visuals are not yet supported. */
 | |
| Bool dmxInitIndexed(ScreenPtr pScreen, PictFormatPtr pFormat)
 | |
| {
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /** Indexed color visuals are not yet supported. */
 | |
| void dmxCloseIndexed(ScreenPtr pScreen, PictFormatPtr pFormat)
 | |
| {
 | |
| }
 | |
| 
 | |
| /** Indexed color visuals are not yet supported. */
 | |
| void dmxUpdateIndexed(ScreenPtr pScreen, PictFormatPtr pFormat,
 | |
| 		      int ndef, xColorItem *pdef)
 | |
| {
 | |
| }
 | |
| 
 | |
| /** Composite a list of trapezoids on the appropriate screen.  For a
 | |
|  *  complete description see the protocol document of the RENDER
 | |
|  *  library. */
 | |
| void dmxTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
 | |
| 		   PictFormatPtr maskFormat,
 | |
| 		   INT16 xSrc, INT16 ySrc,
 | |
| 		   int ntrap, xTrapezoid *traps)
 | |
| {
 | |
|     ScreenPtr         pScreen   = pDst->pDrawable->pScreen;
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps        = GetPictureScreen(pScreen);
 | |
|     dmxPictPrivPtr    pSrcPriv  = DMX_GET_PICT_PRIV(pSrc);
 | |
|     dmxPictPrivPtr    pDstPriv  = DMX_GET_PICT_PRIV(pDst);
 | |
| 
 | |
|     DMX_UNWRAP(Trapezoids, dmxScreen, ps);
 | |
| #if 0
 | |
|     if (ps->Trapezoids)
 | |
| 	ps->Trapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntrap, *traps);
 | |
| #endif
 | |
| 
 | |
|     /* Draw trapezoids on back-end server */
 | |
|     if (pDstPriv->pict) {
 | |
| 	XRenderPictFormat *pFormat;
 | |
| 
 | |
| 	pFormat = dmxFindFormat(dmxScreen, maskFormat);
 | |
| 	if (!pFormat) {
 | |
| 	    /* FIXME: Error! */
 | |
| 	}
 | |
| 
 | |
| 	XRenderCompositeTrapezoids(dmxScreen->beDisplay,
 | |
| 				   op,
 | |
| 				   pSrcPriv->pict,
 | |
| 				   pDstPriv->pict,
 | |
| 				   pFormat,
 | |
| 				   xSrc, ySrc,
 | |
| 				   (XTrapezoid *)traps,
 | |
| 				   ntrap);
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
|     }
 | |
| 
 | |
|     DMX_WRAP(Trapezoids, dmxTrapezoids, dmxScreen, ps);
 | |
| }
 | |
| 
 | |
| /** Composite a list of triangles on the appropriate screen.  For a
 | |
|  *  complete description see the protocol document of the RENDER
 | |
|  *  library. */
 | |
| void dmxTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
 | |
| 		  PictFormatPtr maskFormat,
 | |
| 		  INT16 xSrc, INT16 ySrc,
 | |
| 		  int ntri, xTriangle *tris)
 | |
| {
 | |
|     ScreenPtr         pScreen   = pDst->pDrawable->pScreen;
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps        = GetPictureScreen(pScreen);
 | |
|     dmxPictPrivPtr    pSrcPriv  = DMX_GET_PICT_PRIV(pSrc);
 | |
|     dmxPictPrivPtr    pDstPriv  = DMX_GET_PICT_PRIV(pDst);
 | |
| 
 | |
|     DMX_UNWRAP(Triangles, dmxScreen, ps);
 | |
| #if 0
 | |
|     if (ps->Triangles)
 | |
| 	ps->Triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, *tris);
 | |
| #endif
 | |
| 
 | |
|     /* Draw trapezoids on back-end server */
 | |
|     if (pDstPriv->pict) {
 | |
| 	XRenderPictFormat *pFormat;
 | |
| 
 | |
| 	pFormat = dmxFindFormat(dmxScreen, maskFormat);
 | |
| 	if (!pFormat) {
 | |
| 	    /* FIXME: Error! */
 | |
| 	}
 | |
| 
 | |
| 	XRenderCompositeTriangles(dmxScreen->beDisplay,
 | |
| 				  op,
 | |
| 				  pSrcPriv->pict,
 | |
| 				  pDstPriv->pict,
 | |
| 				  pFormat,
 | |
| 				  xSrc, ySrc,
 | |
| 				  (XTriangle *)tris,
 | |
| 				  ntri);
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
|     }
 | |
| 
 | |
|     DMX_WRAP(Triangles, dmxTriangles, dmxScreen, ps);
 | |
| }
 | |
| 
 | |
| /** Composite a triangle strip on the appropriate screen.  For a
 | |
|  *  complete description see the protocol document of the RENDER
 | |
|  *  library. */
 | |
| void dmxTriStrip(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
 | |
| 		 PictFormatPtr maskFormat,
 | |
| 		 INT16 xSrc, INT16 ySrc,
 | |
| 		 int npoint, xPointFixed *points)
 | |
| {
 | |
|     ScreenPtr         pScreen   = pDst->pDrawable->pScreen;
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps        = GetPictureScreen(pScreen);
 | |
|     dmxPictPrivPtr    pSrcPriv  = DMX_GET_PICT_PRIV(pSrc);
 | |
|     dmxPictPrivPtr    pDstPriv  = DMX_GET_PICT_PRIV(pDst);
 | |
| 
 | |
|     DMX_UNWRAP(TriStrip, dmxScreen, ps);
 | |
| #if 0
 | |
|     if (ps->TriStrip)
 | |
| 	ps->TriStrip(op, pSrc, pDst, maskFormat, xSrc, ySrc, npoint, *points);
 | |
| #endif
 | |
| 
 | |
|     /* Draw trapezoids on back-end server */
 | |
|     if (pDstPriv->pict) {
 | |
| 	XRenderPictFormat *pFormat;
 | |
| 
 | |
| 	pFormat = dmxFindFormat(dmxScreen, maskFormat);
 | |
| 	if (!pFormat) {
 | |
| 	    /* FIXME: Error! */
 | |
| 	}
 | |
| 
 | |
| 	XRenderCompositeTriStrip(dmxScreen->beDisplay,
 | |
| 				 op,
 | |
| 				 pSrcPriv->pict,
 | |
| 				 pDstPriv->pict,
 | |
| 				 pFormat,
 | |
| 				 xSrc, ySrc,
 | |
| 				 (XPointFixed *)points,
 | |
| 				 npoint);
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
|     }
 | |
| 
 | |
|     DMX_WRAP(TriStrip, dmxTriStrip, dmxScreen, ps);
 | |
| }
 | |
| 
 | |
| /** Composite a triangle fan on the appropriate screen.  For a complete
 | |
|  *  description see the protocol document of the RENDER library. */
 | |
| void dmxTriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
 | |
| 	       PictFormatPtr maskFormat,
 | |
| 	       INT16 xSrc, INT16 ySrc,
 | |
| 	       int npoint, xPointFixed *points)
 | |
| {
 | |
|     ScreenPtr         pScreen   = pDst->pDrawable->pScreen;
 | |
|     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
 | |
|     PictureScreenPtr  ps        = GetPictureScreen(pScreen);
 | |
|     dmxPictPrivPtr    pSrcPriv  = DMX_GET_PICT_PRIV(pSrc);
 | |
|     dmxPictPrivPtr    pDstPriv  = DMX_GET_PICT_PRIV(pDst);
 | |
| 
 | |
|     DMX_UNWRAP(TriFan, dmxScreen, ps);
 | |
| #if 0
 | |
|     if (ps->TriFan)
 | |
| 	ps->TriFan(op, pSrc, pDst, maskFormat, xSrc, ySrc, npoint, *points);
 | |
| #endif
 | |
| 
 | |
|     /* Draw trapezoids on back-end server */
 | |
|     if (pDstPriv->pict) {
 | |
| 	XRenderPictFormat *pFormat;
 | |
| 
 | |
| 	pFormat = dmxFindFormat(dmxScreen, maskFormat);
 | |
| 	if (!pFormat) {
 | |
| 	    /* FIXME: Error! */
 | |
| 	}
 | |
| 
 | |
| 	XRenderCompositeTriFan(dmxScreen->beDisplay,
 | |
| 			       op,
 | |
| 			       pSrcPriv->pict,
 | |
| 			       pDstPriv->pict,
 | |
| 			       pFormat,
 | |
| 			       xSrc, ySrc,
 | |
| 			       (XPointFixed *)points,
 | |
| 			       npoint);
 | |
| 	dmxSync(dmxScreen, FALSE);
 | |
|     }
 | |
| 
 | |
|     DMX_WRAP(TriFan, dmxTriFan, dmxScreen, ps);
 | |
| }
 |