gdi32: Use the DIB engine and PutImage for the null driver triangular gradient implementation.

oldstable
Alexandre Julliard 2011-12-05 16:27:28 +01:00
parent 8e8cdc78e6
commit 360d4bc548
3 changed files with 132 additions and 144 deletions

View File

@ -21,7 +21,7 @@
#include "config.h"
#include <stdarg.h>
#include <limits.h>
#include <math.h>
#ifdef HAVE_FLOAT_H
#include <float.h>
@ -407,152 +407,85 @@ BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
struct bitblt_coords src, dst;
struct gdi_image_bits bits;
unsigned int i;
POINT *pts;
RECT clip;
BOOL ret = TRUE;
DWORD err;
HRGN rgn;
switch(mode)
if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
for (i = 0; i < nvert; i++)
{
case GRADIENT_FILL_RECT_H:
case GRADIENT_FILL_RECT_V:
{
const GRADIENT_RECT *rect = grad_array;
TRIVERTEX v[2];
for (i = 0; i < ngrad; i++, rect++)
{
v[0] = vert_array[rect->UpperLeft];
v[1] = vert_array[rect->LowerRight];
dst.log_x = v[0].x;
dst.log_y = v[0].y;
dst.log_width = v[1].x - v[0].x;
dst.log_height = v[1].y - v[0].y;
dst.layout = dc->layout;
if (!get_vis_rectangles( dc, &dst, NULL, NULL )) continue;
if (dst.width < 0)
{
if (mode == GRADIENT_FILL_RECT_H) /* swap the colors */
{
v[0] = vert_array[rect->LowerRight];
v[1] = vert_array[rect->UpperLeft];
}
dst.x += dst.width + 1;
dst.width = -dst.width;
}
if (dst.height < 0)
{
if (mode == GRADIENT_FILL_RECT_V) /* swap the colors */
{
v[0] = vert_array[rect->LowerRight];
v[1] = vert_array[rect->UpperLeft];
}
dst.y += dst.height + 1;
dst.height = -dst.height;
}
/* query the bitmap format */
info->bmiHeader.biSize = sizeof(info->bmiHeader);
info->bmiHeader.biPlanes = 1;
info->bmiHeader.biBitCount = 0;
info->bmiHeader.biCompression = BI_RGB;
info->bmiHeader.biXPelsPerMeter = 0;
info->bmiHeader.biYPelsPerMeter = 0;
info->bmiHeader.biClrUsed = 0;
info->bmiHeader.biClrImportant = 0;
info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
info->bmiHeader.biSizeImage = 0;
dev = GET_DC_PHYSDEV( dc, pPutImage );
err = dev->funcs->pPutImage( dev, 0, 0, info, NULL, NULL, NULL, 0 );
if (!err || err == ERROR_BAD_FORMAT)
{
if (!(bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ))))
return FALSE;
bits.is_copy = TRUE;
bits.free = free_heap_bits;
/* make src relative to the bitmap */
src = dst;
src.x -= src.visrect.left;
src.y -= src.visrect.top;
offset_rect( &src.visrect, -src.visrect.left, -src.visrect.top );
v[0].x = src.x;
v[0].y = src.y;
v[1].x = src.x + src.width;
v[1].y = src.y + src.height;
err = gradient_bitmapinfo( info, bits.ptr, v, mode );
if (!err) err = dev->funcs->pPutImage( dev, 0, 0, info, &bits, &src, &dst, SRCCOPY );
if (bits.free) bits.free( &bits );
}
if (err) return FALSE;
}
break;
pts[i].x = vert_array[i].x;
pts[i].y = vert_array[i].y;
}
case GRADIENT_FILL_TRIANGLE:
for (i = 0; i < ngrad; i++)
{
GRADIENT_TRIANGLE *tri = ((GRADIENT_TRIANGLE *)grad_array) + i;
TRIVERTEX *v1 = vert_array + tri->Vertex1;
TRIVERTEX *v2 = vert_array + tri->Vertex2;
TRIVERTEX *v3 = vert_array + tri->Vertex3;
int y, dy;
LPtoDP( dev->hdc, pts, nvert );
if (v1->y > v2->y)
{ TRIVERTEX *t = v1; v1 = v2; v2 = t; }
if (v2->y > v3->y)
{
TRIVERTEX *t = v2; v2 = v3; v3 = t;
if (v1->y > v2->y)
{ t = v1; v1 = v2; v2 = t; }
}
/* v1->y <= v2->y <= v3->y */
dy = v3->y - v1->y;
for (y = 0; y < dy; y++)
{
/* v1->y <= y < v3->y */
TRIVERTEX *v = y < (v2->y - v1->y) ? v1 : v3;
/* (v->y <= y < v2->y) || (v2->y <= y < v->y) */
int dy2 = v2->y - v->y;
int y2 = y + v1->y - v->y;
int x1 = (v3->x * y + v1->x * (dy - y )) / dy;
int x2 = (v2->x * y2 + v-> x * (dy2 - y2)) / dy2;
int r1 = (v3->Red * y + v1->Red * (dy - y )) / dy;
int r2 = (v2->Red * y2 + v-> Red * (dy2 - y2)) / dy2;
int g1 = (v3->Green * y + v1->Green * (dy - y )) / dy;
int g2 = (v2->Green * y2 + v-> Green * (dy2 - y2)) / dy2;
int b1 = (v3->Blue * y + v1->Blue * (dy - y )) / dy;
int b2 = (v2->Blue * y2 + v-> Blue * (dy2 - y2)) / dy2;
int x;
if (x1 < x2)
{
int dx = x2 - x1;
for (x = 0; x < dx; x++)
SetPixel (dev->hdc, x + x1, y + v1->y, RGB(
(r1 * (dx - x) + r2 * x) / dx >> 8,
(g1 * (dx - x) + g2 * x) / dx >> 8,
(b1 * (dx - x) + b2 * x) / dx >> 8));
}
else
{
int dx = x1 - x2;
for (x = 0; x < dx; x++)
SetPixel (dev->hdc, x + x2, y + v1->y, RGB(
(r2 * (dx - x) + r1 * x) / dx >> 8,
(g2 * (dx - x) + g1 * x) / dx >> 8,
(b2 * (dx - x) + b1 * x) / dx >> 8));
}
}
}
break;
default:
return FALSE;
/* compute bounding rect of all the rectangles/triangles */
dst.visrect.left = dst.visrect.top = INT_MAX;
dst.visrect.right = dst.visrect.bottom = INT_MIN;
for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
{
ULONG v = ((ULONG *)grad_array)[i];
dst.visrect.left = min( dst.visrect.left, pts[v].x );
dst.visrect.top = min( dst.visrect.top, pts[v].y );
dst.visrect.right = max( dst.visrect.right, pts[v].x );
dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
}
return TRUE;
dst.x = dst.visrect.left;
dst.y = dst.visrect.top;
dst.width = dst.visrect.right - dst.visrect.left;
dst.height = dst.visrect.bottom - dst.visrect.top;
if (get_clip_box( dc, &clip )) intersect_rect( &dst.visrect, &dst.visrect, &clip );
if (is_rect_empty( &dst.visrect )) goto done;
/* query the bitmap format */
info->bmiHeader.biSize = sizeof(info->bmiHeader);
info->bmiHeader.biPlanes = 1;
info->bmiHeader.biBitCount = 0;
info->bmiHeader.biCompression = BI_RGB;
info->bmiHeader.biXPelsPerMeter = 0;
info->bmiHeader.biYPelsPerMeter = 0;
info->bmiHeader.biClrUsed = 0;
info->bmiHeader.biClrImportant = 0;
info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
info->bmiHeader.biSizeImage = 0;
dev = GET_DC_PHYSDEV( dc, pPutImage );
err = dev->funcs->pPutImage( dev, 0, 0, info, NULL, NULL, NULL, 0 );
if ((err && err != ERROR_BAD_FORMAT) ||
!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ))))
{
ret = FALSE;
goto done;
}
bits.is_copy = TRUE;
bits.free = free_heap_bits;
/* make src and points relative to the bitmap */
src = dst;
src.x -= dst.visrect.left;
src.y -= dst.visrect.top;
offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
for (i = 0; i < nvert; i++)
{
pts[i].x -= dst.visrect.left;
pts[i].y -= dst.visrect.top;
}
rgn = CreateRectRgn( 0, 0, 0, 0 );
gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
if (dev->funcs->pPutImage( dev, 0, rgn, info, &bits, &src, &dst, SRCCOPY )) ret = FALSE;
if (bits.free) bits.free( &bits );
DeleteObject( rgn );
done:
HeapFree( GetProcessHeap(), 0, pts );
return ret;
}
/***********************************************************************

View File

@ -1334,13 +1334,67 @@ DWORD blend_bitmapinfo( const BITMAPINFO *src_info, void *src_bits, struct bitbl
return blend_rect( &dst_dib, &dst->visrect, &src_dib, &src->visrect, NULL, blend );
}
DWORD gradient_bitmapinfo( const BITMAPINFO *info, void *bits, TRIVERTEX *v, int mode )
DWORD gradient_bitmapinfo( const BITMAPINFO *info, void *bits, TRIVERTEX *vert_array, ULONG nvert,
void *grad_array, ULONG ngrad, ULONG mode, const POINT *dev_pts, HRGN rgn )
{
dib_info dib;
const GRADIENT_TRIANGLE *tri = grad_array;
const GRADIENT_RECT *rect = grad_array;
unsigned int i;
int y;
TRIVERTEX vert[3];
DWORD ret = ERROR_SUCCESS;
HRGN tmp_rgn = 0;
if (!init_dib_info_from_bitmapinfo( &dib, info, bits, 0 )) return ERROR_BAD_FORMAT;
if (!gradient_rect( &dib, v, mode, 0 )) return ERROR_INVALID_PARAMETER;
return ERROR_SUCCESS;
switch (mode)
{
case GRADIENT_FILL_RECT_H:
for (i = 0; i < ngrad; i++, rect++)
{
get_gradient_hrect_vertices( rect, vert_array, dev_pts, vert );
gradient_rect( &dib, vert, mode, 0 );
if (!tmp_rgn) tmp_rgn = CreateRectRgn( vert[0].x, vert[0].y, vert[1].x, vert[1].y );
else SetRectRgn( tmp_rgn, vert[0].x, vert[0].y, vert[1].x, vert[1].y );
CombineRgn( rgn, rgn, tmp_rgn, RGN_OR );
}
break;
case GRADIENT_FILL_RECT_V:
for (i = 0; i < ngrad; i++, rect++)
{
get_gradient_vrect_vertices( rect, vert_array, dev_pts, vert );
gradient_rect( &dib, vert, mode, 0 );
if (!tmp_rgn) tmp_rgn = CreateRectRgn( vert[0].x, vert[0].y, vert[1].x, vert[1].y );
else SetRectRgn( tmp_rgn, vert[0].x, vert[0].y, vert[1].x, vert[1].y );
CombineRgn( rgn, rgn, tmp_rgn, RGN_OR );
}
break;
case GRADIENT_FILL_TRIANGLE:
for (i = 0; i < ngrad; i++, tri++)
{
get_gradient_triangle_vertices( tri, vert_array, dev_pts, vert );
if (gradient_rect( &dib, vert, mode, 0 ))
{
if (!tmp_rgn) tmp_rgn = CreateRectRgn( 0, 0, 0, 0 );
for (y = vert[0].y; y < vert[2].y; y++)
{
int x1, x2 = edge_coord( y, vert[0].x, vert[0].y, vert[2].x, vert[2].y );
if (y < vert[1].y) x1 = edge_coord( y, vert[0].x, vert[0].y, vert[1].x, vert[1].y );
else x1 = edge_coord( y, vert[1].x, vert[1].y, vert[2].x, vert[2].y );
SetRectRgn( tmp_rgn, min(x1,x2), y, max(x1,x2), y + 1 );
CombineRgn( rgn, rgn, tmp_rgn, RGN_OR );
}
}
else ret = ERROR_INVALID_PARAMETER;
}
break;
}
DeleteObject( tmp_rgn );
return ret;
}
/***********************************************************************

View File

@ -246,7 +246,8 @@ extern DWORD stretch_bitmapinfo( const BITMAPINFO *src_info, void *src_bits, str
extern DWORD blend_bitmapinfo( const BITMAPINFO *src_info, void *src_bits, struct bitblt_coords *src,
const BITMAPINFO *dst_info, void *dst_bits, struct bitblt_coords *dst,
BLENDFUNCTION blend ) DECLSPEC_HIDDEN;
extern DWORD gradient_bitmapinfo( const BITMAPINFO *info, void *bits, TRIVERTEX *v, int mode ) DECLSPEC_HIDDEN;
extern DWORD gradient_bitmapinfo( const BITMAPINFO *info, void *bits, TRIVERTEX *vert_array, ULONG nvert,
void *grad_array, ULONG ngrad, ULONG mode, const POINT *dev_pts, HRGN rgn ) DECLSPEC_HIDDEN;
extern BOOL render_aa_text_bitmapinfo( HDC hdc, BITMAPINFO *info, struct gdi_image_bits *bits,
struct bitblt_coords *src, INT x, INT y, UINT flags,
UINT aa_flags, LPCWSTR str, UINT count, const INT *dx ) DECLSPEC_HIDDEN;