[gdiplus]

- Update to current Wine sources
- Now routes BMP drawing to gdi instead of doing ole32 magic (bug #3412)

svn path=/trunk/; revision=44308
This commit is contained in:
Gregor Schneider 2009-11-28 15:26:02 +00:00
parent 8e09c97596
commit 7171029029
6 changed files with 614 additions and 224 deletions

View file

@ -143,7 +143,7 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
}
case BrushTypeLinearGradient:{
GpLineGradient *dest, *src;
INT count;
INT count, pcount;
dest = GdipAlloc(sizeof(GpLineGradient));
if(!dest) return OutOfMemory;
@ -157,11 +157,20 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
count = dest->blendcount;
dest->blendfac = GdipAlloc(count * sizeof(REAL));
dest->blendpos = GdipAlloc(count * sizeof(REAL));
pcount = dest->pblendcount;
if (pcount)
{
dest->pblendcolor = GdipAlloc(pcount * sizeof(ARGB));
dest->pblendpos = GdipAlloc(pcount * sizeof(REAL));
}
if (!dest->blendfac || !dest->blendpos)
if (!dest->blendfac || !dest->blendpos ||
(pcount && (!dest->pblendcolor || !dest->pblendpos)))
{
GdipFree(dest->blendfac);
GdipFree(dest->blendpos);
GdipFree(dest->pblendcolor);
GdipFree(dest->pblendpos);
DeleteObject(dest->brush.gdibrush);
GdipFree(dest);
return OutOfMemory;
@ -170,6 +179,12 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL));
memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL));
if (pcount)
{
memcpy(dest->pblendcolor, src->pblendcolor, pcount * sizeof(ARGB));
memcpy(dest->pblendpos, src->pblendpos, pcount * sizeof(REAL));
}
*clone = &dest->brush;
break;
}
@ -189,19 +204,38 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
return Ok;
}
static LONG HatchStyleToHatch(HatchStyle hatchstyle)
{
switch (hatchstyle)
{
case HatchStyleHorizontal: return HS_HORIZONTAL;
case HatchStyleVertical: return HS_VERTICAL;
case HatchStyleForwardDiagonal: return HS_FDIAGONAL;
case HatchStyleBackwardDiagonal: return HS_BDIAGONAL;
case HatchStyleCross: return HS_CROSS;
case HatchStyleDiagonalCross: return HS_DIAGCROSS;
default: return 0;
}
}
static const char HatchBrushes[][8] = {
{ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HatchStyleHorizontal */
{ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleVertical */
{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HatchStyleForwardDiagonal */
{ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleBackwardDiagonal */
{ 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleCross */
{ 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleDiagonalCross */
{ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */
{ 0x00, 0x02, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88 }, /* HatchStyle10Percent */
{ 0x00, 0x22, 0x00, 0xcc, 0x00, 0x22, 0x00, 0xcc }, /* HatchStyle20Percent */
{ 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc }, /* HatchStyle25Percent */
{ 0x00, 0xcc, 0x04, 0xcc, 0x00, 0xcc, 0x40, 0xcc }, /* HatchStyle30Percent */
{ 0x44, 0xcc, 0x22, 0xcc, 0x44, 0xcc, 0x22, 0xcc }, /* HatchStyle40Percent */
{ 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc }, /* HatchStyle50Percent */
{ 0x55, 0xcd, 0x55, 0xee, 0x55, 0xdc, 0x55, 0xee }, /* HatchStyle60Percent */
{ 0x55, 0xdd, 0x55, 0xff, 0x55, 0xdd, 0x55, 0xff }, /* HatchStyle70Percent */
{ 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff }, /* HatchStyle75Percent */
{ 0x55, 0xff, 0x59, 0xff, 0x55, 0xff, 0x99, 0xff }, /* HatchStyle80Percent */
{ 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xfd, 0xff }, /* HatchStyle90Percent */
{ 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 }, /* HatchStyleLightDownwardDiagonal */
{ 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 }, /* HatchStyleLightUpwardDiagonal */
{ 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc }, /* HatchStyleDarkDownwardDiagonal */
{ 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99 }, /* HatchStyleDarkUpwardDiagonal */
{ 0xc1, 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0 }, /* HatchStyleWideDownwardDiagonal */
{ 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83, 0xc1 }, /* HatchStyleWideUpwardDiagonal */
{ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, /* HatchStyleLightVertical */
{ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleLightHorizontal */
{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, /* HatchStyleNarrowVertical */
{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, /* HatchStyleNarrowHorizontal */
{ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, /* HatchStyleDarkVertical */
{ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */
};
/******************************************************************************
* GdipCreateHatchBrush [GDIPLUS.@]
@ -209,6 +243,7 @@ static LONG HatchStyleToHatch(HatchStyle hatchstyle)
GpStatus WINGDIPAPI GdipCreateHatchBrush(HatchStyle hatchstyle, ARGB forecol, ARGB backcol, GpHatch **brush)
{
COLORREF fgcol = ARGB2COLORREF(forecol);
GpStatus stat = Ok;
TRACE("(%d, %d, %d, %p)\n", hatchstyle, forecol, backcol, brush);
@ -217,37 +252,79 @@ GpStatus WINGDIPAPI GdipCreateHatchBrush(HatchStyle hatchstyle, ARGB forecol, AR
*brush = GdipAlloc(sizeof(GpHatch));
if (!*brush) return OutOfMemory;
switch (hatchstyle)
if (hatchstyle < sizeof(HatchBrushes) / sizeof(HatchBrushes[0]))
{
case HatchStyleHorizontal:
case HatchStyleVertical:
case HatchStyleForwardDiagonal:
case HatchStyleBackwardDiagonal:
case HatchStyleCross:
case HatchStyleDiagonalCross:
/* Brushes that map to BS_HATCHED */
(*brush)->brush.lb.lbStyle = BS_HATCHED;
(*brush)->brush.lb.lbColor = fgcol;
(*brush)->brush.lb.lbHatch = HatchStyleToHatch(hatchstyle);
break;
HBITMAP hbmp;
HDC hdc;
BITMAPINFOHEADER bmih;
DWORD* bits;
int x, y;
default:
FIXME("Unimplemented hatch style %d\n", hatchstyle);
hdc = CreateCompatibleDC(0);
(*brush)->brush.lb.lbStyle = BS_SOLID;
(*brush)->brush.lb.lbColor = fgcol;
(*brush)->brush.lb.lbHatch = 0;
break;
if (hdc)
{
bmih.biSize = sizeof(bmih);
bmih.biWidth = 8;
bmih.biHeight = 8;
bmih.biPlanes = 1;
bmih.biBitCount = 32;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
hbmp = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
if (hbmp)
{
for (y=0; y<8; y++)
for (x=0; x<8; x++)
if ((HatchBrushes[hatchstyle][y] & (0x80 >> x)) != 0)
bits[y*8+x] = forecol;
else
bits[y*8+x] = backcol;
}
else
stat = GenericError;
DeleteDC(hdc);
}
else
stat = GenericError;
if (stat == Ok)
{
(*brush)->brush.lb.lbStyle = BS_PATTERN;
(*brush)->brush.lb.lbColor = 0;
(*brush)->brush.lb.lbHatch = (ULONG_PTR)hbmp;
(*brush)->brush.gdibrush = CreateBrushIndirect(&(*brush)->brush.lb);
DeleteObject(hbmp);
}
}
else
{
FIXME("Unimplemented hatch style %d\n", hatchstyle);
(*brush)->brush.lb.lbStyle = BS_SOLID;
(*brush)->brush.lb.lbColor = fgcol;
(*brush)->brush.lb.lbHatch = 0;
(*brush)->brush.gdibrush = CreateBrushIndirect(&(*brush)->brush.lb);
}
if (stat == Ok)
{
(*brush)->brush.bt = BrushTypeHatchFill;
(*brush)->forecol = forecol;
(*brush)->backcol = backcol;
(*brush)->hatchstyle = hatchstyle;
}
else
{
GdipFree(*brush);
*brush = NULL;
}
(*brush)->brush.gdibrush = CreateBrushIndirect(&(*brush)->brush.lb);
(*brush)->brush.bt = BrushTypeHatchFill;
(*brush)->forecol = forecol;
(*brush)->backcol = backcol;
(*brush)->hatchstyle = hatchstyle;
return Ok;
return stat;
}
/******************************************************************************
@ -316,6 +393,10 @@ GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint,
(*line)->blendfac[0] = 1.0f;
(*line)->blendpos[0] = 1.0f;
(*line)->pblendcolor = NULL;
(*line)->pblendpos = NULL;
(*line)->pblendcount = 0;
return Ok;
}
@ -762,7 +843,7 @@ GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
/* image is flipped */
if(pbmi->bmiHeader.biHeight > 0){
dibits += pbmi->bmiHeader.biSizeImage;
dibits += image_stride * (pbmi->bmiHeader.biHeight - 1);
image_stride *= -1;
textbits += stride * (n_height - 1);
stride *= -1;
@ -893,6 +974,8 @@ GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush)
case BrushTypeLinearGradient:
GdipFree(((GpLineGradient*)brush)->blendfac);
GdipFree(((GpLineGradient*)brush)->blendpos);
GdipFree(((GpLineGradient*)brush)->pblendcolor);
GdipFree(((GpLineGradient*)brush)->pblendpos);
break;
case BrushTypeTextureFill:
GdipDeleteMatrix(((GpTexture*)brush)->transform);
@ -1600,6 +1683,69 @@ GpStatus WINGDIPAPI GdipSetLineLinearBlend(GpLineGradient *brush, REAL focus,
GpStatus WINGDIPAPI GdipSetLinePresetBlend(GpLineGradient *brush,
GDIPCONST ARGB *blend, GDIPCONST REAL* positions, INT count)
{
ARGB *new_color;
REAL *new_pos;
TRACE("(%p,%p,%p,%i)\n", brush, blend, positions, count);
if (!brush || !blend || !positions || count < 2 ||
positions[0] != 0.0f || positions[count-1] != 1.0f)
{
return InvalidParameter;
}
new_color = GdipAlloc(count * sizeof(ARGB));
new_pos = GdipAlloc(count * sizeof(REAL));
if (!new_color || !new_pos)
{
GdipFree(new_color);
GdipFree(new_pos);
return OutOfMemory;
}
memcpy(new_color, blend, sizeof(ARGB) * count);
memcpy(new_pos, positions, sizeof(REAL) * count);
GdipFree(brush->pblendcolor);
GdipFree(brush->pblendpos);
brush->pblendcolor = new_color;
brush->pblendpos = new_pos;
brush->pblendcount = count;
return Ok;
}
GpStatus WINGDIPAPI GdipGetLinePresetBlend(GpLineGradient *brush,
ARGB *blend, REAL* positions, INT count)
{
if (!brush || !blend || !positions || count < 2)
return InvalidParameter;
if (brush->pblendcount == 0)
return GenericError;
if (count < brush->pblendcount)
return InsufficientBuffer;
memcpy(blend, brush->pblendcolor, sizeof(ARGB) * brush->pblendcount);
memcpy(positions, brush->pblendpos, sizeof(REAL) * brush->pblendcount);
return Ok;
}
GpStatus WINGDIPAPI GdipGetLinePresetBlendCount(GpLineGradient *brush,
INT *count)
{
if (!brush || !count)
return InvalidParameter;
*count = brush->pblendcount;
return Ok;
}
GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient *brush)
{
static int calls;
@ -1620,6 +1766,17 @@ GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush,
return NotImplemented;
}
GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient *brush, REAL sx, REAL sy,
GpMatrixOrder order)
{
static int calls;
if(!(calls++))
FIXME("not implemented\n");
return NotImplemented;
}
GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient* brush,
REAL dx, REAL dy, GpMatrixOrder order)
{

View file

@ -86,7 +86,7 @@ Status WINAPI GdiplusStartup(ULONG_PTR *token, const struct GdiplusStartupInput
input->DebugEventCallback, input->SuppressBackgroundThread,
input->SuppressExternalCodecs);
if(input->GdiplusVersion != 1)
if(input->GdiplusVersion < 1 || input->GdiplusVersion > 2)
return UnsupportedGdiplusVersion;
if(input->SuppressBackgroundThread){
@ -211,38 +211,37 @@ static void unstretch_angle(REAL * angle, REAL rad_x, REAL rad_y)
INT arc2polybezier(GpPointF * points, REAL x1, REAL y1, REAL x2, REAL y2,
REAL startAngle, REAL sweepAngle)
{
INT i, count;
INT i;
REAL end_angle, start_angle, endAngle;
endAngle = startAngle + sweepAngle;
unstretch_angle(&startAngle, x2 / 2.0, y2 / 2.0);
unstretch_angle(&endAngle, x2 / 2.0, y2 / 2.0);
count = ceilf(fabs(endAngle - startAngle) / M_PI_2) * 3 + 1;
/* don't make more than a full circle */
count = min(MAX_ARC_PTS, count);
if(count == 1)
return 0;
if(!points)
return count;
/* start_angle and end_angle are the iterative variables */
start_angle = startAngle;
for(i = 0; i < count - 1; i += 3){
for(i = 0; i < MAX_ARC_PTS - 1; i += 3){
/* check if we've overshot the end angle */
if( sweepAngle > 0.0 )
{
if (start_angle >= endAngle) break;
end_angle = min(start_angle + M_PI_2, endAngle);
}
else
{
if (start_angle <= endAngle) break;
end_angle = max(start_angle - M_PI_2, endAngle);
}
add_arc_part(&points[i], x1, y1, x2, y2, start_angle, end_angle, i == 0);
if (points)
add_arc_part(&points[i], x1, y1, x2, y2, start_angle, end_angle, i == 0);
start_angle += M_PI_2 * (sweepAngle < 0.0 ? -1.0 : 1.0);
}
return count;
if (i == 0) return 0;
else return i+1;
}
COLORREF ARGB2COLORREF(ARGB color)
@ -419,7 +418,7 @@ void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height,
}
/* recursive deletion of GpRegion nodes */
inline void delete_element(region_element* element)
void delete_element(region_element* element)
{
switch(element->type)
{

View file

@ -304,8 +304,8 @@
@ stdcall GdipGetLineBlendCount(ptr ptr)
@ stdcall GdipGetLineColors(ptr ptr)
@ stdcall GdipGetLineGammaCorrection(ptr ptr)
@ stub GdipGetLinePresetBlend
@ stub GdipGetLinePresetBlendCount
@ stdcall GdipGetLinePresetBlend(ptr ptr ptr long)
@ stdcall GdipGetLinePresetBlendCount(ptr ptr)
@ stdcall GdipGetLineRect(ptr ptr)
@ stdcall GdipGetLineRectI(ptr ptr)
@ stdcall GdipGetLineSpacing(ptr long ptr)
@ -476,7 +476,7 @@
@ stdcall GdipRemovePropertyItem(ptr long)
@ stdcall GdipResetClip(ptr)
@ stub GdipResetImageAttributes
@ stub GdipResetLineTransform
@ stdcall GdipResetLineTransform(ptr)
@ stub GdipResetPageTransform
@ stdcall GdipResetPath(ptr)
@ stub GdipResetPathGradientTransform
@ -496,7 +496,7 @@
@ stdcall GdipSaveGraphics(ptr ptr)
@ stdcall GdipSaveImageToFile(ptr ptr ptr ptr)
@ stdcall GdipSaveImageToStream(ptr ptr ptr ptr)
@ stub GdipScaleLineTransform
@ stdcall GdipScaleLineTransform(ptr long long long)
@ stdcall GdipScaleMatrix(ptr long long long)
@ stub GdipScalePathGradientTransform
@ stdcall GdipScalePenTransform(ptr long long long)

View file

@ -61,7 +61,7 @@ extern BOOL lengthen_path(GpPath *path, INT len);
extern GpStatus trace_path(GpGraphics *graphics, GpPath *path);
typedef struct region_element region_element;
extern inline void delete_element(region_element *element);
extern void delete_element(region_element *element);
static inline INT roundr(REAL x)
{
@ -166,6 +166,9 @@ struct GpLineGradient{
REAL* blendfac; /* blend factors */
REAL* blendpos; /* blend positions */
INT blendcount;
ARGB* pblendcolor; /* preset blend colors */
REAL* pblendpos; /* preset blend positions */
INT pblendcount;
};
struct GpTexture{
@ -208,6 +211,7 @@ struct GpAdustableArrowCap{
struct GpImage{
IPicture* picture;
ImageType type;
GUID format;
UINT flags;
};

View file

@ -220,7 +220,27 @@ static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)
blendfac = (left_blendfac * (right_blendpos - position) +
right_blendfac * (position - left_blendpos)) / range;
}
return blend_colors(brush->startcolor, brush->endcolor, blendfac);
if (brush->pblendcount == 0)
return blend_colors(brush->startcolor, brush->endcolor, blendfac);
else
{
int i=1;
ARGB left_blendcolor, right_blendcolor;
REAL left_blendpos, right_blendpos;
/* locate the blend colors surrounding this position */
while (blendfac > brush->pblendpos[i])
i++;
/* interpolate between the blend colors */
left_blendpos = brush->pblendpos[i-1];
left_blendcolor = brush->pblendcolor[i-1];
right_blendpos = brush->pblendpos[i];
right_blendcolor = brush->pblendcolor[i];
blendfac = (blendfac - left_blendpos) / (right_blendpos - left_blendpos);
return blend_colors(left_blendcolor, right_blendcolor, blendfac);
}
}
static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
@ -1235,6 +1255,7 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
(*metafile)->image.type = ImageTypeMetafile;
memcpy(&(*metafile)->image.format, &ImageFormatWMF, sizeof(GUID));
(*metafile)->bounds.X = ((REAL) placeable->BoundingBox.Left) / ((REAL) placeable->Inch);
(*metafile)->bounds.Y = ((REAL) placeable->BoundingBox.Right) / ((REAL) placeable->Inch);
(*metafile)->bounds.Width = ((REAL) (placeable->BoundingBox.Right
@ -1795,16 +1816,25 @@ GpStatus WINGDIPAPI GdipDrawImagePointRect(GpGraphics *graphics, GpImage *image,
REAL x, REAL y, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight,
GpUnit srcUnit)
{
FIXME("(%p, %p, %f, %f, %f, %f, %f, %f, %d): stub\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
return NotImplemented;
GpPointF points[3];
TRACE("(%p, %p, %f, %f, %f, %f, %f, %f, %d)\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
points[0].X = points[2].X = x;
points[0].Y = points[1].Y = y;
/* FIXME: convert image coordinates to Graphics coordinates? */
points[1].X = x + srcwidth;
points[2].Y = y + srcheight;
return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy,
srcwidth, srcheight, srcUnit, NULL, NULL, NULL);
}
GpStatus WINGDIPAPI GdipDrawImagePointRectI(GpGraphics *graphics, GpImage *image,
INT x, INT y, INT srcx, INT srcy, INT srcwidth, INT srcheight,
GpUnit srcUnit)
{
FIXME("(%p, %p, %d, %d, %d, %d, %d, %d, %d): stub\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
return NotImplemented;
return GdipDrawImagePointRect(graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
}
GpStatus WINGDIPAPI GdipDrawImagePoints(GpGraphics *graphics, GpImage *image,
@ -1854,15 +1884,6 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
else
return NotImplemented;
/* IPicture renders bitmaps with the y-axis reversed
* FIXME: flipping for unknown image type might not be correct. */
if(image->type != ImageTypeMetafile){
INT temp;
temp = pti[0].y;
pti[0].y = pti[2].y;
pti[2].y = temp;
}
if(IPicture_Render(image->picture, graphics->hdc,
pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y,
srcx * dx, srcy * dy,
@ -2362,7 +2383,7 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
HFONT gdifont;
LOGFONTW lfw;
TEXTMETRICW textmet;
GpPointF pt[2], rectcpy[4];
GpPointF pt[3], rectcpy[4];
POINT corners[4];
WCHAR* stringdup;
REAL angle, ang_cos, ang_sin, rel_width, rel_height;
@ -2409,6 +2430,21 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
SetBkMode(graphics->hdc, TRANSPARENT);
SetTextColor(graphics->hdc, brush->lb.lbColor);
pt[0].X = 0.0;
pt[0].Y = 0.0;
pt[1].X = 1.0;
pt[1].Y = 0.0;
pt[2].X = 0.0;
pt[2].Y = 1.0;
GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
ang_cos = cos(angle);
ang_sin = sin(angle);
rel_width = sqrt((pt[1].Y-pt[0].Y)*(pt[1].Y-pt[0].Y)+
(pt[1].X-pt[0].X)*(pt[1].X-pt[0].X));
rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+
(pt[2].X-pt[0].X)*(pt[2].X-pt[0].X));
rectcpy[3].X = rectcpy[0].X = rect->X;
rectcpy[1].Y = rectcpy[0].Y = rect->Y + offsety;
rectcpy[2].X = rectcpy[1].X = rect->X + rect->Width;
@ -2416,30 +2452,14 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
transform_and_round_points(graphics, corners, rectcpy, 4);
if (roundr(rect->Width) == 0)
{
rel_width = 1.0;
nwidth = INT_MAX;
}
else
{
rel_width = sqrt((corners[1].x - corners[0].x) * (corners[1].x - corners[0].x) +
(corners[1].y - corners[0].y) * (corners[1].y - corners[0].y))
/ rect->Width;
nwidth = roundr(rel_width * rect->Width);
}
if (roundr(rect->Height) == 0)
{
rel_height = 1.0;
nheight = INT_MAX;
}
else
{
rel_height = sqrt((corners[2].x - corners[1].x) * (corners[2].x - corners[1].x) +
(corners[2].y - corners[1].y) * (corners[2].y - corners[1].y))
/ rect->Height;
nheight = roundr(rel_height * rect->Height);
}
if (roundr(rect->Width) != 0 && roundr(rect->Height) != 0)
{
@ -2457,14 +2477,6 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
lfw.lfHeight = roundr(((REAL)lfw.lfHeight) * rel_height);
lfw.lfWidth = roundr(textmet.tmAveCharWidth * rel_width);
pt[0].X = 0.0;
pt[0].Y = 0.0;
pt[1].X = 1.0;
pt[1].Y = 0.0;
GdipTransformMatrixPoints(graphics->worldtrans, pt, 2);
angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
ang_cos = cos(angle);
ang_sin = sin(angle);
lfw.lfEscapement = lfw.lfOrientation = roundr((angle / M_PI) * 1800.0);
gdifont = CreateFontIndirectW(&lfw);

View file

@ -94,36 +94,321 @@ GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap** inputBitmaps,
return NotImplemented;
}
static inline void getpixel_16bppGrayScale(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
const BYTE *row, UINT x)
{
*r = *g = *b = row[x*2+1];
*a = 255;
}
static inline void getpixel_16bppRGB555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
const BYTE *row, UINT x)
{
WORD pixel = *((WORD*)(row)+x);
*r = (pixel>>7&0xf8)|(pixel>>12&0x7);
*g = (pixel>>2&0xf8)|(pixel>>6&0x7);
*b = (pixel<<3&0xf8)|(pixel>>2&0x7);
*a = 255;
}
static inline void getpixel_16bppRGB565(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
const BYTE *row, UINT x)
{
WORD pixel = *((WORD*)(row)+x);
*r = (pixel>>8&0xf8)|(pixel>>13&0x7);
*g = (pixel>>3&0xfc)|(pixel>>9&0x3);
*b = (pixel<<3&0xf8)|(pixel>>2&0x7);
*a = 255;
}
static inline void getpixel_16bppARGB1555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
const BYTE *row, UINT x)
{
WORD pixel = *((WORD*)(row)+x);
*r = (pixel>>7&0xf8)|(pixel>>12&0x7);
*g = (pixel>>2&0xf8)|(pixel>>6&0x7);
*b = (pixel<<3&0xf8)|(pixel>>2&0x7);
if ((pixel&0x8000) == 0x8000)
*a = 255;
else
*a = 0;
}
static inline void getpixel_24bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
const BYTE *row, UINT x)
{
*r = row[x*3+2];
*g = row[x*3+1];
*b = row[x*3];
*a = 255;
}
static inline void getpixel_32bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
const BYTE *row, UINT x)
{
*r = row[x*4+2];
*g = row[x*4+1];
*b = row[x*4];
*a = 255;
}
static inline void getpixel_32bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
const BYTE *row, UINT x)
{
*r = row[x*4+2];
*g = row[x*4+1];
*b = row[x*4];
*a = row[x*4+3];
}
static inline void getpixel_32bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
const BYTE *row, UINT x)
{
*a = row[x*4+3];
if (*a == 0)
*r = *g = *b = 0;
else
{
*r = row[x*4+2] * 255 / *a;
*g = row[x*4+1] * 255 / *a;
*b = row[x*4] * 255 / *a;
}
}
static inline void getpixel_48bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
const BYTE *row, UINT x)
{
*r = row[x*6+5];
*g = row[x*6+3];
*b = row[x*6+1];
*a = 255;
}
static inline void getpixel_64bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
const BYTE *row, UINT x)
{
*r = row[x*8+5];
*g = row[x*8+3];
*b = row[x*8+1];
*a = row[x*8+7];
}
static inline void getpixel_64bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
const BYTE *row, UINT x)
{
*a = row[x*8+7];
if (*a == 0)
*r = *g = *b = 0;
else
{
*r = row[x*8+5] * 255 / *a;
*g = row[x*8+3] * 255 / *a;
*b = row[x*8+1] * 255 / *a;
}
}
GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
ARGB *color)
{
static int calls;
BYTE r, g, b, a;
BYTE *row;
TRACE("%p %d %d %p\n", bitmap, x, y, color);
if(!bitmap || !color)
if(!bitmap || !color ||
x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
return InvalidParameter;
if(!(calls++))
FIXME("not implemented\n");
row = bitmap->bits+bitmap->stride*y;
*color = 0xdeadbeef;
switch (bitmap->format)
{
case PixelFormat16bppGrayScale:
getpixel_16bppGrayScale(&r,&g,&b,&a,row,x);
break;
case PixelFormat16bppRGB555:
getpixel_16bppRGB555(&r,&g,&b,&a,row,x);
break;
case PixelFormat16bppRGB565:
getpixel_16bppRGB565(&r,&g,&b,&a,row,x);
break;
case PixelFormat16bppARGB1555:
getpixel_16bppARGB1555(&r,&g,&b,&a,row,x);
break;
case PixelFormat24bppRGB:
getpixel_24bppRGB(&r,&g,&b,&a,row,x);
break;
case PixelFormat32bppRGB:
getpixel_32bppRGB(&r,&g,&b,&a,row,x);
break;
case PixelFormat32bppARGB:
getpixel_32bppARGB(&r,&g,&b,&a,row,x);
break;
case PixelFormat32bppPARGB:
getpixel_32bppPARGB(&r,&g,&b,&a,row,x);
break;
case PixelFormat48bppRGB:
getpixel_48bppRGB(&r,&g,&b,&a,row,x);
break;
case PixelFormat64bppARGB:
getpixel_64bppARGB(&r,&g,&b,&a,row,x);
break;
case PixelFormat64bppPARGB:
getpixel_64bppPARGB(&r,&g,&b,&a,row,x);
break;
default:
FIXME("not implemented for format 0x%x\n", bitmap->format);
return NotImplemented;
}
return NotImplemented;
*color = a<<24|r<<16|g<<8|b;
return Ok;
}
static inline void setpixel_16bppGrayScale(BYTE r, BYTE g, BYTE b, BYTE a,
BYTE *row, UINT x)
{
*((WORD*)(row)+x) = (r+g+b)*85;
}
static inline void setpixel_16bppRGB555(BYTE r, BYTE g, BYTE b, BYTE a,
BYTE *row, UINT x)
{
*((WORD*)(row)+x) = (r<<7&0x7c00)|
(g<<2&0x03e0)|
(b>>3&0x001f);
}
static inline void setpixel_16bppRGB565(BYTE r, BYTE g, BYTE b, BYTE a,
BYTE *row, UINT x)
{
*((WORD*)(row)+x) = (r<<8&0xf800)|
(g<<3&0x07e0)|
(b>>3&0x001f);
}
static inline void setpixel_16bppARGB1555(BYTE r, BYTE g, BYTE b, BYTE a,
BYTE *row, UINT x)
{
*((WORD*)(row)+x) = (a<<8&0x8000)|
(r<<7&0x7c00)|
(g<<2&0x03e0)|
(b>>3&0x001f);
}
static inline void setpixel_24bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
BYTE *row, UINT x)
{
row[x*3+2] = r;
row[x*3+1] = g;
row[x*3] = b;
}
static inline void setpixel_32bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
BYTE *row, UINT x)
{
*((DWORD*)(row)+x) = (r<<16)|(g<<8)|b;
}
static inline void setpixel_32bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
BYTE *row, UINT x)
{
*((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
}
static inline void setpixel_32bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
BYTE *row, UINT x)
{
r = r * a / 255;
g = g * a / 255;
b = b * a / 255;
*((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
}
static inline void setpixel_48bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
BYTE *row, UINT x)
{
row[x*6+5] = row[x*6+4] = r;
row[x*6+3] = row[x*6+2] = g;
row[x*6+1] = row[x*6] = b;
}
static inline void setpixel_64bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
BYTE *row, UINT x)
{
UINT64 a64=a, r64=r, g64=g, b64=b;
*((UINT64*)(row)+x) = (a64<<56)|(a64<<48)|(r64<<40)|(r64<<32)|(g64<<24)|(g64<<16)|(b64<<8)|b64;
}
static inline void setpixel_64bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
BYTE *row, UINT x)
{
UINT64 a64, r64, g64, b64;
a64 = a * 257;
r64 = r * a / 255;
g64 = g * a / 255;
b64 = b * a / 255;
*((UINT64*)(row)+x) = (a64<<48)|(r64<<32)|(g64<<16)|b64;
}
GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y,
ARGB color)
{
static int calls;
BYTE a, r, g, b;
BYTE *row;
TRACE("bitmap:%p, x:%d, y:%d, color:%08x\n", bitmap, x, y, color);
if(!bitmap)
if(!bitmap || x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
return InvalidParameter;
if(!(calls++))
FIXME("not implemented\n");
a = color>>24;
r = color>>16;
g = color>>8;
b = color;
return NotImplemented;
row = bitmap->bits + bitmap->stride * y;
switch (bitmap->format)
{
case PixelFormat16bppGrayScale:
setpixel_16bppGrayScale(r,g,b,a,row,x);
break;
case PixelFormat16bppRGB555:
setpixel_16bppRGB555(r,g,b,a,row,x);
break;
case PixelFormat16bppRGB565:
setpixel_16bppRGB565(r,g,b,a,row,x);
break;
case PixelFormat16bppARGB1555:
setpixel_16bppARGB1555(r,g,b,a,row,x);
break;
case PixelFormat24bppRGB:
setpixel_24bppRGB(r,g,b,a,row,x);
break;
case PixelFormat32bppRGB:
setpixel_32bppRGB(r,g,b,a,row,x);
break;
case PixelFormat32bppARGB:
setpixel_32bppARGB(r,g,b,a,row,x);
break;
case PixelFormat32bppPARGB:
setpixel_32bppPARGB(r,g,b,a,row,x);
break;
case PixelFormat48bppRGB:
setpixel_48bppRGB(r,g,b,a,row,x);
break;
case PixelFormat64bppARGB:
setpixel_64bppARGB(r,g,b,a,row,x);
break;
case PixelFormat64bppPARGB:
setpixel_64bppPARGB(r,g,b,a,row,x);
break;
default:
FIXME("not implemented for format 0x%x\n", bitmap->format);
return NotImplemented;
}
return Ok;
}
/* This function returns a pointer to an array of pixels that represents the
@ -413,6 +698,8 @@ GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
GdipDisposeImage(*cloneImage);
*cloneImage = NULL;
}
else memcpy(&(*cloneImage)->format, &image->format, sizeof(GUID));
return stat;
}
else
@ -645,11 +932,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap)
TRACE("%p, %p\n", hicon, bitmap);
if(!bitmap || !GetIconInfo(hicon, &iinfo))
{
DeleteObject(iinfo.hbmColor);
DeleteObject(iinfo.hbmMask);
return InvalidParameter;
}
/* get the size of the icon */
ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);
@ -858,6 +1141,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
}
(*bitmap)->image.type = ImageTypeBitmap;
memcpy(&(*bitmap)->image.format, &ImageFormatMemoryBMP, sizeof(GUID));
(*bitmap)->image.flags = ImageFlagsNone;
(*bitmap)->width = width;
(*bitmap)->height = height;
@ -1144,23 +1428,11 @@ GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format)
GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
{
static int calls;
if(!image || !format)
return InvalidParameter;
if(!(calls++))
FIXME("stub\n");
memcpy(format, &image->format, sizeof(GUID));
/* FIXME: should be detected from embedded picture or stored separately */
switch (image->type)
{
case ImageTypeBitmap: *format = ImageFormatBMP; break;
case ImageTypeMetafile: *format = ImageFormatEMF; break;
default:
WARN("unknown type %u\n", image->type);
*format = ImageFormatUndefined;
}
return Ok;
}
@ -1507,107 +1779,39 @@ static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, GpImage **ima
return decode_image_wic(stream, &CLSID_WICIcoDecoder, image);
}
static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, GpImage **image)
{
GpStatus status;
GpBitmap* bitmap;
status = decode_image_wic(stream, &CLSID_WICBmpDecoder, image);
bitmap = (GpBitmap*)*image;
if (status == Ok && bitmap->format == PixelFormat32bppARGB)
{
/* WIC supports bmp files with alpha, but gdiplus does not */
bitmap->format = PixelFormat32bppRGB;
}
return status;
}
static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, GpImage **image)
{
return decode_image_wic(stream, &CLSID_WICJpegDecoder, image);
}
static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, GpImage **image)
{
return decode_image_wic(stream, &CLSID_WICPngDecoder, image);
}
static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, GpImage **image)
{
return decode_image_wic(stream, &CLSID_WICGifDecoder, image);
}
static GpStatus decode_image_olepicture_bitmap(IStream* stream, REFCLSID clsid, GpImage **image)
{
IPicture *pic;
BITMAPINFO *pbmi;
BITMAPCOREHEADER* bmch;
HBITMAP hbm;
HDC hdc;
TRACE("%p %p\n", stream, image);
if(!stream || !image)
return InvalidParameter;
if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
(LPVOID*) &pic) != S_OK){
TRACE("Could not load picture\n");
return GenericError;
}
pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
if (!pbmi)
return OutOfMemory;
*image = GdipAlloc(sizeof(GpBitmap));
if(!*image){
GdipFree(pbmi);
return OutOfMemory;
}
(*image)->type = ImageTypeBitmap;
(*((GpBitmap**) image))->width = ipicture_pixel_width(pic);
(*((GpBitmap**) image))->height = ipicture_pixel_height(pic);
/* get the pixel format */
IPicture_get_Handle(pic, (OLE_HANDLE*)&hbm);
IPicture_get_CurDC(pic, &hdc);
(*((GpBitmap**) image))->hbitmap = hbm;
(*((GpBitmap**) image))->hdc = hdc;
(*((GpBitmap**) image))->bits = NULL;
bmch = (BITMAPCOREHEADER*) (&pbmi->bmiHeader);
bmch->bcSize = sizeof(BITMAPCOREHEADER);
if(!hdc){
HBITMAP old;
hdc = CreateCompatibleDC(0);
old = SelectObject(hdc, hbm);
GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
SelectObject(hdc, old);
DeleteDC(hdc);
}
else
GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
switch(bmch->bcBitCount)
{
case 1:
(*((GpBitmap**) image))->format = PixelFormat1bppIndexed;
break;
case 4:
(*((GpBitmap**) image))->format = PixelFormat4bppIndexed;
break;
case 8:
(*((GpBitmap**) image))->format = PixelFormat8bppIndexed;
break;
case 16:
(*((GpBitmap**) image))->format = PixelFormat16bppRGB565;
break;
case 24:
(*((GpBitmap**) image))->format = PixelFormat24bppRGB;
break;
case 32:
(*((GpBitmap**) image))->format = PixelFormat32bppRGB;
break;
case 48:
(*((GpBitmap**) image))->format = PixelFormat48bppRGB;
break;
default:
FIXME("Bit depth %d is not fully supported yet\n", bmch->bcBitCount);
(*((GpBitmap**) image))->format = (bmch->bcBitCount << 8) | PixelFormatGDI;
break;
}
GdipFree(pbmi);
(*image)->picture = pic;
(*image)->flags = ImageFlagsNone;
return Ok;
}
static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, GpImage **image)
{
IPicture *pic;
@ -1715,7 +1919,15 @@ GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
if (FAILED(hr)) return hresult_to_status(hr);
/* call on the image decoder to do the real work */
return codec->decode_func(stream, &codec->info.Clsid, image);
stat = codec->decode_func(stream, &codec->info.Clsid, image);
/* take note of the original data format */
if (stat == Ok)
{
memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
}
return stat;
}
/* FIXME: no ICM */
@ -1915,6 +2127,12 @@ static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
return encode_image_WIC(image, stream, &CLSID_WICBmpEncoder, params);
}
static GpStatus encode_image_png(GpImage *image, IStream* stream,
GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
{
return encode_image_WIC(image, stream, &CLSID_WICPngEncoder, params);
}
/*****************************************************************************
* GdipSaveImageToStream [GDIPLUS.@]
*/
@ -2051,7 +2269,7 @@ static const struct image_codec codecs[NUM_CODECS] = {
/* SigMask */ bmp_sig_mask,
},
encode_image_BMP,
decode_image_olepicture_bitmap
decode_image_bmp
},
{
{ /* JPEG */
@ -2138,15 +2356,15 @@ static const struct image_codec codecs[NUM_CODECS] = {
/* FormatDescription */ png_format,
/* FilenameExtension */ png_extension,
/* MimeType */ png_mimetype,
/* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
/* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
/* Version */ 1,
/* SigCount */ 1,
/* SigSize */ 8,
/* SigPattern */ png_sig_pattern,
/* SigMask */ png_sig_mask,
},
NULL,
decode_image_olepicture_bitmap
encode_image_png,
decode_image_png
},
{
{ /* ICO */