- Sync gdiplus with Wine 1.1.21
authorDmitry Chapyshev <dmitry@reactos.org>
Sat, 9 May 2009 09:26:16 +0000 (09:26 +0000)
committerDmitry Chapyshev <dmitry@reactos.org>
Sat, 9 May 2009 09:26:16 +0000 (09:26 +0000)
svn path=/trunk/; revision=40851

reactos/dll/win32/gdiplus/brush.c
reactos/dll/win32/gdiplus/font.c
reactos/dll/win32/gdiplus/gdiplus.spec
reactos/dll/win32/gdiplus/gdiplus_private.h
reactos/dll/win32/gdiplus/graphics.c
reactos/dll/win32/gdiplus/image.c

index f0c9b20..f24d8db 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 
 
 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 
+/*
+    Unix stuff
+    Code from http://www.johndcook.com/blog/2009/01/19/stand-alone-error-function-erf/
+*/
+double erf(double x)
+{
+    const float a1 =  0.254829592;
+    const float a2 = -0.284496736;
+    const float a3 =  1.421413741;
+    const float a4 = -1.453152027;
+    const float a5 =  1.061405429;
+    const float p  =  0.3275911;
+    float t, y, sign;
+
+    /* Save the sign of x */
+    sign = 1;
+    if (x < 0)
+        sign = -1;
+    x = abs(x);
+
+    /* A & S 7.1.26 */
+    t = 1.0/(1.0 + p*x);
+    y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*exp(-x*x);
+
+    return sign*y;
+}
+
 /******************************************************************************
  * GdipCloneBrush [GDIPLUS.@]
  */
 /******************************************************************************
  * GdipCloneBrush [GDIPLUS.@]
  */
@@ -108,14 +135,38 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
 
             break;
         }
 
             break;
         }
-        case BrushTypeLinearGradient:
-            *clone = GdipAlloc(sizeof(GpLineGradient));
-            if(!*clone)    return OutOfMemory;
+        case BrushTypeLinearGradient:{
+            GpLineGradient *dest, *src;
+            INT count;
+
+            dest = GdipAlloc(sizeof(GpLineGradient));
+            if(!dest)    return OutOfMemory;
+
+            src = (GpLineGradient*)brush;
 
 
-            memcpy(*clone, brush, sizeof(GpLineGradient));
+            memcpy(dest, src, sizeof(GpLineGradient));
 
 
-            (*clone)->gdibrush = CreateSolidBrush((*clone)->lb.lbColor);
+            dest->brush.gdibrush = CreateSolidBrush(dest->brush.lb.lbColor);
+
+            count = dest->blendcount;
+            dest->blendfac = GdipAlloc(count * sizeof(REAL));
+            dest->blendpos = GdipAlloc(count * sizeof(REAL));
+
+            if (!dest->blendfac || !dest->blendpos)
+            {
+                GdipFree(dest->blendfac);
+                GdipFree(dest->blendpos);
+                DeleteObject(dest->brush.gdibrush);
+                GdipFree(dest);
+                return OutOfMemory;
+            }
+
+            memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL));
+            memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL));
+
+            *clone = &dest->brush;
             break;
             break;
+        }
         case BrushTypeTextureFill:
             *clone = GdipAlloc(sizeof(GpTexture));
             if(!*clone)    return OutOfMemory;
         case BrushTypeTextureFill:
             *clone = GdipAlloc(sizeof(GpTexture));
             if(!*clone)    return OutOfMemory;
@@ -226,6 +277,28 @@ GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint,
     (*line)->wrap = wrap;
     (*line)->gamma = FALSE;
 
     (*line)->wrap = wrap;
     (*line)->gamma = FALSE;
 
+    (*line)->rect.X = (startpoint->X < endpoint->X ? startpoint->X: endpoint->X);
+    (*line)->rect.Y = (startpoint->Y < endpoint->Y ? startpoint->Y: endpoint->Y);
+    (*line)->rect.Width  = fabs(startpoint->X - endpoint->X);
+    (*line)->rect.Height = fabs(startpoint->Y - endpoint->Y);
+
+    (*line)->blendcount = 1;
+    (*line)->blendfac = GdipAlloc(sizeof(REAL));
+    (*line)->blendpos = GdipAlloc(sizeof(REAL));
+
+    if (!(*line)->blendfac || !(*line)->blendpos)
+    {
+        GdipFree((*line)->blendfac);
+        GdipFree((*line)->blendpos);
+        DeleteObject((*line)->brush.gdibrush);
+        GdipFree(*line);
+        *line = NULL;
+        return OutOfMemory;
+    }
+
+    (*line)->blendfac[0] = 1.0f;
+    (*line)->blendpos[0] = 1.0f;
+
     return Ok;
 }
 
     return Ok;
 }
 
@@ -255,6 +328,7 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRect(GDIPCONST GpRectF* rect,
     GpLineGradient **line)
 {
     GpPointF start, end;
     GpLineGradient **line)
 {
     GpPointF start, end;
+    GpStatus stat;
 
     TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
           wrap, line);
 
     TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
           wrap, line);
@@ -262,12 +336,42 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRect(GDIPCONST GpRectF* rect,
     if(!line || !rect)
         return InvalidParameter;
 
     if(!line || !rect)
         return InvalidParameter;
 
-    start.X = rect->X;
-    start.Y = rect->Y;
-    end.X = rect->X + rect->Width;
-    end.Y = rect->Y + rect->Height;
+    switch (mode)
+    {
+    case LinearGradientModeHorizontal:
+        start.X = rect->X;
+        start.Y = rect->Y;
+        end.X = rect->X + rect->Width;
+        end.Y = rect->Y;
+        break;
+    case LinearGradientModeVertical:
+        start.X = rect->X;
+        start.Y = rect->Y;
+        end.X = rect->X;
+        end.Y = rect->Y + rect->Height;
+        break;
+    case LinearGradientModeForwardDiagonal:
+        start.X = rect->X;
+        start.Y = rect->Y;
+        end.X = rect->X + rect->Width;
+        end.Y = rect->Y + rect->Height;
+        break;
+    case LinearGradientModeBackwardDiagonal:
+        start.X = rect->X + rect->Width;
+        start.Y = rect->Y;
+        end.X = rect->X;
+        end.Y = rect->Y + rect->Height;
+        break;
+    default:
+        return InvalidParameter;
+    }
 
 
-    return GdipCreateLineBrush(&start, &end, startcolor, endcolor, wrap, line);
+    stat = GdipCreateLineBrush(&start, &end, startcolor, endcolor, wrap, line);
+
+    if (stat == Ok)
+        (*line)->rect = *rect;
+
+    return stat;
 }
 
 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectI(GDIPCONST GpRect* rect,
 }
 
 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectI(GDIPCONST GpRect* rect,
@@ -765,7 +869,10 @@ GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush)
             GdipFree(((GpPathGradient*) brush)->blendpos);
             break;
         case BrushTypeSolidColor:
             GdipFree(((GpPathGradient*) brush)->blendpos);
             break;
         case BrushTypeSolidColor:
+            break;
         case BrushTypeLinearGradient:
         case BrushTypeLinearGradient:
+            GdipFree(((GpLineGradient*)brush)->blendfac);
+            GdipFree(((GpLineGradient*)brush)->blendpos);
             break;
         case BrushTypeTextureFill:
             GdipDeleteMatrix(((GpTexture*)brush)->transform);
             break;
         case BrushTypeTextureFill:
             GdipDeleteMatrix(((GpTexture*)brush)->transform);
@@ -1071,15 +1178,64 @@ GpStatus WINGDIPAPI GdipScaleTextureTransform(GpTexture* brush,
 }
 
 GpStatus WINGDIPAPI GdipSetLineBlend(GpLineGradient *brush,
 }
 
 GpStatus WINGDIPAPI GdipSetLineBlend(GpLineGradient *brush,
-    GDIPCONST REAL *blend, GDIPCONST REAL* positions, INT count)
+    GDIPCONST REAL *factors, GDIPCONST REAL* positions, INT count)
 {
 {
-    static int calls;
+    REAL *new_blendfac, *new_blendpos;
 
 
-    if(!brush || !blend || !positions || count <= 0)
+    TRACE("(%p, %p, %p, %i)\n", brush, factors, positions, count);
+
+    if(!brush || !factors || !positions || count <= 0 ||
+       (count >= 2 && (positions[0] != 0.0f || positions[count-1] != 1.0f)))
         return InvalidParameter;
 
         return InvalidParameter;
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    new_blendfac = GdipAlloc(count * sizeof(REAL));
+    new_blendpos = GdipAlloc(count * sizeof(REAL));
+
+    if (!new_blendfac || !new_blendpos)
+    {
+        GdipFree(new_blendfac);
+        GdipFree(new_blendpos);
+        return OutOfMemory;
+    }
+
+    memcpy(new_blendfac, factors, count * sizeof(REAL));
+    memcpy(new_blendpos, positions, count * sizeof(REAL));
+
+    GdipFree(brush->blendfac);
+    GdipFree(brush->blendpos);
+
+    brush->blendcount = count;
+    brush->blendfac = new_blendfac;
+    brush->blendpos = new_blendpos;
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipGetLineBlend(GpLineGradient *brush, REAL *factors,
+    REAL *positions, INT count)
+{
+    TRACE("(%p, %p, %p, %i)\n", brush, factors, positions, count);
+
+    if (!brush || !factors || !positions || count <= 0)
+        return InvalidParameter;
+
+    if (count < brush->blendcount)
+        return InsufficientBuffer;
+
+    memcpy(factors, brush->blendfac, brush->blendcount * sizeof(REAL));
+    memcpy(positions, brush->blendpos, brush->blendcount * sizeof(REAL));
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipGetLineBlendCount(GpLineGradient *brush, INT *count)
+{
+    TRACE("(%p, %p)\n", brush, count);
+
+    if (!brush || !count)
+        return InvalidParameter;
+
+    *count = brush->blendcount;
 
     return Ok;
 }
 
     return Ok;
 }
@@ -1100,15 +1256,57 @@ GpStatus WINGDIPAPI GdipSetLineGammaCorrection(GpLineGradient *line,
 GpStatus WINGDIPAPI GdipSetLineSigmaBlend(GpLineGradient *line, REAL focus,
     REAL scale)
 {
 GpStatus WINGDIPAPI GdipSetLineSigmaBlend(GpLineGradient *line, REAL focus,
     REAL scale)
 {
-    static int calls;
+    REAL factors[33];
+    REAL positions[33];
+    int num_points = 0;
+    int i;
+    const int precision = 16;
+    REAL erf_range; /* we use values erf(-erf_range) through erf(+erf_range) */
+    REAL min_erf;
+    REAL scale_erf;
+
+    TRACE("(%p, %0.2f, %0.2f)\n", line, focus, scale);
 
     if(!line || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0)
         return InvalidParameter;
 
 
     if(!line || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0)
         return InvalidParameter;
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    /* we want 2 standard deviations */
+    erf_range = 2.0 / sqrt(2);
 
 
-    return NotImplemented;
+    /* calculate the constants we need to normalize the error function to be
+        between 0.0 and scale over the range we need */
+    min_erf = erf(-erf_range);
+    scale_erf = scale / (-2.0 * min_erf);
+
+    if (focus != 0.0)
+    {
+        positions[0] = 0.0;
+        factors[0] = 0.0;
+        for (i=1; i<precision; i++)
+        {
+            positions[i] = focus * i / precision;
+            factors[i] = scale_erf * (erf(2 * erf_range * i / precision - erf_range) - min_erf);
+        }
+        num_points += precision;
+    }
+
+    positions[num_points] = focus;
+    factors[num_points] = scale;
+    num_points += 1;
+
+    if (focus != 1.0)
+    {
+        for (i=1; i<precision; i++)
+        {
+            positions[i+num_points-1] = (focus + ((1.0-focus) * i / precision));
+            factors[i+num_points-1] = scale_erf * (erf(erf_range - 2 * erf_range * i / precision) - min_erf);
+        }
+        num_points += precision;
+        positions[num_points-1] = 1.0;
+        factors[num_points-1] = 0.0;
+    }
+
+    return GdipSetLineBlend(line, factors, positions, num_points);
 }
 
 GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient *line,
 }
 
 GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient *line,
@@ -1403,11 +1601,7 @@ GpStatus WINGDIPAPI GdipGetLineRect(GpLineGradient *brush, GpRectF *rect)
     if(!brush || !rect)
         return InvalidParameter;
 
     if(!brush || !rect)
         return InvalidParameter;
 
-    rect->X = (brush->startpoint.X < brush->endpoint.X ? brush->startpoint.X: brush->endpoint.X);
-    rect->Y = (brush->startpoint.Y < brush->endpoint.Y ? brush->startpoint.Y: brush->endpoint.Y);
-
-    rect->Width  = fabs(brush->startpoint.X - brush->endpoint.X);
-    rect->Height = fabs(brush->startpoint.Y - brush->endpoint.Y);
+    *rect = brush->rect;
 
     return Ok;
 }
 
     return Ok;
 }
index 6454765..0b582a7 100644 (file)
@@ -36,6 +36,8 @@ WINE_DEFAULT_DEBUG_CHANNEL (gdiplus);
 static const REAL mm_per_inch = 25.4;
 static const REAL inch_per_point = 1.0/72.0;
 
 static const REAL mm_per_inch = 25.4;
 static const REAL inch_per_point = 1.0/72.0;
 
+static GpFontCollection installedFontCollection = {0};
+
 static inline REAL get_dpi (void)
 {
     REAL dpi;
 static inline REAL get_dpi (void)
 {
     REAL dpi;
@@ -193,7 +195,7 @@ GpStatus WINGDIPAPI GdipCreateFontFromLogfontW(HDC hdc,
     oldfont = SelectObject(hdc, hfont);
     GetTextMetricsW(hdc, &textmet);
 
     oldfont = SelectObject(hdc, hfont);
     GetTextMetricsW(hdc, &textmet);
 
-    (*font)->lfw.lfHeight = -textmet.tmHeight;
+    (*font)->lfw.lfHeight = -(textmet.tmHeight-textmet.tmInternalLeading);
     (*font)->lfw.lfWeight = textmet.tmWeight;
     (*font)->lfw.lfCharSet = textmet.tmCharSet;
 
     (*font)->lfw.lfWeight = textmet.tmWeight;
     (*font)->lfw.lfCharSet = textmet.tmCharSet;
 
@@ -936,5 +938,7 @@ GpStatus WINGDIPAPI GdipNewInstalledFontCollection(
     if (!fontCollection)
         return InvalidParameter;
 
     if (!fontCollection)
         return InvalidParameter;
 
-    return NotImplemented;
+    *fontCollection = &installedFontCollection;
+
+    return Ok;
 }
 }
index ba98518..76c7328 100644 (file)
@@ -42,7 +42,7 @@
 @ stub GdipBitmapGetHistogramSize
 @ stdcall GdipBitmapGetPixel(ptr long long ptr)
 @ stdcall GdipBitmapLockBits(ptr ptr long long ptr)
 @ stub GdipBitmapGetHistogramSize
 @ stdcall GdipBitmapGetPixel(ptr long long ptr)
 @ stdcall GdipBitmapLockBits(ptr ptr long long ptr)
-@ stub GdipBitmapSetPixel
+@ stdcall GdipBitmapSetPixel(ptr long long long)
 @ stdcall GdipBitmapSetResolution(ptr long long)
 @ stdcall GdipBitmapUnlockBits(ptr ptr)
 @ stdcall GdipClearPathMarkers(ptr)
 @ stdcall GdipBitmapSetResolution(ptr long long)
 @ stdcall GdipBitmapUnlockBits(ptr ptr)
 @ stdcall GdipClearPathMarkers(ptr)
 @ stdcall GdipGetImagePaletteSize(ptr ptr)
 @ stdcall GdipGetImagePixelFormat(ptr ptr)
 @ stdcall GdipGetImageRawFormat(ptr ptr)
 @ stdcall GdipGetImagePaletteSize(ptr ptr)
 @ stdcall GdipGetImagePixelFormat(ptr ptr)
 @ stdcall GdipGetImageRawFormat(ptr ptr)
-@ stub GdipGetImageThumbnail
+@ stdcall GdipGetImageThumbnail(ptr long long ptr ptr ptr)
 @ stdcall GdipGetImageType(ptr ptr)
 @ stdcall GdipGetImageVerticalResolution(ptr ptr)
 @ stdcall GdipGetImageWidth(ptr ptr)
 @ stdcall GdipGetInterpolationMode(ptr ptr)
 @ stdcall GdipGetImageType(ptr ptr)
 @ stdcall GdipGetImageVerticalResolution(ptr ptr)
 @ stdcall GdipGetImageWidth(ptr ptr)
 @ stdcall GdipGetInterpolationMode(ptr ptr)
-@ stub GdipGetLineBlend
-@ stub GdipGetLineBlendCount
+@ stdcall GdipGetLineBlend(ptr ptr ptr long)
+@ stdcall GdipGetLineBlendCount(ptr ptr)
 @ stdcall GdipGetLineColors(ptr ptr)
 @ stdcall GdipGetLineGammaCorrection(ptr ptr)
 @ stub GdipGetLinePresetBlend
 @ stdcall GdipGetLineColors(ptr ptr)
 @ stdcall GdipGetLineGammaCorrection(ptr ptr)
 @ stub GdipGetLinePresetBlend
 @ stdcall GdipImageGetFrameCount(ptr ptr ptr)
 @ stdcall GdipImageGetFrameDimensionsCount(ptr ptr)
 @ stdcall GdipImageGetFrameDimensionsList(ptr ptr long)
 @ stdcall GdipImageGetFrameCount(ptr ptr ptr)
 @ stdcall GdipImageGetFrameDimensionsCount(ptr ptr)
 @ stdcall GdipImageGetFrameDimensionsList(ptr ptr long)
-@ stub GdipImageRotateFlip
+@ stdcall GdipImageRotateFlip(ptr long)
 @ stdcall GdipImageSelectActiveFrame(ptr ptr long)
 @ stub GdipImageSetAbort
 @ stub GdipInitializePalette
 @ stdcall GdipImageSelectActiveFrame(ptr ptr long)
 @ stub GdipImageSetAbort
 @ stub GdipInitializePalette
 @ stdcall GdipSetPenWidth(ptr long)
 @ stdcall GdipSetPixelOffsetMode(ptr long)
 @ stdcall GdipSetPropertyItem(ptr ptr)
 @ stdcall GdipSetPenWidth(ptr long)
 @ stdcall GdipSetPixelOffsetMode(ptr long)
 @ stdcall GdipSetPropertyItem(ptr ptr)
-@ stub GdipSetRenderingOrigin
+@ stdcall GdipSetRenderingOrigin(ptr long long)
 @ stdcall GdipSetSmoothingMode(ptr long)
 @ stdcall GdipSetSolidFillColor(ptr ptr)
 @ stdcall GdipSetStringFormatAlign(ptr long)
 @ stdcall GdipSetSmoothingMode(ptr long)
 @ stdcall GdipSetSolidFillColor(ptr ptr)
 @ stdcall GdipSetStringFormatAlign(ptr long)
index dbeebe3..f3bf797 100644 (file)
@@ -91,6 +91,7 @@ struct GpPen{
 struct GpGraphics{
     HDC hdc;
     HWND hwnd;
 struct GpGraphics{
     HDC hdc;
     HWND hwnd;
+    BOOL owndc;
     SmoothingMode smoothing;
     CompositingQuality compqual;
     InterpolationMode interpolation;
     SmoothingMode smoothing;
     CompositingQuality compqual;
     InterpolationMode interpolation;
@@ -142,8 +143,12 @@ struct GpLineGradient{
     GpPointF endpoint;
     ARGB startcolor;
     ARGB endcolor;
     GpPointF endpoint;
     ARGB startcolor;
     ARGB endcolor;
+    RectF rect;
     GpWrapMode wrap;
     BOOL gamma;
     GpWrapMode wrap;
     BOOL gamma;
+    REAL* blendfac;  /* blend factors */
+    REAL* blendpos;  /* blend positions */
+    INT blendcount;
 };
 
 struct GpTexture{
 };
 
 struct GpTexture{
index 2a98ee5..07b2114 100644 (file)
@@ -172,15 +172,56 @@ static void transform_and_round_points(GpGraphics *graphics, POINT *pti,
     }
 }
 
     }
 }
 
-static ARGB blend_colors(ARGB start, ARGB end, int current, int total)
+static ARGB blend_colors(ARGB start, ARGB end, REAL position)
 {
     ARGB result=0;
     ARGB i;
     for (i=0xff; i<=0xff0000; i = i << 8)
 {
     ARGB result=0;
     ARGB i;
     for (i=0xff; i<=0xff0000; i = i << 8)
-        result |= (((start&i)*(total - current)+(end&i)*(current))/total)&i;
+        result |= (int)((start&i)*(1.0f - position)+(end&i)*(position))&i;
     return result;
 }
 
     return result;
 }
 
+static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)
+{
+    REAL blendfac;
+
+    /* clamp to between 0.0 and 1.0, using the wrap mode */
+    if (brush->wrap == WrapModeTile)
+    {
+        position = fmodf(position, 1.0f);
+        if (position < 0.0f) position += 1.0f;
+    }
+    else /* WrapModeFlip* */
+    {
+        position = fmodf(position, 2.0f);
+        if (position < 0.0f) position += 2.0f;
+        if (position > 1.0f) position = 2.0f - position;
+    }
+
+    if (brush->blendcount == 1)
+        blendfac = position;
+    else
+    {
+        int i=1;
+        REAL left_blendpos, left_blendfac, right_blendpos, right_blendfac;
+        REAL range;
+
+        /* locate the blend positions surrounding this position */
+        while (position > brush->blendpos[i])
+            i++;
+
+        /* interpolate between the blend positions */
+        left_blendpos = brush->blendpos[i-1];
+        left_blendfac = brush->blendfac[i-1];
+        right_blendpos = brush->blendpos[i];
+        right_blendfac = brush->blendfac[i];
+        range = right_blendpos - left_blendpos;
+        blendfac = (left_blendfac * (right_blendpos - position) +
+                    right_blendfac * (position - left_blendpos)) / range;
+    }
+    return blend_colors(brush->startcolor, brush->endcolor, blendfac);
+}
+
 static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
 {
     switch (brush->bt)
 static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
 {
     switch (brush->bt)
@@ -189,7 +230,6 @@ static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
     {
         GpLineGradient *line = (GpLineGradient*)brush;
         RECT rc;
     {
         GpLineGradient *line = (GpLineGradient*)brush;
         RECT rc;
-        int num_steps = 255;
 
         SelectClipPath(graphics->hdc, RGN_AND);
         if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
 
         SelectClipPath(graphics->hdc, RGN_AND);
         if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
@@ -200,9 +240,6 @@ static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
 
             SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
 
 
             SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
 
-            /* fill with starting color */
-            FillRect(graphics->hdc, &rc, brush->gdibrush);
-
             endpointsf[0] = line->startpoint;
             endpointsf[1] = line->endpoint;
             transform_and_round_points(graphics, endpointsi, endpointsf, 2);
             endpointsf[0] = line->startpoint;
             endpointsf[1] = line->endpoint;
             transform_and_round_points(graphics, endpointsi, endpointsf, 2);
@@ -210,114 +247,100 @@ static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
             if (abs(endpointsi[0].x-endpointsi[1].x) > abs(endpointsi[0].y-endpointsi[1].y))
             {
                 /* vertical-ish gradient */
             if (abs(endpointsi[0].x-endpointsi[1].x) > abs(endpointsi[0].y-endpointsi[1].y))
             {
                 /* vertical-ish gradient */
-                int endborderx; /* vertical rectangle boundary near endpoint */
                 int startx, endx; /* x co-ordinates of endpoints shifted to intersect the top of the visible rectangle */
                 int startx, endx; /* x co-ordinates of endpoints shifted to intersect the top of the visible rectangle */
-                int startbottomx, endbottomx; /* x co-ordinate of endpoints shifted to intersect the bottom of the visible rectangle */
+                int startbottomx; /* x co-ordinate of start point shifted to intersect the bottom of the visible rectangle */
                 int width;
                 COLORREF col;
                 HBRUSH hbrush, hprevbrush;
                 int width;
                 COLORREF col;
                 HBRUSH hbrush, hprevbrush;
-                int i;
-
-                if (endpointsi[1].x > endpointsi[0].x)
-                    endborderx = rc.right;
-                else
-                    endborderx = rc.left;
+                int leftx, rightx; /* x co-ordinates where the leftmost and rightmost gradient lines hit the top of the visible rectangle */
+                int x;
+                int tilt; /* horizontal distance covered by a gradient line */
 
                 startx = roundr((rc.top - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
                 endx = roundr((rc.top - endpointsf[1].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[1].X);
                 width = endx - startx;
                 startbottomx = roundr((rc.bottom - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
 
                 startx = roundr((rc.top - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
                 endx = roundr((rc.top - endpointsf[1].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[1].X);
                 width = endx - startx;
                 startbottomx = roundr((rc.bottom - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
-                endbottomx = startbottomx+width;
+                tilt = startx - startbottomx;
 
 
-                if (num_steps > abs(width)) num_steps = abs(width);
+                if (startx >= startbottomx)
+                {
+                    leftx = rc.left;
+                    rightx = rc.right + tilt;
+                }
+                else
+                {
+                    leftx = rc.left + tilt;
+                    rightx = rc.right;
+                }
 
 
-                poly[0].x = endborderx;
                 poly[0].y = rc.bottom;
                 poly[0].y = rc.bottom;
-                poly[1].x = endborderx;
                 poly[1].y = rc.top;
                 poly[2].y = rc.top;
                 poly[3].y = rc.bottom;
 
                 poly[1].y = rc.top;
                 poly[2].y = rc.top;
                 poly[3].y = rc.bottom;
 
-                for (i=1; i<num_steps; i++)
+                for (x=leftx; x<=rightx; x++)
                 {
                 {
-                    ARGB argb = blend_colors(line->startcolor, line->endcolor, i, num_steps);
-                    int ofs = width * i / num_steps;
+                    ARGB argb = blend_line_gradient(line, (x-startx)/(REAL)width);
                     col = ARGB2COLORREF(argb);
                     hbrush = CreateSolidBrush(col);
                     hprevbrush = SelectObject(graphics->hdc, hbrush);
                     col = ARGB2COLORREF(argb);
                     hbrush = CreateSolidBrush(col);
                     hprevbrush = SelectObject(graphics->hdc, hbrush);
-                    poly[2].x = startx + ofs;
-                    poly[3].x = startbottomx + ofs;
+                    poly[0].x = x - tilt - 1;
+                    poly[1].x = x - 1;
+                    poly[2].x = x;
+                    poly[3].x = x - tilt;
                     Polygon(graphics->hdc, poly, 4);
                     SelectObject(graphics->hdc, hprevbrush);
                     DeleteObject(hbrush);
                 }
                     Polygon(graphics->hdc, poly, 4);
                     SelectObject(graphics->hdc, hprevbrush);
                     DeleteObject(hbrush);
                 }
-
-                poly[2].x = endx;
-                poly[3].x = endbottomx;
-
-                /* draw the ending color */
-                col = ARGB2COLORREF(line->endcolor);
-                hbrush = CreateSolidBrush(col);
-                hprevbrush = SelectObject(graphics->hdc, hbrush);
-                Polygon(graphics->hdc, poly, 4);
-                SelectObject(graphics->hdc, hprevbrush);
-                DeleteObject(hbrush);
             }
             else if (endpointsi[0].y != endpointsi[1].y)
             {
                 /* horizontal-ish gradient */
             }
             else if (endpointsi[0].y != endpointsi[1].y)
             {
                 /* horizontal-ish gradient */
-                int endbordery; /* horizontal rectangle boundary near endpoint */
                 int starty, endy; /* y co-ordinates of endpoints shifted to intersect the left of the visible rectangle */
                 int starty, endy; /* y co-ordinates of endpoints shifted to intersect the left of the visible rectangle */
-                int startrighty, endrighty; /* y co-ordinate of endpoints shifted to intersect the right of the visible rectangle */
+                int startrighty; /* y co-ordinate of start point shifted to intersect the right of the visible rectangle */
                 int height;
                 COLORREF col;
                 HBRUSH hbrush, hprevbrush;
                 int height;
                 COLORREF col;
                 HBRUSH hbrush, hprevbrush;
-                int i;
-
-                if (endpointsi[1].y > endpointsi[0].y)
-                    endbordery = rc.bottom;
-                else
-                    endbordery = rc.top;
+                int topy, bottomy; /* y co-ordinates where the topmost and bottommost gradient lines hit the left of the visible rectangle */
+                int y;
+                int tilt; /* vertical distance covered by a gradient line */
 
                 starty = roundr((rc.left - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
                 endy = roundr((rc.left - endpointsf[1].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[1].Y);
                 height = endy - starty;
                 startrighty = roundr((rc.right - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
 
                 starty = roundr((rc.left - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
                 endy = roundr((rc.left - endpointsf[1].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[1].Y);
                 height = endy - starty;
                 startrighty = roundr((rc.right - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
-                endrighty = startrighty+height;
+                tilt = starty - startrighty;
 
 
-                if (num_steps > abs(height)) num_steps = abs(height);
+                if (starty >= startrighty)
+                {
+                    topy = rc.top;
+                    bottomy = rc.bottom + tilt;
+                }
+                else
+                {
+                    topy = rc.top + tilt;
+                    bottomy = rc.bottom;
+                }
 
                 poly[0].x = rc.right;
 
                 poly[0].x = rc.right;
-                poly[0].y = endbordery;
                 poly[1].x = rc.left;
                 poly[1].x = rc.left;
-                poly[1].y = endbordery;
                 poly[2].x = rc.left;
                 poly[3].x = rc.right;
 
                 poly[2].x = rc.left;
                 poly[3].x = rc.right;
 
-                for (i=1; i<num_steps; i++)
+                for (y=topy; y<=bottomy; y++)
                 {
                 {
-                    ARGB argb = blend_colors(line->startcolor, line->endcolor, i, num_steps);
-                    int ofs = height * i / num_steps;
+                    ARGB argb = blend_line_gradient(line, (y-starty)/(REAL)height);
                     col = ARGB2COLORREF(argb);
                     hbrush = CreateSolidBrush(col);
                     hprevbrush = SelectObject(graphics->hdc, hbrush);
                     col = ARGB2COLORREF(argb);
                     hbrush = CreateSolidBrush(col);
                     hprevbrush = SelectObject(graphics->hdc, hbrush);
-                    poly[2].y = starty + ofs;
-                    poly[3].y = startrighty + ofs;
+                    poly[0].y = y - tilt - 1;
+                    poly[1].y = y - 1;
+                    poly[2].y = y;
+                    poly[3].y = y - tilt;
                     Polygon(graphics->hdc, poly, 4);
                     SelectObject(graphics->hdc, hprevbrush);
                     DeleteObject(hbrush);
                 }
                     Polygon(graphics->hdc, poly, 4);
                     SelectObject(graphics->hdc, hprevbrush);
                     DeleteObject(hbrush);
                 }
-
-                poly[2].y = endy;
-                poly[3].y = endrighty;
-
-                /* draw the ending color */
-                col = ARGB2COLORREF(line->endcolor);
-                hbrush = CreateSolidBrush(col);
-                hprevbrush = SelectObject(graphics->hdc, hbrush);
-                Polygon(graphics->hdc, poly, 4);
-                SelectObject(graphics->hdc, hprevbrush);
-                DeleteObject(hbrush);
             }
             /* else startpoint == endpoint */
         }
             }
             /* else startpoint == endpoint */
         }
@@ -924,6 +947,7 @@ GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **gra
 
     (*graphics)->hdc = hdc;
     (*graphics)->hwnd = WindowFromDC(hdc);
 
     (*graphics)->hdc = hdc;
     (*graphics)->hwnd = WindowFromDC(hdc);
+    (*graphics)->owndc = FALSE;
     (*graphics)->smoothing = SmoothingModeDefault;
     (*graphics)->compqual = CompositingQualityDefault;
     (*graphics)->interpolation = InterpolationModeDefault;
     (*graphics)->smoothing = SmoothingModeDefault;
     (*graphics)->compqual = CompositingQualityDefault;
     (*graphics)->interpolation = InterpolationModeDefault;
@@ -940,13 +964,20 @@ GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **gra
 GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics)
 {
     GpStatus ret;
 GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics)
 {
     GpStatus ret;
+    HDC hdc;
 
     TRACE("(%p, %p)\n", hwnd, graphics);
 
 
     TRACE("(%p, %p)\n", hwnd, graphics);
 
-    if((ret = GdipCreateFromHDC(GetDC(hwnd), graphics)) != Ok)
+    hdc = GetDC(hwnd);
+
+    if((ret = GdipCreateFromHDC(hdc, graphics)) != Ok)
+    {
+        ReleaseDC(hwnd, hdc);
         return ret;
         return ret;
+    }
 
     (*graphics)->hwnd = hwnd;
 
     (*graphics)->hwnd = hwnd;
+    (*graphics)->owndc = TRUE;
 
     return Ok;
 }
 
     return Ok;
 }
@@ -1081,7 +1112,7 @@ GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
     if(!graphics) return InvalidParameter;
     if(graphics->busy) return ObjectBusy;
 
     if(!graphics) return InvalidParameter;
     if(graphics->busy) return ObjectBusy;
 
-    if(graphics->hwnd)
+    if(graphics->owndc)
         ReleaseDC(graphics->hwnd, graphics->hdc);
 
     GdipDeleteRegion(graphics->clip);
         ReleaseDC(graphics->hwnd, graphics->hdc);
 
     GdipDeleteRegion(graphics->clip);
@@ -2448,12 +2479,14 @@ GpStatus WINGDIPAPI GdipFillRectangle(GpGraphics *graphics, GpBrush *brush,
 
     save_state = SaveDC(graphics->hdc);
     EndPath(graphics->hdc);
 
     save_state = SaveDC(graphics->hdc);
     EndPath(graphics->hdc);
-    SelectObject(graphics->hdc, brush->gdibrush);
-    SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
 
     transform_and_round_points(graphics, pti, ptf, 4);
 
 
     transform_and_round_points(graphics, pti, ptf, 4);
 
+    BeginPath(graphics->hdc);
     Polygon(graphics->hdc, pti, 4);
     Polygon(graphics->hdc, pti, 4);
+    EndPath(graphics->hdc);
+
+    brush_fill_path(graphics, brush);
 
     RestoreDC(graphics->hdc, save_state);
 
 
     RestoreDC(graphics->hdc, save_state);
 
@@ -3210,6 +3243,18 @@ GpStatus WINGDIPAPI GdipSetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode
     return Ok;
 }
 
     return Ok;
 }
 
+GpStatus WINGDIPAPI GdipSetRenderingOrigin(GpGraphics *graphics, INT x, INT y)
+{
+    static int calls;
+
+    TRACE("(%p,%i,%i)\n", graphics, x, y);
+
+    if (!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
 GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode mode)
 {
     TRACE("(%p, %d)\n", graphics, mode);
 GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode mode)
 {
     TRACE("(%p, %d)\n", graphics, mode);
index 5552225..9902f0f 100644 (file)
@@ -87,6 +87,21 @@ GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
     return NotImplemented;
 }
 
     return NotImplemented;
 }
 
+GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y,
+    ARGB color)
+{
+    static int calls;
+    TRACE("bitmap:%p, x:%d, y:%d, color:%08x\n", bitmap, x, y, color);
+
+    if(!bitmap)
+        return InvalidParameter;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
 /* This function returns a pointer to an array of pixels that represents the
  * bitmap. The *entire* bitmap is locked according to the lock mode specified by
  * flags.  It is correct behavior that a user who calls this function with write
 /* This function returns a pointer to an array of pixels that represents the
  * bitmap. The *entire* bitmap is locked according to the lock mode specified by
  * flags.  It is correct behavior that a user who calls this function with write
@@ -1648,3 +1663,24 @@ GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image)
 
     return Ok;
 }
 
     return Ok;
 }
+
+/*****************************************************************************
+ * GdipGetImageThumbnail [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipGetImageThumbnail(GpImage *image, UINT width, UINT height,
+                            GpImage **ret_image, GetThumbnailImageAbort cb,
+                            VOID * cb_data)
+{
+    FIXME("(%p %u %u %p %p %p) stub\n",
+        image, width, height, ret_image, cb, cb_data);
+    return NotImplemented;
+}
+
+/*****************************************************************************
+ * GdipImageRotateFlip [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
+{
+    FIXME("(%p %u) stub\n", image, type);
+    return NotImplemented;
+}