/* * * 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 <dix-config.h> #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" DevPrivateKeyRec PictureScreenPrivateKeyRec; DevPrivateKeyRec PictureWindowPrivateKeyRec; static int PictureGeneration; RESTYPE PictureType; RESTYPE PictFormatType; RESTYPE GlyphSetType; int PictureCmapPolicy = PictureCmapPolicyDefault; 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 ((pointer) pPicture, pPicture->id); } pScreen->DestroyWindow = ps->DestroyWindow; ret = (*pScreen->DestroyWindow) (pWindow); ps->DestroyWindow = pScreen->DestroyWindow; pScreen->DestroyWindow = PictureDestroyWindow; return ret; } Bool PictureCloseScreen (int index, ScreenPtr pScreen) { PictureScreenPtr ps = GetPictureScreen(pScreen); Bool ret; int n; pScreen->CloseScreen = ps->CloseScreen; ret = (*pScreen->CloseScreen) (index, 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) ((n) == 32 ? 0xffffffff : ((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((pointer *)&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; } 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; 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, (pointer) (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->clientClipType = CT_NONE; 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 = dixAllocateObjectWithPrivates(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 unsigned int premultiply(unsigned int x) { unsigned int a = x >> 24; unsigned int t = (x & 0xff00ff) * a + 0x800080; t = (t + ((t >> 8) & 0xff00ff)) >> 8; t &= 0xff00ff; x = ((x >> 8) & 0xff) * a + 0x80; x = (x + ((x >> 8) & 0xff)); x &= 0xff00; x |= t | (a << 24); return x; } static unsigned int INTERPOLATE_PIXEL_256(unsigned int x, unsigned int a, unsigned int y, unsigned int b) { CARD32 t = (x & 0xff00ff) * a + (y & 0xff00ff) * b; t >>= 8; t &= 0xff00ff; x = ((x >> 8) & 0xff00ff) * a + ((y >> 8) & 0xff00ff) * b; x &= 0xff00ff00; x |= t; return x; } CARD32 PictureGradientColor (PictGradientStopPtr stop1, PictGradientStopPtr stop2, CARD32 x) { CARD32 current_color, next_color; int dist, idist; current_color = xRenderColorToCard32 (stop1->color); next_color = xRenderColorToCard32 (stop2->color); dist = (int) (256 * (x - stop1->x) / (stop2->x - stop1->x)); idist = 256 - dist; return premultiply (INTERPOLATE_PIXEL_256 (current_color, idist, next_color, dist)); } 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]; } pGradient->gradient.class = SourcePictClassUnknown; pGradient->gradient.stopRange = 0xffff; pGradient->gradient.colorTable = NULL; pGradient->gradient.colorTableSize = 0; } static PicturePtr createSourcePicture(void) { PicturePtr pPicture; pPicture = dixAllocateObjectWithPrivates(PictureRec, PRIVATE_PICTURE); 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 < 2) { *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; } #define FixedToDouble(x) ((x)/65536.) 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 < 2) { *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; radial->cdx = (radial->c2.x - radial->c1.x) / 65536.; radial->cdy = (radial->c2.y - radial->c1.y) / 65536.; radial->dr = (radial->c2.radius - radial->c1.radius) / 65536.; radial->A = ( radial->cdx * radial->cdx + radial->cdy * radial->cdy - radial->dr * radial->dr); 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 < 2) { *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; } #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 = dixLookupResourceByType((pointer *)&pAlpha, pid, PictureType, 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 ((pointer) 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 = dixLookupResourceByType((pointer *)&pPixmap, pid, RT_PIXMAP, 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, (pointer)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, (pointer) 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, (pointer) 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; } void CopyPicture (PicturePtr pSrc, Mask mask, PicturePtr pDst) { PictureScreenPtr ps = GetPictureScreen(pSrc->pDrawable->pScreen); Mask origMask = mask; pDst->serialNumber |= GC_CHANGE_SERIAL_BIT; pDst->stateChanges |= mask; while (mask) { Mask bit = lowbit(mask); switch (bit) { case CPRepeat: pDst->repeat = pSrc->repeat; pDst->repeatType = pSrc->repeatType; break; case CPAlphaMap: if (pSrc->alphaMap && pSrc->alphaMap->pDrawable->type == DRAWABLE_PIXMAP) pSrc->alphaMap->refcnt++; if (pDst->alphaMap) FreePicture ((pointer) pDst->alphaMap, (XID) 0); pDst->alphaMap = pSrc->alphaMap; break; case CPAlphaXOrigin: pDst->alphaOrigin.x = pSrc->alphaOrigin.x; break; case CPAlphaYOrigin: pDst->alphaOrigin.y = pSrc->alphaOrigin.y; break; case CPClipXOrigin: pDst->clipOrigin.x = pSrc->clipOrigin.x; break; case CPClipYOrigin: pDst->clipOrigin.y = pSrc->clipOrigin.y; break; case CPClipMask: switch (pSrc->clientClipType) { case CT_NONE: (*ps->ChangePictureClip)(pDst, CT_NONE, NULL, 0); break; case CT_REGION: if (!pSrc->clientClip) { (*ps->ChangePictureClip)(pDst, CT_NONE, NULL, 0); } else { RegionPtr clientClip; RegionPtr srcClientClip = (RegionPtr)pSrc->clientClip; clientClip = RegionCreate( RegionExtents(srcClientClip), RegionNumRects(srcClientClip)); (*ps->ChangePictureClip)(pDst, CT_REGION, clientClip, 0); } break; default: /* XXX: CT_PIXMAP unimplemented */ break; } break; case CPGraphicsExposure: pDst->graphicsExposures = pSrc->graphicsExposures; break; case CPPolyEdge: pDst->polyEdge = pSrc->polyEdge; break; case CPPolyMode: pDst->polyMode = pSrc->polyMode; break; case CPDither: break; case CPComponentAlpha: pDst->componentAlpha = pSrc->componentAlpha; break; } mask &= ~bit; } (*ps->ChangePicture)(pDst, origMask); } 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 (pointer value, XID pid) { PicturePtr pPicture = (PicturePtr) value; if (--pPicture->refcnt == 0) { free(pPicture->transform); 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 ((pointer) 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 (pointer 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); 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); 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); }