/* * 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; } slim_hidden_def(pixman_image_create); 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 = 0; image->pixels = 0; 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 0; image = _pixman_create_source_image (); if (!image) return 0; linear = malloc (sizeof (pixman_linear_gradient_image_t) + sizeof (pixman_gradient_stop_t) * n_stops); if (!linear) { free (image); return 0; } 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 (image); return 0; } 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; double x; if (n_stops < 2) return 0; image = _pixman_create_source_image (); if (!image) return 0; radial = malloc (sizeof (pixman_radial_gradient_image_t) + sizeof (pixman_gradient_stop_t) * n_stops); if (!radial) { free (image); return 0; } 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; x = (double) gradient->inner.radius / (double) gradient->outer.radius; radial->dx = (gradient->outer.x - gradient->inner.x); radial->dy = (gradient->outer.y - gradient->inner.y); radial->fx = (gradient->inner.x) - x * radial->dx; radial->fy = (gradient->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 = gradient->outer.radius / 65536.; radial->a = x * x - radial->dx * radial->dx - radial->dy * radial->dy; image->pSourcePict = (pixman_source_image_t *) radial; if (_pixman_init_gradient (&image->pSourcePict->gradient, stops, n_stops)) { free (image); return 0; } 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; } slim_hidden_def(pixman_image_set_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; } slim_hidden_def(pixman_image_set_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 0; } 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); } slim_hidden_def(pixman_image_destroy); 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; } }