4f58590a42
Tested by naddy@, jsg@ & kettenis@
1701 lines
49 KiB
C
1701 lines
49 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.
|
|
*/
|
|
|
|
#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;
|
|
|
|
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->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 = 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);
|
|
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;
|
|
}
|
|
|
|
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;
|
|
|
|
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((void **) &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((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 = dixLookupResourceByType((void **) &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,
|
|
(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;
|
|
}
|
|
|
|
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((void *) 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(void *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((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);
|
|
}
|