Module: wine Branch: master Commit: 870fdaf6cef2fa194c17b2cfb74b14cd92cd8a81 URL: http://source.winehq.org/git/wine.git/?a=commit;h=870fdaf6cef2fa194c17b2cfb7...
Author: Vincent Povirk vincent@codeweavers.com Date: Thu Mar 3 14:18:47 2011 -0600
gdiplus: Read drawn bitmaps in one step instead of using getpixel.
---
dlls/gdiplus/graphics.c | 200 ++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 163 insertions(+), 37 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 09eaa01..7b51c61 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -414,6 +414,95 @@ static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE d } }
+/* Given a bitmap and its source rectangle, find the smallest rectangle in the + * bitmap that contains all the pixels we may need to draw it. */ +static void get_bitmap_sample_size(InterpolationMode interpolation, WrapMode wrap, + GpBitmap* bitmap, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight, + GpRect *rect) +{ + INT left, top, right, bottom; + + switch (interpolation) + { + case InterpolationModeHighQualityBilinear: + case InterpolationModeHighQualityBicubic: + /* FIXME: Include a greater range for the prefilter? */ + case InterpolationModeBicubic: + case InterpolationModeBilinear: + left = (INT)(floorf(srcx)); + top = (INT)(floorf(srcy)); + right = (INT)(ceilf(srcx+srcwidth)); + bottom = (INT)(ceilf(srcy+srcheight)); + break; + case InterpolationModeNearestNeighbor: + default: + left = roundr(srcx); + top = roundr(srcy); + right = roundr(srcx+srcwidth); + bottom = roundr(srcy+srcheight); + break; + } + + if (wrap == WrapModeClamp) + { + if (left < 0) + left = 0; + if (top < 0) + top = 0; + if (right >= bitmap->width) + right = bitmap->width-1; + if (bottom >= bitmap->height) + bottom = bitmap->height-1; + } + else + { + /* In some cases we can make the rectangle smaller here, but the logic + * is hard to get right, and tiling suggests we're likely to use the + * entire source image. */ + if (left < 0 || right >= bitmap->width) + { + left = 0; + right = bitmap->width-1; + } + + if (top < 0 || bottom >= bitmap->height) + { + top = 0; + bottom = bitmap->height-1; + } + } + + rect->X = left; + rect->Y = top; + rect->Width = right - left + 1; + rect->Height = bottom - top + 1; +} + +static ARGB sample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT width, + UINT height, INT x, INT y, GDIPCONST GpImageAttributes *attributes) +{ + static int fixme[4]; + + switch (attributes->wrap) + { + default: + if (!fixme[attributes->wrap]++) + FIXME("not implemented for wrap mode %i\n", attributes->wrap); + case WrapModeClamp: + if (x < 0 || y < 0 || x >= width || y >= height) + return attributes->outside_color; + break; + } + + if (x < src_rect->X || y < src_rect->Y || x >= src_rect->X + src_rect->Width || y >= src_rect->Y + src_rect->Height) + { + ERR("out of range pixel requested\n"); + return 0xffcd0084; + } + + return ((DWORD*)(bits))[(x - src_rect->X) + (y - src_rect->Y) * src_rect->Width]; +} + static void brush_fill_path(GpGraphics *graphics, GpBrush* brush) { switch (brush->bt) @@ -2309,16 +2398,25 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
if (use_software) { - RECT src_area, dst_area; - int i, x, y, stride; + RECT dst_area; + GpRect src_area; + int i, x, y, src_stride, dst_stride; GpMatrix *dst_to_src; REAL m11, m12, m21, m22, mdx, mdy; - LPBYTE data; + LPBYTE src_data, dst_data; + BitmapData lockeddata; + InterpolationMode interpolation = graphics->interpolation; + GpPointF dst_to_src_points[3] = {{0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}}; + REAL x_dx, x_dy, y_dx, y_dy; + static const GpImageAttributes defaultImageAttributes = {WrapModeClamp, 0, FALSE}; + + if (!imageAttributes) + imageAttributes = &defaultImageAttributes;
- src_area.left = srcx*dx; - src_area.top = srcy*dy; - src_area.right = (srcx+srcwidth)*dx; - src_area.bottom = (srcy+srcheight)*dy; + srcx = srcx * dx; + srcy = srcy * dy; + srcwidth = srcwidth * dx; + srcheight = srcheight * dy;
dst_area.left = dst_area.right = pti[0].x; dst_area.top = dst_area.bottom = pti[0].y; @@ -2347,65 +2445,93 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image return stat; }
- data = GdipAlloc(sizeof(ARGB) * (dst_area.right - dst_area.left) * (dst_area.bottom - dst_area.top)); - if (!data) + dst_data = GdipAlloc(sizeof(ARGB) * (dst_area.right - dst_area.left) * (dst_area.bottom - dst_area.top)); + if (!dst_data) + { + GdipDeleteMatrix(dst_to_src); + 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); + + src_data = GdipAlloc(sizeof(ARGB) * src_area.Width * src_area.Height); + if (!src_data) { + GdipFree(dst_data); GdipDeleteMatrix(dst_to_src); return OutOfMemory; } + src_stride = sizeof(ARGB) * src_area.Width; + + /* Read the bits we need from the source bitmap into an ARGB buffer. */ + lockeddata.Width = src_area.Width; + lockeddata.Height = src_area.Height; + lockeddata.Stride = src_stride; + lockeddata.PixelFormat = PixelFormat32bppARGB; + lockeddata.Scan0 = src_data;
- stride = sizeof(ARGB) * (dst_area.right - dst_area.left); + stat = GdipBitmapLockBits(bitmap, &src_area, ImageLockModeRead|ImageLockModeUserInputBuf, + PixelFormat32bppARGB, &lockeddata); + + if (stat == Ok) + stat = GdipBitmapUnlockBits(bitmap, &lockeddata);
- if (imageAttributes && - (imageAttributes->wrap != WrapModeClamp || - imageAttributes->outside_color != 0x00000000 || - imageAttributes->clamp)) + if (stat != Ok) { - static int fixme; - if (!fixme++) - FIXME("Image wrap mode not implemented\n"); + if (src_data != dst_data) + GdipFree(src_data); + GdipFree(dst_data); + GdipDeleteMatrix(dst_to_src); + return OutOfMemory; }
+ /* Transform the bits as needed to the destination. */ + 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++) { for (y=dst_area.top; y<dst_area.bottom; y++) { GpPointF src_pointf; - int src_x, src_y; - ARGB *src_color; - - src_pointf.X = x; - src_pointf.Y = y; + INT src_x, src_y; + ARGB *dst_color;
- GdipTransformMatrixPoints(dst_to_src, &src_pointf, 1); + 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_x = roundr(src_pointf.X); src_y = roundr(src_pointf.Y);
- src_color = (ARGB*)(data + 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_x < src_area.left || src_x >= src_area.right || - src_y < src_area.top || src_y >= src_area.bottom) - *src_color = 0; + if (src_pointf.X >= srcx && src_pointf.X < srcx + srcwidth && src_pointf.Y >= srcy && src_pointf.Y < srcy+srcheight) + *dst_color = sample_bitmap_pixel(&src_area, src_data, bitmap->width, bitmap->height, src_x, src_y, imageAttributes); else - GdipBitmapGetPixel(bitmap, src_x, src_y, src_color); + *dst_color = 0; } }
GdipDeleteMatrix(dst_to_src);
- if (imageAttributes) - { - apply_image_attributes(imageAttributes, data, - dst_area.right - dst_area.left, - dst_area.bottom - dst_area.top, - stride, ColorAdjustTypeBitmap); - } + GdipFree(src_data); + + apply_image_attributes(imageAttributes, dst_data, + dst_area.right - dst_area.left, + dst_area.bottom - dst_area.top, + dst_stride, ColorAdjustTypeBitmap);
stat = alpha_blend_pixels(graphics, dst_area.left, dst_area.top, - data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, stride); + dst_data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, dst_stride);
- GdipFree(data); + GdipFree(dst_data);
return stat; }