/* * * 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. */ #ifdef HAVE_DIX_CONFIG_H #include #endif #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 "colormapst.h" #include "cursorstr.h" #include "dixstruct.h" #include "gcstruct.h" #include "servermd.h" #include "picturestr.h" #include "xace.h" #ifdef PANORAMIX #include "panoramiXsrv.h" #endif 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)); } Bool PictureDestroyWindow(WindowPtr pWindow) { ScreenPtr pScreen = pWindow->drawable.pScreen; PicturePtr pPicture; PictureScreenPtr ps = GetPictureScreen(pScreen); Bool ret; while ((pPicture = GetPictureWindow(pWindow))) { SetPictureWindow(pWindow, pPicture->pNext); if (pPicture->id) FreeResource(pPicture->id, PictureType); FreePicture((void *) pPicture, pPicture->id); } pScreen->DestroyWindow = ps->DestroyWindow; ret = (*pScreen->DestroyWindow) (pWindow); ps->DestroyWindow = pScreen->DestroyWindow; pScreen->DestroyWindow = PictureDestroyWindow; return ret; } Bool PictureCloseScreen(ScreenPtr pScreen) { PictureScreenPtr ps = GetPictureScreen(pScreen); Bool ret; int n; pScreen->CloseScreen = ps->CloseScreen; ret = (*pScreen->CloseScreen) (pScreen); 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); return ret; } 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 int 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 nformat; formats[nformat].format = format; formats[nformat].depth = depth; return ++nformat; } #define Mask(n) ((1 << (n)) - 1) PictFormatPtr PictureCreateDefaultFormats(ScreenPtr pScreen, int *nformatp) { int nformats, 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_FORMAT(BitsPerPixel(4), PICT_TYPE_A, 4, 0, 0, 0); formats[nformats].depth = 4; 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); nformats = addFormat(formats, nformats, format, depth); } break; case StaticColor: case PseudoColor: format = PICT_VISFORMAT(bpp, PICT_TYPE_COLOR, v); nformats = addFormat(formats, nformats, format, depth); break; case StaticGray: case GrayScale: format = PICT_VISFORMAT(bpp, PICT_TYPE_GRAY, v); nformats = 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) { nformats = addFormat(formats, nformats, PICT_x4r4g4b4, pDepth->depth); nformats = addFormat(formats, nformats, PICT_x4b4g4r4, pDepth->depth); } /* depth 15 formats */ if (pDepth->depth >= 15) { nformats = addFormat(formats, nformats, PICT_x1r5g5b5, pDepth->depth); nformats = addFormat(formats, nformats, PICT_x1b5g5r5, pDepth->depth); } /* depth 16 formats */ if (pDepth->depth >= 16) { nformats = addFormat(formats, nformats, PICT_a1r5g5b5, pDepth->depth); nformats = addFormat(formats, nformats, PICT_a1b5g5r5, pDepth->depth); nformats = addFormat(formats, nformats, PICT_r5g6b5, pDepth->depth); nformats = addFormat(formats, nformats, PICT_b5g6r5, pDepth->depth); nformats = addFormat(formats, nformats, PICT_a4r4g4b4, pDepth->depth); nformats = addFormat(formats, nformats, PICT_a4b4g4r4, pDepth->depth); } break; case 24: if (pDepth->depth >= 24) { nformats = addFormat(formats, nformats, PICT_r8g8b8, pDepth->depth); nformats = addFormat(formats, nformats, PICT_b8g8r8, pDepth->depth); } break; case 32: if (pDepth->depth >= 24) { nformats = addFormat(formats, nformats, PICT_x8r8g8b8, pDepth->depth); nformats = addFormat(formats, nformats, PICT_x8b8g8r8, pDepth->depth); } if (pDepth->depth >= 30) { nformats = addFormat(formats, nformats, PICT_a2r10g10b10, pDepth->depth); nformats = addFormat(formats, nformats, PICT_x2r10g10b10, pDepth->depth); nformats = addFormat(formats, nformats, PICT_a2b10g10r10, pDepth->depth); nformats = 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; } 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, RT_COLORMAP, serverClient, DixGetAttrAccess); } else { VisualPtr pVisual = PictureFindVisual(pScreen, format->index.vid); if (CreateColormap(FakeClientID(0), pScreen, pVisual, &format->index.pColormap, AllocNone, 0) != 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 (format->direct.redMask << format->direct.red == pVisual->redMask && format->direct.greenMask << format->direct.green == pVisual->greenMask && 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(RT_PIXMAP); ResourceSizeRec pixmapSize = { 0, 0, 0 }; PixmapPtr pixmap = (PixmapPtr)picture->pDrawable; pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize); size->pixmapRefSize += pixmapSize.pixmapRefSize; } } Bool PictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats) { PictureScreenPtr ps; 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))) { 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); } ps = (PictureScreenPtr) malloc(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->CloseScreen = pScreen->CloseScreen; ps->DestroyWindow = pScreen->DestroyWindow; ps->StoreColors = pScreen->StoreColors; pScreen->DestroyWindow = PictureDestroyWindow; pScreen->CloseScreen = PictureCloseScreen; pScreen->StoreColors = PictureStoreColors; if (!PictureSetDefaultFilters(pScreen)) { PictureResetFilters(pScreen); SetPictureScreen(pScreen, 0); free(formats); free(ps); return FALSE; } return TRUE; } 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 = XaceHook(XACE_RESOURCE_ACCESS, client, pid, PictureType, pPicture, RT_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 (c.alpha >> 8 << 24) | (c.red >> 8 << 16) | (c.green & 0xff00) | (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 = malloc(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 = (SourcePictPtr) malloc(sizeof(PictSolidFill)); if (!pPicture->pSourcePict) { *error = BadAlloc; free(pPicture); return 0; } pPicture->pSourcePict->type = SourcePictTypeSolidFill; pPicture->pSourcePict->solidFill.color = xRenderColorToCard32(*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 = (SourcePictPtr) malloc(sizeof(PictLinearGradient)); 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 = (SourcePictPtr) malloc(sizeof(PictRadialGradient)); 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 = (SourcePictPtr) malloc(sizeof(PictConicalGradient)); 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 PANORAMIX if (!noPanoramiXExtension) { PanoramiXRes *res; int err = dixLookupResourceByType((void **)&res, id, XRT_PICTURE, client, mode); if (err != Success) return err; id = res->info[screen->myNum].id; } #endif return dixLookupResourceByType(result, id, PictureType, client, mode); } static int cpClipMask(void **result, XID id, ScreenPtr screen, ClientPtr client, Mask mode) { #ifdef PANORAMIX 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 return dixLookupResourceByType(result, id, RT_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 = (PictTransform *) malloc(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) { (*pScreen->DestroyPixmap) ((PixmapPtr) pPicture->pDrawable); } } dixFreeObjectWithPrivates(pPicture, PRIVATE_PICTURE); } return Success; } int FreePictFormat(void *pPictFormat, XID pid) { 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); }