* Sync up to trunk head (r64377).
[reactos.git] / dll / win32 / gdiplus / graphics.c
index 8be792a..3270c89 100644 (file)
@@ -589,30 +589,47 @@ static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)
     }
 }
 
-static ARGB transform_color(ARGB color, const ColorMatrix *matrix)
+static BOOL round_color_matrix(const ColorMatrix *matrix, int values[5][5])
 {
-    REAL val[5], res[4];
+    /* Convert floating point color matrix to int[5][5], return TRUE if it's an identity */
+    BOOL identity = TRUE;
+    int i, j;
+
+    for (i=0; i<4; i++)
+        for (j=0; j<5; j++)
+        {
+            if (matrix->m[j][i] != (i == j ? 1.0 : 0.0))
+                identity = FALSE;
+            values[j][i] = gdip_round(matrix->m[j][i] * 256.0);
+        }
+
+    return identity;
+}
+
+static ARGB transform_color(ARGB color, int matrix[5][5])
+{
+    int val[5], res[4];
     int i, j;
     unsigned char a, r, g, b;
 
-    val[0] = ((color >> 16) & 0xff) / 255.0; /* red */
-    val[1] = ((color >> 8) & 0xff) / 255.0; /* green */
-    val[2] = (color & 0xff) / 255.0; /* blue */
-    val[3] = ((color >> 24) & 0xff) / 255.0; /* alpha */
-    val[4] = 1.0; /* translation */
+    val[0] = ((color >> 16) & 0xff); /* red */
+    val[1] = ((color >> 8) & 0xff); /* green */
+    val[2] = (color & 0xff); /* blue */
+    val[3] = ((color >> 24) & 0xff); /* alpha */
+    val[4] = 255; /* translation */
 
     for (i=0; i<4; i++)
     {
-        res[i] = 0.0;
+        res[i] = 0;
 
         for (j=0; j<5; j++)
-            res[i] += matrix->m[j][i] * val[j];
+            res[i] += matrix[j][i] * val[j];
     }
 
-    a = min(max(floorf(res[3]*255.0), 0.0), 255.0);
-    r = min(max(floorf(res[0]*255.0), 0.0), 255.0);
-    g = min(max(floorf(res[1]*255.0), 0.0), 255.0);
-    b = min(max(floorf(res[2]*255.0), 0.0), 255.0);
+    a = min(max(res[3] / 256, 0), 255);
+    r = min(max(res[0] / 256, 0), 255);
+    g = min(max(res[1] / 256, 0), 255);
+    b = min(max(res[2] / 256, 0), 255);
 
     return (a << 24) | (r << 16) | (g << 8) | b;
 }
@@ -699,28 +716,41 @@ static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE d
         attributes->colormatrices[ColorAdjustTypeDefault].enabled)
     {
         const struct color_matrix *colormatrices;
+        int color_matrix[5][5];
+        int gray_matrix[5][5];
+        BOOL identity;
 
         if (attributes->colormatrices[type].enabled)
             colormatrices = &attributes->colormatrices[type];
         else
             colormatrices = &attributes->colormatrices[ColorAdjustTypeDefault];
 
-        for (x=0; x<width; x++)
-            for (y=0; y<height; y++)
-            {
-                ARGB *src_color;
-                src_color = (ARGB*)(data + stride * y + sizeof(ARGB) * x);
+        identity = round_color_matrix(&colormatrices->colormatrix, color_matrix);
 
-                if (colormatrices->flags == ColorMatrixFlagsDefault ||
-                    !color_is_gray(*src_color))
-                {
-                    *src_color = transform_color(*src_color, &colormatrices->colormatrix);
-                }
-                else if (colormatrices->flags == ColorMatrixFlagsAltGray)
+        if (colormatrices->flags == ColorMatrixFlagsAltGray)
+            identity = (round_color_matrix(&colormatrices->graymatrix, gray_matrix) && identity);
+
+        if (!identity)
+        {
+            for (x=0; x<width; x++)
+            {
+                for (y=0; y<height; y++)
                 {
-                    *src_color = transform_color(*src_color, &colormatrices->graymatrix);
+                    ARGB *src_color;
+                    src_color = (ARGB*)(data + stride * y + sizeof(ARGB) * x);
+
+                    if (colormatrices->flags == ColorMatrixFlagsDefault ||
+                        !color_is_gray(*src_color))
+                    {
+                        *src_color = transform_color(*src_color, color_matrix);
+                    }
+                    else if (colormatrices->flags == ColorMatrixFlagsAltGray)
+                    {
+                        *src_color = transform_color(*src_color, gray_matrix);
+                    }
                 }
             }
+        }
     }
 
     if (attributes->gamma_enabled[type] ||
@@ -1991,6 +2021,24 @@ static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect)
         rect->Height = GetDeviceCaps(graphics->hdc, VERTRES);
     }
 
+    if (graphics->hdc &&
+        (GetMapMode(graphics->hdc) != MM_TEXT || GetGraphicsMode(graphics->hdc) != GM_COMPATIBLE))
+    {
+        POINT points[2];
+
+        points[0].x = rect->X;
+        points[0].y = rect->Y;
+        points[1].x = rect->X + rect->Width;
+        points[1].y = rect->Y + rect->Height;
+
+        DPtoLP(graphics->hdc, points, sizeof(points)/sizeof(points[0]));
+
+        rect->X = min(points[0].x, points[1].x);
+        rect->Y = min(points[0].y, points[1].y);
+        rect->Width = abs(points[1].x - points[0].x);
+        rect->Height = abs(points[1].y - points[0].y);
+    }
+
     return stat;
 }
 
@@ -2835,6 +2883,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
     else if (image->type == ImageTypeBitmap)
     {
         GpBitmap* bitmap = (GpBitmap*)image;
+        BOOL do_resampling = FALSE;
         BOOL use_software = FALSE;
 
         TRACE("graphics: %.2fx%.2f dpi, fmt %#x, scale %f, image: %.2fx%.2f dpi, fmt %#x, color %08x\n",
@@ -2843,12 +2892,14 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
             graphics->scale, image->xres, image->yres, bitmap->format,
             imageAttributes ? imageAttributes->outside_color : 0);
 
-        if (imageAttributes || graphics->alpha_hdc ||
-            (graphics->image && graphics->image->type == ImageTypeBitmap) ||
-            ptf[1].Y != ptf[0].Y || ptf[2].X != ptf[0].X ||
+        if (ptf[1].Y != ptf[0].Y || ptf[2].X != ptf[0].X ||
             ptf[1].X - ptf[0].X != srcwidth || ptf[2].Y - ptf[0].Y != srcheight ||
             srcx < 0 || srcy < 0 ||
             srcx + srcwidth > bitmap->width || srcy + srcheight > bitmap->height)
+            do_resampling = TRUE;
+
+        if (imageAttributes || graphics->alpha_hdc || do_resampling ||
+            (graphics->image && graphics->image->type == ImageTypeBitmap))
             use_software = TRUE;
 
         if (use_software)
@@ -2859,7 +2910,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
             int i, x, y, src_stride, dst_stride;
             GpMatrix dst_to_src;
             REAL m11, m12, m21, m22, mdx, mdy;
-            LPBYTE src_data, dst_data;
+            LPBYTE src_data, dst_data, dst_dyn_data=NULL;
             BitmapData lockeddata;
             InterpolationMode interpolation = graphics->interpolation;
             PixelOffsetMode offset_mode = graphics->pixeloffset;
@@ -2904,22 +2955,25 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
             stat = GdipInvertMatrix(&dst_to_src);
             if (stat != Ok) return stat;
 
-            dst_data = GdipAlloc(sizeof(ARGB) * (dst_area.right - dst_area.left) * (dst_area.bottom - dst_area.top));
-            if (!dst_data) return OutOfMemory;
-
-            dst_stride = sizeof(ARGB) * (dst_area.right - dst_area.left);
-
-            get_bitmap_sample_size(interpolation, imageAttributes->wrap,
-                bitmap, srcx, srcy, srcwidth, srcheight, &src_area);
+            if (do_resampling)
+            {
+                get_bitmap_sample_size(interpolation, imageAttributes->wrap,
+                    bitmap, srcx, srcy, srcwidth, srcheight, &src_area);
+            }
+            else
+            {
+                /* Make sure src_area is equal in size to dst_area. */
+                src_area.X = srcx + dst_area.left - pti[0].x;
+                src_area.Y = srcy + dst_area.top - pti[0].y;
+                src_area.Width = dst_area.right - dst_area.left;
+                src_area.Height = dst_area.bottom - dst_area.top;
+            }
 
             TRACE("src_area: %d x %d\n", src_area.Width, src_area.Height);
 
             src_data = GdipAlloc(sizeof(ARGB) * src_area.Width * src_area.Height);
             if (!src_data)
-            {
-                GdipFree(dst_data);
                 return OutOfMemory;
-            }
             src_stride = sizeof(ARGB) * src_area.Width;
 
             /* Read the bits we need from the source bitmap into an ARGB buffer. */
@@ -2938,7 +2992,6 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
             if (stat != Ok)
             {
                 GdipFree(src_data);
-                GdipFree(dst_data);
                 return stat;
             }
 
@@ -2946,40 +2999,57 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
                 src_area.Width, src_area.Height,
                 src_stride, ColorAdjustTypeBitmap);
 
-            /* Transform the bits as needed to the destination. */
-            GdipTransformMatrixPoints(&dst_to_src, dst_to_src_points, 3);
+            if (do_resampling)
+            {
+                /* Transform the bits as needed to the destination. */
+                dst_data = dst_dyn_data = GdipAlloc(sizeof(ARGB) * (dst_area.right - dst_area.left) * (dst_area.bottom - dst_area.top));
+                if (!dst_data)
+                {
+                    GdipFree(src_data);
+                    return OutOfMemory;
+                }
 
-            x_dx = dst_to_src_points[1].X - dst_to_src_points[0].X;
-            x_dy = dst_to_src_points[1].Y - dst_to_src_points[0].Y;
-            y_dx = dst_to_src_points[2].X - dst_to_src_points[0].X;
-            y_dy = dst_to_src_points[2].Y - dst_to_src_points[0].Y;
+                dst_stride = sizeof(ARGB) * (dst_area.right - dst_area.left);
 
-            for (x=dst_area.left; x<dst_area.right; x++)
-            {
-                for (y=dst_area.top; y<dst_area.bottom; y++)
+                GdipTransformMatrixPoints(&dst_to_src, dst_to_src_points, 3);
+
+                x_dx = dst_to_src_points[1].X - dst_to_src_points[0].X;
+                x_dy = dst_to_src_points[1].Y - dst_to_src_points[0].Y;
+                y_dx = dst_to_src_points[2].X - dst_to_src_points[0].X;
+                y_dy = dst_to_src_points[2].Y - dst_to_src_points[0].Y;
+
+                for (x=dst_area.left; x<dst_area.right; x++)
                 {
-                    GpPointF src_pointf;
-                    ARGB *dst_color;
+                    for (y=dst_area.top; y<dst_area.bottom; y++)
+                    {
+                        GpPointF src_pointf;
+                        ARGB *dst_color;
 
-                    src_pointf.X = dst_to_src_points[0].X + x * x_dx + y * y_dx;
-                    src_pointf.Y = dst_to_src_points[0].Y + x * x_dy + y * y_dy;
+                        src_pointf.X = dst_to_src_points[0].X + x * x_dx + y * y_dx;
+                        src_pointf.Y = dst_to_src_points[0].Y + x * x_dy + y * y_dy;
 
-                    dst_color = (ARGB*)(dst_data + dst_stride * (y - dst_area.top) + sizeof(ARGB) * (x - dst_area.left));
+                        dst_color = (ARGB*)(dst_data + dst_stride * (y - dst_area.top) + sizeof(ARGB) * (x - dst_area.left));
 
-                    if (src_pointf.X >= srcx && src_pointf.X < srcx + srcwidth && src_pointf.Y >= srcy && src_pointf.Y < srcy+srcheight)
-                        *dst_color = resample_bitmap_pixel(&src_area, src_data, bitmap->width, bitmap->height, &src_pointf,
-                                                           imageAttributes, interpolation, offset_mode);
-                    else
-                        *dst_color = 0;
+                        if (src_pointf.X >= srcx && src_pointf.X < srcx + srcwidth && src_pointf.Y >= srcy && src_pointf.Y < srcy+srcheight)
+                            *dst_color = resample_bitmap_pixel(&src_area, src_data, bitmap->width, bitmap->height, &src_pointf,
+                                                               imageAttributes, interpolation, offset_mode);
+                        else
+                            *dst_color = 0;
+                    }
                 }
             }
-
-            GdipFree(src_data);
+            else
+            {
+                dst_data = src_data;
+                dst_stride = src_stride;
+            }
 
             stat = alpha_blend_pixels(graphics, dst_area.left, dst_area.top,
                 dst_data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, dst_stride);
 
-            GdipFree(dst_data);
+            GdipFree(src_data);
+
+            GdipFree(dst_dyn_data);
 
             return stat;
         }