508 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			508 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 *
 | 
						|
 * Copyright © 2000 SuSE, Inc.
 | 
						|
 * Copyright © 2007 Red Hat, 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 <string.h>
 | 
						|
 | 
						|
#include "fb.h"
 | 
						|
 | 
						|
#include "picturestr.h"
 | 
						|
#include "mipict.h"
 | 
						|
#include "fbpict.h"
 | 
						|
 | 
						|
void
 | 
						|
fbComposite(CARD8 op,
 | 
						|
            PicturePtr pSrc,
 | 
						|
            PicturePtr pMask,
 | 
						|
            PicturePtr pDst,
 | 
						|
            INT16 xSrc,
 | 
						|
            INT16 ySrc,
 | 
						|
            INT16 xMask,
 | 
						|
            INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
 | 
						|
{
 | 
						|
    pixman_image_t *src, *mask, *dest;
 | 
						|
    int src_xoff, src_yoff;
 | 
						|
    int msk_xoff, msk_yoff;
 | 
						|
    int dst_xoff, dst_yoff;
 | 
						|
 | 
						|
    miCompositeSourceValidate(pSrc);
 | 
						|
    if (pMask)
 | 
						|
        miCompositeSourceValidate(pMask);
 | 
						|
 | 
						|
    src = image_from_pict(pSrc, FALSE, &src_xoff, &src_yoff);
 | 
						|
    mask = image_from_pict(pMask, FALSE, &msk_xoff, &msk_yoff);
 | 
						|
    dest = image_from_pict(pDst, TRUE, &dst_xoff, &dst_yoff);
 | 
						|
 | 
						|
    if (src && dest && !(pMask && !mask)) {
 | 
						|
        pixman_image_composite(op, src, mask, dest,
 | 
						|
                               xSrc + src_xoff, ySrc + src_yoff,
 | 
						|
                               xMask + msk_xoff, yMask + msk_yoff,
 | 
						|
                               xDst + dst_xoff, yDst + dst_yoff, width, height);
 | 
						|
    }
 | 
						|
 | 
						|
    free_pixman_pict(pSrc, src);
 | 
						|
    free_pixman_pict(pMask, mask);
 | 
						|
    free_pixman_pict(pDst, dest);
 | 
						|
}
 | 
						|
 | 
						|
static pixman_glyph_cache_t *glyphCache;
 | 
						|
 | 
						|
void
 | 
						|
fbDestroyGlyphCache(void)
 | 
						|
{
 | 
						|
    if (glyphCache)
 | 
						|
    {
 | 
						|
	pixman_glyph_cache_destroy (glyphCache);
 | 
						|
	glyphCache = NULL;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
fbUnrealizeGlyph(ScreenPtr pScreen,
 | 
						|
		 GlyphPtr pGlyph)
 | 
						|
{
 | 
						|
    if (glyphCache)
 | 
						|
	pixman_glyph_cache_remove (glyphCache, pGlyph, NULL);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
fbGlyphs(CARD8 op,
 | 
						|
	 PicturePtr pSrc,
 | 
						|
	 PicturePtr pDst,
 | 
						|
	 PictFormatPtr maskFormat,
 | 
						|
	 INT16 xSrc,
 | 
						|
	 INT16 ySrc, int nlist,
 | 
						|
	 GlyphListPtr list,
 | 
						|
	 GlyphPtr *glyphs)
 | 
						|
{
 | 
						|
#define N_STACK_GLYPHS 512
 | 
						|
    ScreenPtr pScreen = pDst->pDrawable->pScreen;
 | 
						|
    pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
 | 
						|
    pixman_glyph_t *pglyphs = stack_glyphs;
 | 
						|
    pixman_image_t *srcImage, *dstImage;
 | 
						|
    int srcXoff, srcYoff, dstXoff, dstYoff;
 | 
						|
    GlyphPtr glyph;
 | 
						|
    int n_glyphs;
 | 
						|
    int x, y;
 | 
						|
    int i, n;
 | 
						|
    int xDst = list->xOff, yDst = list->yOff;
 | 
						|
 | 
						|
    miCompositeSourceValidate(pSrc);
 | 
						|
 | 
						|
    n_glyphs = 0;
 | 
						|
    for (i = 0; i < nlist; ++i)
 | 
						|
	n_glyphs += list[i].len;
 | 
						|
 | 
						|
    if (!glyphCache)
 | 
						|
	glyphCache = pixman_glyph_cache_create();
 | 
						|
 | 
						|
    pixman_glyph_cache_freeze (glyphCache);
 | 
						|
 | 
						|
    if (n_glyphs > N_STACK_GLYPHS) {
 | 
						|
	if (!(pglyphs = xallocarray(n_glyphs, sizeof(pixman_glyph_t))))
 | 
						|
	    goto out;
 | 
						|
    }
 | 
						|
 | 
						|
    i = 0;
 | 
						|
    x = y = 0;
 | 
						|
    while (nlist--) {
 | 
						|
        x += list->xOff;
 | 
						|
        y += list->yOff;
 | 
						|
        n = list->len;
 | 
						|
        while (n--) {
 | 
						|
	    const void *g;
 | 
						|
 | 
						|
            glyph = *glyphs++;
 | 
						|
 | 
						|
	    if (!(g = pixman_glyph_cache_lookup (glyphCache, glyph, NULL))) {
 | 
						|
		pixman_image_t *glyphImage;
 | 
						|
		PicturePtr pPicture;
 | 
						|
		int xoff, yoff;
 | 
						|
 | 
						|
		pPicture = GetGlyphPicture(glyph, pScreen);
 | 
						|
		if (!pPicture) {
 | 
						|
		    n_glyphs--;
 | 
						|
		    goto next;
 | 
						|
		}
 | 
						|
 | 
						|
		if (!(glyphImage = image_from_pict(pPicture, FALSE, &xoff, &yoff)))
 | 
						|
		    goto out;
 | 
						|
 | 
						|
		g = pixman_glyph_cache_insert(glyphCache, glyph, NULL,
 | 
						|
					      glyph->info.x,
 | 
						|
					      glyph->info.y,
 | 
						|
					      glyphImage);
 | 
						|
 | 
						|
		free_pixman_pict(pPicture, glyphImage);
 | 
						|
 | 
						|
		if (!g)
 | 
						|
		    goto out;
 | 
						|
	    }
 | 
						|
 | 
						|
	    pglyphs[i].x = x;
 | 
						|
	    pglyphs[i].y = y;
 | 
						|
	    pglyphs[i].glyph = g;
 | 
						|
	    i++;
 | 
						|
 | 
						|
	next:
 | 
						|
            x += glyph->info.xOff;
 | 
						|
            y += glyph->info.yOff;
 | 
						|
	}
 | 
						|
	list++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!(srcImage = image_from_pict(pSrc, FALSE, &srcXoff, &srcYoff)))
 | 
						|
	goto out;
 | 
						|
 | 
						|
    if (!(dstImage = image_from_pict(pDst, TRUE, &dstXoff, &dstYoff)))
 | 
						|
	goto out_free_src;
 | 
						|
 | 
						|
    if (maskFormat) {
 | 
						|
	pixman_format_code_t format;
 | 
						|
	pixman_box32_t extents;
 | 
						|
 | 
						|
	format = maskFormat->format | (maskFormat->depth << 24);
 | 
						|
 | 
						|
	pixman_glyph_get_extents(glyphCache, n_glyphs, pglyphs, &extents);
 | 
						|
 | 
						|
	pixman_composite_glyphs(op, srcImage, dstImage, format,
 | 
						|
				xSrc + srcXoff + extents.x1 - xDst, ySrc + srcYoff + extents.y1 - yDst,
 | 
						|
				extents.x1, extents.y1,
 | 
						|
				extents.x1 + dstXoff, extents.y1 + dstYoff,
 | 
						|
				extents.x2 - extents.x1,
 | 
						|
				extents.y2 - extents.y1,
 | 
						|
				glyphCache, n_glyphs, pglyphs);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	pixman_composite_glyphs_no_mask(op, srcImage, dstImage,
 | 
						|
					xSrc + srcXoff - xDst, ySrc + srcYoff - yDst,
 | 
						|
					dstXoff, dstYoff,
 | 
						|
					glyphCache, n_glyphs, pglyphs);
 | 
						|
    }
 | 
						|
 | 
						|
    free_pixman_pict(pDst, dstImage);
 | 
						|
 | 
						|
out_free_src:
 | 
						|
    free_pixman_pict(pSrc, srcImage);
 | 
						|
 | 
						|
out:
 | 
						|
    pixman_glyph_cache_thaw(glyphCache);
 | 
						|
    if (pglyphs != stack_glyphs)
 | 
						|
	free(pglyphs);
 | 
						|
}
 | 
						|
 | 
						|
static pixman_image_t *
 | 
						|
create_solid_fill_image(PicturePtr pict)
 | 
						|
{
 | 
						|
    PictSolidFill *solid = &pict->pSourcePict->solidFill;
 | 
						|
    /* pixman_color_t and xRenderColor have the same layout */
 | 
						|
    pixman_color_t *color = (pixman_color_t *)&solid->fullcolor;
 | 
						|
 | 
						|
    return pixman_image_create_solid_fill(color);
 | 
						|
}
 | 
						|
 | 
						|
static pixman_image_t *
 | 
						|
create_linear_gradient_image(PictGradient * gradient)
 | 
						|
{
 | 
						|
    PictLinearGradient *linear = (PictLinearGradient *) gradient;
 | 
						|
    pixman_point_fixed_t p1;
 | 
						|
    pixman_point_fixed_t p2;
 | 
						|
 | 
						|
    p1.x = linear->p1.x;
 | 
						|
    p1.y = linear->p1.y;
 | 
						|
    p2.x = linear->p2.x;
 | 
						|
    p2.y = linear->p2.y;
 | 
						|
 | 
						|
    return pixman_image_create_linear_gradient(&p1, &p2,
 | 
						|
                                               (pixman_gradient_stop_t *)
 | 
						|
                                               gradient->stops,
 | 
						|
                                               gradient->nstops);
 | 
						|
}
 | 
						|
 | 
						|
static pixman_image_t *
 | 
						|
create_radial_gradient_image(PictGradient * gradient)
 | 
						|
{
 | 
						|
    PictRadialGradient *radial = (PictRadialGradient *) gradient;
 | 
						|
    pixman_point_fixed_t c1;
 | 
						|
    pixman_point_fixed_t c2;
 | 
						|
 | 
						|
    c1.x = radial->c1.x;
 | 
						|
    c1.y = radial->c1.y;
 | 
						|
    c2.x = radial->c2.x;
 | 
						|
    c2.y = radial->c2.y;
 | 
						|
 | 
						|
    return pixman_image_create_radial_gradient(&c1, &c2, radial->c1.radius,
 | 
						|
                                               radial->c2.radius,
 | 
						|
                                               (pixman_gradient_stop_t *)
 | 
						|
                                               gradient->stops,
 | 
						|
                                               gradient->nstops);
 | 
						|
}
 | 
						|
 | 
						|
static pixman_image_t *
 | 
						|
create_conical_gradient_image(PictGradient * gradient)
 | 
						|
{
 | 
						|
    PictConicalGradient *conical = (PictConicalGradient *) gradient;
 | 
						|
    pixman_point_fixed_t center;
 | 
						|
 | 
						|
    center.x = conical->center.x;
 | 
						|
    center.y = conical->center.y;
 | 
						|
 | 
						|
    return pixman_image_create_conical_gradient(¢er, conical->angle,
 | 
						|
                                                (pixman_gradient_stop_t *)
 | 
						|
                                                gradient->stops,
 | 
						|
                                                gradient->nstops);
 | 
						|
}
 | 
						|
 | 
						|
static pixman_image_t *
 | 
						|
create_bits_picture(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
 | 
						|
{
 | 
						|
    PixmapPtr pixmap;
 | 
						|
    FbBits *bits;
 | 
						|
    FbStride stride;
 | 
						|
    int bpp;
 | 
						|
    pixman_image_t *image;
 | 
						|
 | 
						|
    fbGetDrawablePixmap(pict->pDrawable, pixmap, *xoff, *yoff);
 | 
						|
    fbGetPixmapBitsData(pixmap, bits, stride, bpp);
 | 
						|
 | 
						|
    image = pixman_image_create_bits((pixman_format_code_t) pict->format,
 | 
						|
                                     pixmap->drawable.width,
 | 
						|
                                     pixmap->drawable.height, (uint32_t *) bits,
 | 
						|
                                     stride * sizeof(FbStride));
 | 
						|
 | 
						|
    if (!image)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
#ifdef FB_ACCESS_WRAPPER
 | 
						|
    pixman_image_set_accessors(image,
 | 
						|
                               (pixman_read_memory_func_t) wfbReadMemory,
 | 
						|
                               (pixman_write_memory_func_t) wfbWriteMemory);
 | 
						|
#endif
 | 
						|
 | 
						|
    /* pCompositeClip is undefined for source pictures, so
 | 
						|
     * only set the clip region for pictures with drawables
 | 
						|
     */
 | 
						|
    if (has_clip) {
 | 
						|
        if (pict->clientClip)
 | 
						|
            pixman_image_set_has_client_clip(image, TRUE);
 | 
						|
 | 
						|
        if (*xoff || *yoff)
 | 
						|
            pixman_region_translate(pict->pCompositeClip, *xoff, *yoff);
 | 
						|
 | 
						|
        pixman_image_set_clip_region(image, pict->pCompositeClip);
 | 
						|
 | 
						|
        if (*xoff || *yoff)
 | 
						|
            pixman_region_translate(pict->pCompositeClip, -*xoff, -*yoff);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Indexed table */
 | 
						|
    if (pict->pFormat->index.devPrivate)
 | 
						|
        pixman_image_set_indexed(image, pict->pFormat->index.devPrivate);
 | 
						|
 | 
						|
    /* Add in drawable origin to position within the image */
 | 
						|
    *xoff += pict->pDrawable->x;
 | 
						|
    *yoff += pict->pDrawable->y;
 | 
						|
 | 
						|
    return image;
 | 
						|
}
 | 
						|
 | 
						|
static pixman_image_t *image_from_pict_internal(PicturePtr pict, Bool has_clip,
 | 
						|
                                                int *xoff, int *yoff,
 | 
						|
                                                Bool is_alpha_map);
 | 
						|
 | 
						|
static void image_destroy(pixman_image_t *image, void *data)
 | 
						|
{
 | 
						|
    fbFinishAccess((DrawablePtr)data);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
set_image_properties(pixman_image_t * image, PicturePtr pict, Bool has_clip,
 | 
						|
                     int *xoff, int *yoff, Bool is_alpha_map)
 | 
						|
{
 | 
						|
    pixman_repeat_t repeat;
 | 
						|
    pixman_filter_t filter;
 | 
						|
 | 
						|
    if (pict->transform) {
 | 
						|
        /* For source images, adjust the transform to account
 | 
						|
         * for the drawable offset within the pixman image,
 | 
						|
         * then set the offset to 0 as it will be used
 | 
						|
         * to compute positions within the transformed image.
 | 
						|
         */
 | 
						|
        if (!has_clip) {
 | 
						|
            struct pixman_transform adjusted;
 | 
						|
 | 
						|
            adjusted = *pict->transform;
 | 
						|
            pixman_transform_translate(&adjusted,
 | 
						|
                                       NULL,
 | 
						|
                                       pixman_int_to_fixed(*xoff),
 | 
						|
                                       pixman_int_to_fixed(*yoff));
 | 
						|
            pixman_image_set_transform(image, &adjusted);
 | 
						|
            *xoff = 0;
 | 
						|
            *yoff = 0;
 | 
						|
        }
 | 
						|
        else
 | 
						|
            pixman_image_set_transform(image, pict->transform);
 | 
						|
    }
 | 
						|
 | 
						|
    switch (pict->repeatType) {
 | 
						|
    default:
 | 
						|
    case RepeatNone:
 | 
						|
        repeat = PIXMAN_REPEAT_NONE;
 | 
						|
        break;
 | 
						|
 | 
						|
    case RepeatPad:
 | 
						|
        repeat = PIXMAN_REPEAT_PAD;
 | 
						|
        break;
 | 
						|
 | 
						|
    case RepeatNormal:
 | 
						|
        repeat = PIXMAN_REPEAT_NORMAL;
 | 
						|
        break;
 | 
						|
 | 
						|
    case RepeatReflect:
 | 
						|
        repeat = PIXMAN_REPEAT_REFLECT;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    pixman_image_set_repeat(image, repeat);
 | 
						|
 | 
						|
    /* Fetch alpha map unless 'pict' is being used
 | 
						|
     * as the alpha map for this operation
 | 
						|
     */
 | 
						|
    if (pict->alphaMap && !is_alpha_map) {
 | 
						|
        int alpha_xoff, alpha_yoff;
 | 
						|
        pixman_image_t *alpha_map =
 | 
						|
            image_from_pict_internal(pict->alphaMap, FALSE, &alpha_xoff,
 | 
						|
                                     &alpha_yoff, TRUE);
 | 
						|
 | 
						|
        pixman_image_set_alpha_map(image, alpha_map, pict->alphaOrigin.x,
 | 
						|
                                   pict->alphaOrigin.y);
 | 
						|
 | 
						|
        free_pixman_pict(pict->alphaMap, alpha_map);
 | 
						|
    }
 | 
						|
 | 
						|
    pixman_image_set_component_alpha(image, pict->componentAlpha);
 | 
						|
 | 
						|
    switch (pict->filter) {
 | 
						|
    default:
 | 
						|
    case PictFilterNearest:
 | 
						|
    case PictFilterFast:
 | 
						|
        filter = PIXMAN_FILTER_NEAREST;
 | 
						|
        break;
 | 
						|
 | 
						|
    case PictFilterBilinear:
 | 
						|
    case PictFilterGood:
 | 
						|
        filter = PIXMAN_FILTER_BILINEAR;
 | 
						|
        break;
 | 
						|
 | 
						|
    case PictFilterConvolution:
 | 
						|
        filter = PIXMAN_FILTER_CONVOLUTION;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (pict->pDrawable)
 | 
						|
        pixman_image_set_destroy_function(image, &image_destroy,
 | 
						|
                                          pict->pDrawable);
 | 
						|
 | 
						|
    pixman_image_set_filter(image, filter,
 | 
						|
                            (pixman_fixed_t *) pict->filter_params,
 | 
						|
                            pict->filter_nparams);
 | 
						|
    pixman_image_set_source_clipping(image, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
static pixman_image_t *
 | 
						|
image_from_pict_internal(PicturePtr pict, Bool has_clip, int *xoff, int *yoff,
 | 
						|
                         Bool is_alpha_map)
 | 
						|
{
 | 
						|
    pixman_image_t *image = NULL;
 | 
						|
 | 
						|
    if (!pict)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    if (pict->pDrawable) {
 | 
						|
        image = create_bits_picture(pict, has_clip, xoff, yoff);
 | 
						|
    }
 | 
						|
    else if (pict->pSourcePict) {
 | 
						|
        SourcePict *sp = pict->pSourcePict;
 | 
						|
 | 
						|
        if (sp->type == SourcePictTypeSolidFill) {
 | 
						|
            image = create_solid_fill_image(pict);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            PictGradient *gradient = &pict->pSourcePict->gradient;
 | 
						|
 | 
						|
            if (sp->type == SourcePictTypeLinear)
 | 
						|
                image = create_linear_gradient_image(gradient);
 | 
						|
            else if (sp->type == SourcePictTypeRadial)
 | 
						|
                image = create_radial_gradient_image(gradient);
 | 
						|
            else if (sp->type == SourcePictTypeConical)
 | 
						|
                image = create_conical_gradient_image(gradient);
 | 
						|
        }
 | 
						|
        *xoff = *yoff = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (image)
 | 
						|
        set_image_properties(image, pict, has_clip, xoff, yoff, is_alpha_map);
 | 
						|
 | 
						|
    return image;
 | 
						|
}
 | 
						|
 | 
						|
pixman_image_t *
 | 
						|
image_from_pict(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
 | 
						|
{
 | 
						|
    return image_from_pict_internal(pict, has_clip, xoff, yoff, FALSE);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
free_pixman_pict(PicturePtr pict, pixman_image_t * image)
 | 
						|
{
 | 
						|
    if (image)
 | 
						|
        pixman_image_unref(image);
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
fbPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
 | 
						|
{
 | 
						|
 | 
						|
    PictureScreenPtr ps;
 | 
						|
 | 
						|
    if (!miPictureInit(pScreen, formats, nformats))
 | 
						|
        return FALSE;
 | 
						|
    ps = GetPictureScreen(pScreen);
 | 
						|
    ps->Composite = fbComposite;
 | 
						|
    ps->Glyphs = fbGlyphs;
 | 
						|
    ps->UnrealizeGlyph = fbUnrealizeGlyph;
 | 
						|
    ps->CompositeRects = miCompositeRects;
 | 
						|
    ps->RasterizeTrapezoid = fbRasterizeTrapezoid;
 | 
						|
    ps->Trapezoids = fbTrapezoids;
 | 
						|
    ps->AddTraps = fbAddTraps;
 | 
						|
    ps->AddTriangles = fbAddTriangles;
 | 
						|
    ps->Triangles = fbTriangles;
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 |