1847 lines
50 KiB
C
1847 lines
50 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"
|
||
|
|
||
|
_X_EXPORT int PictureScreenPrivateIndex = -1;
|
||
|
|
||
|
int PictureWindowPrivateIndex;
|
||
|
|
||
|
int PictureGeneration;
|
||
|
|
||
|
RESTYPE PictureType;
|
||
|
|
||
|
RESTYPE PictFormatType;
|
||
|
|
||
|
RESTYPE GlyphSetType;
|
||
|
|
||
|
int PictureCmapPolicy = PictureCmapPolicyDefault;
|
||
|
|
||
|
/* Picture Private machinery */
|
||
|
|
||
|
static int picturePrivateCount;
|
||
|
|
||
|
void
|
||
|
ResetPicturePrivateIndex(void)
|
||
|
{
|
||
|
picturePrivateCount = 0;
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
if (ps->PicturePrivateSizes)
|
||
|
free(ps->PicturePrivateSizes);
|
||
|
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++;
|
||
|
|
||
|
/* 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 two direct formats,
|
||
|
* fields must be packed together at the bottom of the pixel
|
||
|
* and must be either RGB or BGR
|
||
|
*/
|
||
|
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;
|
||
|
}
|
||
|
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);
|
||
|
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);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pFormats = malloc(nformats * sizeof(PictFormatRec));
|
||
|
if (!pFormats)
|
||
|
return 0;
|
||
|
memset(pFormats, '\0', nformats * sizeof(PictFormatRec));
|
||
|
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_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
|
||
|
PictureInitIndexedFormats(ScreenPtr pScreen)
|
||
|
{
|
||
|
PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
|
||
|
|
||
|
PictFormatPtr format;
|
||
|
|
||
|
int nformat;
|
||
|
|
||
|
if (!ps)
|
||
|
return FALSE;
|
||
|
format = ps->formats;
|
||
|
nformat = ps->nformats;
|
||
|
while (nformat--) {
|
||
|
if (format->type == PictTypeIndexed && !format->index.pColormap) {
|
||
|
if (format->index.vid == pScreen->rootVisual)
|
||
|
format->index.pColormap =
|
||
|
(ColormapPtr) LookupIDByType(pScreen->defColormap,
|
||
|
RT_COLORMAP);
|
||
|
else {
|
||
|
VisualPtr pVisual;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
format++;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
Bool
|
||
|
PictureFinishInit(void)
|
||
|
{
|
||
|
int s;
|
||
|
|
||
|
for (s = 0; s < screenInfo.numScreens; s++) {
|
||
|
if (!GlyphFinishInit(screenInfo.screens[s]))
|
||
|
return FALSE;
|
||
|
if (!PictureInitIndexedFormats(screenInfo.screens[s]))
|
||
|
return FALSE;
|
||
|
(void) AnimCurInit(screenInfo.screens[s]);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT Bool
|
||
|
PictureSetSubpixelOrder(ScreenPtr pScreen, int subpixel)
|
||
|
{
|
||
|
PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
|
||
|
|
||
|
if (!ps)
|
||
|
return FALSE;
|
||
|
ps->subpixel = subpixel;
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
_X_EXPORT 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;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT Bool
|
||
|
PictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
|
||
|
{
|
||
|
PictureScreenPtr ps;
|
||
|
|
||
|
int n;
|
||
|
|
||
|
CARD32 type, a, r, g, b;
|
||
|
|
||
|
if (PictureGeneration != serverGeneration) {
|
||
|
PictureType = CreateNewResourceType(FreePicture);
|
||
|
if (!PictureType)
|
||
|
return FALSE;
|
||
|
PictFormatType = CreateNewResourceType(FreePictFormat);
|
||
|
if (!PictFormatType)
|
||
|
return FALSE;
|
||
|
GlyphSetType = CreateNewResourceType(FreeGlyphSet);
|
||
|
if (!GlyphSetType)
|
||
|
return FALSE;
|
||
|
PictureScreenPrivateIndex = AllocateScreenPrivateIndex();
|
||
|
if (PictureScreenPrivateIndex < 0)
|
||
|
return FALSE;
|
||
|
PictureWindowPrivateIndex = AllocateWindowPrivateIndex();
|
||
|
PictureGeneration = serverGeneration;
|
||
|
#ifdef XResExtension
|
||
|
RegisterResourceName(PictureType, "PICTURE");
|
||
|
RegisterResourceName(PictFormatType, "PICTFORMAT");
|
||
|
RegisterResourceName(GlyphSetType, "GLYPHSET");
|
||
|
#endif
|
||
|
}
|
||
|
if (!AllocateWindowPrivate(pScreen, PictureWindowPrivateIndex, 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
|
||
|
type = PICT_TYPE_ABGR;
|
||
|
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 = malloc(sizeof(PictureScreenRec));
|
||
|
if (!ps) {
|
||
|
free(formats);
|
||
|
return FALSE;
|
||
|
}
|
||
|
SetPictureScreen(pScreen, ps);
|
||
|
if (!GlyphInit(pScreen)) {
|
||
|
SetPictureScreen(pScreen, 0);
|
||
|
free(formats);
|
||
|
free(ps);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
ps->totalPictureSize = sizeof(PictureRec);
|
||
|
ps->PicturePrivateSizes = 0;
|
||
|
ps->PicturePrivateLen = 0;
|
||
|
|
||
|
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
|
||
|
AllocatePicture(ScreenPtr pScreen)
|
||
|
{
|
||
|
PictureScreenPtr ps = GetPictureScreen(pScreen);
|
||
|
|
||
|
PicturePtr pPicture;
|
||
|
|
||
|
char *ptr;
|
||
|
|
||
|
DevUnion *ppriv;
|
||
|
|
||
|
unsigned int *sizes;
|
||
|
|
||
|
unsigned int size;
|
||
|
|
||
|
int i;
|
||
|
|
||
|
pPicture = malloc(ps->totalPictureSize);
|
||
|
if (!pPicture)
|
||
|
return 0;
|
||
|
ppriv = (DevUnion *) (pPicture + 1);
|
||
|
pPicture->devPrivates = ppriv;
|
||
|
sizes = ps->PicturePrivateSizes;
|
||
|
ptr = (char *) (ppriv + ps->PicturePrivateLen);
|
||
|
for (i = ps->PicturePrivateLen; --i >= 0; ppriv++, sizes++) {
|
||
|
if ((size = *sizes)) {
|
||
|
ppriv->ptr = (pointer) ptr;
|
||
|
ptr += size;
|
||
|
}
|
||
|
else
|
||
|
ppriv->ptr = (pointer) NULL;
|
||
|
}
|
||
|
return pPicture;
|
||
|
}
|
||
|
|
||
|
PicturePtr
|
||
|
CreatePicture(Picture pid,
|
||
|
DrawablePtr pDrawable,
|
||
|
PictFormatPtr pFormat,
|
||
|
Mask vmask, XID *vlist, ClientPtr client, int *error)
|
||
|
{
|
||
|
PicturePtr pPicture;
|
||
|
|
||
|
PictureScreenPtr ps = GetPictureScreen(pDrawable->pScreen);
|
||
|
|
||
|
pPicture = AllocatePicture(pDrawable->pScreen);
|
||
|
if (!pPicture) {
|
||
|
*error = BadAlloc;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
pPicture->id = pid;
|
||
|
pPicture->pDrawable = pDrawable;
|
||
|
pPicture->pFormat = pFormat;
|
||
|
pPicture->format = pFormat->format | (pDrawable->bitsPerPixel << 24);
|
||
|
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);
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
initGradientColorTable(SourcePictPtr pGradient, int *error)
|
||
|
{
|
||
|
int begin_pos, end_pos;
|
||
|
|
||
|
xFixed incr, dpos;
|
||
|
|
||
|
int pos, current_stop;
|
||
|
|
||
|
PictGradientStopPtr stops = pGradient->linear.stops;
|
||
|
|
||
|
int nstops = pGradient->linear.nstops;
|
||
|
|
||
|
/* The position where the gradient begins and ends */
|
||
|
begin_pos = (stops[0].x * PICT_GRADIENT_STOPTABLE_SIZE) >> 16;
|
||
|
end_pos = (stops[nstops - 1].x * PICT_GRADIENT_STOPTABLE_SIZE) >> 16;
|
||
|
|
||
|
pos = 0; /* The position in the color table. */
|
||
|
|
||
|
/* Up to first point */
|
||
|
while (pos <= begin_pos) {
|
||
|
pGradient->linear.colorTable[pos] =
|
||
|
xRenderColorToCard32(stops[0].color);
|
||
|
++pos;
|
||
|
}
|
||
|
|
||
|
incr = (1 << 16) / PICT_GRADIENT_STOPTABLE_SIZE; /* the double increment. */
|
||
|
dpos = incr * pos; /* The position in terms of 0-1. */
|
||
|
|
||
|
current_stop = 0; /* We always interpolate between current and current + 1. */
|
||
|
|
||
|
/* Gradient area */
|
||
|
while (pos < end_pos) {
|
||
|
unsigned int current_color =
|
||
|
xRenderColorToCard32(stops[current_stop].color);
|
||
|
unsigned int next_color =
|
||
|
xRenderColorToCard32(stops[current_stop + 1].color);
|
||
|
|
||
|
int dist = (int) (256 * (dpos - stops[current_stop].x)
|
||
|
/ (stops[current_stop + 1].x -
|
||
|
stops[current_stop].x));
|
||
|
int idist = 256 - dist;
|
||
|
|
||
|
pGradient->linear.colorTable[pos] =
|
||
|
premultiply(INTERPOLATE_PIXEL_256
|
||
|
(current_color, idist, next_color, dist));
|
||
|
|
||
|
++pos;
|
||
|
dpos += incr;
|
||
|
|
||
|
if (dpos > stops[current_stop + 1].x)
|
||
|
++current_stop;
|
||
|
}
|
||
|
|
||
|
/* After last point */
|
||
|
while (pos < PICT_GRADIENT_STOPTABLE_SIZE) {
|
||
|
pGradient->linear.colorTable[pos] =
|
||
|
xRenderColorToCard32(stops[nstops - 1].color);
|
||
|
++pos;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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->linear.stops = malloc(stopCount * sizeof(PictGradientStop));
|
||
|
if (!pGradient->linear.stops) {
|
||
|
*error = BadAlloc;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pGradient->linear.nstops = stopCount;
|
||
|
|
||
|
for (i = 0; i < stopCount; ++i) {
|
||
|
pGradient->linear.stops[i].x = stopPoints[i];
|
||
|
pGradient->linear.stops[i].color = stopColors[i];
|
||
|
}
|
||
|
initGradientColorTable(pGradient, error);
|
||
|
}
|
||
|
|
||
|
static PicturePtr
|
||
|
createSourcePicture(void)
|
||
|
{
|
||
|
PicturePtr pPicture;
|
||
|
|
||
|
pPicture = malloc(sizeof(PictureRec));
|
||
|
pPicture->pDrawable = 0;
|
||
|
pPicture->format = PICT_a8r8g8b8;
|
||
|
pPicture->pFormat = 0;
|
||
|
pPicture->pNext = 0;
|
||
|
pPicture->devPrivates = 0;
|
||
|
|
||
|
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 = 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;
|
||
|
}
|
||
|
if (p1->x == p2->x && p1->y == p2->y) {
|
||
|
*error = BadValue;
|
||
|
free(pPicture);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
pPicture->id = pid;
|
||
|
pPicture->pSourcePict = 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;
|
||
|
}
|
||
|
{
|
||
|
double dx = (double) (inner->x - outer->x);
|
||
|
|
||
|
double dy = (double) (inner->y - outer->y);
|
||
|
|
||
|
if (sqrt(dx * dx + dy * dy) + (double) (innerRadius) >
|
||
|
(double) (outerRadius)) {
|
||
|
*error = BadValue;
|
||
|
free(pPicture);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pPicture->id = pid;
|
||
|
pPicture->pSourcePict = malloc(sizeof(PictRadialGradient));
|
||
|
if (!pPicture->pSourcePict) {
|
||
|
*error = BadAlloc;
|
||
|
free(pPicture);
|
||
|
return 0;
|
||
|
}
|
||
|
radial = &pPicture->pSourcePict->radial;
|
||
|
|
||
|
radial->type = SourcePictTypeRadial;
|
||
|
{
|
||
|
double x = (double) innerRadius / (double) outerRadius;
|
||
|
|
||
|
radial->dx = (outer->x - inner->x);
|
||
|
radial->dy = (outer->y - inner->y);
|
||
|
radial->fx = (inner->x) - x * radial->dx;
|
||
|
radial->fy = (inner->y) - x * radial->dy;
|
||
|
radial->m = 1. / (1 + x);
|
||
|
radial->b = -x * radial->m;
|
||
|
radial->dx /= 65536.;
|
||
|
radial->dy /= 65536.;
|
||
|
radial->fx /= 65536.;
|
||
|
radial->fy /= 65536.;
|
||
|
x = outerRadius / 65536.;
|
||
|
radial->a = x * x - radial->dx * radial->dx - radial->dy * radial->dy;
|
||
|
}
|
||
|
|
||
|
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 = 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) {
|
||
|