/*
 * Copyright © 1998 Keith Packard
 *
 * 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 Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD 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.
 */

/** @file glamor_fillspans.c
 *
 * FillSpans implementation, taken from fb_fillsp.c
 */
#include "glamor_priv.h"

static Bool
_glamor_fill_spans(DrawablePtr drawable,
                   GCPtr gc,
                   int n, DDXPointPtr points, int *widths, int sorted,
                   Bool fallback)
{
    DDXPointPtr ppt;
    int nbox;
    BoxPtr pbox;
    int x1, x2, y;
    RegionPtr pClip = fbGetCompositeClip(gc);
    Bool ret = FALSE;

    if (gc->fillStyle != FillSolid && gc->fillStyle != FillTiled)
        goto fail;

    ppt = points;
    while (n--) {
        x1 = ppt->x;
        y = ppt->y;
        x2 = x1 + (int) *widths;
        ppt++;
        widths++;

        nbox = REGION_NUM_RECTS(pClip);
        pbox = REGION_RECTS(pClip);
        while (nbox--) {
            int real_x1 = x1, real_x2 = x2;

            if (real_x1 < pbox->x1)
                real_x1 = pbox->x1;

            if (real_x2 > pbox->x2)
                real_x2 = pbox->x2;

            if (real_x2 > real_x1 && pbox->y1 <= y && pbox->y2 > y) {
                if (!glamor_fill(drawable, gc, real_x1, y,
                                 real_x2 - real_x1, 1, fallback))
                    goto fail;
            }
            pbox++;
        }
    }
    ret = TRUE;
    goto done;

 fail:
    if (!fallback && glamor_ddx_fallback_check_pixmap(drawable)
        && glamor_ddx_fallback_check_gc(gc)) {
        goto done;
    }
    glamor_fallback("to %p (%c)\n", drawable,
                    glamor_get_drawable_location(drawable));
    if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW) &&
        glamor_prepare_access_gc(gc)) {
        fbFillSpans(drawable, gc, n, points, widths, sorted);
    }
    glamor_finish_access_gc(gc);
    glamor_finish_access(drawable);
    ret = TRUE;

 done:
    return ret;
}

void
glamor_fill_spans(DrawablePtr drawable,
                  GCPtr gc, int n, DDXPointPtr points, int *widths, int sorted)
{
    _glamor_fill_spans(drawable, gc, n, points, widths, sorted, TRUE);
}

Bool
glamor_fill_spans_nf(DrawablePtr drawable,
                     GCPtr gc,
                     int n, DDXPointPtr points, int *widths, int sorted)
{
    return _glamor_fill_spans(drawable, gc, n, points, widths, sorted, FALSE);
}
