wine/dlls/gdi32/dibdrv/graphics.c

243 lines
6.8 KiB
C

/*
* DIB driver graphics operations.
*
* Copyright 2011 Huw 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 "gdi_private.h"
#include "dibdrv.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dib);
static RECT get_device_rect( HDC hdc, int left, int top, int right, int bottom, BOOL rtl_correction )
{
RECT rect;
rect.left = left;
rect.top = top;
rect.right = right;
rect.bottom = bottom;
if (rtl_correction && GetLayout( hdc ) & LAYOUT_RTL)
{
/* shift the rectangle so that the right border is included after mirroring */
/* it would be more correct to do this after LPtoDP but that's not what Windows does */
rect.left--;
rect.right--;
}
LPtoDP( hdc, (POINT *)&rect, 2 );
if (rect.left > rect.right)
{
int tmp = rect.left;
rect.left = rect.right;
rect.right = tmp;
}
if (rect.top > rect.bottom)
{
int tmp = rect.top;
rect.top = rect.bottom;
rect.bottom = tmp;
}
return rect;
}
/***********************************************************************
* dibdrv_LineTo
*/
BOOL dibdrv_LineTo( PHYSDEV dev, INT x, INT y )
{
PHYSDEV next = GET_NEXT_PHYSDEV( dev, pLineTo );
dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
POINT pts[2];
GetCurrentPositionEx(dev->hdc, pts);
pts[1].x = x;
pts[1].y = y;
LPtoDP(dev->hdc, pts, 2);
reset_dash_origin(pdev);
if(defer_pen(pdev) || !pdev->pen_lines(pdev, 2, pts))
return next->funcs->pLineTo( next, x, y );
return TRUE;
}
/***********************************************************************
* get_rop2_from_rop
*
* Returns the binary rop that is equivalent to the provided ternary rop
* if the src bits are ignored.
*/
static inline INT get_rop2_from_rop(INT rop)
{
return (((rop >> 18) & 0x0c) | ((rop >> 16) & 0x03)) + 1;
}
/***********************************************************************
* dibdrv_PatBlt
*/
BOOL dibdrv_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
{
PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPatBlt );
dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
INT rop2 = get_rop2_from_rop(rop);
BOOL done;
TRACE("(%p, %d, %d, %d, %d, %06x)\n", dev, dst->x, dst->y, dst->width, dst->height, rop);
if(defer_brush(pdev))
return next->funcs->pPatBlt( next, dst, rop );
update_brush_rop( pdev, rop2 );
done = brush_rects( pdev, 1, &dst->visrect );
update_brush_rop( pdev, GetROP2(dev->hdc) );
if(!done)
return next->funcs->pPatBlt( next, dst, rop );
return TRUE;
}
/***********************************************************************
* dibdrv_PaintRgn
*/
BOOL dibdrv_PaintRgn( PHYSDEV dev, HRGN rgn )
{
PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPaintRgn );
dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
const WINEREGION *region;
int i;
RECT rect;
TRACE("%p, %p\n", dev, rgn);
if(defer_brush(pdev)) return next->funcs->pPaintRgn( next, rgn );
region = get_wine_region( rgn );
if(!region) return FALSE;
for(i = 0; i < region->numRects; i++)
{
rect = get_device_rect( dev->hdc, region->rects[i].left, region->rects[i].top,
region->rects[i].right, region->rects[i].bottom, FALSE );
brush_rects( pdev, 1, &rect );
}
release_wine_region( rgn );
return TRUE;
}
/***********************************************************************
* dibdrv_PolyPolyline
*/
BOOL dibdrv_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polylines )
{
dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPolyPolyline );
DWORD max_points = 0, i;
POINT *points;
if (defer_pen( pdev )) return next->funcs->pPolyPolyline( next, pt, counts, polylines );
for (i = 0; i < polylines; i++) max_points = max( counts[i], max_points );
points = HeapAlloc( GetProcessHeap(), 0, max_points * sizeof(*pt) );
if (!points) return FALSE;
for (i = 0; i < polylines; i++)
{
memcpy( points, pt, counts[i] * sizeof(*pt) );
pt += counts[i];
LPtoDP( dev->hdc, points, counts[i] );
reset_dash_origin( pdev );
pdev->pen_lines( pdev, counts[i], points );
}
HeapFree( GetProcessHeap(), 0, points );
return TRUE;
}
/***********************************************************************
* dibdrv_Polyline
*/
BOOL dibdrv_Polyline( PHYSDEV dev, const POINT* pt, INT count )
{
dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPolyline );
POINT *points;
if (defer_pen( pdev )) return next->funcs->pPolyline( next, pt, count );
points = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pt) );
if (!points) return FALSE;
memcpy( points, pt, count * sizeof(*pt) );
LPtoDP( dev->hdc, points, count );
reset_dash_origin( pdev );
pdev->pen_lines( pdev, count, points );
HeapFree( GetProcessHeap(), 0, points );
return TRUE;
}
/***********************************************************************
* dibdrv_Rectangle
*/
BOOL dibdrv_Rectangle( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
{
PHYSDEV next = GET_NEXT_PHYSDEV( dev, pRectangle );
dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
RECT rect = get_device_rect( dev->hdc, left, top, right, bottom, TRUE );
POINT pts[5];
TRACE("(%p, %d, %d, %d, %d)\n", dev, left, top, right, bottom);
if(rect.left == rect.right || rect.top == rect.bottom) return TRUE;
if(defer_pen(pdev) || defer_brush(pdev))
return next->funcs->pRectangle( next, left, top, right, bottom );
reset_dash_origin(pdev);
/* 4 pts going anti-clockwise starting from top-right */
pts[0].x = pts[3].x = rect.right - 1;
pts[0].y = pts[1].y = rect.top;
pts[1].x = pts[2].x = rect.left;
pts[2].y = pts[3].y = rect.bottom - 1;
pts[4] = pts[0];
pdev->pen_lines(pdev, 5, pts);
/* FIXME: Will need updating when we support wide pens */
rect.left += 1;
rect.top += 1;
rect.right -= 1;
rect.bottom -= 1;
brush_rects(pdev, 1, &rect);
return TRUE;
}