/*
 *
 * 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 "scrnintstr.h"
#include "gcstruct.h"
#include "pixmapstr.h"
#include "windowstr.h"
#include "mi.h"
#include "picturestr.h"
#include "mipict.h"

Bool
miRealizeGlyph(ScreenPtr pScreen, GlyphPtr glyph)
{
    return TRUE;
}

void
miUnrealizeGlyph(ScreenPtr pScreen, GlyphPtr glyph)
{
}

_X_EXPORT void
miGlyphExtents(int nlist, GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents)
{
    int x1, x2, y1, y2;

    int n;

    GlyphPtr glyph;

    int x, y;

    x = 0;
    y = 0;
    extents->x1 = MAXSHORT;
    extents->x2 = MINSHORT;
    extents->y1 = MAXSHORT;
    extents->y2 = MINSHORT;
    while (nlist--) {
        x += list->xOff;
        y += list->yOff;
        n = list->len;
        list++;
        while (n--) {
            glyph = *glyphs++;
            x1 = x - glyph->info.x;
            if (x1 < MINSHORT)
                x1 = MINSHORT;
            y1 = y - glyph->info.y;
            if (y1 < MINSHORT)
                y1 = MINSHORT;
            x2 = x1 + glyph->info.width;
            if (x2 > MAXSHORT)
                x2 = MAXSHORT;
            y2 = y1 + glyph->info.height;
            if (y2 > MAXSHORT)
                y2 = MAXSHORT;
            if (x1 < extents->x1)
                extents->x1 = x1;
            if (x2 > extents->x2)
                extents->x2 = x2;
            if (y1 < extents->y1)
                extents->y1 = y1;
            if (y2 > extents->y2)
                extents->y2 = y2;
            x += glyph->info.xOff;
            y += glyph->info.yOff;
        }
    }
}

#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)

_X_EXPORT void
miGlyphs(CARD8 op,
         PicturePtr pSrc,
         PicturePtr pDst,
         PictFormatPtr maskFormat,
         INT16 xSrc,
         INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
{
    PixmapPtr pPixmap = 0;

    PicturePtr pPicture;

    PixmapPtr pMaskPixmap = 0;

    PicturePtr pMask;

    ScreenPtr pScreen = pDst->pDrawable->pScreen;

    int width = 0, height = 0;

    int x, y;

    int xDst = list->xOff, yDst = list->yOff;

    int n;

    GlyphPtr glyph;

    int error;

    BoxRec extents;

    CARD32 component_alpha;

    if (maskFormat) {
        GCPtr pGC;

        xRectangle rect;

        miGlyphExtents(nlist, list, glyphs, &extents);

        if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
            return;
        width = extents.x2 - extents.x1;
        height = extents.y2 - extents.y1;
        pMaskPixmap =
            (*pScreen->CreatePixmap) (pScreen, width, height,
                                      maskFormat->depth);
        if (!pMaskPixmap)
            return;
        component_alpha = NeedsComponent(maskFormat->format);
        pMask = CreatePicture(0, &pMaskPixmap->drawable,
                              maskFormat, CPComponentAlpha, &component_alpha,
                              serverClient, &error);
        if (!pMask) {
            (*pScreen->DestroyPixmap) (pMaskPixmap);
            return;
        }
        pGC = GetScratchGC(pMaskPixmap->drawable.depth, pScreen);
        ValidateGC(&pMaskPixmap->drawable, pGC);
        rect.x = 0;
        rect.y = 0;
        rect.width = width;
        rect.height = height;
        (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
        FreeScratchGC(pGC);
        x = -extents.x1;
        y = -extents.y1;
    }
    else {
        pMask = pDst;
        x = 0;
        y = 0;
    }
    pPicture = 0;
    while (nlist--) {
        x += list->xOff;
        y += list->yOff;
        n = list->len;
        while (n--) {
            glyph = *glyphs++;
            if (!pPicture) {
                pPixmap =
                    GetScratchPixmapHeader(pScreen, glyph->info.width,
                                           glyph->info.height,
                                           list->format->depth,
                                           list->format->depth, 0,
                                           (pointer) (glyph + 1));
                if (!pPixmap)
                    return;
                component_alpha = NeedsComponent(list->format->format);
                pPicture = CreatePicture(0, &pPixmap->drawable, list->format,
                                         CPComponentAlpha, &component_alpha,
                                         serverClient, &error);
                if (!pPicture) {
                    FreeScratchPixmapHeader(pPixmap);
                    return;
                }
            }
            (*pScreen->ModifyPixmapHeader) (pPixmap,
                                            glyph->info.width,
                                            glyph->info.height, 0, 0, -1,
                                            (pointer) (glyph + 1));
            pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
            if (maskFormat) {
                CompositePicture(PictOpAdd,
                                 pPicture,
                                 None,
                                 pMask,
                                 0, 0,
                                 0, 0,
                                 x - glyph->info.x,
                                 y - glyph->info.y,
                                 glyph->info.width, glyph->info.height);
            }
            else {
                CompositePicture(op,
                                 pSrc,
                                 pPicture,
                                 pDst,
                                 xSrc + (x - glyph->info.x) - xDst,
                                 ySrc + (y - glyph->info.y) - yDst,
                                 0, 0,
                                 x - glyph->info.x,
                                 y - glyph->info.y,
                                 glyph->info.width, glyph->info.height);
            }
            x += glyph->info.xOff;
            y += glyph->info.yOff;
        }
        list++;
        if (pPicture) {
            FreeScratchPixmapHeader(pPixmap);
            FreePicture((pointer) pPicture, 0);
            pPicture = 0;
            pPixmap = 0;
        }
    }
    if (maskFormat) {
        x = extents.x1;
        y = extents.y1;
        CompositePicture(op,
                         pSrc,
                         pMask,
                         pDst,
                         xSrc + x - xDst,
                         ySrc + y - yDst, 0, 0, x, y, width, height);
        FreePicture((pointer) pMask, (XID) 0);
        (*pScreen->DestroyPixmap) (pMaskPixmap);
    }
}
