1628 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1628 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  *
 | |
|  * Copyright © 2000 SuSE, Inc.
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute, and sell this software and its
 | |
|  * documentation for any purpose is hereby granted without fee, provided that
 | |
|  * the above copyright notice appear in all copies and that both that
 | |
|  * copyright notice and this permission notice appear in supporting
 | |
|  * documentation, and that the name of SuSE not be used in advertising or
 | |
|  * publicity pertaining to distribution of the software without specific,
 | |
|  * written prior permission.  SuSE makes no representations about the
 | |
|  * suitability of this software for any purpose.  It is provided "as is"
 | |
|  * without express or implied warranty.
 | |
|  *
 | |
|  * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 | |
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
 | |
|  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | |
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 | |
|  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 | |
|  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
|  *
 | |
|  * Author:  Keith Packard, SuSE, Inc.
 | |
|  */
 | |
| 
 | |
| #include <dix-config.h>
 | |
| 
 | |
| #include "dix/colormap_priv.h"
 | |
| #include "dix/screen_hooks_priv.h"
 | |
| #include "os/osdep.h"
 | |
| 
 | |
| #include "misc.h"
 | |
| #include "scrnintstr.h"
 | |
| #include "os.h"
 | |
| #include "regionstr.h"
 | |
| #include "validate.h"
 | |
| #include "windowstr.h"
 | |
| #include "input.h"
 | |
| #include "resource.h"
 | |
| #include "cursorstr.h"
 | |
| #include "dixstruct.h"
 | |
| #include "gcstruct.h"
 | |
| #include "servermd.h"
 | |
| #include "picturestr_priv.h"
 | |
| #include "glyphstr_priv.h"
 | |
| #include "xace.h"
 | |
| #ifdef XINERAMA
 | |
| #include "panoramiXsrv.h"
 | |
| #endif /* XINERAMA */
 | |
| 
 | |
| DevPrivateKeyRec PictureScreenPrivateKeyRec;
 | |
| DevPrivateKeyRec PictureWindowPrivateKeyRec;
 | |
| static int PictureGeneration;
 | |
| RESTYPE PictureType;
 | |
| RESTYPE PictFormatType;
 | |
| RESTYPE GlyphSetType;
 | |
| int PictureCmapPolicy = PictureCmapPolicyDefault;
 | |
| 
 | |
| PictFormatPtr
 | |
| PictureWindowFormat(WindowPtr pWindow)
 | |
| {
 | |
|     ScreenPtr pScreen = pWindow->drawable.pScreen;
 | |
|     return PictureMatchVisual(pScreen, pWindow->drawable.depth,
 | |
|                               WindowGetVisual(pWindow));
 | |
| }
 | |
| 
 | |
| static void
 | |
| picture_window_destructor(CallbackListPtr *pcbl, ScreenPtr pScreen, WindowPtr pWindow)
 | |
| {
 | |
|     PicturePtr pPicture;
 | |
| 
 | |
|     while ((pPicture = GetPictureWindow(pWindow))) {
 | |
|         SetPictureWindow(pWindow, pPicture->pNext);
 | |
|         if (pPicture->id)
 | |
|             FreeResource(pPicture->id, PictureType);
 | |
|         FreePicture((void *) pPicture, pPicture->id);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void PictureScreenClose(CallbackListPtr *pcbl, ScreenPtr pScreen, void *unused)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreen(pScreen);
 | |
|     int n;
 | |
| 
 | |
|     PictureResetFilters(pScreen);
 | |
|     for (n = 0; n < ps->nformats; n++)
 | |
|         if (ps->formats[n].type == PictTypeIndexed)
 | |
|             (*ps->CloseIndexed) (pScreen, &ps->formats[n]);
 | |
|     GlyphUninit(pScreen);
 | |
|     SetPictureScreen(pScreen, 0);
 | |
|     free(ps->formats);
 | |
|     free(ps);
 | |
|     dixScreenUnhookClose(pScreen, PictureScreenClose);
 | |
| }
 | |
| 
 | |
| static void
 | |
| PictureStoreColors(ColormapPtr pColormap, int ndef, xColorItem * pdef)
 | |
| {
 | |
|     ScreenPtr pScreen = pColormap->pScreen;
 | |
|     PictureScreenPtr ps = GetPictureScreen(pScreen);
 | |
| 
 | |
|     pScreen->StoreColors = ps->StoreColors;
 | |
|     (*pScreen->StoreColors) (pColormap, ndef, pdef);
 | |
|     ps->StoreColors = pScreen->StoreColors;
 | |
|     pScreen->StoreColors = PictureStoreColors;
 | |
| 
 | |
|     if (pColormap->class == PseudoColor || pColormap->class == GrayScale) {
 | |
|         PictFormatPtr format = ps->formats;
 | |
|         int nformats = ps->nformats;
 | |
| 
 | |
|         while (nformats--) {
 | |
|             if (format->type == PictTypeIndexed &&
 | |
|                 format->index.pColormap == pColormap) {
 | |
|                 (*ps->UpdateIndexed) (pScreen, format, ndef, pdef);
 | |
|                 break;
 | |
|             }
 | |
|             format++;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static int
 | |
| visualDepth(ScreenPtr pScreen, VisualPtr pVisual)
 | |
| {
 | |
|     int d, v;
 | |
|     DepthPtr pDepth;
 | |
| 
 | |
|     for (d = 0; d < pScreen->numDepths; d++) {
 | |
|         pDepth = &pScreen->allowedDepths[d];
 | |
|         for (v = 0; v < pDepth->numVids; v++)
 | |
|             if (pDepth->vids[v] == pVisual->vid)
 | |
|                 return pDepth->depth;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| typedef struct _formatInit {
 | |
|     CARD32 format;
 | |
|     CARD8 depth;
 | |
| } FormatInitRec, *FormatInitPtr;
 | |
| 
 | |
| static void
 | |
| addFormat(FormatInitRec formats[256], int *nformat, CARD32 format, CARD8 depth)
 | |
| {
 | |
|     int n;
 | |
| 
 | |
|     for (n = 0; n < *nformat; n++)
 | |
|         if (formats[n].format == format && formats[n].depth == depth)
 | |
|             return;
 | |
|     formats[*nformat].format = format;
 | |
|     formats[*nformat].depth = depth;
 | |
|     ++*nformat;
 | |
| }
 | |
| 
 | |
| #define Mask(n) ((1 << (n)) - 1)
 | |
| 
 | |
| static PictFormatPtr
 | |
| PictureCreateDefaultFormats(ScreenPtr pScreen, int *nformatp)
 | |
| {
 | |
|     int nformats = 0, f;
 | |
|     PictFormatPtr pFormats;
 | |
|     FormatInitRec formats[1024];
 | |
|     CARD32 format;
 | |
|     CARD8 depth;
 | |
|     VisualPtr pVisual;
 | |
|     int v;
 | |
|     int bpp;
 | |
|     int type;
 | |
|     int r, g, b;
 | |
|     int d;
 | |
|     DepthPtr pDepth;
 | |
| 
 | |
|     nformats = 0;
 | |
|     /* formats required by protocol */
 | |
|     formats[nformats].format = PICT_a1;
 | |
|     formats[nformats].depth = 1;
 | |
|     nformats++;
 | |
|     formats[nformats].format = PICT_FORMAT(BitsPerPixel(8),
 | |
|                                            PICT_TYPE_A, 8, 0, 0, 0);
 | |
|     formats[nformats].depth = 8;
 | |
|     nformats++;
 | |
|     formats[nformats].format = PICT_a8r8g8b8;
 | |
|     formats[nformats].depth = 32;
 | |
|     nformats++;
 | |
|     formats[nformats].format = PICT_x8r8g8b8;
 | |
|     formats[nformats].depth = 32;
 | |
|     nformats++;
 | |
|     formats[nformats].format = PICT_b8g8r8a8;
 | |
|     formats[nformats].depth = 32;
 | |
|     nformats++;
 | |
|     formats[nformats].format = PICT_b8g8r8x8;
 | |
|     formats[nformats].depth = 32;
 | |
|     nformats++;
 | |
| 
 | |
|     /* now look through the depths and visuals adding other formats */
 | |
|     for (v = 0; v < pScreen->numVisuals; v++) {
 | |
|         pVisual = &pScreen->visuals[v];
 | |
|         depth = visualDepth(pScreen, pVisual);
 | |
|         if (!depth)
 | |
|             continue;
 | |
|         bpp = BitsPerPixel(depth);
 | |
|         switch (pVisual->class) {
 | |
|         case DirectColor:
 | |
|         case TrueColor:
 | |
|             r = Ones(pVisual->redMask);
 | |
|             g = Ones(pVisual->greenMask);
 | |
|             b = Ones(pVisual->blueMask);
 | |
|             type = PICT_TYPE_OTHER;
 | |
|             /*
 | |
|              * Current rendering code supports only three direct formats,
 | |
|              * fields must be packed together at the bottom of the pixel
 | |
|              */
 | |
|             if (pVisual->offsetBlue == 0 &&
 | |
|                 pVisual->offsetGreen == b && pVisual->offsetRed == b + g) {
 | |
|                 type = PICT_TYPE_ARGB;
 | |
|             }
 | |
|             else if (pVisual->offsetRed == 0 &&
 | |
|                      pVisual->offsetGreen == r &&
 | |
|                      pVisual->offsetBlue == r + g) {
 | |
|                 type = PICT_TYPE_ABGR;
 | |
|             }
 | |
|             else if (pVisual->offsetRed == pVisual->offsetGreen - r &&
 | |
|                      pVisual->offsetGreen == pVisual->offsetBlue - g &&
 | |
|                      pVisual->offsetBlue == bpp - b) {
 | |
|                 type = PICT_TYPE_BGRA;
 | |
|             }
 | |
|             if (type != PICT_TYPE_OTHER) {
 | |
|                 format = PICT_FORMAT(bpp, type, 0, r, g, b);
 | |
|                 addFormat(formats, &nformats, format, depth);
 | |
|             }
 | |
|             break;
 | |
|         case StaticColor:
 | |
|         case PseudoColor:
 | |
|             format = PICT_VISFORMAT(bpp, PICT_TYPE_COLOR, v);
 | |
|             addFormat(formats, &nformats, format, depth);
 | |
|             break;
 | |
|         case StaticGray:
 | |
|         case GrayScale:
 | |
|             format = PICT_VISFORMAT(bpp, PICT_TYPE_GRAY, v);
 | |
|             addFormat(formats, &nformats, format, depth);
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
|     /*
 | |
|      * Walk supported depths and add useful Direct formats
 | |
|      */
 | |
|     for (d = 0; d < pScreen->numDepths; d++) {
 | |
|         pDepth = &pScreen->allowedDepths[d];
 | |
|         bpp = BitsPerPixel(pDepth->depth);
 | |
|         format = 0;
 | |
|         switch (bpp) {
 | |
|         case 16:
 | |
|             /* depth 12 formats */
 | |
|             if (pDepth->depth >= 12) {
 | |
|                 addFormat(formats, &nformats, PICT_x4r4g4b4, pDepth->depth);
 | |
|                 addFormat(formats, &nformats, PICT_x4b4g4r4, pDepth->depth);
 | |
|             }
 | |
|             /* depth 15 formats */
 | |
|             if (pDepth->depth >= 15) {
 | |
|                 addFormat(formats, &nformats, PICT_x1r5g5b5, pDepth->depth);
 | |
|                 addFormat(formats, &nformats, PICT_x1b5g5r5, pDepth->depth);
 | |
|             }
 | |
|             /* depth 16 formats */
 | |
|             if (pDepth->depth >= 16) {
 | |
|                 addFormat(formats, &nformats, PICT_a1r5g5b5, pDepth->depth);
 | |
|                 addFormat(formats, &nformats, PICT_a1b5g5r5, pDepth->depth);
 | |
|                 addFormat(formats, &nformats, PICT_r5g6b5, pDepth->depth);
 | |
|                 addFormat(formats, &nformats, PICT_b5g6r5, pDepth->depth);
 | |
|                 addFormat(formats, &nformats, PICT_a4r4g4b4, pDepth->depth);
 | |
|                 addFormat(formats, &nformats, PICT_a4b4g4r4, pDepth->depth);
 | |
|             }
 | |
|             break;
 | |
|         case 32:
 | |
|             if (pDepth->depth >= 24) {
 | |
|                 addFormat(formats, &nformats, PICT_x8r8g8b8, pDepth->depth);
 | |
|                 addFormat(formats, &nformats, PICT_x8b8g8r8, pDepth->depth);
 | |
|             }
 | |
|             if (pDepth->depth >= 30) {
 | |
|                 addFormat(formats, &nformats, PICT_a2r10g10b10, pDepth->depth);
 | |
|                 addFormat(formats, &nformats, PICT_x2r10g10b10, pDepth->depth);
 | |
|                 addFormat(formats, &nformats, PICT_a2b10g10r10, pDepth->depth);
 | |
|                 addFormat(formats, &nformats, PICT_x2b10g10r10, pDepth->depth);
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pFormats = calloc(nformats, sizeof(PictFormatRec));
 | |
|     if (!pFormats)
 | |
|         return 0;
 | |
|     for (f = 0; f < nformats; f++) {
 | |
|         pFormats[f].id = FakeClientID(0);
 | |
|         pFormats[f].depth = formats[f].depth;
 | |
|         format = formats[f].format;
 | |
|         pFormats[f].format = format;
 | |
|         switch (PICT_FORMAT_TYPE(format)) {
 | |
|         case PICT_TYPE_ARGB:
 | |
|             pFormats[f].type = PictTypeDirect;
 | |
| 
 | |
|             pFormats[f].direct.alphaMask = Mask (PICT_FORMAT_A(format));
 | |
| 
 | |
|             if (pFormats[f].direct.alphaMask)
 | |
|                 pFormats[f].direct.alpha = (PICT_FORMAT_R(format) +
 | |
|                                             PICT_FORMAT_G(format) +
 | |
|                                             PICT_FORMAT_B(format));
 | |
| 
 | |
|             pFormats[f].direct.redMask = Mask (PICT_FORMAT_R(format));
 | |
| 
 | |
|             pFormats[f].direct.red = (PICT_FORMAT_G(format) +
 | |
|                                       PICT_FORMAT_B(format));
 | |
| 
 | |
|             pFormats[f].direct.greenMask = Mask (PICT_FORMAT_G(format));
 | |
| 
 | |
|             pFormats[f].direct.green = PICT_FORMAT_B(format);
 | |
| 
 | |
|             pFormats[f].direct.blueMask = Mask (PICT_FORMAT_B(format));
 | |
| 
 | |
|             pFormats[f].direct.blue = 0;
 | |
|             break;
 | |
| 
 | |
|         case PICT_TYPE_ABGR:
 | |
|             pFormats[f].type = PictTypeDirect;
 | |
| 
 | |
|             pFormats[f].direct.alphaMask = Mask (PICT_FORMAT_A(format));
 | |
| 
 | |
|             if (pFormats[f].direct.alphaMask)
 | |
|                 pFormats[f].direct.alpha = (PICT_FORMAT_B(format) +
 | |
|                                             PICT_FORMAT_G(format) +
 | |
|                                             PICT_FORMAT_R(format));
 | |
| 
 | |
|             pFormats[f].direct.blueMask = Mask (PICT_FORMAT_B(format));
 | |
| 
 | |
|             pFormats[f].direct.blue = (PICT_FORMAT_G(format) +
 | |
|                                        PICT_FORMAT_R(format));
 | |
| 
 | |
|             pFormats[f].direct.greenMask = Mask (PICT_FORMAT_G(format));
 | |
| 
 | |
|             pFormats[f].direct.green = PICT_FORMAT_R(format);
 | |
| 
 | |
|             pFormats[f].direct.redMask = Mask (PICT_FORMAT_R(format));
 | |
| 
 | |
|             pFormats[f].direct.red = 0;
 | |
|             break;
 | |
| 
 | |
|         case PICT_TYPE_BGRA:
 | |
|             pFormats[f].type = PictTypeDirect;
 | |
| 
 | |
|             pFormats[f].direct.blueMask = Mask (PICT_FORMAT_B(format));
 | |
| 
 | |
|             pFormats[f].direct.blue =
 | |
|                 (PICT_FORMAT_BPP(format) - PICT_FORMAT_B(format));
 | |
| 
 | |
|             pFormats[f].direct.greenMask = Mask (PICT_FORMAT_G(format));
 | |
| 
 | |
|             pFormats[f].direct.green =
 | |
|                 (PICT_FORMAT_BPP(format) - PICT_FORMAT_B(format) -
 | |
|                  PICT_FORMAT_G(format));
 | |
| 
 | |
|             pFormats[f].direct.redMask = Mask (PICT_FORMAT_R(format));
 | |
| 
 | |
|             pFormats[f].direct.red =
 | |
|                 (PICT_FORMAT_BPP(format) - PICT_FORMAT_B(format) -
 | |
|                  PICT_FORMAT_G(format) - PICT_FORMAT_R(format));
 | |
| 
 | |
|             pFormats[f].direct.alphaMask = Mask (PICT_FORMAT_A(format));
 | |
| 
 | |
|             pFormats[f].direct.alpha = 0;
 | |
|             break;
 | |
| 
 | |
|         case PICT_TYPE_A:
 | |
|             pFormats[f].type = PictTypeDirect;
 | |
| 
 | |
|             pFormats[f].direct.alpha = 0;
 | |
|             pFormats[f].direct.alphaMask = Mask (PICT_FORMAT_A(format));
 | |
| 
 | |
|             /* remaining fields already set to zero */
 | |
|             break;
 | |
| 
 | |
|         case PICT_TYPE_COLOR:
 | |
|         case PICT_TYPE_GRAY:
 | |
|             pFormats[f].type = PictTypeIndexed;
 | |
|             pFormats[f].index.vid =
 | |
|                 pScreen->visuals[PICT_FORMAT_VIS(format)].vid;
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
|     *nformatp = nformats;
 | |
|     return pFormats;
 | |
| }
 | |
| 
 | |
| static VisualPtr
 | |
| PictureFindVisual(ScreenPtr pScreen, VisualID visual)
 | |
| {
 | |
|     int i;
 | |
|     VisualPtr pVisual;
 | |
| 
 | |
|     for (i = 0, pVisual = pScreen->visuals;
 | |
|          i < pScreen->numVisuals; i++, pVisual++) {
 | |
|         if (pVisual->vid == visual)
 | |
|             return pVisual;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| PictureInitIndexedFormat(ScreenPtr pScreen, PictFormatPtr format)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
 | |
| 
 | |
|     if (format->type != PictTypeIndexed || format->index.pColormap)
 | |
|         return TRUE;
 | |
| 
 | |
|     if (format->index.vid == pScreen->rootVisual) {
 | |
|         dixLookupResourceByType((void **) &format->index.pColormap,
 | |
|                                 pScreen->defColormap, X11_RESTYPE_COLORMAP,
 | |
|                                 serverClient, DixGetAttrAccess);
 | |
|     }
 | |
|     else {
 | |
|         VisualPtr pVisual = PictureFindVisual(pScreen, format->index.vid);
 | |
| 
 | |
|         if (pVisual == NULL)
 | |
|             return FALSE;
 | |
| 
 | |
|         if (dixCreateColormap(FakeClientID(0), pScreen, pVisual,
 | |
|                               &format->index.pColormap, AllocNone, serverClient)
 | |
|             != Success)
 | |
|             return FALSE;
 | |
|     }
 | |
|     if (!ps->InitIndexed(pScreen, format))
 | |
|         return FALSE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| PictureInitIndexedFormats(ScreenPtr pScreen)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
 | |
|     PictFormatPtr format;
 | |
|     int nformat;
 | |
| 
 | |
|     if (!ps)
 | |
|         return FALSE;
 | |
|     format = ps->formats;
 | |
|     nformat = ps->nformats;
 | |
|     while (nformat--)
 | |
|         if (!PictureInitIndexedFormat(pScreen, format++))
 | |
|             return FALSE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| PictureFinishInit(void)
 | |
| {
 | |
|     int s;
 | |
| 
 | |
|     for (s = 0; s < screenInfo.numScreens; s++) {
 | |
|         if (!PictureInitIndexedFormats(screenInfo.screens[s]))
 | |
|             return FALSE;
 | |
|         (void) AnimCurInit(screenInfo.screens[s]);
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| PictureSetSubpixelOrder(ScreenPtr pScreen, int subpixel)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
 | |
| 
 | |
|     if (!ps)
 | |
|         return FALSE;
 | |
|     ps->subpixel = subpixel;
 | |
|     return TRUE;
 | |
| 
 | |
| }
 | |
| 
 | |
| int
 | |
| PictureGetSubpixelOrder(ScreenPtr pScreen)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
 | |
| 
 | |
|     if (!ps)
 | |
|         return SubPixelUnknown;
 | |
|     return ps->subpixel;
 | |
| }
 | |
| 
 | |
| PictFormatPtr
 | |
| PictureMatchVisual(ScreenPtr pScreen, int depth, VisualPtr pVisual)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
 | |
|     PictFormatPtr format;
 | |
|     int nformat;
 | |
|     int type;
 | |
| 
 | |
|     if (!ps)
 | |
|         return 0;
 | |
|     format = ps->formats;
 | |
|     nformat = ps->nformats;
 | |
|     switch (pVisual->class) {
 | |
|     case StaticGray:
 | |
|     case GrayScale:
 | |
|     case StaticColor:
 | |
|     case PseudoColor:
 | |
|         type = PictTypeIndexed;
 | |
|         break;
 | |
|     case TrueColor:
 | |
|     case DirectColor:
 | |
|         type = PictTypeDirect;
 | |
|         break;
 | |
|     default:
 | |
|         return 0;
 | |
|     }
 | |
|     while (nformat--) {
 | |
|         if (format->depth == depth && format->type == type) {
 | |
|             if (type == PictTypeIndexed) {
 | |
|                 if (format->index.vid == pVisual->vid)
 | |
|                     return format;
 | |
|             }
 | |
|             else {
 | |
|                 if ((unsigned long)format->direct.redMask <<
 | |
|                         format->direct.red == pVisual->redMask &&
 | |
|                     (unsigned long)format->direct.greenMask <<
 | |
|                         format->direct.green == pVisual->greenMask &&
 | |
|                     (unsigned long)format->direct.blueMask <<
 | |
|                         format->direct.blue == pVisual->blueMask) {
 | |
|                     return format;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         format++;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| PictFormatPtr
 | |
| PictureMatchFormat(ScreenPtr pScreen, int depth, CARD32 f)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
 | |
|     PictFormatPtr format;
 | |
|     int nformat;
 | |
| 
 | |
|     if (!ps)
 | |
|         return 0;
 | |
|     format = ps->formats;
 | |
|     nformat = ps->nformats;
 | |
|     while (nformat--) {
 | |
|         if (format->depth == depth && format->format == (f & 0xffffff))
 | |
|             return format;
 | |
|         format++;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| PictureParseCmapPolicy(const char *name)
 | |
| {
 | |
|     if (strcmp(name, "default") == 0)
 | |
|         return PictureCmapPolicyDefault;
 | |
|     else if (strcmp(name, "mono") == 0)
 | |
|         return PictureCmapPolicyMono;
 | |
|     else if (strcmp(name, "gray") == 0)
 | |
|         return PictureCmapPolicyGray;
 | |
|     else if (strcmp(name, "color") == 0)
 | |
|         return PictureCmapPolicyColor;
 | |
|     else if (strcmp(name, "all") == 0)
 | |
|         return PictureCmapPolicyAll;
 | |
|     else
 | |
|         return PictureCmapPolicyInvalid;
 | |
| }
 | |
| 
 | |
| /** @see GetDefaultBytes */
 | |
| static void
 | |
| GetPictureBytes(void *value, XID id, ResourceSizePtr size)
 | |
| {
 | |
|     PicturePtr picture = value;
 | |
| 
 | |
|     /* Currently only pixmap bytes are reported to clients. */
 | |
|     size->resourceSize = 0;
 | |
| 
 | |
|     size->refCnt = picture->refcnt;
 | |
| 
 | |
|     /* Calculate pixmap reference sizes. */
 | |
|     size->pixmapRefSize = 0;
 | |
|     if (picture->pDrawable && (picture->pDrawable->type == DRAWABLE_PIXMAP))
 | |
|     {
 | |
|         SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(X11_RESTYPE_PIXMAP);
 | |
|         ResourceSizeRec pixmapSize = { 0, 0, 0 };
 | |
|         PixmapPtr pixmap = (PixmapPtr)picture->pDrawable;
 | |
|         pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
 | |
|         size->pixmapRefSize += pixmapSize.pixmapRefSize;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static int
 | |
| FreePictFormat(void *pPictFormat, XID pid)
 | |
| {
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| PictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
 | |
| {
 | |
|     int n;
 | |
|     CARD32 type, a, r, g, b;
 | |
| 
 | |
|     if (PictureGeneration != serverGeneration) {
 | |
|         PictureType = CreateNewResourceType(FreePicture, "PICTURE");
 | |
|         if (!PictureType)
 | |
|             return FALSE;
 | |
|         SetResourceTypeSizeFunc(PictureType, GetPictureBytes);
 | |
|         PictFormatType = CreateNewResourceType(FreePictFormat, "PICTFORMAT");
 | |
|         if (!PictFormatType)
 | |
|             return FALSE;
 | |
|         GlyphSetType = CreateNewResourceType(FreeGlyphSet, "GLYPHSET");
 | |
|         if (!GlyphSetType)
 | |
|             return FALSE;
 | |
|         PictureGeneration = serverGeneration;
 | |
|     }
 | |
|     if (!dixRegisterPrivateKey(&PictureScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
 | |
|         return FALSE;
 | |
| 
 | |
|     if (!dixRegisterPrivateKey(&PictureWindowPrivateKeyRec, PRIVATE_WINDOW, 0))
 | |
|         return FALSE;
 | |
| 
 | |
|     if (!formats) {
 | |
|         formats = PictureCreateDefaultFormats(pScreen, &nformats);
 | |
|         if (!formats)
 | |
|             return FALSE;
 | |
|     }
 | |
|     for (n = 0; n < nformats; n++) {
 | |
|         if (!AddResource
 | |
|             (formats[n].id, PictFormatType, (void *) (formats + n))) {
 | |
|             int i;
 | |
|             for (i = 0; i < n; i++)
 | |
|                 FreeResource(formats[i].id, X11_RESTYPE_NONE);
 | |
|             free(formats);
 | |
|             return FALSE;
 | |
|         }
 | |
|         if (formats[n].type == PictTypeIndexed) {
 | |
|             VisualPtr pVisual =
 | |
|                 PictureFindVisual(pScreen, formats[n].index.vid);
 | |
|             if ((pVisual->class | DynamicClass) == PseudoColor)
 | |
|                 type = PICT_TYPE_COLOR;
 | |
|             else
 | |
|                 type = PICT_TYPE_GRAY;
 | |
|             a = r = g = b = 0;
 | |
|         }
 | |
|         else {
 | |
|             if ((formats[n].direct.redMask |
 | |
|                  formats[n].direct.blueMask | formats[n].direct.greenMask) == 0)
 | |
|                 type = PICT_TYPE_A;
 | |
|             else if (formats[n].direct.red > formats[n].direct.blue)
 | |
|                 type = PICT_TYPE_ARGB;
 | |
|             else if (formats[n].direct.red == 0)
 | |
|                 type = PICT_TYPE_ABGR;
 | |
|             else
 | |
|                 type = PICT_TYPE_BGRA;
 | |
|             a = Ones(formats[n].direct.alphaMask);
 | |
|             r = Ones(formats[n].direct.redMask);
 | |
|             g = Ones(formats[n].direct.greenMask);
 | |
|             b = Ones(formats[n].direct.blueMask);
 | |
|         }
 | |
|         formats[n].format = PICT_FORMAT(0, type, a, r, g, b);
 | |
|     }
 | |
|     PictureScreenPtr ps = calloc(1, sizeof(PictureScreenRec));
 | |
|     if (!ps) {
 | |
|         free(formats);
 | |
|         return FALSE;
 | |
|     }
 | |
|     SetPictureScreen(pScreen, ps);
 | |
| 
 | |
|     ps->formats = formats;
 | |
|     ps->fallback = formats;
 | |
|     ps->nformats = nformats;
 | |
| 
 | |
|     ps->filters = 0;
 | |
|     ps->nfilters = 0;
 | |
|     ps->filterAliases = 0;
 | |
|     ps->nfilterAliases = 0;
 | |
| 
 | |
|     ps->subpixel = SubPixelUnknown;
 | |
| 
 | |
|     ps->StoreColors = pScreen->StoreColors;
 | |
|     pScreen->StoreColors = PictureStoreColors;
 | |
| 
 | |
|     dixScreenHookWindowDestroy(pScreen, picture_window_destructor);
 | |
|     dixScreenHookClose(pScreen, PictureScreenClose);
 | |
| 
 | |
|     if (!PictureSetDefaultFilters(pScreen)) {
 | |
|         PictureResetFilters(pScreen);
 | |
|         SetPictureScreen(pScreen, 0);
 | |
|         free(formats);
 | |
|         free(ps);
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| SetPictureToDefaults(PicturePtr pPicture)
 | |
| {
 | |
|     pPicture->refcnt = 1;
 | |
|     pPicture->repeat = 0;
 | |
|     pPicture->graphicsExposures = FALSE;
 | |
|     pPicture->subWindowMode = ClipByChildren;
 | |
|     pPicture->polyEdge = PolyEdgeSharp;
 | |
|     pPicture->polyMode = PolyModePrecise;
 | |
|     pPicture->freeCompClip = FALSE;
 | |
|     pPicture->componentAlpha = FALSE;
 | |
|     pPicture->repeatType = RepeatNone;
 | |
| 
 | |
|     pPicture->alphaMap = 0;
 | |
|     pPicture->alphaOrigin.x = 0;
 | |
|     pPicture->alphaOrigin.y = 0;
 | |
| 
 | |
|     pPicture->clipOrigin.x = 0;
 | |
|     pPicture->clipOrigin.y = 0;
 | |
|     pPicture->clientClip = 0;
 | |
| 
 | |
|     pPicture->transform = 0;
 | |
| 
 | |
|     pPicture->filter = PictureGetFilterId(FilterNearest, -1, TRUE);
 | |
|     pPicture->filter_params = 0;
 | |
|     pPicture->filter_nparams = 0;
 | |
| 
 | |
|     pPicture->serialNumber = GC_CHANGE_SERIAL_BIT;
 | |
|     pPicture->stateChanges = -1;
 | |
|     pPicture->pSourcePict = 0;
 | |
| }
 | |
| 
 | |
| PicturePtr
 | |
| CreatePicture(Picture pid,
 | |
|               DrawablePtr pDrawable,
 | |
|               PictFormatPtr pFormat,
 | |
|               Mask vmask, XID *vlist, ClientPtr client, int *error)
 | |
| {
 | |
|     PicturePtr pPicture;
 | |
|     PictureScreenPtr ps = GetPictureScreen(pDrawable->pScreen);
 | |
| 
 | |
|     pPicture = dixAllocateScreenObjectWithPrivates(pDrawable->pScreen,
 | |
|                                                    PictureRec, PRIVATE_PICTURE);
 | |
|     if (!pPicture) {
 | |
|         *error = BadAlloc;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     pPicture->id = pid;
 | |
|     pPicture->pDrawable = pDrawable;
 | |
|     pPicture->pFormat = pFormat;
 | |
|     pPicture->format = pFormat->format | (pDrawable->bitsPerPixel << 24);
 | |
| 
 | |
|     /* security creation/labeling check */
 | |
|     *error = XaceHookResourceAccess(client, pid, PictureType, pPicture,
 | |
|                       X11_RESTYPE_PIXMAP, pDrawable, DixCreateAccess | DixSetAttrAccess);
 | |
|     if (*error != Success)
 | |
|         goto out;
 | |
| 
 | |
|     if (pDrawable->type == DRAWABLE_PIXMAP) {
 | |
|         ++((PixmapPtr) pDrawable)->refcnt;
 | |
|         pPicture->pNext = 0;
 | |
|     }
 | |
|     else {
 | |
|         pPicture->pNext = GetPictureWindow(((WindowPtr) pDrawable));
 | |
|         SetPictureWindow(((WindowPtr) pDrawable), pPicture);
 | |
|     }
 | |
| 
 | |
|     SetPictureToDefaults(pPicture);
 | |
| 
 | |
|     if (vmask)
 | |
|         *error = ChangePicture(pPicture, vmask, vlist, 0, client);
 | |
|     else
 | |
|         *error = Success;
 | |
|     if (*error == Success)
 | |
|         *error = (*ps->CreatePicture) (pPicture);
 | |
|  out:
 | |
|     if (*error != Success) {
 | |
|         FreePicture(pPicture, (XID) 0);
 | |
|         pPicture = 0;
 | |
|     }
 | |
|     return pPicture;
 | |
| }
 | |
| 
 | |
| static CARD32
 | |
| xRenderColorToCard32(xRenderColor c)
 | |
| {
 | |
|     return
 | |
|         ((unsigned)c.alpha >> 8 << 24) |
 | |
|         ((unsigned)c.red >> 8 << 16) |
 | |
|         ((unsigned)c.green & 0xff00) |
 | |
|         ((unsigned)c.blue >> 8);
 | |
| }
 | |
| 
 | |
| static void
 | |
| initGradient(SourcePictPtr pGradient, int stopCount,
 | |
|              xFixed * stopPoints, xRenderColor * stopColors, int *error)
 | |
| {
 | |
|     int i;
 | |
|     xFixed dpos;
 | |
| 
 | |
|     if (stopCount <= 0) {
 | |
|         *error = BadValue;
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     dpos = -1;
 | |
|     for (i = 0; i < stopCount; ++i) {
 | |
|         if (stopPoints[i] < dpos || stopPoints[i] > (1 << 16)) {
 | |
|             *error = BadValue;
 | |
|             return;
 | |
|         }
 | |
|         dpos = stopPoints[i];
 | |
|     }
 | |
| 
 | |
|     pGradient->gradient.stops = calloc(stopCount, sizeof(PictGradientStop));
 | |
|     if (!pGradient->gradient.stops) {
 | |
|         *error = BadAlloc;
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     pGradient->gradient.nstops = stopCount;
 | |
| 
 | |
|     for (i = 0; i < stopCount; ++i) {
 | |
|         pGradient->gradient.stops[i].x = stopPoints[i];
 | |
|         pGradient->gradient.stops[i].color = stopColors[i];
 | |
|     }
 | |
| }
 | |
| 
 | |
| static PicturePtr
 | |
| createSourcePicture(void)
 | |
| {
 | |
|     PicturePtr pPicture;
 | |
| 
 | |
|     pPicture = dixAllocateScreenObjectWithPrivates(NULL, PictureRec,
 | |
|                                                    PRIVATE_PICTURE);
 | |
|     if (!pPicture)
 | |
| 	return 0;
 | |
| 
 | |
|     pPicture->pDrawable = 0;
 | |
|     pPicture->pFormat = 0;
 | |
|     pPicture->pNext = 0;
 | |
|     pPicture->format = PICT_a8r8g8b8;
 | |
| 
 | |
|     SetPictureToDefaults(pPicture);
 | |
|     return pPicture;
 | |
| }
 | |
| 
 | |
| PicturePtr
 | |
| CreateSolidPicture(Picture pid, xRenderColor * color, int *error)
 | |
| {
 | |
|     PicturePtr pPicture;
 | |
| 
 | |
|     pPicture = createSourcePicture();
 | |
|     if (!pPicture) {
 | |
|         *error = BadAlloc;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     pPicture->id = pid;
 | |
|     pPicture->pSourcePict = calloc(1, sizeof(SourcePict));
 | |
|     if (!pPicture->pSourcePict) {
 | |
|         *error = BadAlloc;
 | |
|         free(pPicture);
 | |
|         return 0;
 | |
|     }
 | |
|     pPicture->pSourcePict->type = SourcePictTypeSolidFill;
 | |
|     pPicture->pSourcePict->solidFill.color = xRenderColorToCard32(*color);
 | |
|     memcpy(&pPicture->pSourcePict->solidFill.fullcolor, color, sizeof(*color));
 | |
|     return pPicture;
 | |
| }
 | |
| 
 | |
| PicturePtr
 | |
| CreateLinearGradientPicture(Picture pid, xPointFixed * p1, xPointFixed * p2,
 | |
|                             int nStops, xFixed * stops, xRenderColor * colors,
 | |
|                             int *error)
 | |
| {
 | |
|     PicturePtr pPicture;
 | |
| 
 | |
|     if (nStops < 1) {
 | |
|         *error = BadValue;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     pPicture = createSourcePicture();
 | |
|     if (!pPicture) {
 | |
|         *error = BadAlloc;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     pPicture->id = pid;
 | |
|     pPicture->pSourcePict = calloc(1, sizeof(SourcePict));
 | |
|     if (!pPicture->pSourcePict) {
 | |
|         *error = BadAlloc;
 | |
|         free(pPicture);
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     pPicture->pSourcePict->linear.type = SourcePictTypeLinear;
 | |
|     pPicture->pSourcePict->linear.p1 = *p1;
 | |
|     pPicture->pSourcePict->linear.p2 = *p2;
 | |
| 
 | |
|     initGradient(pPicture->pSourcePict, nStops, stops, colors, error);
 | |
|     if (*error) {
 | |
|         free(pPicture);
 | |
|         return 0;
 | |
|     }
 | |
|     return pPicture;
 | |
| }
 | |
| 
 | |
| PicturePtr
 | |
| CreateRadialGradientPicture(Picture pid, xPointFixed * inner,
 | |
|                             xPointFixed * outer, xFixed innerRadius,
 | |
|                             xFixed outerRadius, int nStops, xFixed * stops,
 | |
|                             xRenderColor * colors, int *error)
 | |
| {
 | |
|     PicturePtr pPicture;
 | |
|     PictRadialGradient *radial;
 | |
| 
 | |
|     if (nStops < 1) {
 | |
|         *error = BadValue;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     pPicture = createSourcePicture();
 | |
|     if (!pPicture) {
 | |
|         *error = BadAlloc;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     pPicture->id = pid;
 | |
|     pPicture->pSourcePict = calloc(1, sizeof(SourcePict));
 | |
|     if (!pPicture->pSourcePict) {
 | |
|         *error = BadAlloc;
 | |
|         free(pPicture);
 | |
|         return 0;
 | |
|     }
 | |
|     radial = &pPicture->pSourcePict->radial;
 | |
| 
 | |
|     radial->type = SourcePictTypeRadial;
 | |
|     radial->c1.x = inner->x;
 | |
|     radial->c1.y = inner->y;
 | |
|     radial->c1.radius = innerRadius;
 | |
|     radial->c2.x = outer->x;
 | |
|     radial->c2.y = outer->y;
 | |
|     radial->c2.radius = outerRadius;
 | |
| 
 | |
|     initGradient(pPicture->pSourcePict, nStops, stops, colors, error);
 | |
|     if (*error) {
 | |
|         free(pPicture);
 | |
|         return 0;
 | |
|     }
 | |
|     return pPicture;
 | |
| }
 | |
| 
 | |
| PicturePtr
 | |
| CreateConicalGradientPicture(Picture pid, xPointFixed * center, xFixed angle,
 | |
|                              int nStops, xFixed * stops, xRenderColor * colors,
 | |
|                              int *error)
 | |
| {
 | |
|     PicturePtr pPicture;
 | |
| 
 | |
|     if (nStops < 1) {
 | |
|         *error = BadValue;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     pPicture = createSourcePicture();
 | |
|     if (!pPicture) {
 | |
|         *error = BadAlloc;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     pPicture->id = pid;
 | |
|     pPicture->pSourcePict = calloc(1, sizeof(SourcePict));
 | |
|     if (!pPicture->pSourcePict) {
 | |
|         *error = BadAlloc;
 | |
|         free(pPicture);
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     pPicture->pSourcePict->conical.type = SourcePictTypeConical;
 | |
|     pPicture->pSourcePict->conical.center = *center;
 | |
|     pPicture->pSourcePict->conical.angle = angle;
 | |
| 
 | |
|     initGradient(pPicture->pSourcePict, nStops, stops, colors, error);
 | |
|     if (*error) {
 | |
|         free(pPicture);
 | |
|         return 0;
 | |
|     }
 | |
|     return pPicture;
 | |
| }
 | |
| 
 | |
| static int
 | |
| cpAlphaMap(void **result, XID id, ScreenPtr screen, ClientPtr client, Mask mode)
 | |
| {
 | |
| #ifdef XINERAMA
 | |
|     if (!noPanoramiXExtension) {
 | |
|         PanoramiXRes *res;
 | |
|         int err = dixLookupResourceByType((void **)&res, id, XRT_PICTURE,
 | |
|                                           client, mode);
 | |
|         if (err != Success)
 | |
|             return err;
 | |
|         if (screen == NULL)
 | |
|             LogMessage(X_WARNING, "cpAlphaMap() screen == NULL\n");
 | |
|         else
 | |
|             id = res->info[screen->myNum].id;
 | |
|     }
 | |
| #endif /* XINERAMA */
 | |
|     return dixLookupResourceByType(result, id, PictureType, client, mode);
 | |
| }
 | |
| 
 | |
| static int
 | |
| cpClipMask(void **result, XID id, ScreenPtr screen, ClientPtr client, Mask mode)
 | |
| {
 | |
| #ifdef XINERAMA
 | |
|     if (!noPanoramiXExtension) {
 | |
|         PanoramiXRes *res;
 | |
|         int err = dixLookupResourceByType((void **)&res, id, XRT_PIXMAP,
 | |
|                                           client, mode);
 | |
|         if (err != Success)
 | |
|             return err;
 | |
|         id = res->info[screen->myNum].id;
 | |
|     }
 | |
| #endif /* XINERAMA */
 | |
|     return dixLookupResourceByType(result, id, X11_RESTYPE_PIXMAP, client, mode);
 | |
| }
 | |
| 
 | |
| #define NEXT_VAL(_type) (vlist ? (_type) *vlist++ : (_type) ulist++->val)
 | |
| 
 | |
| #define NEXT_PTR(_type) ((_type) ulist++->ptr)
 | |
| 
 | |
| int
 | |
| ChangePicture(PicturePtr pPicture,
 | |
|               Mask vmask, XID *vlist, DevUnion *ulist, ClientPtr client)
 | |
| {
 | |
|     ScreenPtr pScreen = pPicture->pDrawable ? pPicture->pDrawable->pScreen : 0;
 | |
|     PictureScreenPtr ps = pScreen ? GetPictureScreen(pScreen) : 0;
 | |
|     BITS32 index2;
 | |
|     int error = 0;
 | |
|     BITS32 maskQ;
 | |
| 
 | |
|     pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
 | |
|     maskQ = vmask;
 | |
|     while (vmask && !error) {
 | |
|         index2 = (BITS32) lowbit(vmask);
 | |
|         vmask &= ~index2;
 | |
|         pPicture->stateChanges |= index2;
 | |
|         switch (index2) {
 | |
|         case CPRepeat:
 | |
|         {
 | |
|             unsigned int newr;
 | |
|             newr = NEXT_VAL(unsigned int);
 | |
| 
 | |
|             if (newr <= RepeatReflect) {
 | |
|                 pPicture->repeat = (newr != RepeatNone);
 | |
|                 pPicture->repeatType = newr;
 | |
|             }
 | |
|             else {
 | |
|                 client->errorValue = newr;
 | |
|                 error = BadValue;
 | |
|             }
 | |
|         }
 | |
|             break;
 | |
|         case CPAlphaMap:
 | |
|         {
 | |
|             PicturePtr pAlpha;
 | |
| 
 | |
|             if (vlist) {
 | |
|                 Picture pid = NEXT_VAL(Picture);
 | |
| 
 | |
|                 if (pid == None)
 | |
|                     pAlpha = 0;
 | |
|                 else {
 | |
|                     error = cpAlphaMap((void **) &pAlpha, pid, pScreen,
 | |
|                                        client, DixReadAccess);
 | |
|                     if (error != Success) {
 | |
|                         client->errorValue = pid;
 | |
|                         break;
 | |
|                     }
 | |
|                     if (pAlpha->pDrawable == NULL ||
 | |
|                         pAlpha->pDrawable->type != DRAWABLE_PIXMAP) {
 | |
|                         client->errorValue = pid;
 | |
|                         error = BadMatch;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|                 pAlpha = NEXT_PTR(PicturePtr);
 | |
|             if (!error) {
 | |
|                 if (pAlpha && pAlpha->pDrawable->type == DRAWABLE_PIXMAP)
 | |
|                     pAlpha->refcnt++;
 | |
|                 if (pPicture->alphaMap)
 | |
|                     FreePicture((void *) pPicture->alphaMap, (XID) 0);
 | |
|                 pPicture->alphaMap = pAlpha;
 | |
|             }
 | |
|         }
 | |
|             break;
 | |
|         case CPAlphaXOrigin:
 | |
|             pPicture->alphaOrigin.x = NEXT_VAL(INT16);
 | |
| 
 | |
|             break;
 | |
|         case CPAlphaYOrigin:
 | |
|             pPicture->alphaOrigin.y = NEXT_VAL(INT16);
 | |
| 
 | |
|             break;
 | |
|         case CPClipXOrigin:
 | |
|             pPicture->clipOrigin.x = NEXT_VAL(INT16);
 | |
| 
 | |
|             break;
 | |
|         case CPClipYOrigin:
 | |
|             pPicture->clipOrigin.y = NEXT_VAL(INT16);
 | |
| 
 | |
|             break;
 | |
|         case CPClipMask:
 | |
|         {
 | |
|             Pixmap pid;
 | |
|             PixmapPtr pPixmap;
 | |
|             int clipType;
 | |
| 
 | |
|             if (!pScreen)
 | |
|                 return BadDrawable;
 | |
| 
 | |
|             if (vlist) {
 | |
|                 pid = NEXT_VAL(Pixmap);
 | |
|                 if (pid == None) {
 | |
|                     clipType = CT_NONE;
 | |
|                     pPixmap = NullPixmap;
 | |
|                 }
 | |
|                 else {
 | |
|                     clipType = CT_PIXMAP;
 | |
|                     error = cpClipMask((void **) &pPixmap, pid, pScreen,
 | |
|                                        client, DixReadAccess);
 | |
|                     if (error != Success) {
 | |
|                         client->errorValue = pid;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else {
 | |
|                 pPixmap = NEXT_PTR(PixmapPtr);
 | |
| 
 | |
|                 if (pPixmap)
 | |
|                     clipType = CT_PIXMAP;
 | |
|                 else
 | |
|                     clipType = CT_NONE;
 | |
|             }
 | |
| 
 | |
|             if (pPixmap) {
 | |
|                 if ((pPixmap->drawable.depth != 1) ||
 | |
|                     (pPixmap->drawable.pScreen != pScreen)) {
 | |
|                     error = BadMatch;
 | |
|                     break;
 | |
|                 }
 | |
|                 else {
 | |
|                     clipType = CT_PIXMAP;
 | |
|                     pPixmap->refcnt++;
 | |
|                 }
 | |
|             }
 | |
|             error = (*ps->ChangePictureClip) (pPicture, clipType,
 | |
|                                               (void *) pPixmap, 0);
 | |
|             break;
 | |
|         }
 | |
|         case CPGraphicsExposure:
 | |
|         {
 | |
|             unsigned int newe;
 | |
|             newe = NEXT_VAL(unsigned int);
 | |
| 
 | |
|             if (newe <= xTrue)
 | |
|                 pPicture->graphicsExposures = newe;
 | |
|             else {
 | |
|                 client->errorValue = newe;
 | |
|                 error = BadValue;
 | |
|             }
 | |
|         }
 | |
|             break;
 | |
|         case CPSubwindowMode:
 | |
|         {
 | |
|             unsigned int news;
 | |
|             news = NEXT_VAL(unsigned int);
 | |
| 
 | |
|             if (news == ClipByChildren || news == IncludeInferiors)
 | |
|                 pPicture->subWindowMode = news;
 | |
|             else {
 | |
|                 client->errorValue = news;
 | |
|                 error = BadValue;
 | |
|             }
 | |
|         }
 | |
|             break;
 | |
|         case CPPolyEdge:
 | |
|         {
 | |
|             unsigned int newe;
 | |
|             newe = NEXT_VAL(unsigned int);
 | |
| 
 | |
|             if (newe == PolyEdgeSharp || newe == PolyEdgeSmooth)
 | |
|                 pPicture->polyEdge = newe;
 | |
|             else {
 | |
|                 client->errorValue = newe;
 | |
|                 error = BadValue;
 | |
|             }
 | |
|         }
 | |
|             break;
 | |
|         case CPPolyMode:
 | |
|         {
 | |
|             unsigned int newm;
 | |
|             newm = NEXT_VAL(unsigned int);
 | |
| 
 | |
|             if (newm == PolyModePrecise || newm == PolyModeImprecise)
 | |
|                 pPicture->polyMode = newm;
 | |
|             else {
 | |
|                 client->errorValue = newm;
 | |
|                 error = BadValue;
 | |
|             }
 | |
|         }
 | |
|             break;
 | |
|         case CPDither:
 | |
|             (void) NEXT_VAL(Atom);      /* unimplemented */
 | |
| 
 | |
|             break;
 | |
|         case CPComponentAlpha:
 | |
|         {
 | |
|             unsigned int newca;
 | |
| 
 | |
|             newca = NEXT_VAL(unsigned int);
 | |
| 
 | |
|             if (newca <= xTrue)
 | |
|                 pPicture->componentAlpha = newca;
 | |
|             else {
 | |
|                 client->errorValue = newca;
 | |
|                 error = BadValue;
 | |
|             }
 | |
|         }
 | |
|             break;
 | |
|         default:
 | |
|             client->errorValue = maskQ;
 | |
|             error = BadValue;
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
|     if (ps)
 | |
|         (*ps->ChangePicture) (pPicture, maskQ);
 | |
|     return error;
 | |
| }
 | |
| 
 | |
| int
 | |
| SetPictureClipRects(PicturePtr pPicture,
 | |
|                     int xOrigin, int yOrigin, int nRect, xRectangle *rects)
 | |
| {
 | |
|     ScreenPtr pScreen = pPicture->pDrawable->pScreen;
 | |
|     PictureScreenPtr ps = GetPictureScreen(pScreen);
 | |
|     RegionPtr clientClip;
 | |
|     int result;
 | |
| 
 | |
|     clientClip = RegionFromRects(nRect, rects, CT_UNSORTED);
 | |
|     if (!clientClip)
 | |
|         return BadAlloc;
 | |
|     result = (*ps->ChangePictureClip) (pPicture, CT_REGION,
 | |
|                                        (void *) clientClip, 0);
 | |
|     if (result == Success) {
 | |
|         pPicture->clipOrigin.x = xOrigin;
 | |
|         pPicture->clipOrigin.y = yOrigin;
 | |
|         pPicture->stateChanges |= CPClipXOrigin | CPClipYOrigin | CPClipMask;
 | |
|         pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| int
 | |
| SetPictureClipRegion(PicturePtr pPicture,
 | |
|                      int xOrigin, int yOrigin, RegionPtr pRegion)
 | |
| {
 | |
|     ScreenPtr pScreen = pPicture->pDrawable->pScreen;
 | |
|     PictureScreenPtr ps = GetPictureScreen(pScreen);
 | |
|     RegionPtr clientClip;
 | |
|     int result;
 | |
|     int type;
 | |
| 
 | |
|     if (pRegion) {
 | |
|         type = CT_REGION;
 | |
|         clientClip = RegionCreate(RegionExtents(pRegion),
 | |
|                                   RegionNumRects(pRegion));
 | |
|         if (!clientClip)
 | |
|             return BadAlloc;
 | |
|         if (!RegionCopy(clientClip, pRegion)) {
 | |
|             RegionDestroy(clientClip);
 | |
|             return BadAlloc;
 | |
|         }
 | |
|     }
 | |
|     else {
 | |
|         type = CT_NONE;
 | |
|         clientClip = 0;
 | |
|     }
 | |
| 
 | |
|     result = (*ps->ChangePictureClip) (pPicture, type, (void *) clientClip, 0);
 | |
|     if (result == Success) {
 | |
|         pPicture->clipOrigin.x = xOrigin;
 | |
|         pPicture->clipOrigin.y = yOrigin;
 | |
|         pPicture->stateChanges |= CPClipXOrigin | CPClipYOrigin | CPClipMask;
 | |
|         pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| transformIsIdentity(PictTransform * t)
 | |
| {
 | |
|     return ((t->matrix[0][0] == t->matrix[1][1]) &&
 | |
|             (t->matrix[0][0] == t->matrix[2][2]) &&
 | |
|             (t->matrix[0][0] != 0) &&
 | |
|             (t->matrix[0][1] == 0) &&
 | |
|             (t->matrix[0][2] == 0) &&
 | |
|             (t->matrix[1][0] == 0) &&
 | |
|             (t->matrix[1][2] == 0) &&
 | |
|             (t->matrix[2][0] == 0) && (t->matrix[2][1] == 0));
 | |
| }
 | |
| 
 | |
| int
 | |
| SetPictureTransform(PicturePtr pPicture, PictTransform * transform)
 | |
| {
 | |
|     if (transform && transformIsIdentity(transform))
 | |
|         transform = 0;
 | |
| 
 | |
|     if (transform) {
 | |
|         if (!pPicture->transform) {
 | |
|             pPicture->transform = calloc(1, sizeof(PictTransform));
 | |
|             if (!pPicture->transform)
 | |
|                 return BadAlloc;
 | |
|         }
 | |
|         *pPicture->transform = *transform;
 | |
|     }
 | |
|     else {
 | |
|         free(pPicture->transform);
 | |
|         pPicture->transform = NULL;
 | |
|     }
 | |
|     pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
 | |
| 
 | |
|     if (pPicture->pDrawable != NULL) {
 | |
|         int result;
 | |
|         PictureScreenPtr ps = GetPictureScreen(pPicture->pDrawable->pScreen);
 | |
| 
 | |
|         result = (*ps->ChangePictureTransform) (pPicture, transform);
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static void
 | |
| ValidateOnePicture(PicturePtr pPicture)
 | |
| {
 | |
|     if (pPicture->pDrawable &&
 | |
|         pPicture->serialNumber != pPicture->pDrawable->serialNumber) {
 | |
|         PictureScreenPtr ps = GetPictureScreen(pPicture->pDrawable->pScreen);
 | |
| 
 | |
|         (*ps->ValidatePicture) (pPicture, pPicture->stateChanges);
 | |
|         pPicture->stateChanges = 0;
 | |
|         pPicture->serialNumber = pPicture->pDrawable->serialNumber;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| ValidatePicture(PicturePtr pPicture)
 | |
| {
 | |
|     ValidateOnePicture(pPicture);
 | |
|     if (pPicture->alphaMap)
 | |
|         ValidateOnePicture(pPicture->alphaMap);
 | |
| }
 | |
| 
 | |
| int
 | |
| FreePicture(void *value, XID pid)
 | |
| {
 | |
|     PicturePtr pPicture = (PicturePtr) value;
 | |
| 
 | |
|     if (--pPicture->refcnt == 0) {
 | |
|         free(pPicture->transform);
 | |
|         free(pPicture->filter_params);
 | |
| 
 | |
|         if (pPicture->pSourcePict) {
 | |
|             if (pPicture->pSourcePict->type != SourcePictTypeSolidFill)
 | |
|                 free(pPicture->pSourcePict->linear.stops);
 | |
| 
 | |
|             free(pPicture->pSourcePict);
 | |
|         }
 | |
| 
 | |
|         if (pPicture->pDrawable) {
 | |
|             ScreenPtr pScreen = pPicture->pDrawable->pScreen;
 | |
|             PictureScreenPtr ps = GetPictureScreen(pScreen);
 | |
| 
 | |
|             if (pPicture->alphaMap)
 | |
|                 FreePicture((void *) pPicture->alphaMap, (XID) 0);
 | |
|             (*ps->DestroyPicture) (pPicture);
 | |
|             (*ps->DestroyPictureClip) (pPicture);
 | |
|             if (pPicture->pDrawable->type == DRAWABLE_WINDOW) {
 | |
|                 WindowPtr pWindow = (WindowPtr) pPicture->pDrawable;
 | |
|                 PicturePtr *pPrev;
 | |
| 
 | |
|                 for (pPrev = (PicturePtr *) dixLookupPrivateAddr
 | |
|                      (&pWindow->devPrivates, PictureWindowPrivateKey);
 | |
|                      *pPrev; pPrev = &(*pPrev)->pNext) {
 | |
|                     if (*pPrev == pPicture) {
 | |
|                         *pPrev = pPicture->pNext;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else if (pPicture->pDrawable->type == DRAWABLE_PIXMAP) {
 | |
|                 dixDestroyPixmap((PixmapPtr) pPicture->pDrawable, 0);
 | |
|             }
 | |
|         }
 | |
|         dixFreeObjectWithPrivates(pPicture, PRIVATE_PICTURE);
 | |
|     }
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ReduceCompositeOp is used to choose simpler ops for cases where alpha
 | |
|  * channels are always one and so math on the alpha channel per pixel becomes
 | |
|  * unnecessary.  It may also avoid destination reads sometimes if apps aren't
 | |
|  * being careful to avoid these cases.
 | |
|  */
 | |
| static CARD8
 | |
| ReduceCompositeOp(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
 | |
|                   INT16 xSrc, INT16 ySrc, CARD16 width, CARD16 height)
 | |
| {
 | |
|     Bool no_src_alpha, no_dst_alpha;
 | |
| 
 | |
|     /* Sampling off the edge of a RepeatNone picture introduces alpha
 | |
|      * even if the picture itself doesn't have alpha. We don't try to
 | |
|      * detect every case where we don't sample off the edge, just the
 | |
|      * simplest case where there is no transform on the source
 | |
|      * picture.
 | |
|      */
 | |
|     no_src_alpha = PICT_FORMAT_COLOR(pSrc->format) &&
 | |
|         PICT_FORMAT_A(pSrc->format) == 0 &&
 | |
|         (pSrc->repeatType != RepeatNone ||
 | |
|          (!pSrc->transform &&
 | |
|           xSrc >= 0 && ySrc >= 0 &&
 | |
|           xSrc + width <= pSrc->pDrawable->width &&
 | |
|           ySrc + height <= pSrc->pDrawable->height)) &&
 | |
|         pSrc->alphaMap == NULL && pMask == NULL;
 | |
|     no_dst_alpha = PICT_FORMAT_COLOR(pDst->format) &&
 | |
|         PICT_FORMAT_A(pDst->format) == 0 && pDst->alphaMap == NULL;
 | |
| 
 | |
|     /* TODO, maybe: Conjoint and Disjoint op reductions? */
 | |
| 
 | |
|     /* Deal with simplifications where the source alpha is always 1. */
 | |
|     if (no_src_alpha) {
 | |
|         switch (op) {
 | |
|         case PictOpOver:
 | |
|             op = PictOpSrc;
 | |
|             break;
 | |
|         case PictOpInReverse:
 | |
|             op = PictOpDst;
 | |
|             break;
 | |
|         case PictOpOutReverse:
 | |
|             op = PictOpClear;
 | |
|             break;
 | |
|         case PictOpAtop:
 | |
|             op = PictOpIn;
 | |
|             break;
 | |
|         case PictOpAtopReverse:
 | |
|             op = PictOpOverReverse;
 | |
|             break;
 | |
|         case PictOpXor:
 | |
|             op = PictOpOut;
 | |
|             break;
 | |
|         default:
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* Deal with simplifications when the destination alpha is always 1 */
 | |
|     if (no_dst_alpha) {
 | |
|         switch (op) {
 | |
|         case PictOpOverReverse:
 | |
|             op = PictOpDst;
 | |
|             break;
 | |
|         case PictOpIn:
 | |
|             op = PictOpSrc;
 | |
|             break;
 | |
|         case PictOpOut:
 | |
|             op = PictOpClear;
 | |
|             break;
 | |
|         case PictOpAtop:
 | |
|             op = PictOpOver;
 | |
|             break;
 | |
|         case PictOpXor:
 | |
|             op = PictOpOutReverse;
 | |
|             break;
 | |
|         default:
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* Reduce some con/disjoint ops to the basic names. */
 | |
|     switch (op) {
 | |
|     case PictOpDisjointClear:
 | |
|     case PictOpConjointClear:
 | |
|         op = PictOpClear;
 | |
|         break;
 | |
|     case PictOpDisjointSrc:
 | |
|     case PictOpConjointSrc:
 | |
|         op = PictOpSrc;
 | |
|         break;
 | |
|     case PictOpDisjointDst:
 | |
|     case PictOpConjointDst:
 | |
|         op = PictOpDst;
 | |
|         break;
 | |
|     default:
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     return op;
 | |
| }
 | |
| 
 | |
| void
 | |
| CompositePicture(CARD8 op,
 | |
|                  PicturePtr pSrc,
 | |
|                  PicturePtr pMask,
 | |
|                  PicturePtr pDst,
 | |
|                  INT16 xSrc,
 | |
|                  INT16 ySrc,
 | |
|                  INT16 xMask,
 | |
|                  INT16 yMask,
 | |
|                  INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
 | |
| 
 | |
|     ValidatePicture(pSrc);
 | |
|     if (pMask)
 | |
|         ValidatePicture(pMask);
 | |
|     ValidatePicture(pDst);
 | |
| 
 | |
|     op = ReduceCompositeOp(op, pSrc, pMask, pDst, xSrc, ySrc, width, height);
 | |
|     if (op == PictOpDst)
 | |
|         return;
 | |
| 
 | |
|     (*ps->Composite) (op,
 | |
|                       pSrc,
 | |
|                       pMask,
 | |
|                       pDst,
 | |
|                       xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
 | |
| }
 | |
| 
 | |
| void
 | |
| CompositeRects(CARD8 op,
 | |
|                PicturePtr pDst,
 | |
|                xRenderColor * color, int nRect, xRectangle *rects)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
 | |
| 
 | |
|     ValidatePicture(pDst);
 | |
|     (*ps->CompositeRects) (op, pDst, color, nRect, rects);
 | |
| }
 | |
| 
 | |
| void
 | |
| CompositeTrapezoids(CARD8 op,
 | |
|                     PicturePtr pSrc,
 | |
|                     PicturePtr pDst,
 | |
|                     PictFormatPtr maskFormat,
 | |
|                     INT16 xSrc, INT16 ySrc, int ntrap, xTrapezoid * traps)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
 | |
| 
 | |
|     ValidatePicture(pSrc);
 | |
|     ValidatePicture(pDst);
 | |
|     (*ps->Trapezoids) (op, pSrc, pDst, maskFormat, xSrc, ySrc, ntrap, traps);
 | |
| }
 | |
| 
 | |
| void
 | |
| CompositeTriangles(CARD8 op,
 | |
|                    PicturePtr pSrc,
 | |
|                    PicturePtr pDst,
 | |
|                    PictFormatPtr maskFormat,
 | |
|                    INT16 xSrc,
 | |
|                    INT16 ySrc, int ntriangles, xTriangle * triangles)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
 | |
| 
 | |
|     ValidatePicture(pSrc);
 | |
|     ValidatePicture(pDst);
 | |
|     (*ps->Triangles) (op, pSrc, pDst, maskFormat, xSrc, ySrc, ntriangles,
 | |
|                       triangles);
 | |
| }
 | |
| 
 | |
| void
 | |
| CompositeTriStrip(CARD8 op,
 | |
|                   PicturePtr pSrc,
 | |
|                   PicturePtr pDst,
 | |
|                   PictFormatPtr maskFormat,
 | |
|                   INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
 | |
| 
 | |
|     if (npoints < 3)
 | |
|         return;
 | |
| 
 | |
|     ValidatePicture(pSrc);
 | |
|     ValidatePicture(pDst);
 | |
|     (*ps->TriStrip) (op, pSrc, pDst, maskFormat, xSrc, ySrc, npoints, points);
 | |
| }
 | |
| 
 | |
| void
 | |
| CompositeTriFan(CARD8 op,
 | |
|                 PicturePtr pSrc,
 | |
|                 PicturePtr pDst,
 | |
|                 PictFormatPtr maskFormat,
 | |
|                 INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
 | |
| 
 | |
|     if (npoints < 3)
 | |
|         return;
 | |
| 
 | |
|     ValidatePicture(pSrc);
 | |
|     ValidatePicture(pDst);
 | |
|     (*ps->TriFan) (op, pSrc, pDst, maskFormat, xSrc, ySrc, npoints, points);
 | |
| }
 | |
| 
 | |
| void
 | |
| AddTraps(PicturePtr pPicture, INT16 xOff, INT16 yOff, int ntrap, xTrap * traps)
 | |
| {
 | |
|     PictureScreenPtr ps = GetPictureScreen(pPicture->pDrawable->pScreen);
 | |
| 
 | |
|     ValidatePicture(pPicture);
 | |
|     (*ps->AddTraps) (pPicture, xOff, yOff, ntrap, traps);
 | |
| }
 |