mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-02-16 22:30:30 +01:00
The previous implementation fell apart quite badly when neither radius value was equal to 0.0. I derived the math from scratch, (much thanks to Vincent Torri <vtorri@univ-evry.fr> for guiding me to a simpler derivation than I was doing originally), and it's working much better now without being any slower, (in fact, cairo-perf shows speedup of 1.05x to 1.58x on my laptop here). This work also provides groundwork for defining the behavior of radial gradients where neither circle is wholly contained within the other, (though we haven't done that definition yet---it will require a new test case and a very little bit of work on the implementation). This is a fix for the following bug report: Radial Gradients with nonzero inner radius misplace stops https://bugs.freedesktop.org/show_bug.cgi?id=7685
937 lines
21 KiB
C
937 lines
21 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.
|
|
*/
|
|
|
|
#include "pixman-xserver-compat.h"
|
|
|
|
pixman_image_t *
|
|
pixman_image_create (pixman_format_t *format,
|
|
int width,
|
|
int height)
|
|
{
|
|
pixman_image_t *image;
|
|
FbPixels *pixels;
|
|
|
|
pixels = FbPixelsCreate (width, height, format->depth);
|
|
if (pixels == NULL)
|
|
return NULL;
|
|
|
|
image = pixman_image_createForPixels (pixels, format);
|
|
if (image == NULL) {
|
|
FbPixelsDestroy (pixels);
|
|
return NULL;
|
|
}
|
|
|
|
image->owns_pixels = 1;
|
|
|
|
return image;
|
|
}
|
|
|
|
pixman_image_t *
|
|
pixman_image_create_for_data (FbBits *data, pixman_format_t *format, int width, int height, int bpp, int stride)
|
|
{
|
|
pixman_image_t *image;
|
|
FbPixels *pixels;
|
|
|
|
pixels = FbPixelsCreateForData (data, width, height, format->depth, bpp, stride);
|
|
if (pixels == NULL)
|
|
return NULL;
|
|
|
|
image = pixman_image_createForPixels (pixels, format);
|
|
if (image == NULL) {
|
|
FbPixelsDestroy (pixels);
|
|
return NULL;
|
|
}
|
|
|
|
image->owns_pixels = 1;
|
|
|
|
return image;
|
|
}
|
|
|
|
pixman_image_t *
|
|
pixman_image_createForPixels (FbPixels *pixels,
|
|
pixman_format_t *format)
|
|
{
|
|
pixman_image_t *image;
|
|
|
|
image = malloc (sizeof (pixman_image_t));
|
|
if (!image)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
image->pixels = pixels;
|
|
image->image_format = *format;
|
|
image->format_code = format->format_code;
|
|
/* XXX: What's all this about?
|
|
if (pDrawable->type == DRAWABLE_PIXMAP)
|
|
{
|
|
++((PixmapPtr)pDrawable)->refcnt;
|
|
image->pNext = 0;
|
|
}
|
|
else
|
|
{
|
|
image->pNext = GetPictureWindow(((WindowPtr) pDrawable));
|
|
SetPictureWindow(((WindowPtr) pDrawable), image);
|
|
}
|
|
*/
|
|
|
|
pixman_image_init (image);
|
|
|
|
return image;
|
|
}
|
|
|
|
static CARD32 xRenderColorToCard32(pixman_color_t c)
|
|
{
|
|
return
|
|
(c.alpha >> 8 << 24) |
|
|
(c.red >> 8 << 16) |
|
|
(c.green & 0xff00) |
|
|
(c.blue >> 8);
|
|
}
|
|
|
|
static uint32_t premultiply(uint32_t x)
|
|
{
|
|
uint32_t a = x >> 24;
|
|
uint32_t 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 uint32_t INTERPOLATE_PIXEL_256(uint32_t x, uint32_t a, uint32_t y, uint32_t 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;
|
|
}
|
|
|
|
uint32_t
|
|
pixman_gradient_color (pixman_gradient_stop_t *stop1,
|
|
pixman_gradient_stop_t *stop2,
|
|
uint32_t x)
|
|
{
|
|
uint32_t 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 int
|
|
_pixman_init_gradient (pixman_gradient_image_t *gradient,
|
|
const pixman_gradient_stop_t *stops,
|
|
int n_stops)
|
|
{
|
|
pixman_fixed16_16_t dpos;
|
|
int i;
|
|
|
|
if (n_stops <= 0)
|
|
return 1;
|
|
|
|
dpos = -1;
|
|
for (i = 0; i < n_stops; i++)
|
|
{
|
|
if (stops[i].x < dpos || stops[i].x > (1 << 16))
|
|
return 1;
|
|
|
|
dpos = stops[i].x;
|
|
}
|
|
|
|
gradient->class = SourcePictClassUnknown;
|
|
gradient->stopRange = 0xffff;
|
|
gradient->colorTable = NULL;
|
|
gradient->colorTableSize = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static pixman_image_t *
|
|
_pixman_create_source_image (void)
|
|
{
|
|
pixman_image_t *image;
|
|
|
|
image = (pixman_image_t *) malloc (sizeof (pixman_image_t));
|
|
image->pDrawable = NULL;
|
|
image->pixels = NULL;
|
|
image->format_code = PICT_a8r8g8b8;
|
|
|
|
pixman_image_init (image);
|
|
|
|
return image;
|
|
}
|
|
|
|
pixman_image_t *
|
|
pixman_image_create_linear_gradient (const pixman_linear_gradient_t *gradient,
|
|
const pixman_gradient_stop_t *stops,
|
|
int n_stops)
|
|
{
|
|
pixman_linear_gradient_image_t *linear;
|
|
pixman_image_t *image;
|
|
|
|
if (n_stops < 2)
|
|
return NULL;
|
|
|
|
image = _pixman_create_source_image ();
|
|
if (!image)
|
|
return NULL;
|
|
|
|
linear = malloc (sizeof (pixman_linear_gradient_image_t) +
|
|
sizeof (pixman_gradient_stop_t) * n_stops);
|
|
if (!linear)
|
|
{
|
|
free (image);
|
|
return NULL;
|
|
}
|
|
|
|
linear->stops = (pixman_gradient_stop_t *) (linear + 1);
|
|
linear->nstops = n_stops;
|
|
|
|
memcpy (linear->stops, stops, sizeof (pixman_gradient_stop_t) * n_stops);
|
|
|
|
linear->type = SourcePictTypeLinear;
|
|
linear->p1 = gradient->p1;
|
|
linear->p2 = gradient->p2;
|
|
|
|
image->pSourcePict = (pixman_source_image_t *) linear;
|
|
|
|
if (_pixman_init_gradient (&image->pSourcePict->gradient, stops, n_stops))
|
|
{
|
|
free (linear);
|
|
free (image);
|
|
return NULL;
|
|
}
|
|
|
|
return image;
|
|
}
|
|
|
|
pixman_image_t *
|
|
pixman_image_create_radial_gradient (const pixman_radial_gradient_t *gradient,
|
|
const pixman_gradient_stop_t *stops,
|
|
int n_stops)
|
|
{
|
|
pixman_radial_gradient_image_t *radial;
|
|
pixman_image_t *image;
|
|
|
|
if (n_stops < 2)
|
|
return NULL;
|
|
|
|
image = _pixman_create_source_image ();
|
|
if (!image)
|
|
return NULL;
|
|
|
|
radial = malloc (sizeof (pixman_radial_gradient_image_t) +
|
|
sizeof (pixman_gradient_stop_t) * n_stops);
|
|
if (!radial)
|
|
{
|
|
free (image);
|
|
return NULL;
|
|
}
|
|
|
|
radial->stops = (pixman_gradient_stop_t *) (radial + 1);
|
|
radial->nstops = n_stops;
|
|
|
|
memcpy (radial->stops, stops, sizeof (pixman_gradient_stop_t) * n_stops);
|
|
|
|
radial->type = SourcePictTypeRadial;
|
|
radial->c1 = gradient->c1;
|
|
radial->c2 = gradient->c2;
|
|
radial->cdx = xFixedToDouble (gradient->c2.x - gradient->c1.x);
|
|
radial->cdy = xFixedToDouble (gradient->c2.y - gradient->c1.y);
|
|
radial->dr = xFixedToDouble (gradient->c2.radius - gradient->c1.radius);
|
|
radial->A = ( radial->cdx * radial->cdx
|
|
+ radial->cdy * radial->cdy
|
|
- radial->dr * radial->dr);
|
|
|
|
image->pSourcePict = (pixman_source_image_t *) radial;
|
|
|
|
if (_pixman_init_gradient (&image->pSourcePict->gradient, stops, n_stops))
|
|
{
|
|
free (radial);
|
|
free (image);
|
|
return NULL;
|
|
}
|
|
|
|
return image;
|
|
}
|
|
|
|
void
|
|
pixman_image_init (pixman_image_t *image)
|
|
{
|
|
image->refcnt = 1;
|
|
image->repeat = PIXMAN_REPEAT_NONE;
|
|
image->graphicsExposures = 0;
|
|
image->subWindowMode = ClipByChildren;
|
|
image->polyEdge = PolyEdgeSharp;
|
|
image->polyMode = PolyModePrecise;
|
|
/*
|
|
* In the server this was 0 because the composite clip list
|
|
* can be referenced from a window (and often is)
|
|
*/
|
|
image->freeCompClip = 0;
|
|
image->freeSourceClip = 0;
|
|
image->clientClipType = CT_NONE;
|
|
image->componentAlpha = 0;
|
|
image->compositeClipSource = 0;
|
|
|
|
image->alphaMap = NULL;
|
|
image->alphaOrigin.x = 0;
|
|
image->alphaOrigin.y = 0;
|
|
|
|
image->clipOrigin.x = 0;
|
|
image->clipOrigin.y = 0;
|
|
image->clientClip = NULL;
|
|
|
|
image->dither = 0L;
|
|
|
|
image->stateChanges = (1 << (CPLastBit+1)) - 1;
|
|
/* XXX: What to lodge here?
|
|
image->serialNumber = GC_CHANGE_SERIAL_BIT;
|
|
*/
|
|
|
|
if (image->pixels)
|
|
{
|
|
image->pCompositeClip = pixman_region_create();
|
|
pixman_region_union_rect (image->pCompositeClip, image->pCompositeClip,
|
|
0, 0, image->pixels->width,
|
|
image->pixels->height);
|
|
image->freeCompClip = 1;
|
|
|
|
image->pSourceClip = pixman_region_create ();
|
|
pixman_region_union_rect (image->pSourceClip, image->pSourceClip,
|
|
0, 0, image->pixels->width,
|
|
image->pixels->height);
|
|
image->freeSourceClip = 1;
|
|
}
|
|
else
|
|
{
|
|
image->pCompositeClip = NULL;
|
|
image->pSourceClip = NULL;
|
|
}
|
|
|
|
image->transform = NULL;
|
|
|
|
image->filter = PIXMAN_FILTER_NEAREST;
|
|
image->filter_params = NULL;
|
|
image->filter_nparams = 0;
|
|
|
|
image->owns_pixels = 0;
|
|
|
|
image->pSourcePict = NULL;
|
|
}
|
|
|
|
void
|
|
pixman_image_set_component_alpha (pixman_image_t *image,
|
|
int component_alpha)
|
|
{
|
|
if (image)
|
|
image->componentAlpha = component_alpha;
|
|
}
|
|
|
|
int
|
|
pixman_image_set_transform (pixman_image_t *image,
|
|
pixman_transform_t *transform)
|
|
{
|
|
static const pixman_transform_t identity = { {
|
|
{ xFixed1, 0x00000, 0x00000 },
|
|
{ 0x00000, xFixed1, 0x00000 },
|
|
{ 0x00000, 0x00000, xFixed1 },
|
|
} };
|
|
|
|
if (transform && memcmp (transform, &identity, sizeof (pixman_transform_t)) == 0)
|
|
transform = NULL;
|
|
|
|
if (transform)
|
|
{
|
|
if (!image->transform)
|
|
{
|
|
image->transform = malloc (sizeof (pixman_transform_t));
|
|
if (!image->transform)
|
|
return 1;
|
|
}
|
|
*image->transform = *transform;
|
|
}
|
|
else
|
|
{
|
|
if (image->transform)
|
|
{
|
|
free (image->transform);
|
|
image->transform = NULL;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
pixman_image_set_repeat (pixman_image_t *image,
|
|
pixman_repeat_t repeat)
|
|
{
|
|
if (image)
|
|
image->repeat = repeat;
|
|
}
|
|
|
|
void
|
|
pixman_image_set_filter (pixman_image_t *image,
|
|
pixman_filter_t filter)
|
|
{
|
|
if (image)
|
|
image->filter = filter;
|
|
}
|
|
|
|
int
|
|
pixman_image_get_width (pixman_image_t *image)
|
|
{
|
|
if (image->pixels)
|
|
return image->pixels->width;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pixman_image_get_height (pixman_image_t *image)
|
|
{
|
|
if (image->pixels)
|
|
return image->pixels->height;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pixman_image_get_depth (pixman_image_t *image)
|
|
{
|
|
if (image->pixels)
|
|
return image->pixels->depth;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pixman_image_get_stride (pixman_image_t *image)
|
|
{
|
|
if (image->pixels)
|
|
return image->pixels->stride;
|
|
|
|
return 0;
|
|
}
|
|
|
|
pixman_format_t *
|
|
pixman_image_get_format (pixman_image_t *image)
|
|
{
|
|
return &image->image_format;
|
|
}
|
|
|
|
FbBits *
|
|
pixman_image_get_data (pixman_image_t *image)
|
|
{
|
|
if (image->pixels)
|
|
return image->pixels->data;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
pixman_image_destroy (pixman_image_t *image)
|
|
{
|
|
pixman_image_destroyClip (image);
|
|
|
|
if (image->freeCompClip) {
|
|
pixman_region_destroy (image->pCompositeClip);
|
|
image->pCompositeClip = NULL;
|
|
}
|
|
|
|
if (image->freeSourceClip) {
|
|
pixman_region_destroy (image->pSourceClip);
|
|
image->pSourceClip = NULL;
|
|
}
|
|
|
|
if (image->owns_pixels) {
|
|
FbPixelsDestroy (image->pixels);
|
|
image->pixels = NULL;
|
|
}
|
|
|
|
if (image->transform) {
|
|
free (image->transform);
|
|
image->transform = NULL;
|
|
}
|
|
|
|
if (image->pSourcePict) {
|
|
free (image->pSourcePict);
|
|
image->pSourcePict = NULL;
|
|
}
|
|
|
|
free (image);
|
|
}
|
|
|
|
void
|
|
pixman_image_destroyClip (pixman_image_t *image)
|
|
{
|
|
switch (image->clientClipType) {
|
|
case CT_NONE:
|
|
return;
|
|
case CT_PIXMAP:
|
|
pixman_image_destroy (image->clientClip);
|
|
break;
|
|
default:
|
|
pixman_region_destroy (image->clientClip);
|
|
break;
|
|
}
|
|
image->clientClip = NULL;
|
|
image->clientClipType = CT_NONE;
|
|
}
|
|
|
|
int
|
|
pixman_image_set_clip_region (pixman_image_t *image,
|
|
pixman_region16_t *region)
|
|
{
|
|
pixman_image_destroyClip (image);
|
|
if (region) {
|
|
image->clientClip = pixman_region_create ();
|
|
pixman_region_copy (image->clientClip, region);
|
|
image->clientClipType = CT_REGION;
|
|
}
|
|
|
|
image->stateChanges |= CPClipMask;
|
|
if (image->pSourcePict)
|
|
return 0;
|
|
|
|
if (image->freeCompClip)
|
|
pixman_region_destroy (image->pCompositeClip);
|
|
image->pCompositeClip = pixman_region_create();
|
|
pixman_region_union_rect (image->pCompositeClip, image->pCompositeClip,
|
|
0, 0, image->pixels->width, image->pixels->height);
|
|
image->freeCompClip = 1;
|
|
if (region) {
|
|
pixman_region_translate (image->pCompositeClip,
|
|
- image->clipOrigin.x,
|
|
- image->clipOrigin.y);
|
|
pixman_region_intersect (image->pCompositeClip,
|
|
image->pCompositeClip,
|
|
region);
|
|
pixman_region_translate (image->pCompositeClip,
|
|
image->clipOrigin.x,
|
|
image->clipOrigin.y);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define BOUND(v) (int16_t) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v))
|
|
|
|
static __inline int
|
|
FbClipImageReg (pixman_region16_t *region,
|
|
pixman_region16_t *clip,
|
|
int dx,
|
|
int dy)
|
|
{
|
|
if (pixman_region_num_rects (region) == 1 &&
|
|
pixman_region_num_rects (clip) == 1)
|
|
{
|
|
pixman_box16_t *pRbox = pixman_region_rects (region);
|
|
pixman_box16_t *pCbox = pixman_region_rects (clip);
|
|
int v;
|
|
|
|
if (pRbox->x1 < (v = pCbox->x1 + dx))
|
|
pRbox->x1 = BOUND(v);
|
|
if (pRbox->x2 > (v = pCbox->x2 + dx))
|
|
pRbox->x2 = BOUND(v);
|
|
if (pRbox->y1 < (v = pCbox->y1 + dy))
|
|
pRbox->y1 = BOUND(v);
|
|
if (pRbox->y2 > (v = pCbox->y2 + dy))
|
|
pRbox->y2 = BOUND(v);
|
|
if (pRbox->x1 >= pRbox->x2 ||
|
|
pRbox->y1 >= pRbox->y2)
|
|
{
|
|
pixman_region_empty (region);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pixman_region_translate (region, dx, dy);
|
|
pixman_region_intersect (region, clip, region);
|
|
pixman_region_translate (region, -dx, -dy);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static __inline int
|
|
FbClipImageSrc (pixman_region16_t *region,
|
|
pixman_image_t *image,
|
|
int dx,
|
|
int dy)
|
|
{
|
|
/* XXX what to do with clipping from transformed pictures? */
|
|
if (image->transform)
|
|
return 1;
|
|
/* XXX davidr hates this, wants to never use source-based clipping */
|
|
if (image->repeat != PIXMAN_REPEAT_NONE || image->pSourcePict)
|
|
{
|
|
/* XXX no source clipping */
|
|
if (image->compositeClipSource &&
|
|
image->clientClipType != CT_NONE)
|
|
{
|
|
pixman_region_translate (region,
|
|
dx - image->clipOrigin.x,
|
|
dy - image->clipOrigin.y);
|
|
pixman_region_intersect (region, image->clientClip, region);
|
|
pixman_region_translate (region,
|
|
- (dx - image->clipOrigin.x),
|
|
- (dy - image->clipOrigin.y));
|
|
}
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
pixman_region16_t *clip;
|
|
|
|
if (image->compositeClipSource)
|
|
clip = image->pCompositeClip;
|
|
else
|
|
clip = image->pSourceClip;
|
|
return FbClipImageReg (region,
|
|
clip,
|
|
dx,
|
|
dy);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* XXX: Need to decide what to do with this
|
|
#define NEXT_VAL(_type) (vlist ? (_type) *vlist++ : (_type) ulist++->val)
|
|
|
|
#define NEXT_PTR(_type) ((_type) ulist++->ptr)
|
|
|
|
int
|
|
pixman_image_change (pixman_image_t *image,
|
|
Mask vmask,
|
|
unsigned int *vlist,
|
|
DevUnion *ulist,
|
|
int *error_value)
|
|
{
|
|
BITS32 index2;
|
|
int error = 0;
|
|
BITS32 maskQ;
|
|
|
|
maskQ = vmask;
|
|
while (vmask && !error)
|
|
{
|
|
index2 = (BITS32) lowbit (vmask);
|
|
vmask &= ~index2;
|
|
image->stateChanges |= index2;
|
|
switch (index2)
|
|
{
|
|
case CPRepeat:
|
|
{
|
|
unsigned int newr;
|
|
newr = NEXT_VAL(unsigned int);
|
|
if (newr <= xTrue)
|
|
image->repeat = newr;
|
|
else
|
|
{
|
|
*error_value = newr;
|
|
error = BadValue;
|
|
}
|
|
}
|
|
break;
|
|
case CPAlphaMap:
|
|
{
|
|
pixman_image_t *iAlpha;
|
|
|
|
iAlpha = NEXT_PTR(pixman_image_t *);
|
|
if (iAlpha)
|
|
iAlpha->refcnt++;
|
|
if (image->alphaMap)
|
|
pixman_image_destroy ((void *) image->alphaMap);
|
|
image->alphaMap = iAlpha;
|
|
}
|
|
break;
|
|
case CPAlphaXOrigin:
|
|
image->alphaOrigin.x = NEXT_VAL(int16_t);
|
|
break;
|
|
case CPAlphaYOrigin:
|
|
image->alphaOrigin.y = NEXT_VAL(int16_t);
|
|
break;
|
|
case CPClipXOrigin:
|
|
image->clipOrigin.x = NEXT_VAL(int16_t);
|
|
break;
|
|
case CPClipYOrigin:
|
|
image->clipOrigin.y = NEXT_VAL(int16_t);
|
|
break;
|
|
case CPClipMask:
|
|
{
|
|
pixman_image_t *mask;
|
|
int clipType;
|
|
|
|
mask = NEXT_PTR(pixman_image_t *);
|
|
if (mask) {
|
|
clipType = CT_PIXMAP;
|
|
mask->refcnt++;
|
|
} else {
|
|
clipType = CT_NONE;
|
|
}
|
|
error = pixman_image_change_clip (image, clipType,
|
|
(void *)mask, 0);
|
|
break;
|
|
}
|
|
case CPGraphicsExposure:
|
|
{
|
|
unsigned int newe;
|
|
newe = NEXT_VAL(unsigned int);
|
|
if (newe <= xTrue)
|
|
image->graphicsExposures = newe;
|
|
else
|
|
{
|
|
*error_value = newe;
|
|
error = BadValue;
|
|
}
|
|
}
|
|
break;
|
|
case CPSubwindowMode:
|
|
{
|
|
unsigned int news;
|
|
news = NEXT_VAL(unsigned int);
|
|
if (news == ClipByChildren || news == IncludeInferiors)
|
|
image->subWindowMode = news;
|
|
else
|
|
{
|
|
*error_value = news;
|
|
error = BadValue;
|
|
}
|
|
}
|
|
break;
|
|
case CPPolyEdge:
|
|
{
|
|
unsigned int newe;
|
|
newe = NEXT_VAL(unsigned int);
|
|
if (newe == PolyEdgeSharp || newe == PolyEdgeSmooth)
|
|
image->polyEdge = newe;
|
|
else
|
|
{
|
|
*error_value = newe;
|
|
error = BadValue;
|
|
}
|
|
}
|
|
break;
|
|
case CPPolyMode:
|
|
{
|
|
unsigned int newm;
|
|
newm = NEXT_VAL(unsigned int);
|
|
if (newm == PolyModePrecise || newm == PolyModeImprecise)
|
|
image->polyMode = newm;
|
|
else
|
|
{
|
|
*error_value = newm;
|
|
error = BadValue;
|
|
}
|
|
}
|
|
break;
|
|
case CPDither:
|
|
image->dither = NEXT_VAL(unsigned long);
|
|
break;
|
|
case CPComponentAlpha:
|
|
{
|
|
unsigned int newca;
|
|
|
|
newca = NEXT_VAL (unsigned int);
|
|
if (newca <= xTrue)
|
|
image->componentAlpha = newca;
|
|
else
|
|
{
|
|
*error_value = newca;
|
|
error = BadValue;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
*error_value = maskQ;
|
|
error = BadValue;
|
|
break;
|
|
}
|
|
}
|
|
return error;
|
|
}
|
|
*/
|
|
|
|
/* XXX: Do we need this?
|
|
int
|
|
SetPictureClipRects (PicturePtr pPicture,
|
|
int xOrigin,
|
|
int yOrigin,
|
|
int nRect,
|
|
xRectangle *rects)
|
|
{
|
|
ScreenPtr pScreen = pPicture->pDrawable->pScreen;
|
|
PictureScreenPtr ps = GetPictureScreen(pScreen);
|
|
pixman_region16_t *clientClip;
|
|
int result;
|
|
|
|
clientClip = RECTS_TO_REGION(pScreen,
|
|
nRect, rects, CT_UNSORTED);
|
|
if (!clientClip)
|
|
return 1;
|
|
result =(*ps->ChangePictureClip) (pPicture, CT_REGION,
|
|
(void *) clientClip, 0);
|
|
if (result == 0)
|
|
{
|
|
pPicture->clipOrigin.x = xOrigin;
|
|
pPicture->clipOrigin.y = yOrigin;
|
|
pPicture->stateChanges |= CPClipXOrigin|CPClipYOrigin|CPClipMask;
|
|
pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
|
|
}
|
|
return result;
|
|
}
|
|
*/
|
|
|
|
int
|
|
FbComputeCompositeRegion (pixman_region16_t *region,
|
|
pixman_image_t *iSrc,
|
|
pixman_image_t *iMask,
|
|
pixman_image_t *iDst,
|
|
int16_t xSrc,
|
|
int16_t ySrc,
|
|
int16_t xMask,
|
|
int16_t yMask,
|
|
int16_t xDst,
|
|
int16_t yDst,
|
|
uint16_t width,
|
|
uint16_t height)
|
|
{
|
|
int v;
|
|
int x1, y1, x2, y2;
|
|
|
|
/* XXX: This code previously directly set the extents of the
|
|
region here. I need to decide whether removing that has broken
|
|
this. Also, it might be necessary to just make the pixman_region16_t
|
|
data structure transparent anyway in which case I can just put
|
|
the code back. */
|
|
x1 = xDst;
|
|
v = xDst + width;
|
|
x2 = BOUND(v);
|
|
y1 = yDst;
|
|
v = yDst + height;
|
|
y2 = BOUND(v);
|
|
/* Check for empty operation */
|
|
if (x1 >= x2 ||
|
|
y1 >= y2)
|
|
{
|
|
pixman_region_empty (region);
|
|
return 1;
|
|
}
|
|
/* clip against src */
|
|
if (!FbClipImageSrc (region, iSrc, xDst - xSrc, yDst - ySrc))
|
|
{
|
|
pixman_region_destroy (region);
|
|
return 0;
|
|
}
|
|
if (iSrc->alphaMap)
|
|
{
|
|
if (!FbClipImageSrc (region, iSrc->alphaMap,
|
|
xDst - (xSrc + iSrc->alphaOrigin.x),
|
|
yDst - (ySrc + iSrc->alphaOrigin.y)))
|
|
{
|
|
pixman_region_destroy (region);
|
|
return 0;
|
|
}
|
|
}
|
|
/* clip against mask */
|
|
if (iMask)
|
|
{
|
|
if (!FbClipImageSrc (region, iMask, xDst - xMask, yDst - yMask))
|
|
{
|
|
pixman_region_destroy (region);
|
|
return 0;
|
|
}
|
|
if (iMask->alphaMap)
|
|
{
|
|
if (!FbClipImageSrc (region, iMask->alphaMap,
|
|
xDst - (xMask + iMask->alphaOrigin.x),
|
|
yDst - (yMask + iMask->alphaOrigin.y)))
|
|
{
|
|
pixman_region_destroy (region);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
if (!FbClipImageReg (region, iDst->pCompositeClip, 0, 0))
|
|
{
|
|
pixman_region_destroy (region);
|
|
return 0;
|
|
}
|
|
if (iDst->alphaMap)
|
|
{
|
|
if (!FbClipImageReg (region, iDst->alphaMap->pCompositeClip,
|
|
-iDst->alphaOrigin.x,
|
|
-iDst->alphaOrigin.y))
|
|
{
|
|
pixman_region_destroy (region);
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
miIsSolidAlpha (pixman_image_t *src)
|
|
{
|
|
char line[1];
|
|
|
|
/* Alpha-only */
|
|
if (PICT_FORMAT_TYPE (src->format_code) != PICT_TYPE_A)
|
|
return 0;
|
|
/* repeat */
|
|
if (!src->repeat)
|
|
return 0;
|
|
/* 1x1 */
|
|
if (src->pixels->width != 1 || src->pixels->height != 1)
|
|
return 0;
|
|
line[0] = 1;
|
|
/* XXX: For the next line, fb has:
|
|
(*pScreen->GetImage) (src->pixels, 0, 0, 1, 1, ZPixmap, ~0L, line);
|
|
Is the following simple assignment sufficient?
|
|
*/
|
|
line[0] = src->pixels->data[0];
|
|
switch (src->pixels->bpp) {
|
|
case 1:
|
|
return (uint8_t) line[0] == 1 || (uint8_t) line[0] == 0x80;
|
|
case 4:
|
|
return (uint8_t) line[0] == 0xf || (uint8_t) line[0] == 0xf0;
|
|
case 8:
|
|
return (uint8_t) line[0] == 0xff;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|