/*
 *	PostScript brush handling
 *
 * Copyright 1998  Huw D M Davies
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "psdrv.h"
#include "wine/debug.h"
#include "winbase.h"

WINE_DEFAULT_DEBUG_CHANNEL(psdrv);

/***********************************************************************
 *           SelectBrush   (WINEPS.@)
 */
HBRUSH CDECL PSDRV_SelectBrush( PSDRV_PDEVICE *physDev, HBRUSH hbrush )
{
    LOGBRUSH logbrush;

    if (!GetObjectA( hbrush, sizeof(logbrush), &logbrush )) return 0;

    TRACE("hbrush = %p\n", hbrush);

    switch(logbrush.lbStyle) {

    case BS_SOLID:
        PSDRV_CreateColor(physDev, &physDev->brush.color, logbrush.lbColor);
	break;

    case BS_NULL:
        break;

    case BS_HATCHED:
        PSDRV_CreateColor(physDev, &physDev->brush.color, logbrush.lbColor);
        break;

    case BS_PATTERN:
    case BS_DIBPATTERN:
	break;

    default:
        FIXME("Unrecognized brush style %d\n", logbrush.lbStyle);
	break;
    }

    physDev->brush.set = FALSE;
    return hbrush;
}


/**********************************************************************
 *
 *	PSDRV_SetBrush
 *
 */
static BOOL PSDRV_SetBrush(PSDRV_PDEVICE *physDev)
{
    LOGBRUSH logbrush;
    BOOL ret = TRUE;

    if (!GetObjectA( GetCurrentObject(physDev->hdc,OBJ_BRUSH), sizeof(logbrush), &logbrush ))
    {
        ERR("Can't get BRUSHOBJ\n");
	return FALSE;
    }

    switch (logbrush.lbStyle) {
    case BS_SOLID:
    case BS_HATCHED:
        PSDRV_WriteSetColor(physDev, &physDev->brush.color);
	break;

    case BS_NULL:
        break;

    default:
        ret = FALSE;
        break;

    }
    physDev->brush.set = TRUE;
    return TRUE;
}


/**********************************************************************
 *
 *	PSDRV_Fill
 *
 */
static BOOL PSDRV_Fill(PSDRV_PDEVICE *physDev, BOOL EO)
{
    if(!EO)
        return PSDRV_WriteFill(physDev);
    else
        return PSDRV_WriteEOFill(physDev);
}


/**********************************************************************
 *
 *	PSDRV_Clip
 *
 */
static BOOL PSDRV_Clip(PSDRV_PDEVICE *physDev, BOOL EO)
{
    if(!EO)
        return PSDRV_WriteClip(physDev);
    else
        return PSDRV_WriteEOClip(physDev);
}

/**********************************************************************
 *
 *	PSDRV_Brush
 *
 */
BOOL PSDRV_Brush(PSDRV_PDEVICE *physDev, BOOL EO)
{
    LOGBRUSH logbrush;
    BOOL ret = TRUE;

    if(physDev->pathdepth)
        return FALSE;

    if (!GetObjectA( GetCurrentObject(physDev->hdc,OBJ_BRUSH), sizeof(logbrush), &logbrush ))
    {
        ERR("Can't get BRUSHOBJ\n");
	return FALSE;
    }

    switch (logbrush.lbStyle) {
    case BS_SOLID:
	PSDRV_WriteGSave(physDev);
        PSDRV_SetBrush(physDev);
        PSDRV_Fill(physDev, EO);
	PSDRV_WriteGRestore(physDev);
	break;

    case BS_HATCHED:
        PSDRV_WriteGSave(physDev);
        PSDRV_SetBrush(physDev);

	switch(logbrush.lbHatch) {
	case HS_VERTICAL:
	case HS_CROSS:
            PSDRV_WriteGSave(physDev);
	    PSDRV_Clip(physDev, EO);
	    PSDRV_WriteHatch(physDev);
	    PSDRV_WriteStroke(physDev);
	    PSDRV_WriteGRestore(physDev);
	    if(logbrush.lbHatch == HS_VERTICAL)
	        break;
	    /* else fallthrough for HS_CROSS */

	case HS_HORIZONTAL:
            PSDRV_WriteGSave(physDev);
	    PSDRV_Clip(physDev, EO);
	    PSDRV_WriteRotate(physDev, 90.0);
	    PSDRV_WriteHatch(physDev);
	    PSDRV_WriteStroke(physDev);
	    PSDRV_WriteGRestore(physDev);
	    break;

	case HS_FDIAGONAL:
	case HS_DIAGCROSS:
	    PSDRV_WriteGSave(physDev);
	    PSDRV_Clip(physDev, EO);
	    PSDRV_WriteRotate(physDev, -45.0);
	    PSDRV_WriteHatch(physDev);
	    PSDRV_WriteStroke(physDev);
	    PSDRV_WriteGRestore(physDev);
	    if(logbrush.lbHatch == HS_FDIAGONAL)
	        break;
	    /* else fallthrough for HS_DIAGCROSS */

	case HS_BDIAGONAL:
	    PSDRV_WriteGSave(physDev);
	    PSDRV_Clip(physDev, EO);
	    PSDRV_WriteRotate(physDev, 45.0);
	    PSDRV_WriteHatch(physDev);
	    PSDRV_WriteStroke(physDev);
	    PSDRV_WriteGRestore(physDev);
	    break;

	default:
	    ERR("Unknown hatch style\n");
	    ret = FALSE;
            break;
	}
        PSDRV_WriteGRestore(physDev);
	break;

    case BS_NULL:
	break;

    case BS_PATTERN:
        {
	    BITMAP bm;
	    BYTE *bits;
	    GetObjectA( (HBITMAP)logbrush.lbHatch, sizeof(BITMAP), &bm);
	    TRACE("BS_PATTERN %dx%d %d bpp\n", bm.bmWidth, bm.bmHeight,
		  bm.bmBitsPixel);
	    bits = HeapAlloc(PSDRV_Heap, 0, bm.bmWidthBytes * bm.bmHeight);
	    GetBitmapBits( (HBITMAP)logbrush.lbHatch, bm.bmWidthBytes * bm.bmHeight, bits);

	    if(physDev->pi->ppd->LanguageLevel > 1) {
	        PSDRV_WriteGSave(physDev);
	        PSDRV_WritePatternDict(physDev, &bm, bits);
		PSDRV_Fill(physDev, EO);
		PSDRV_WriteGRestore(physDev);
	    } else {
	        FIXME("Trying to set a pattern brush on a level 1 printer\n");
		ret = FALSE;
	    }
	    HeapFree(PSDRV_Heap, 0, bits);
	}
	break;

    case BS_DIBPATTERN:
        {
	    BITMAPINFO *bmi = GlobalLock16(logbrush.lbHatch);
	    UINT usage = logbrush.lbColor;
	    TRACE("size %dx%dx%d\n", bmi->bmiHeader.biWidth,
		  bmi->bmiHeader.biHeight, bmi->bmiHeader.biBitCount);
	    if(physDev->pi->ppd->LanguageLevel > 1) {
	        PSDRV_WriteGSave(physDev);
		ret = PSDRV_WriteDIBPatternDict(physDev, bmi, usage);
		PSDRV_Fill(physDev, EO);
		PSDRV_WriteGRestore(physDev);
	    } else {
	        FIXME("Trying to set a pattern brush on a level 1 printer\n");
		ret = FALSE;
	    }
	    GlobalUnlock16(logbrush.lbHatch);
	}
	break;

    default:
        ret = FALSE;
	break;
    }
    return ret;
}