428261197a
Tested by ajacoutot@, krw@, shadchin@ and jasper@ on various configurations including multihead with both zaphod and xrandr.
1818 lines
45 KiB
C
1818 lines
45 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;
|
|
|
|
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->dither = None;
|
|
pPicture->filter = PictureGetFilterId (FilterNearest, -1, TRUE);
|
|
pPicture->filter_params = 0;
|
|
pPicture->filter_nparams = 0;
|
|
|
|
pPicture->serialNumber = GC_CHANGE_SERIAL_BIT;
|
|
pPicture->stateChanges = (1 << (CPLastBit+1)) - 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:
|
|
pPicture->dither = NEXT_VAL(Atom);
|
|
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
|
|
{
|
|
if (pPicture->transform)
|
|
{
|
|
free(pPicture->transform);
|
|
pPicture->transform = 0;
|
|
}
|
|
}
|
|
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:
|
|
pDst->dither = pSrc->dither;
|
|
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);
|
|
}
|
|
|