Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygengraphics.c
Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 2007 Google (Evan Stade) 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00017 */ 00018 00019 #include <stdarg.h> 00020 #include <math.h> 00021 #include <limits.h> 00022 00023 #include "windef.h" 00024 #include "winbase.h" 00025 #include "winuser.h" 00026 #include "wingdi.h" 00027 #include "wine/unicode.h" 00028 00029 #define COBJMACROS 00030 #include "objbase.h" 00031 #include "ocidl.h" 00032 #include "olectl.h" 00033 #include "ole2.h" 00034 00035 #include "winreg.h" 00036 #include "shlwapi.h" 00037 00038 #include "gdiplus.h" 00039 #include "gdiplus_private.h" 00040 #include "wine/debug.h" 00041 #include "wine/list.h" 00042 00043 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus); 00044 00045 /* looks-right constants */ 00046 #define ANCHOR_WIDTH (2.0) 00047 #define MAX_ITERS (50) 00048 00049 /* Converts angle (in degrees) to x/y coordinates */ 00050 static void deg2xy(REAL angle, REAL x_0, REAL y_0, REAL *x, REAL *y) 00051 { 00052 REAL radAngle, hypotenuse; 00053 00054 radAngle = deg2rad(angle); 00055 hypotenuse = 50.0; /* arbitrary */ 00056 00057 *x = x_0 + cos(radAngle) * hypotenuse; 00058 *y = y_0 + sin(radAngle) * hypotenuse; 00059 } 00060 00061 /* Converts from gdiplus path point type to gdi path point type. */ 00062 static BYTE convert_path_point_type(BYTE type) 00063 { 00064 BYTE ret; 00065 00066 switch(type & PathPointTypePathTypeMask){ 00067 case PathPointTypeBezier: 00068 ret = PT_BEZIERTO; 00069 break; 00070 case PathPointTypeLine: 00071 ret = PT_LINETO; 00072 break; 00073 case PathPointTypeStart: 00074 ret = PT_MOVETO; 00075 break; 00076 default: 00077 ERR("Bad point type\n"); 00078 return 0; 00079 } 00080 00081 if(type & PathPointTypeCloseSubpath) 00082 ret |= PT_CLOSEFIGURE; 00083 00084 return ret; 00085 } 00086 00087 static REAL graphics_res(GpGraphics *graphics) 00088 { 00089 if (graphics->image) return graphics->image->xres; 00090 else return (REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSX); 00091 } 00092 00093 static COLORREF get_gdi_brush_color(const GpBrush *brush) 00094 { 00095 ARGB argb; 00096 00097 switch (brush->bt) 00098 { 00099 case BrushTypeSolidColor: 00100 { 00101 const GpSolidFill *sf = (const GpSolidFill *)brush; 00102 argb = sf->color; 00103 break; 00104 } 00105 case BrushTypeHatchFill: 00106 { 00107 const GpHatch *hatch = (const GpHatch *)brush; 00108 argb = hatch->forecol; 00109 break; 00110 } 00111 case BrushTypeLinearGradient: 00112 { 00113 const GpLineGradient *line = (const GpLineGradient *)brush; 00114 argb = line->startcolor; 00115 break; 00116 } 00117 case BrushTypePathGradient: 00118 { 00119 const GpPathGradient *grad = (const GpPathGradient *)brush; 00120 argb = grad->centercolor; 00121 break; 00122 } 00123 default: 00124 FIXME("unhandled brush type %d\n", brush->bt); 00125 argb = 0; 00126 break; 00127 } 00128 return ARGB2COLORREF(argb); 00129 } 00130 00131 static HBITMAP create_hatch_bitmap(const GpHatch *hatch) 00132 { 00133 HBITMAP hbmp; 00134 BITMAPINFOHEADER bmih; 00135 DWORD *bits; 00136 int x, y; 00137 00138 bmih.biSize = sizeof(bmih); 00139 bmih.biWidth = 8; 00140 bmih.biHeight = 8; 00141 bmih.biPlanes = 1; 00142 bmih.biBitCount = 32; 00143 bmih.biCompression = BI_RGB; 00144 bmih.biSizeImage = 0; 00145 00146 hbmp = CreateDIBSection(0, (BITMAPINFO *)&bmih, DIB_RGB_COLORS, (void **)&bits, NULL, 0); 00147 if (hbmp) 00148 { 00149 const char *hatch_data; 00150 00151 if (get_hatch_data(hatch->hatchstyle, &hatch_data) == Ok) 00152 { 00153 for (y = 0; y < 8; y++) 00154 { 00155 for (x = 0; x < 8; x++) 00156 { 00157 if (hatch_data[y] & (0x80 >> x)) 00158 bits[y * 8 + x] = hatch->forecol; 00159 else 00160 bits[y * 8 + x] = hatch->backcol; 00161 } 00162 } 00163 } 00164 else 00165 { 00166 FIXME("Unimplemented hatch style %d\n", hatch->hatchstyle); 00167 00168 for (y = 0; y < 64; y++) 00169 bits[y] = hatch->forecol; 00170 } 00171 } 00172 00173 return hbmp; 00174 } 00175 00176 static GpStatus create_gdi_logbrush(const GpBrush *brush, LOGBRUSH *lb) 00177 { 00178 switch (brush->bt) 00179 { 00180 case BrushTypeSolidColor: 00181 { 00182 const GpSolidFill *sf = (const GpSolidFill *)brush; 00183 lb->lbStyle = BS_SOLID; 00184 lb->lbColor = ARGB2COLORREF(sf->color); 00185 lb->lbHatch = 0; 00186 return Ok; 00187 } 00188 00189 case BrushTypeHatchFill: 00190 { 00191 const GpHatch *hatch = (const GpHatch *)brush; 00192 HBITMAP hbmp; 00193 00194 hbmp = create_hatch_bitmap(hatch); 00195 if (!hbmp) return OutOfMemory; 00196 00197 lb->lbStyle = BS_PATTERN; 00198 lb->lbColor = 0; 00199 lb->lbHatch = (ULONG_PTR)hbmp; 00200 return Ok; 00201 } 00202 00203 default: 00204 FIXME("unhandled brush type %d\n", brush->bt); 00205 lb->lbStyle = BS_SOLID; 00206 lb->lbColor = get_gdi_brush_color(brush); 00207 lb->lbHatch = 0; 00208 return Ok; 00209 } 00210 } 00211 00212 static GpStatus free_gdi_logbrush(LOGBRUSH *lb) 00213 { 00214 switch (lb->lbStyle) 00215 { 00216 case BS_PATTERN: 00217 DeleteObject((HGDIOBJ)(ULONG_PTR)lb->lbHatch); 00218 break; 00219 } 00220 return Ok; 00221 } 00222 00223 static HBRUSH create_gdi_brush(const GpBrush *brush) 00224 { 00225 LOGBRUSH lb; 00226 HBRUSH gdibrush; 00227 00228 if (create_gdi_logbrush(brush, &lb) != Ok) return 0; 00229 00230 gdibrush = CreateBrushIndirect(&lb); 00231 free_gdi_logbrush(&lb); 00232 00233 return gdibrush; 00234 } 00235 00236 static INT prepare_dc(GpGraphics *graphics, GpPen *pen) 00237 { 00238 LOGBRUSH lb; 00239 HPEN gdipen; 00240 REAL width; 00241 INT save_state, i, numdashes; 00242 GpPointF pt[2]; 00243 DWORD dash_array[MAX_DASHLEN]; 00244 00245 save_state = SaveDC(graphics->hdc); 00246 00247 EndPath(graphics->hdc); 00248 00249 if(pen->unit == UnitPixel){ 00250 width = pen->width; 00251 } 00252 else{ 00253 /* Get an estimate for the amount the pen width is affected by the world 00254 * transform. (This is similar to what some of the wine drivers do.) */ 00255 pt[0].X = 0.0; 00256 pt[0].Y = 0.0; 00257 pt[1].X = 1.0; 00258 pt[1].Y = 1.0; 00259 GdipTransformMatrixPoints(graphics->worldtrans, pt, 2); 00260 width = sqrt((pt[1].X - pt[0].X) * (pt[1].X - pt[0].X) + 00261 (pt[1].Y - pt[0].Y) * (pt[1].Y - pt[0].Y)) / sqrt(2.0); 00262 00263 width *= pen->width * convert_unit(graphics_res(graphics), 00264 pen->unit == UnitWorld ? graphics->unit : pen->unit); 00265 } 00266 00267 if(pen->dash == DashStyleCustom){ 00268 numdashes = min(pen->numdashes, MAX_DASHLEN); 00269 00270 TRACE("dashes are: "); 00271 for(i = 0; i < numdashes; i++){ 00272 dash_array[i] = roundr(width * pen->dashes[i]); 00273 TRACE("%d, ", dash_array[i]); 00274 } 00275 TRACE("\n and the pen style is %x\n", pen->style); 00276 00277 create_gdi_logbrush(pen->brush, &lb); 00278 gdipen = ExtCreatePen(pen->style, roundr(width), &lb, 00279 numdashes, dash_array); 00280 free_gdi_logbrush(&lb); 00281 } 00282 else 00283 { 00284 create_gdi_logbrush(pen->brush, &lb); 00285 gdipen = ExtCreatePen(pen->style, roundr(width), &lb, 0, NULL); 00286 free_gdi_logbrush(&lb); 00287 } 00288 00289 SelectObject(graphics->hdc, gdipen); 00290 00291 return save_state; 00292 } 00293 00294 static void restore_dc(GpGraphics *graphics, INT state) 00295 { 00296 DeleteObject(SelectObject(graphics->hdc, GetStockObject(NULL_PEN))); 00297 RestoreDC(graphics->hdc, state); 00298 } 00299 00300 static GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space, 00301 GpCoordinateSpace src_space, GpMatrix **matrix); 00302 00303 /* This helper applies all the changes that the points listed in ptf need in 00304 * order to be drawn on the device context. In the end, this should include at 00305 * least: 00306 * -scaling by page unit 00307 * -applying world transformation 00308 * -converting from float to int 00309 * Native gdiplus uses gdi32 to do all this (via SetMapMode, SetViewportExtEx, 00310 * SetWindowExtEx, SetWorldTransform, etc.) but we cannot because we are using 00311 * gdi to draw, and these functions would irreparably mess with line widths. 00312 */ 00313 static void transform_and_round_points(GpGraphics *graphics, POINT *pti, 00314 GpPointF *ptf, INT count) 00315 { 00316 REAL unitscale; 00317 GpMatrix *matrix; 00318 int i; 00319 00320 unitscale = convert_unit(graphics_res(graphics), graphics->unit); 00321 00322 /* apply page scale */ 00323 if(graphics->unit != UnitDisplay) 00324 unitscale *= graphics->scale; 00325 00326 GdipCloneMatrix(graphics->worldtrans, &matrix); 00327 GdipScaleMatrix(matrix, unitscale, unitscale, MatrixOrderAppend); 00328 GdipTransformMatrixPoints(matrix, ptf, count); 00329 GdipDeleteMatrix(matrix); 00330 00331 for(i = 0; i < count; i++){ 00332 pti[i].x = roundr(ptf[i].X); 00333 pti[i].y = roundr(ptf[i].Y); 00334 } 00335 } 00336 00337 static void gdi_alpha_blend(GpGraphics *graphics, INT dst_x, INT dst_y, INT dst_width, INT dst_height, 00338 HDC hdc, INT src_x, INT src_y, INT src_width, INT src_height) 00339 { 00340 if (GetDeviceCaps(graphics->hdc, SHADEBLENDCAPS) == SB_NONE) 00341 { 00342 TRACE("alpha blending not supported by device, fallback to StretchBlt\n"); 00343 00344 StretchBlt(graphics->hdc, dst_x, dst_y, dst_width, dst_height, 00345 hdc, src_x, src_y, src_width, src_height, SRCCOPY); 00346 } 00347 else 00348 { 00349 BLENDFUNCTION bf; 00350 00351 bf.BlendOp = AC_SRC_OVER; 00352 bf.BlendFlags = 0; 00353 bf.SourceConstantAlpha = 255; 00354 bf.AlphaFormat = AC_SRC_ALPHA; 00355 00356 GdiAlphaBlend(graphics->hdc, dst_x, dst_y, dst_width, dst_height, 00357 hdc, src_x, src_y, src_width, src_height, bf); 00358 } 00359 } 00360 00361 /* Draw non-premultiplied ARGB data to the given graphics object */ 00362 static GpStatus alpha_blend_pixels(GpGraphics *graphics, INT dst_x, INT dst_y, 00363 const BYTE *src, INT src_width, INT src_height, INT src_stride) 00364 { 00365 if (graphics->image && graphics->image->type == ImageTypeBitmap) 00366 { 00367 GpBitmap *dst_bitmap = (GpBitmap*)graphics->image; 00368 INT x, y; 00369 00370 for (x=0; x<src_width; x++) 00371 { 00372 for (y=0; y<src_height; y++) 00373 { 00374 ARGB dst_color, src_color; 00375 GdipBitmapGetPixel(dst_bitmap, x+dst_x, y+dst_y, &dst_color); 00376 src_color = ((ARGB*)(src + src_stride * y))[x]; 00377 GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over(dst_color, src_color)); 00378 } 00379 } 00380 00381 return Ok; 00382 } 00383 else if (graphics->image && graphics->image->type == ImageTypeMetafile) 00384 { 00385 ERR("This should not be used for metafiles; fix caller\n"); 00386 return NotImplemented; 00387 } 00388 else 00389 { 00390 HDC hdc; 00391 HBITMAP hbitmap; 00392 BITMAPINFOHEADER bih; 00393 BYTE *temp_bits; 00394 00395 hdc = CreateCompatibleDC(0); 00396 00397 bih.biSize = sizeof(BITMAPINFOHEADER); 00398 bih.biWidth = src_width; 00399 bih.biHeight = -src_height; 00400 bih.biPlanes = 1; 00401 bih.biBitCount = 32; 00402 bih.biCompression = BI_RGB; 00403 bih.biSizeImage = 0; 00404 bih.biXPelsPerMeter = 0; 00405 bih.biYPelsPerMeter = 0; 00406 bih.biClrUsed = 0; 00407 bih.biClrImportant = 0; 00408 00409 hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, 00410 (void**)&temp_bits, NULL, 0); 00411 00412 convert_32bppARGB_to_32bppPARGB(src_width, src_height, temp_bits, 00413 4 * src_width, src, src_stride); 00414 00415 SelectObject(hdc, hbitmap); 00416 gdi_alpha_blend(graphics, dst_x, dst_y, src_width, src_height, 00417 hdc, 0, 0, src_width, src_height); 00418 DeleteDC(hdc); 00419 DeleteObject(hbitmap); 00420 00421 return Ok; 00422 } 00423 } 00424 00425 static GpStatus alpha_blend_pixels_hrgn(GpGraphics *graphics, INT dst_x, INT dst_y, 00426 const BYTE *src, INT src_width, INT src_height, INT src_stride, HRGN hregion) 00427 { 00428 GpStatus stat=Ok; 00429 00430 if (graphics->image && graphics->image->type == ImageTypeBitmap) 00431 { 00432 int i, size; 00433 RGNDATA *rgndata; 00434 RECT *rects; 00435 00436 size = GetRegionData(hregion, 0, NULL); 00437 00438 rgndata = GdipAlloc(size); 00439 if (!rgndata) 00440 return OutOfMemory; 00441 00442 GetRegionData(hregion, size, rgndata); 00443 00444 rects = (RECT*)&rgndata->Buffer; 00445 00446 for (i=0; stat == Ok && i<rgndata->rdh.nCount; i++) 00447 { 00448 stat = alpha_blend_pixels(graphics, rects[i].left, rects[i].top, 00449 &src[(rects[i].left - dst_x) * 4 + (rects[i].top - dst_y) * src_stride], 00450 rects[i].right - rects[i].left, rects[i].bottom - rects[i].top, 00451 src_stride); 00452 } 00453 00454 GdipFree(rgndata); 00455 00456 return stat; 00457 } 00458 else if (graphics->image && graphics->image->type == ImageTypeMetafile) 00459 { 00460 ERR("This should not be used for metafiles; fix caller\n"); 00461 return NotImplemented; 00462 } 00463 else 00464 { 00465 int save; 00466 00467 save = SaveDC(graphics->hdc); 00468 00469 ExtSelectClipRgn(graphics->hdc, hregion, RGN_AND); 00470 00471 stat = alpha_blend_pixels(graphics, dst_x, dst_y, src, src_width, 00472 src_height, src_stride); 00473 00474 RestoreDC(graphics->hdc, save); 00475 00476 return stat; 00477 } 00478 } 00479 00480 static ARGB blend_colors(ARGB start, ARGB end, REAL position) 00481 { 00482 ARGB result=0; 00483 ARGB i; 00484 INT a1, a2, a3; 00485 00486 a1 = (start >> 24) & 0xff; 00487 a2 = (end >> 24) & 0xff; 00488 00489 a3 = (int)(a1*(1.0f - position)+a2*(position)); 00490 00491 result |= a3 << 24; 00492 00493 for (i=0xff; i<=0xff0000; i = i << 8) 00494 result |= (int)((start&i)*(1.0f - position)+(end&i)*(position))&i; 00495 return result; 00496 } 00497 00498 static ARGB blend_line_gradient(GpLineGradient* brush, REAL position) 00499 { 00500 REAL blendfac; 00501 00502 /* clamp to between 0.0 and 1.0, using the wrap mode */ 00503 if (brush->wrap == WrapModeTile) 00504 { 00505 position = fmodf(position, 1.0f); 00506 if (position < 0.0f) position += 1.0f; 00507 } 00508 else /* WrapModeFlip* */ 00509 { 00510 position = fmodf(position, 2.0f); 00511 if (position < 0.0f) position += 2.0f; 00512 if (position > 1.0f) position = 2.0f - position; 00513 } 00514 00515 if (brush->blendcount == 1) 00516 blendfac = position; 00517 else 00518 { 00519 int i=1; 00520 REAL left_blendpos, left_blendfac, right_blendpos, right_blendfac; 00521 REAL range; 00522 00523 /* locate the blend positions surrounding this position */ 00524 while (position > brush->blendpos[i]) 00525 i++; 00526 00527 /* interpolate between the blend positions */ 00528 left_blendpos = brush->blendpos[i-1]; 00529 left_blendfac = brush->blendfac[i-1]; 00530 right_blendpos = brush->blendpos[i]; 00531 right_blendfac = brush->blendfac[i]; 00532 range = right_blendpos - left_blendpos; 00533 blendfac = (left_blendfac * (right_blendpos - position) + 00534 right_blendfac * (position - left_blendpos)) / range; 00535 } 00536 00537 if (brush->pblendcount == 0) 00538 return blend_colors(brush->startcolor, brush->endcolor, blendfac); 00539 else 00540 { 00541 int i=1; 00542 ARGB left_blendcolor, right_blendcolor; 00543 REAL left_blendpos, right_blendpos; 00544 00545 /* locate the blend colors surrounding this position */ 00546 while (blendfac > brush->pblendpos[i]) 00547 i++; 00548 00549 /* interpolate between the blend colors */ 00550 left_blendpos = brush->pblendpos[i-1]; 00551 left_blendcolor = brush->pblendcolor[i-1]; 00552 right_blendpos = brush->pblendpos[i]; 00553 right_blendcolor = brush->pblendcolor[i]; 00554 blendfac = (blendfac - left_blendpos) / (right_blendpos - left_blendpos); 00555 return blend_colors(left_blendcolor, right_blendcolor, blendfac); 00556 } 00557 } 00558 00559 static ARGB transform_color(ARGB color, const ColorMatrix *matrix) 00560 { 00561 REAL val[5], res[4]; 00562 int i, j; 00563 unsigned char a, r, g, b; 00564 00565 val[0] = ((color >> 16) & 0xff) / 255.0; /* red */ 00566 val[1] = ((color >> 8) & 0xff) / 255.0; /* green */ 00567 val[2] = (color & 0xff) / 255.0; /* blue */ 00568 val[3] = ((color >> 24) & 0xff) / 255.0; /* alpha */ 00569 val[4] = 1.0; /* translation */ 00570 00571 for (i=0; i<4; i++) 00572 { 00573 res[i] = 0.0; 00574 00575 for (j=0; j<5; j++) 00576 res[i] += matrix->m[j][i] * val[j]; 00577 } 00578 00579 a = min(max(floorf(res[3]*255.0), 0.0), 255.0); 00580 r = min(max(floorf(res[0]*255.0), 0.0), 255.0); 00581 g = min(max(floorf(res[1]*255.0), 0.0), 255.0); 00582 b = min(max(floorf(res[2]*255.0), 0.0), 255.0); 00583 00584 return (a << 24) | (r << 16) | (g << 8) | b; 00585 } 00586 00587 static int color_is_gray(ARGB color) 00588 { 00589 unsigned char r, g, b; 00590 00591 r = (color >> 16) & 0xff; 00592 g = (color >> 8) & 0xff; 00593 b = color & 0xff; 00594 00595 return (r == g) && (g == b); 00596 } 00597 00598 static void apply_image_attributes(const GpImageAttributes *attributes, LPBYTE data, 00599 UINT width, UINT height, INT stride, ColorAdjustType type) 00600 { 00601 UINT x, y, i; 00602 00603 if (attributes->colorkeys[type].enabled || 00604 attributes->colorkeys[ColorAdjustTypeDefault].enabled) 00605 { 00606 const struct color_key *key; 00607 BYTE min_blue, min_green, min_red; 00608 BYTE max_blue, max_green, max_red; 00609 00610 if (attributes->colorkeys[type].enabled) 00611 key = &attributes->colorkeys[type]; 00612 else 00613 key = &attributes->colorkeys[ColorAdjustTypeDefault]; 00614 00615 min_blue = key->low&0xff; 00616 min_green = (key->low>>8)&0xff; 00617 min_red = (key->low>>16)&0xff; 00618 00619 max_blue = key->high&0xff; 00620 max_green = (key->high>>8)&0xff; 00621 max_red = (key->high>>16)&0xff; 00622 00623 for (x=0; x<width; x++) 00624 for (y=0; y<height; y++) 00625 { 00626 ARGB *src_color; 00627 BYTE blue, green, red; 00628 src_color = (ARGB*)(data + stride * y + sizeof(ARGB) * x); 00629 blue = *src_color&0xff; 00630 green = (*src_color>>8)&0xff; 00631 red = (*src_color>>16)&0xff; 00632 if (blue >= min_blue && green >= min_green && red >= min_red && 00633 blue <= max_blue && green <= max_green && red <= max_red) 00634 *src_color = 0x00000000; 00635 } 00636 } 00637 00638 if (attributes->colorremaptables[type].enabled || 00639 attributes->colorremaptables[ColorAdjustTypeDefault].enabled) 00640 { 00641 const struct color_remap_table *table; 00642 00643 if (attributes->colorremaptables[type].enabled) 00644 table = &attributes->colorremaptables[type]; 00645 else 00646 table = &attributes->colorremaptables[ColorAdjustTypeDefault]; 00647 00648 for (x=0; x<width; x++) 00649 for (y=0; y<height; y++) 00650 { 00651 ARGB *src_color; 00652 src_color = (ARGB*)(data + stride * y + sizeof(ARGB) * x); 00653 for (i=0; i<table->mapsize; i++) 00654 { 00655 if (*src_color == table->colormap[i].oldColor.Argb) 00656 { 00657 *src_color = table->colormap[i].newColor.Argb; 00658 break; 00659 } 00660 } 00661 } 00662 } 00663 00664 if (attributes->colormatrices[type].enabled || 00665 attributes->colormatrices[ColorAdjustTypeDefault].enabled) 00666 { 00667 const struct color_matrix *colormatrices; 00668 00669 if (attributes->colormatrices[type].enabled) 00670 colormatrices = &attributes->colormatrices[type]; 00671 else 00672 colormatrices = &attributes->colormatrices[ColorAdjustTypeDefault]; 00673 00674 for (x=0; x<width; x++) 00675 for (y=0; y<height; y++) 00676 { 00677 ARGB *src_color; 00678 src_color = (ARGB*)(data + stride * y + sizeof(ARGB) * x); 00679 00680 if (colormatrices->flags == ColorMatrixFlagsDefault || 00681 !color_is_gray(*src_color)) 00682 { 00683 *src_color = transform_color(*src_color, &colormatrices->colormatrix); 00684 } 00685 else if (colormatrices->flags == ColorMatrixFlagsAltGray) 00686 { 00687 *src_color = transform_color(*src_color, &colormatrices->graymatrix); 00688 } 00689 } 00690 } 00691 00692 if (attributes->gamma_enabled[type] || 00693 attributes->gamma_enabled[ColorAdjustTypeDefault]) 00694 { 00695 REAL gamma; 00696 00697 if (attributes->gamma_enabled[type]) 00698 gamma = attributes->gamma[type]; 00699 else 00700 gamma = attributes->gamma[ColorAdjustTypeDefault]; 00701 00702 for (x=0; x<width; x++) 00703 for (y=0; y<height; y++) 00704 { 00705 ARGB *src_color; 00706 BYTE blue, green, red; 00707 src_color = (ARGB*)(data + stride * y + sizeof(ARGB) * x); 00708 00709 blue = *src_color&0xff; 00710 green = (*src_color>>8)&0xff; 00711 red = (*src_color>>16)&0xff; 00712 00713 /* FIXME: We should probably use a table for this. */ 00714 blue = floorf(powf(blue / 255.0, gamma) * 255.0); 00715 green = floorf(powf(green / 255.0, gamma) * 255.0); 00716 red = floorf(powf(red / 255.0, gamma) * 255.0); 00717 00718 *src_color = (*src_color & 0xff000000) | (red << 16) | (green << 8) | blue; 00719 } 00720 } 00721 } 00722 00723 /* Given a bitmap and its source rectangle, find the smallest rectangle in the 00724 * bitmap that contains all the pixels we may need to draw it. */ 00725 static void get_bitmap_sample_size(InterpolationMode interpolation, WrapMode wrap, 00726 GpBitmap* bitmap, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight, 00727 GpRect *rect) 00728 { 00729 INT left, top, right, bottom; 00730 00731 switch (interpolation) 00732 { 00733 case InterpolationModeHighQualityBilinear: 00734 case InterpolationModeHighQualityBicubic: 00735 /* FIXME: Include a greater range for the prefilter? */ 00736 case InterpolationModeBicubic: 00737 case InterpolationModeBilinear: 00738 left = (INT)(floorf(srcx)); 00739 top = (INT)(floorf(srcy)); 00740 right = (INT)(ceilf(srcx+srcwidth)); 00741 bottom = (INT)(ceilf(srcy+srcheight)); 00742 break; 00743 case InterpolationModeNearestNeighbor: 00744 default: 00745 left = roundr(srcx); 00746 top = roundr(srcy); 00747 right = roundr(srcx+srcwidth); 00748 bottom = roundr(srcy+srcheight); 00749 break; 00750 } 00751 00752 if (wrap == WrapModeClamp) 00753 { 00754 if (left < 0) 00755 left = 0; 00756 if (top < 0) 00757 top = 0; 00758 if (right >= bitmap->width) 00759 right = bitmap->width-1; 00760 if (bottom >= bitmap->height) 00761 bottom = bitmap->height-1; 00762 } 00763 else 00764 { 00765 /* In some cases we can make the rectangle smaller here, but the logic 00766 * is hard to get right, and tiling suggests we're likely to use the 00767 * entire source image. */ 00768 if (left < 0 || right >= bitmap->width) 00769 { 00770 left = 0; 00771 right = bitmap->width-1; 00772 } 00773 00774 if (top < 0 || bottom >= bitmap->height) 00775 { 00776 top = 0; 00777 bottom = bitmap->height-1; 00778 } 00779 } 00780 00781 rect->X = left; 00782 rect->Y = top; 00783 rect->Width = right - left + 1; 00784 rect->Height = bottom - top + 1; 00785 } 00786 00787 static ARGB sample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT width, 00788 UINT height, INT x, INT y, GDIPCONST GpImageAttributes *attributes) 00789 { 00790 if (attributes->wrap == WrapModeClamp) 00791 { 00792 if (x < 0 || y < 0 || x >= width || y >= height) 00793 return attributes->outside_color; 00794 } 00795 else 00796 { 00797 /* Tiling. Make sure co-ordinates are positive as it simplifies the math. */ 00798 if (x < 0) 00799 x = width*2 + x % (width * 2); 00800 if (y < 0) 00801 y = height*2 + y % (height * 2); 00802 00803 if ((attributes->wrap & 1) == 1) 00804 { 00805 /* Flip X */ 00806 if ((x / width) % 2 == 0) 00807 x = x % width; 00808 else 00809 x = width - 1 - x % width; 00810 } 00811 else 00812 x = x % width; 00813 00814 if ((attributes->wrap & 2) == 2) 00815 { 00816 /* Flip Y */ 00817 if ((y / height) % 2 == 0) 00818 y = y % height; 00819 else 00820 y = height - 1 - y % height; 00821 } 00822 else 00823 y = y % height; 00824 } 00825 00826 if (x < src_rect->X || y < src_rect->Y || x >= src_rect->X + src_rect->Width || y >= src_rect->Y + src_rect->Height) 00827 { 00828 ERR("out of range pixel requested\n"); 00829 return 0xffcd0084; 00830 } 00831 00832 return ((DWORD*)(bits))[(x - src_rect->X) + (y - src_rect->Y) * src_rect->Width]; 00833 } 00834 00835 static ARGB resample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT width, 00836 UINT height, GpPointF *point, GDIPCONST GpImageAttributes *attributes, 00837 InterpolationMode interpolation) 00838 { 00839 static int fixme; 00840 00841 switch (interpolation) 00842 { 00843 default: 00844 if (!fixme++) 00845 FIXME("Unimplemented interpolation %i\n", interpolation); 00846 /* fall-through */ 00847 case InterpolationModeBilinear: 00848 { 00849 REAL leftxf, topyf; 00850 INT leftx, rightx, topy, bottomy; 00851 ARGB topleft, topright, bottomleft, bottomright; 00852 ARGB top, bottom; 00853 float x_offset; 00854 00855 leftxf = floorf(point->X); 00856 leftx = (INT)leftxf; 00857 rightx = (INT)ceilf(point->X); 00858 topyf = floorf(point->Y); 00859 topy = (INT)topyf; 00860 bottomy = (INT)ceilf(point->Y); 00861 00862 if (leftx == rightx && topy == bottomy) 00863 return sample_bitmap_pixel(src_rect, bits, width, height, 00864 leftx, topy, attributes); 00865 00866 topleft = sample_bitmap_pixel(src_rect, bits, width, height, 00867 leftx, topy, attributes); 00868 topright = sample_bitmap_pixel(src_rect, bits, width, height, 00869 rightx, topy, attributes); 00870 bottomleft = sample_bitmap_pixel(src_rect, bits, width, height, 00871 leftx, bottomy, attributes); 00872 bottomright = sample_bitmap_pixel(src_rect, bits, width, height, 00873 rightx, bottomy, attributes); 00874 00875 x_offset = point->X - leftxf; 00876 top = blend_colors(topleft, topright, x_offset); 00877 bottom = blend_colors(bottomleft, bottomright, x_offset); 00878 00879 return blend_colors(top, bottom, point->Y - topyf); 00880 } 00881 case InterpolationModeNearestNeighbor: 00882 return sample_bitmap_pixel(src_rect, bits, width, height, 00883 roundr(point->X), roundr(point->Y), attributes); 00884 } 00885 } 00886 00887 static REAL intersect_line_scanline(const GpPointF *p1, const GpPointF *p2, REAL y) 00888 { 00889 return (p1->X - p2->X) * (p2->Y - y) / (p2->Y - p1->Y) + p2->X; 00890 } 00891 00892 static INT brush_can_fill_path(GpBrush *brush) 00893 { 00894 switch (brush->bt) 00895 { 00896 case BrushTypeSolidColor: 00897 return 1; 00898 case BrushTypeHatchFill: 00899 { 00900 GpHatch *hatch = (GpHatch*)brush; 00901 return ((hatch->forecol & 0xff000000) == 0xff000000) && 00902 ((hatch->backcol & 0xff000000) == 0xff000000); 00903 } 00904 case BrushTypeLinearGradient: 00905 case BrushTypeTextureFill: 00906 /* Gdi32 isn't much help with these, so we should use brush_fill_pixels instead. */ 00907 default: 00908 return 0; 00909 } 00910 } 00911 00912 static void brush_fill_path(GpGraphics *graphics, GpBrush* brush) 00913 { 00914 switch (brush->bt) 00915 { 00916 case BrushTypeSolidColor: 00917 { 00918 GpSolidFill *fill = (GpSolidFill*)brush; 00919 HBITMAP bmp = ARGB2BMP(fill->color); 00920 00921 if (bmp) 00922 { 00923 RECT rc; 00924 /* partially transparent fill */ 00925 00926 SelectClipPath(graphics->hdc, RGN_AND); 00927 if (GetClipBox(graphics->hdc, &rc) != NULLREGION) 00928 { 00929 HDC hdc = CreateCompatibleDC(NULL); 00930 00931 if (!hdc) break; 00932 00933 SelectObject(hdc, bmp); 00934 gdi_alpha_blend(graphics, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 00935 hdc, 0, 0, 1, 1); 00936 DeleteDC(hdc); 00937 } 00938 00939 DeleteObject(bmp); 00940 break; 00941 } 00942 /* else fall through */ 00943 } 00944 default: 00945 { 00946 HBRUSH gdibrush, old_brush; 00947 00948 gdibrush = create_gdi_brush(brush); 00949 if (!gdibrush) return; 00950 00951 old_brush = SelectObject(graphics->hdc, gdibrush); 00952 FillPath(graphics->hdc); 00953 SelectObject(graphics->hdc, old_brush); 00954 DeleteObject(gdibrush); 00955 break; 00956 } 00957 } 00958 } 00959 00960 static INT brush_can_fill_pixels(GpBrush *brush) 00961 { 00962 switch (brush->bt) 00963 { 00964 case BrushTypeSolidColor: 00965 case BrushTypeHatchFill: 00966 case BrushTypeLinearGradient: 00967 case BrushTypeTextureFill: 00968 case BrushTypePathGradient: 00969 return 1; 00970 default: 00971 return 0; 00972 } 00973 } 00974 00975 static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush, 00976 DWORD *argb_pixels, GpRect *fill_area, UINT cdwStride) 00977 { 00978 switch (brush->bt) 00979 { 00980 case BrushTypeSolidColor: 00981 { 00982 int x, y; 00983 GpSolidFill *fill = (GpSolidFill*)brush; 00984 for (x=0; x<fill_area->Width; x++) 00985 for (y=0; y<fill_area->Height; y++) 00986 argb_pixels[x + y*cdwStride] = fill->color; 00987 return Ok; 00988 } 00989 case BrushTypeHatchFill: 00990 { 00991 int x, y; 00992 GpHatch *fill = (GpHatch*)brush; 00993 const char *hatch_data; 00994 00995 if (get_hatch_data(fill->hatchstyle, &hatch_data) != Ok) 00996 return NotImplemented; 00997 00998 for (x=0; x<fill_area->Width; x++) 00999 for (y=0; y<fill_area->Height; y++) 01000 { 01001 int hx, hy; 01002 01003 /* FIXME: Account for the rendering origin */ 01004 hx = (x + fill_area->X) % 8; 01005 hy = (y + fill_area->Y) % 8; 01006 01007 if ((hatch_data[7-hy] & (0x80 >> hx)) != 0) 01008 argb_pixels[x + y*cdwStride] = fill->forecol; 01009 else 01010 argb_pixels[x + y*cdwStride] = fill->backcol; 01011 } 01012 01013 return Ok; 01014 } 01015 case BrushTypeLinearGradient: 01016 { 01017 GpLineGradient *fill = (GpLineGradient*)brush; 01018 GpPointF draw_points[3], line_points[3]; 01019 GpStatus stat; 01020 static const GpRectF box_1 = { 0.0, 0.0, 1.0, 1.0 }; 01021 GpMatrix *world_to_gradient; /* FIXME: Store this in the brush? */ 01022 int x, y; 01023 01024 draw_points[0].X = fill_area->X; 01025 draw_points[0].Y = fill_area->Y; 01026 draw_points[1].X = fill_area->X+1; 01027 draw_points[1].Y = fill_area->Y; 01028 draw_points[2].X = fill_area->X; 01029 draw_points[2].Y = fill_area->Y+1; 01030 01031 /* Transform the points to a co-ordinate space where X is the point's 01032 * position in the gradient, 0.0 being the start point and 1.0 the 01033 * end point. */ 01034 stat = GdipTransformPoints(graphics, CoordinateSpaceWorld, 01035 CoordinateSpaceDevice, draw_points, 3); 01036 01037 if (stat == Ok) 01038 { 01039 line_points[0] = fill->startpoint; 01040 line_points[1] = fill->endpoint; 01041 line_points[2].X = fill->startpoint.X + (fill->startpoint.Y - fill->endpoint.Y); 01042 line_points[2].Y = fill->startpoint.Y + (fill->endpoint.X - fill->startpoint.X); 01043 01044 stat = GdipCreateMatrix3(&box_1, line_points, &world_to_gradient); 01045 } 01046 01047 if (stat == Ok) 01048 { 01049 stat = GdipInvertMatrix(world_to_gradient); 01050 01051 if (stat == Ok) 01052 stat = GdipTransformMatrixPoints(world_to_gradient, draw_points, 3); 01053 01054 GdipDeleteMatrix(world_to_gradient); 01055 } 01056 01057 if (stat == Ok) 01058 { 01059 REAL x_delta = draw_points[1].X - draw_points[0].X; 01060 REAL y_delta = draw_points[2].X - draw_points[0].X; 01061 01062 for (y=0; y<fill_area->Height; y++) 01063 { 01064 for (x=0; x<fill_area->Width; x++) 01065 { 01066 REAL pos = draw_points[0].X + x * x_delta + y * y_delta; 01067 01068 argb_pixels[x + y*cdwStride] = blend_line_gradient(fill, pos); 01069 } 01070 } 01071 } 01072 01073 return stat; 01074 } 01075 case BrushTypeTextureFill: 01076 { 01077 GpTexture *fill = (GpTexture*)brush; 01078 GpPointF draw_points[3]; 01079 GpStatus stat; 01080 GpMatrix *world_to_texture; 01081 int x, y; 01082 GpBitmap *bitmap; 01083 int src_stride; 01084 GpRect src_area; 01085 01086 if (fill->image->type != ImageTypeBitmap) 01087 { 01088 FIXME("metafile texture brushes not implemented\n"); 01089 return NotImplemented; 01090 } 01091 01092 bitmap = (GpBitmap*)fill->image; 01093 src_stride = sizeof(ARGB) * bitmap->width; 01094 01095 src_area.X = src_area.Y = 0; 01096 src_area.Width = bitmap->width; 01097 src_area.Height = bitmap->height; 01098 01099 draw_points[0].X = fill_area->X; 01100 draw_points[0].Y = fill_area->Y; 01101 draw_points[1].X = fill_area->X+1; 01102 draw_points[1].Y = fill_area->Y; 01103 draw_points[2].X = fill_area->X; 01104 draw_points[2].Y = fill_area->Y+1; 01105 01106 /* Transform the points to the co-ordinate space of the bitmap. */ 01107 stat = GdipTransformPoints(graphics, CoordinateSpaceWorld, 01108 CoordinateSpaceDevice, draw_points, 3); 01109 01110 if (stat == Ok) 01111 { 01112 stat = GdipCloneMatrix(fill->transform, &world_to_texture); 01113 } 01114 01115 if (stat == Ok) 01116 { 01117 stat = GdipInvertMatrix(world_to_texture); 01118 01119 if (stat == Ok) 01120 stat = GdipTransformMatrixPoints(world_to_texture, draw_points, 3); 01121 01122 GdipDeleteMatrix(world_to_texture); 01123 } 01124 01125 if (stat == Ok && !fill->bitmap_bits) 01126 { 01127 BitmapData lockeddata; 01128 01129 fill->bitmap_bits = GdipAlloc(sizeof(ARGB) * bitmap->width * bitmap->height); 01130 if (!fill->bitmap_bits) 01131 stat = OutOfMemory; 01132 01133 if (stat == Ok) 01134 { 01135 lockeddata.Width = bitmap->width; 01136 lockeddata.Height = bitmap->height; 01137 lockeddata.Stride = src_stride; 01138 lockeddata.PixelFormat = PixelFormat32bppARGB; 01139 lockeddata.Scan0 = fill->bitmap_bits; 01140 01141 stat = GdipBitmapLockBits(bitmap, &src_area, ImageLockModeRead|ImageLockModeUserInputBuf, 01142 PixelFormat32bppARGB, &lockeddata); 01143 } 01144 01145 if (stat == Ok) 01146 stat = GdipBitmapUnlockBits(bitmap, &lockeddata); 01147 01148 if (stat == Ok) 01149 apply_image_attributes(fill->imageattributes, fill->bitmap_bits, 01150 bitmap->width, bitmap->height, 01151 src_stride, ColorAdjustTypeBitmap); 01152 01153 if (stat != Ok) 01154 { 01155 GdipFree(fill->bitmap_bits); 01156 fill->bitmap_bits = NULL; 01157 } 01158 } 01159 01160 if (stat == Ok) 01161 { 01162 REAL x_dx = draw_points[1].X - draw_points[0].X; 01163 REAL x_dy = draw_points[1].Y - draw_points[0].Y; 01164 REAL y_dx = draw_points[2].X - draw_points[0].X; 01165 REAL y_dy = draw_points[2].Y - draw_points[0].Y; 01166 01167 for (y=0; y<fill_area->Height; y++) 01168 { 01169 for (x=0; x<fill_area->Width; x++) 01170 { 01171 GpPointF point; 01172 point.X = draw_points[0].X + x * x_dx + y * y_dx; 01173 point.Y = draw_points[0].Y + y * x_dy + y * y_dy; 01174 01175 argb_pixels[x + y*cdwStride] = resample_bitmap_pixel( 01176 &src_area, fill->bitmap_bits, bitmap->width, bitmap->height, 01177 &point, fill->imageattributes, graphics->interpolation); 01178 } 01179 } 01180 } 01181 01182 return stat; 01183 } 01184 case BrushTypePathGradient: 01185 { 01186 GpPathGradient *fill = (GpPathGradient*)brush; 01187 GpPath *flat_path; 01188 GpMatrix *world_to_device; 01189 GpStatus stat; 01190 int i, figure_start=0; 01191 GpPointF start_point, end_point, center_point; 01192 BYTE type; 01193 REAL min_yf, max_yf, line1_xf, line2_xf; 01194 INT min_y, max_y, min_x, max_x; 01195 INT x, y; 01196 ARGB outer_color; 01197 static int transform_fixme_once; 01198 01199 if (fill->focus.X != 0.0 || fill->focus.Y != 0.0) 01200 { 01201 static int once; 01202 if (!once++) 01203 FIXME("path gradient focus not implemented\n"); 01204 } 01205 01206 if (fill->gamma) 01207 { 01208 static int once; 01209 if (!once++) 01210 FIXME("path gradient gamma correction not implemented\n"); 01211 } 01212 01213 if (fill->blendcount) 01214 { 01215 static int once; 01216 if (!once++) 01217 FIXME("path gradient blend not implemented\n"); 01218 } 01219 01220 if (fill->pblendcount) 01221 { 01222 static int once; 01223 if (!once++) 01224 FIXME("path gradient preset blend not implemented\n"); 01225 } 01226 01227 if (!transform_fixme_once) 01228 { 01229 BOOL is_identity=TRUE; 01230 GdipIsMatrixIdentity(fill->transform, &is_identity); 01231 if (!is_identity) 01232 { 01233 FIXME("path gradient transform not implemented\n"); 01234 transform_fixme_once = 1; 01235 } 01236 } 01237 01238 stat = GdipClonePath(fill->path, &flat_path); 01239 01240 if (stat != Ok) 01241 return stat; 01242 01243 stat = get_graphics_transform(graphics, CoordinateSpaceDevice, 01244 CoordinateSpaceWorld, &world_to_device); 01245 if (stat == Ok) 01246 { 01247 stat = GdipTransformPath(flat_path, world_to_device); 01248 01249 if (stat == Ok) 01250 { 01251 center_point = fill->center; 01252 stat = GdipTransformMatrixPoints(world_to_device, ¢er_point, 1); 01253 } 01254 01255 if (stat == Ok) 01256 stat = GdipFlattenPath(flat_path, NULL, 0.5); 01257 01258 GdipDeleteMatrix(world_to_device); 01259 } 01260 01261 if (stat != Ok) 01262 { 01263 GdipDeletePath(flat_path); 01264 return stat; 01265 } 01266 01267 for (i=0; i<flat_path->pathdata.Count; i++) 01268 { 01269 int start_center_line=0, end_center_line=0; 01270 int seen_start=0, seen_end=0, seen_center=0; 01271 REAL center_distance; 01272 ARGB start_color, end_color; 01273 REAL dy, dx; 01274 01275 type = flat_path->pathdata.Types[i]; 01276 01277 if ((type&PathPointTypePathTypeMask) == PathPointTypeStart) 01278 figure_start = i; 01279 01280 start_point = flat_path->pathdata.Points[i]; 01281 01282 start_color = fill->surroundcolors[min(i, fill->surroundcolorcount-1)]; 01283 01284 if ((type&PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath || i+1 >= flat_path->pathdata.Count) 01285 { 01286 end_point = flat_path->pathdata.Points[figure_start]; 01287 end_color = fill->surroundcolors[min(figure_start, fill->surroundcolorcount-1)]; 01288 } 01289 else if ((flat_path->pathdata.Types[i+1] & PathPointTypePathTypeMask) == PathPointTypeLine) 01290 { 01291 end_point = flat_path->pathdata.Points[i+1]; 01292 end_color = fill->surroundcolors[min(i+1, fill->surroundcolorcount-1)]; 01293 } 01294 else 01295 continue; 01296 01297 outer_color = start_color; 01298 01299 min_yf = center_point.Y; 01300 if (min_yf > start_point.Y) min_yf = start_point.Y; 01301 if (min_yf > end_point.Y) min_yf = end_point.Y; 01302 01303 if (min_yf < fill_area->Y) 01304 min_y = fill_area->Y; 01305 else 01306 min_y = (INT)ceil(min_yf); 01307 01308 max_yf = center_point.Y; 01309 if (max_yf < start_point.Y) max_yf = start_point.Y; 01310 if (max_yf < end_point.Y) max_yf = end_point.Y; 01311 01312 if (max_yf > fill_area->Y + fill_area->Height) 01313 max_y = fill_area->Y + fill_area->Height; 01314 else 01315 max_y = (INT)ceil(max_yf); 01316 01317 dy = end_point.Y - start_point.Y; 01318 dx = end_point.X - start_point.X; 01319 01320 /* This is proportional to the distance from start-end line to center point. */ 01321 center_distance = dy * (start_point.X - center_point.X) + 01322 dx * (center_point.Y - start_point.Y); 01323 01324 for (y=min_y; y<max_y; y++) 01325 { 01326 REAL yf = (REAL)y; 01327 01328 if (!seen_start && yf >= start_point.Y) 01329 { 01330 seen_start = 1; 01331 start_center_line ^= 1; 01332 } 01333 if (!seen_end && yf >= end_point.Y) 01334 { 01335 seen_end = 1; 01336 end_center_line ^= 1; 01337 } 01338 if (!seen_center && yf >= center_point.Y) 01339 { 01340 seen_center = 1; 01341 start_center_line ^= 1; 01342 end_center_line ^= 1; 01343 } 01344 01345 if (start_center_line) 01346 line1_xf = intersect_line_scanline(&start_point, ¢er_point, yf); 01347 else 01348 line1_xf = intersect_line_scanline(&start_point, &end_point, yf); 01349 01350 if (end_center_line) 01351 line2_xf = intersect_line_scanline(&end_point, ¢er_point, yf); 01352 else 01353 line2_xf = intersect_line_scanline(&start_point, &end_point, yf); 01354 01355 if (line1_xf < line2_xf) 01356 { 01357 min_x = (INT)ceil(line1_xf); 01358 max_x = (INT)ceil(line2_xf); 01359 } 01360 else 01361 { 01362 min_x = (INT)ceil(line2_xf); 01363 max_x = (INT)ceil(line1_xf); 01364 } 01365 01366 if (min_x < fill_area->X) 01367 min_x = fill_area->X; 01368 if (max_x > fill_area->X + fill_area->Width) 01369 max_x = fill_area->X + fill_area->Width; 01370 01371 for (x=min_x; x<max_x; x++) 01372 { 01373 REAL xf = (REAL)x; 01374 REAL distance; 01375 01376 if (start_color != end_color) 01377 { 01378 REAL blend_amount, pdy, pdx; 01379 pdy = yf - center_point.Y; 01380 pdx = xf - center_point.X; 01381 blend_amount = ( (center_point.Y - start_point.Y) * pdx + (start_point.X - center_point.X) * pdy ) / ( dy * pdx - dx * pdy ); 01382 outer_color = blend_colors(start_color, end_color, blend_amount); 01383 } 01384 01385 distance = (end_point.Y - start_point.Y) * (start_point.X - xf) + 01386 (end_point.X - start_point.X) * (yf - start_point.Y); 01387 01388 distance = distance / center_distance; 01389 01390 argb_pixels[(x-fill_area->X) + (y-fill_area->Y)*cdwStride] = 01391 blend_colors(outer_color, fill->centercolor, distance); 01392 } 01393 } 01394 } 01395 01396 GdipDeletePath(flat_path); 01397 return stat; 01398 } 01399 default: 01400 return NotImplemented; 01401 } 01402 } 01403 01404 /* GdipDrawPie/GdipFillPie helper function */ 01405 static void draw_pie(GpGraphics *graphics, REAL x, REAL y, REAL width, 01406 REAL height, REAL startAngle, REAL sweepAngle) 01407 { 01408 GpPointF ptf[4]; 01409 POINT pti[4]; 01410 01411 ptf[0].X = x; 01412 ptf[0].Y = y; 01413 ptf[1].X = x + width; 01414 ptf[1].Y = y + height; 01415 01416 deg2xy(startAngle+sweepAngle, x + width / 2.0, y + width / 2.0, &ptf[2].X, &ptf[2].Y); 01417 deg2xy(startAngle, x + width / 2.0, y + width / 2.0, &ptf[3].X, &ptf[3].Y); 01418 01419 transform_and_round_points(graphics, pti, ptf, 4); 01420 01421 Pie(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y, pti[2].x, 01422 pti[2].y, pti[3].x, pti[3].y); 01423 } 01424 01425 /* Draws the linecap the specified color and size on the hdc. The linecap is in 01426 * direction of the line from x1, y1 to x2, y2 and is anchored on x2, y2. Probably 01427 * should not be called on an hdc that has a path you care about. */ 01428 static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL size, 01429 const GpCustomLineCap *custom, REAL x1, REAL y1, REAL x2, REAL y2) 01430 { 01431 HGDIOBJ oldbrush = NULL, oldpen = NULL; 01432 GpMatrix *matrix = NULL; 01433 HBRUSH brush = NULL; 01434 HPEN pen = NULL; 01435 PointF ptf[4], *custptf = NULL; 01436 POINT pt[4], *custpt = NULL; 01437 BYTE *tp = NULL; 01438 REAL theta, dsmall, dbig, dx, dy = 0.0; 01439 INT i, count; 01440 LOGBRUSH lb; 01441 BOOL customstroke; 01442 01443 if((x1 == x2) && (y1 == y2)) 01444 return; 01445 01446 theta = gdiplus_atan2(y2 - y1, x2 - x1); 01447 01448 customstroke = (cap == LineCapCustom) && custom && (!custom->fill); 01449 if(!customstroke){ 01450 brush = CreateSolidBrush(color); 01451 lb.lbStyle = BS_SOLID; 01452 lb.lbColor = color; 01453 lb.lbHatch = 0; 01454 pen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT | 01455 PS_JOIN_MITER, 1, &lb, 0, 01456 NULL); 01457 oldbrush = SelectObject(graphics->hdc, brush); 01458 oldpen = SelectObject(graphics->hdc, pen); 01459 } 01460 01461 switch(cap){ 01462 case LineCapFlat: 01463 break; 01464 case LineCapSquare: 01465 case LineCapSquareAnchor: 01466 case LineCapDiamondAnchor: 01467 size = size * (cap & LineCapNoAnchor ? ANCHOR_WIDTH : 1.0) / 2.0; 01468 if(cap == LineCapDiamondAnchor){ 01469 dsmall = cos(theta + M_PI_2) * size; 01470 dbig = sin(theta + M_PI_2) * size; 01471 } 01472 else{ 01473 dsmall = cos(theta + M_PI_4) * size; 01474 dbig = sin(theta + M_PI_4) * size; 01475 } 01476 01477 ptf[0].X = x2 - dsmall; 01478 ptf[1].X = x2 + dbig; 01479 01480 ptf[0].Y = y2 - dbig; 01481 ptf[3].Y = y2 + dsmall; 01482 01483 ptf[1].Y = y2 - dsmall; 01484 ptf[2].Y = y2 + dbig; 01485 01486 ptf[3].X = x2 - dbig; 01487 ptf[2].X = x2 + dsmall; 01488 01489 transform_and_round_points(graphics, pt, ptf, 4); 01490 Polygon(graphics->hdc, pt, 4); 01491 01492 break; 01493 case LineCapArrowAnchor: 01494 size = size * 4.0 / sqrt(3.0); 01495 01496 dx = cos(M_PI / 6.0 + theta) * size; 01497 dy = sin(M_PI / 6.0 + theta) * size; 01498 01499 ptf[0].X = x2 - dx; 01500 ptf[0].Y = y2 - dy; 01501 01502 dx = cos(- M_PI / 6.0 + theta) * size; 01503 dy = sin(- M_PI / 6.0 + theta) * size; 01504 01505 ptf[1].X = x2 - dx; 01506 ptf[1].Y = y2 - dy; 01507 01508 ptf[2].X = x2; 01509 ptf[2].Y = y2; 01510 01511 transform_and_round_points(graphics, pt, ptf, 3); 01512 Polygon(graphics->hdc, pt, 3); 01513 01514 break; 01515 case LineCapRoundAnchor: 01516 dx = dy = ANCHOR_WIDTH * size / 2.0; 01517 01518 ptf[0].X = x2 - dx; 01519 ptf[0].Y = y2 - dy; 01520 ptf[1].X = x2 + dx; 01521 ptf[1].Y = y2 + dy; 01522 01523 transform_and_round_points(graphics, pt, ptf, 2); 01524 Ellipse(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y); 01525 01526 break; 01527 case LineCapTriangle: 01528 size = size / 2.0; 01529 dx = cos(M_PI_2 + theta) * size; 01530 dy = sin(M_PI_2 + theta) * size; 01531 01532 ptf[0].X = x2 - dx; 01533 ptf[0].Y = y2 - dy; 01534 ptf[1].X = x2 + dx; 01535 ptf[1].Y = y2 + dy; 01536 01537 dx = cos(theta) * size; 01538 dy = sin(theta) * size; 01539 01540 ptf[2].X = x2 + dx; 01541 ptf[2].Y = y2 + dy; 01542 01543 transform_and_round_points(graphics, pt, ptf, 3); 01544 Polygon(graphics->hdc, pt, 3); 01545 01546 break; 01547 case LineCapRound: 01548 dx = dy = size / 2.0; 01549 01550 ptf[0].X = x2 - dx; 01551 ptf[0].Y = y2 - dy; 01552 ptf[1].X = x2 + dx; 01553 ptf[1].Y = y2 + dy; 01554 01555 dx = -cos(M_PI_2 + theta) * size; 01556 dy = -sin(M_PI_2 + theta) * size; 01557 01558 ptf[2].X = x2 - dx; 01559 ptf[2].Y = y2 - dy; 01560 ptf[3].X = x2 + dx; 01561 ptf[3].Y = y2 + dy; 01562 01563 transform_and_round_points(graphics, pt, ptf, 4); 01564 Pie(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y, pt[2].x, 01565 pt[2].y, pt[3].x, pt[3].y); 01566 01567 break; 01568 case LineCapCustom: 01569 if(!custom) 01570 break; 01571 01572 count = custom->pathdata.Count; 01573 custptf = GdipAlloc(count * sizeof(PointF)); 01574 custpt = GdipAlloc(count * sizeof(POINT)); 01575 tp = GdipAlloc(count); 01576 01577 if(!custptf || !custpt || !tp || (GdipCreateMatrix(&matrix) != Ok)) 01578 goto custend; 01579 01580 memcpy(custptf, custom->pathdata.Points, count * sizeof(PointF)); 01581 01582 GdipScaleMatrix(matrix, size, size, MatrixOrderAppend); 01583 GdipRotateMatrix(matrix, (180.0 / M_PI) * (theta - M_PI_2), 01584 MatrixOrderAppend); 01585 GdipTranslateMatrix(matrix, x2, y2, MatrixOrderAppend); 01586 GdipTransformMatrixPoints(matrix, custptf, count); 01587 01588 transform_and_round_points(graphics, custpt, custptf, count); 01589 01590 for(i = 0; i < count; i++) 01591 tp[i] = convert_path_point_type(custom->pathdata.Types[i]); 01592 01593 if(custom->fill){ 01594 BeginPath(graphics->hdc); 01595 PolyDraw(graphics->hdc, custpt, tp, count); 01596 EndPath(graphics->hdc); 01597 StrokeAndFillPath(graphics->hdc); 01598 } 01599 else 01600 PolyDraw(graphics->hdc, custpt, tp, count); 01601 01602 custend: 01603 GdipFree(custptf); 01604 GdipFree(custpt); 01605 GdipFree(tp); 01606 GdipDeleteMatrix(matrix); 01607 break; 01608 default: 01609 break; 01610 } 01611 01612 if(!customstroke){ 01613 SelectObject(graphics->hdc, oldbrush); 01614 SelectObject(graphics->hdc, oldpen); 01615 DeleteObject(brush); 01616 DeleteObject(pen); 01617 } 01618 } 01619 01620 /* Shortens the line by the given percent by changing x2, y2. 01621 * If percent is > 1.0 then the line will change direction. 01622 * If percent is negative it can lengthen the line. */ 01623 static void shorten_line_percent(REAL x1, REAL y1, REAL *x2, REAL *y2, REAL percent) 01624 { 01625 REAL dist, theta, dx, dy; 01626 01627 if((y1 == *y2) && (x1 == *x2)) 01628 return; 01629 01630 dist = sqrt((*x2 - x1) * (*x2 - x1) + (*y2 - y1) * (*y2 - y1)) * -percent; 01631 theta = gdiplus_atan2((*y2 - y1), (*x2 - x1)); 01632 dx = cos(theta) * dist; 01633 dy = sin(theta) * dist; 01634 01635 *x2 = *x2 + dx; 01636 *y2 = *y2 + dy; 01637 } 01638 01639 /* Shortens the line by the given amount by changing x2, y2. 01640 * If the amount is greater than the distance, the line will become length 0. 01641 * If the amount is negative, it can lengthen the line. */ 01642 static void shorten_line_amt(REAL x1, REAL y1, REAL *x2, REAL *y2, REAL amt) 01643 { 01644 REAL dx, dy, percent; 01645 01646 dx = *x2 - x1; 01647 dy = *y2 - y1; 01648 if(dx == 0 && dy == 0) 01649 return; 01650 01651 percent = amt / sqrt(dx * dx + dy * dy); 01652 if(percent >= 1.0){ 01653 *x2 = x1; 01654 *y2 = y1; 01655 return; 01656 } 01657 01658 shorten_line_percent(x1, y1, x2, y2, percent); 01659 } 01660 01661 /* Draws lines between the given points, and if caps is true then draws an endcap 01662 * at the end of the last line. */ 01663 static GpStatus draw_polyline(GpGraphics *graphics, GpPen *pen, 01664 GDIPCONST GpPointF * pt, INT count, BOOL caps) 01665 { 01666 POINT *pti = NULL; 01667 GpPointF *ptcopy = NULL; 01668 GpStatus status = GenericError; 01669 01670 if(!count) 01671 return Ok; 01672 01673 pti = GdipAlloc(count * sizeof(POINT)); 01674 ptcopy = GdipAlloc(count * sizeof(GpPointF)); 01675 01676 if(!pti || !ptcopy){ 01677 status = OutOfMemory; 01678 goto end; 01679 } 01680 01681 memcpy(ptcopy, pt, count * sizeof(GpPointF)); 01682 01683 if(caps){ 01684 if(pen->endcap == LineCapArrowAnchor) 01685 shorten_line_amt(ptcopy[count-2].X, ptcopy[count-2].Y, 01686 &ptcopy[count-1].X, &ptcopy[count-1].Y, pen->width); 01687 else if((pen->endcap == LineCapCustom) && pen->customend) 01688 shorten_line_amt(ptcopy[count-2].X, ptcopy[count-2].Y, 01689 &ptcopy[count-1].X, &ptcopy[count-1].Y, 01690 pen->customend->inset * pen->width); 01691 01692 if(pen->startcap == LineCapArrowAnchor) 01693 shorten_line_amt(ptcopy[1].X, ptcopy[1].Y, 01694 &ptcopy[0].X, &ptcopy[0].Y, pen->width); 01695 else if((pen->startcap == LineCapCustom) && pen->customstart) 01696 shorten_line_amt(ptcopy[1].X, ptcopy[1].Y, 01697 &ptcopy[0].X, &ptcopy[0].Y, 01698 pen->customstart->inset * pen->width); 01699 01700 draw_cap(graphics, get_gdi_brush_color(pen->brush), pen->endcap, pen->width, pen->customend, 01701 pt[count - 2].X, pt[count - 2].Y, pt[count - 1].X, pt[count - 1].Y); 01702 draw_cap(graphics, get_gdi_brush_color(pen->brush), pen->startcap, pen->width, pen->customstart, 01703 pt[1].X, pt[1].Y, pt[0].X, pt[0].Y); 01704 } 01705 01706 transform_and_round_points(graphics, pti, ptcopy, count); 01707 01708 if(Polyline(graphics->hdc, pti, count)) 01709 status = Ok; 01710 01711 end: 01712 GdipFree(pti); 01713 GdipFree(ptcopy); 01714 01715 return status; 01716 } 01717 01718 /* Conducts a linear search to find the bezier points that will back off 01719 * the endpoint of the curve by a distance of amt. Linear search works 01720 * better than binary in this case because there are multiple solutions, 01721 * and binary searches often find a bad one. I don't think this is what 01722 * Windows does but short of rendering the bezier without GDI's help it's 01723 * the best we can do. If rev then work from the start of the passed points 01724 * instead of the end. */ 01725 static void shorten_bezier_amt(GpPointF * pt, REAL amt, BOOL rev) 01726 { 01727 GpPointF origpt[4]; 01728 REAL percent = 0.00, dx, dy, origx, origy, diff = -1.0; 01729 INT i, first = 0, second = 1, third = 2, fourth = 3; 01730 01731 if(rev){ 01732 first = 3; 01733 second = 2; 01734 third = 1; 01735 fourth = 0; 01736 } 01737 01738 origx = pt[fourth].X; 01739 origy = pt[fourth].Y; 01740 memcpy(origpt, pt, sizeof(GpPointF) * 4); 01741 01742 for(i = 0; (i < MAX_ITERS) && (diff < amt); i++){ 01743 /* reset bezier points to original values */ 01744 memcpy(pt, origpt, sizeof(GpPointF) * 4); 01745 /* Perform magic on bezier points. Order is important here.*/ 01746 shorten_line_percent(pt[third].X, pt[third].Y, &pt[fourth].X, &pt[fourth].Y, percent); 01747 shorten_line_percent(pt[second].X, pt[second].Y, &pt[third].X, &pt[third].Y, percent); 01748 shorten_line_percent(pt[third].X, pt[third].Y, &pt[fourth].X, &pt[fourth].Y, percent); 01749 shorten_line_percent(pt[first].X, pt[first].Y, &pt[second].X, &pt[second].Y, percent); 01750 shorten_line_percent(pt[second].X, pt[second].Y, &pt[third].X, &pt[third].Y, percent); 01751 shorten_line_percent(pt[third].X, pt[third].Y, &pt[fourth].X, &pt[fourth].Y, percent); 01752 01753 dx = pt[fourth].X - origx; 01754 dy = pt[fourth].Y - origy; 01755 01756 diff = sqrt(dx * dx + dy * dy); 01757 percent += 0.0005 * amt; 01758 } 01759 } 01760 01761 /* Draws bezier curves between given points, and if caps is true then draws an 01762 * endcap at the end of the last line. */ 01763 static GpStatus draw_polybezier(GpGraphics *graphics, GpPen *pen, 01764 GDIPCONST GpPointF * pt, INT count, BOOL caps) 01765 { 01766 POINT *pti; 01767 GpPointF *ptcopy; 01768 GpStatus status = GenericError; 01769 01770 if(!count) 01771 return Ok; 01772 01773 pti = GdipAlloc(count * sizeof(POINT)); 01774 ptcopy = GdipAlloc(count * sizeof(GpPointF)); 01775 01776 if(!pti || !ptcopy){ 01777 status = OutOfMemory; 01778 goto end; 01779 } 01780 01781 memcpy(ptcopy, pt, count * sizeof(GpPointF)); 01782 01783 if(caps){ 01784 if(pen->endcap == LineCapArrowAnchor) 01785 shorten_bezier_amt(&ptcopy[count-4], pen->width, FALSE); 01786 else if((pen->endcap == LineCapCustom) && pen->customend) 01787 shorten_bezier_amt(&ptcopy[count-4], pen->width * pen->customend->inset, 01788 FALSE); 01789 01790 if(pen->startcap == LineCapArrowAnchor) 01791 shorten_bezier_amt(ptcopy, pen->width, TRUE); 01792 else if((pen->startcap == LineCapCustom) && pen->customstart) 01793 shorten_bezier_amt(ptcopy, pen->width * pen->customstart->inset, TRUE); 01794 01795 /* the direction of the line cap is parallel to the direction at the 01796 * end of the bezier (which, if it has been shortened, is not the same 01797 * as the direction from pt[count-2] to pt[count-1]) */ 01798 draw_cap(graphics, get_gdi_brush_color(pen->brush), pen->endcap, pen->width, pen->customend, 01799 pt[count - 1].X - (ptcopy[count - 1].X - ptcopy[count - 2].X), 01800 pt[count - 1].Y - (ptcopy[count - 1].Y - ptcopy[count - 2].Y), 01801 pt[count - 1].X, pt[count - 1].Y); 01802 01803 draw_cap(graphics, get_gdi_brush_color(pen->brush), pen->startcap, pen->width, pen->customstart, 01804 pt[0].X - (ptcopy[0].X - ptcopy[1].X), 01805 pt[0].Y - (ptcopy[0].Y - ptcopy[1].Y), pt[0].X, pt[0].Y); 01806 } 01807 01808 transform_and_round_points(graphics, pti, ptcopy, count); 01809 01810 PolyBezier(graphics->hdc, pti, count); 01811 01812 status = Ok; 01813 01814 end: 01815 GdipFree(pti); 01816 GdipFree(ptcopy); 01817 01818 return status; 01819 } 01820 01821 /* Draws a combination of bezier curves and lines between points. */ 01822 static GpStatus draw_poly(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF * pt, 01823 GDIPCONST BYTE * types, INT count, BOOL caps) 01824 { 01825 POINT *pti = GdipAlloc(count * sizeof(POINT)); 01826 BYTE *tp = GdipAlloc(count); 01827 GpPointF *ptcopy = GdipAlloc(count * sizeof(GpPointF)); 01828 INT i, j; 01829 GpStatus status = GenericError; 01830 01831 if(!count){ 01832 status = Ok; 01833 goto end; 01834 } 01835 if(!pti || !tp || !ptcopy){ 01836 status = OutOfMemory; 01837 goto end; 01838 } 01839 01840 for(i = 1; i < count; i++){ 01841 if((types[i] & PathPointTypePathTypeMask) == PathPointTypeBezier){ 01842 if((i + 2 >= count) || !(types[i + 1] & PathPointTypeBezier) 01843 || !(types[i + 1] & PathPointTypeBezier)){ 01844 ERR("Bad bezier points\n"); 01845 goto end; 01846 } 01847 i += 2; 01848 } 01849 } 01850 01851 memcpy(ptcopy, pt, count * sizeof(GpPointF)); 01852 01853 /* If we are drawing caps, go through the points and adjust them accordingly, 01854 * and draw the caps. */ 01855 if(caps){ 01856 switch(types[count - 1] & PathPointTypePathTypeMask){ 01857 case PathPointTypeBezier: 01858 if(pen->endcap == LineCapArrowAnchor) 01859 shorten_bezier_amt(&ptcopy[count - 4], pen->width, FALSE); 01860 else if((pen->endcap == LineCapCustom) && pen->customend) 01861 shorten_bezier_amt(&ptcopy[count - 4], 01862 pen->width * pen->customend->inset, FALSE); 01863 01864 draw_cap(graphics, get_gdi_brush_color(pen->brush), pen->endcap, pen->width, pen->customend, 01865 pt[count - 1].X - (ptcopy[count - 1].X - ptcopy[count - 2].X), 01866 pt[count - 1].Y - (ptcopy[count - 1].Y - ptcopy[count - 2].Y), 01867 pt[count - 1].X, pt[count - 1].Y); 01868 01869 break; 01870 case PathPointTypeLine: 01871 if(pen->endcap == LineCapArrowAnchor) 01872 shorten_line_amt(ptcopy[count - 2].X, ptcopy[count - 2].Y, 01873 &ptcopy[count - 1].X, &ptcopy[count - 1].Y, 01874 pen->width); 01875 else if((pen->endcap == LineCapCustom) && pen->customend) 01876 shorten_line_amt(ptcopy[count - 2].X, ptcopy[count - 2].Y, 01877 &ptcopy[count - 1].X, &ptcopy[count - 1].Y, 01878 pen->customend->inset * pen->width); 01879 01880 draw_cap(graphics, get_gdi_brush_color(pen->brush), pen->endcap, pen->width, pen->customend, 01881 pt[count - 2].X, pt[count - 2].Y, pt[count - 1].X, 01882 pt[count - 1].Y); 01883 01884 break; 01885 default: 01886 ERR("Bad path last point\n"); 01887 goto end; 01888 } 01889 01890 /* Find start of points */ 01891 for(j = 1; j < count && ((types[j] & PathPointTypePathTypeMask) 01892 == PathPointTypeStart); j++); 01893 01894 switch(types[j] & PathPointTypePathTypeMask){ 01895 case PathPointTypeBezier: 01896 if(pen->startcap == LineCapArrowAnchor) 01897 shorten_bezier_amt(&ptcopy[j - 1], pen->width, TRUE); 01898 else if((pen->startcap == LineCapCustom) && pen->customstart) 01899 shorten_bezier_amt(&ptcopy[j - 1], 01900 pen->width * pen->customstart->inset, TRUE); 01901 01902 draw_cap(graphics, get_gdi_brush_color(pen->brush), pen->startcap, pen->width, pen->customstart, 01903 pt[j - 1].X - (ptcopy[j - 1].X - ptcopy[j].X), 01904 pt[j - 1].Y - (ptcopy[j - 1].Y - ptcopy[j].Y), 01905 pt[j - 1].X, pt[j - 1].Y); 01906 01907 break; 01908 case PathPointTypeLine: 01909 if(pen->startcap == LineCapArrowAnchor) 01910 shorten_line_amt(ptcopy[j].X, ptcopy[j].Y, 01911 &ptcopy[j - 1].X, &ptcopy[j - 1].Y, 01912 pen->width); 01913 else if((pen->startcap == LineCapCustom) && pen->customstart) 01914 shorten_line_amt(ptcopy[j].X, ptcopy[j].Y, 01915 &ptcopy[j - 1].X, &ptcopy[j - 1].Y, 01916 pen->customstart->inset * pen->width); 01917 01918 draw_cap(graphics, get_gdi_brush_color(pen->brush), pen->startcap, pen->width, pen->customstart, 01919 pt[j].X, pt[j].Y, pt[j - 1].X, 01920 pt[j - 1].Y); 01921 01922 break; 01923 default: 01924 ERR("Bad path points\n"); 01925 goto end; 01926 } 01927 } 01928 01929 transform_and_round_points(graphics, pti, ptcopy, count); 01930 01931 for(i = 0; i < count; i++){ 01932 tp[i] = convert_path_point_type(types[i]); 01933 } 01934 01935 PolyDraw(graphics->hdc, pti, tp, count); 01936 01937 status = Ok; 01938 01939 end: 01940 GdipFree(pti); 01941 GdipFree(ptcopy); 01942 GdipFree(tp); 01943 01944 return status; 01945 } 01946 01947 GpStatus trace_path(GpGraphics *graphics, GpPath *path) 01948 { 01949 GpStatus result; 01950 01951 BeginPath(graphics->hdc); 01952 result = draw_poly(graphics, NULL, path->pathdata.Points, 01953 path->pathdata.Types, path->pathdata.Count, FALSE); 01954 EndPath(graphics->hdc); 01955 return result; 01956 } 01957 01958 typedef struct _GraphicsContainerItem { 01959 struct list entry; 01960 GraphicsContainer contid; 01961 01962 SmoothingMode smoothing; 01963 CompositingQuality compqual; 01964 InterpolationMode interpolation; 01965 CompositingMode compmode; 01966 TextRenderingHint texthint; 01967 REAL scale; 01968 GpUnit unit; 01969 PixelOffsetMode pixeloffset; 01970 UINT textcontrast; 01971 GpMatrix* worldtrans; 01972 GpRegion* clip; 01973 INT origin_x, origin_y; 01974 } GraphicsContainerItem; 01975 01976 static GpStatus init_container(GraphicsContainerItem** container, 01977 GDIPCONST GpGraphics* graphics){ 01978 GpStatus sts; 01979 01980 *container = GdipAlloc(sizeof(GraphicsContainerItem)); 01981 if(!(*container)) 01982 return OutOfMemory; 01983 01984 (*container)->contid = graphics->contid + 1; 01985 01986 (*container)->smoothing = graphics->smoothing; 01987 (*container)->compqual = graphics->compqual; 01988 (*container)->interpolation = graphics->interpolation; 01989 (*container)->compmode = graphics->compmode; 01990 (*container)->texthint = graphics->texthint; 01991 (*container)->scale = graphics->scale; 01992 (*container)->unit = graphics->unit; 01993 (*container)->textcontrast = graphics->textcontrast; 01994 (*container)->pixeloffset = graphics->pixeloffset; 01995 (*container)->origin_x = graphics->origin_x; 01996 (*container)->origin_y = graphics->origin_y; 01997 01998 sts = GdipCloneMatrix(graphics->worldtrans, &(*container)->worldtrans); 01999 if(sts != Ok){ 02000 GdipFree(*container); 02001 *container = NULL; 02002 return sts; 02003 } 02004 02005 sts = GdipCloneRegion(graphics->clip, &(*container)->clip); 02006 if(sts != Ok){ 02007 GdipDeleteMatrix((*container)->worldtrans); 02008 GdipFree(*container); 02009 *container = NULL; 02010 return sts; 02011 } 02012 02013 return Ok; 02014 } 02015 02016 static void delete_container(GraphicsContainerItem* container){ 02017 GdipDeleteMatrix(container->worldtrans); 02018 GdipDeleteRegion(container->clip); 02019 GdipFree(container); 02020 } 02021 02022 static GpStatus restore_container(GpGraphics* graphics, 02023 GDIPCONST GraphicsContainerItem* container){ 02024 GpStatus sts; 02025 GpMatrix *newTrans; 02026 GpRegion *newClip; 02027 02028 sts = GdipCloneMatrix(container->worldtrans, &newTrans); 02029 if(sts != Ok) 02030 return sts; 02031 02032 sts = GdipCloneRegion(container->clip, &newClip); 02033 if(sts != Ok){ 02034 GdipDeleteMatrix(newTrans); 02035 return sts; 02036 } 02037 02038 GdipDeleteMatrix(graphics->worldtrans); 02039 graphics->worldtrans = newTrans; 02040 02041 GdipDeleteRegion(graphics->clip); 02042 graphics->clip = newClip; 02043 02044 graphics->contid = container->contid - 1; 02045 02046 graphics->smoothing = container->smoothing; 02047 graphics->compqual = container->compqual; 02048 graphics->interpolation = container->interpolation; 02049 graphics->compmode = container->compmode; 02050 graphics->texthint = container->texthint; 02051 graphics->scale = container->scale; 02052 graphics->unit = container->unit; 02053 graphics->textcontrast = container->textcontrast; 02054 graphics->pixeloffset = container->pixeloffset; 02055 graphics->origin_x = container->origin_x; 02056 graphics->origin_y = container->origin_y; 02057 02058 return Ok; 02059 } 02060 02061 static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect) 02062 { 02063 RECT wnd_rect; 02064 GpStatus stat=Ok; 02065 GpUnit unit; 02066 02067 if(graphics->hwnd) { 02068 if(!GetClientRect(graphics->hwnd, &wnd_rect)) 02069 return GenericError; 02070 02071 rect->X = wnd_rect.left; 02072 rect->Y = wnd_rect.top; 02073 rect->Width = wnd_rect.right - wnd_rect.left; 02074 rect->Height = wnd_rect.bottom - wnd_rect.top; 02075 }else if (graphics->image){ 02076 stat = GdipGetImageBounds(graphics->image, rect, &unit); 02077 if (stat == Ok && unit != UnitPixel) 02078 FIXME("need to convert from unit %i\n", unit); 02079 }else{ 02080 rect->X = 0; 02081 rect->Y = 0; 02082 rect->Width = GetDeviceCaps(graphics->hdc, HORZRES); 02083 rect->Height = GetDeviceCaps(graphics->hdc, VERTRES); 02084 } 02085 02086 return stat; 02087 } 02088 02089 /* on success, rgn will contain the region of the graphics object which 02090 * is visible after clipping has been applied */ 02091 static GpStatus get_visible_clip_region(GpGraphics *graphics, GpRegion *rgn) 02092 { 02093 GpStatus stat; 02094 GpRectF rectf; 02095 GpRegion* tmp; 02096 02097 if((stat = get_graphics_bounds(graphics, &rectf)) != Ok) 02098 return stat; 02099 02100 if((stat = GdipCreateRegion(&tmp)) != Ok) 02101 return stat; 02102 02103 if((stat = GdipCombineRegionRect(tmp, &rectf, CombineModeReplace)) != Ok) 02104 goto end; 02105 02106 if((stat = GdipCombineRegionRegion(tmp, graphics->clip, CombineModeIntersect)) != Ok) 02107 goto end; 02108 02109 stat = GdipCombineRegionRegion(rgn, tmp, CombineModeReplace); 02110 02111 end: 02112 GdipDeleteRegion(tmp); 02113 return stat; 02114 } 02115 02116 void get_font_hfont(GpGraphics *graphics, GDIPCONST GpFont *font, HFONT *hfont) 02117 { 02118 HDC hdc = CreateCompatibleDC(0); 02119 GpPointF pt[3]; 02120 REAL angle, rel_width, rel_height; 02121 LOGFONTW lfw; 02122 HFONT unscaled_font; 02123 TEXTMETRICW textmet; 02124 02125 pt[0].X = 0.0; 02126 pt[0].Y = 0.0; 02127 pt[1].X = 1.0; 02128 pt[1].Y = 0.0; 02129 pt[2].X = 0.0; 02130 pt[2].Y = 1.0; 02131 if (graphics) 02132 GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3); 02133 angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X)); 02134 rel_width = sqrt((pt[1].Y-pt[0].Y)*(pt[1].Y-pt[0].Y)+ 02135 (pt[1].X-pt[0].X)*(pt[1].X-pt[0].X)); 02136 rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+ 02137 (pt[2].X-pt[0].X)*(pt[2].X-pt[0].X)); 02138 02139 GdipGetLogFontW((GpFont *)font, graphics, &lfw); 02140 lfw.lfHeight = roundr(lfw.lfHeight * rel_height); 02141 unscaled_font = CreateFontIndirectW(&lfw); 02142 02143 SelectObject(hdc, unscaled_font); 02144 GetTextMetricsW(hdc, &textmet); 02145 02146 lfw.lfWidth = roundr(textmet.tmAveCharWidth * rel_width / rel_height); 02147 lfw.lfEscapement = lfw.lfOrientation = roundr((angle / M_PI) * 1800.0); 02148 02149 *hfont = CreateFontIndirectW(&lfw); 02150 02151 DeleteDC(hdc); 02152 DeleteObject(unscaled_font); 02153 } 02154 02155 GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics) 02156 { 02157 TRACE("(%p, %p)\n", hdc, graphics); 02158 02159 return GdipCreateFromHDC2(hdc, NULL, graphics); 02160 } 02161 02162 GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **graphics) 02163 { 02164 GpStatus retval; 02165 02166 TRACE("(%p, %p, %p)\n", hdc, hDevice, graphics); 02167 02168 if(hDevice != NULL) { 02169 FIXME("Don't know how to handle parameter hDevice\n"); 02170 return NotImplemented; 02171 } 02172 02173 if(hdc == NULL) 02174 return OutOfMemory; 02175 02176 if(graphics == NULL) 02177 return InvalidParameter; 02178 02179 *graphics = GdipAlloc(sizeof(GpGraphics)); 02180 if(!*graphics) return OutOfMemory; 02181 02182 if((retval = GdipCreateMatrix(&(*graphics)->worldtrans)) != Ok){ 02183 GdipFree(*graphics); 02184 return retval; 02185 } 02186 02187 if((retval = GdipCreateRegion(&(*graphics)->clip)) != Ok){ 02188 GdipFree((*graphics)->worldtrans); 02189 GdipFree(*graphics); 02190 return retval; 02191 } 02192 02193 (*graphics)->hdc = hdc; 02194 (*graphics)->hwnd = WindowFromDC(hdc); 02195 (*graphics)->owndc = FALSE; 02196 (*graphics)->smoothing = SmoothingModeDefault; 02197 (*graphics)->compqual = CompositingQualityDefault; 02198 (*graphics)->interpolation = InterpolationModeBilinear; 02199 (*graphics)->pixeloffset = PixelOffsetModeDefault; 02200 (*graphics)->compmode = CompositingModeSourceOver; 02201 (*graphics)->unit = UnitDisplay; 02202 (*graphics)->scale = 1.0; 02203 (*graphics)->busy = FALSE; 02204 (*graphics)->textcontrast = 4; 02205 list_init(&(*graphics)->containers); 02206 (*graphics)->contid = 0; 02207 02208 TRACE("<-- %p\n", *graphics); 02209 02210 return Ok; 02211 } 02212 02213 GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) 02214 { 02215 GpStatus retval; 02216 02217 *graphics = GdipAlloc(sizeof(GpGraphics)); 02218 if(!*graphics) return OutOfMemory; 02219 02220 if((retval = GdipCreateMatrix(&(*graphics)->worldtrans)) != Ok){ 02221 GdipFree(*graphics); 02222 return retval; 02223 } 02224 02225 if((retval = GdipCreateRegion(&(*graphics)->clip)) != Ok){ 02226 GdipFree((*graphics)->worldtrans); 02227 GdipFree(*graphics); 02228 return retval; 02229 } 02230 02231 (*graphics)->hdc = NULL; 02232 (*graphics)->hwnd = NULL; 02233 (*graphics)->owndc = FALSE; 02234 (*graphics)->image = image; 02235 (*graphics)->smoothing = SmoothingModeDefault; 02236 (*graphics)->compqual = CompositingQualityDefault; 02237 (*graphics)->interpolation = InterpolationModeBilinear; 02238 (*graphics)->pixeloffset = PixelOffsetModeDefault; 02239 (*graphics)->compmode = CompositingModeSourceOver; 02240 (*graphics)->unit = UnitDisplay; 02241 (*graphics)->scale = 1.0; 02242 (*graphics)->busy = FALSE; 02243 (*graphics)->textcontrast = 4; 02244 list_init(&(*graphics)->containers); 02245 (*graphics)->contid = 0; 02246 02247 TRACE("<-- %p\n", *graphics); 02248 02249 return Ok; 02250 } 02251 02252 GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics) 02253 { 02254 GpStatus ret; 02255 HDC hdc; 02256 02257 TRACE("(%p, %p)\n", hwnd, graphics); 02258 02259 hdc = GetDC(hwnd); 02260 02261 if((ret = GdipCreateFromHDC(hdc, graphics)) != Ok) 02262 { 02263 ReleaseDC(hwnd, hdc); 02264 return ret; 02265 } 02266 02267 (*graphics)->hwnd = hwnd; 02268 (*graphics)->owndc = TRUE; 02269 02270 return Ok; 02271 } 02272 02273 /* FIXME: no icm handling */ 02274 GpStatus WINGDIPAPI GdipCreateFromHWNDICM(HWND hwnd, GpGraphics **graphics) 02275 { 02276 TRACE("(%p, %p)\n", hwnd, graphics); 02277 02278 return GdipCreateFromHWND(hwnd, graphics); 02279 } 02280 02281 GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete, 02282 GpMetafile **metafile) 02283 { 02284 IStream *stream = NULL; 02285 UINT read; 02286 ENHMETAHEADER *copy; 02287 GpStatus retval = Ok; 02288 02289 TRACE("(%p,%i,%p)\n", hemf, delete, metafile); 02290 02291 if(!hemf || !metafile) 02292 return InvalidParameter; 02293 02294 read = GetEnhMetaFileBits(hemf, 0, NULL); 02295 copy = GdipAlloc(read); 02296 GetEnhMetaFileBits(hemf, read, (BYTE *)copy); 02297 02298 if(CreateStreamOnHGlobal(copy, TRUE, &stream) != S_OK){ 02299 ERR("could not make stream\n"); 02300 GdipFree(copy); 02301 retval = GenericError; 02302 goto err; 02303 } 02304 02305 *metafile = GdipAlloc(sizeof(GpMetafile)); 02306 if(!*metafile){ 02307 retval = OutOfMemory; 02308 goto err; 02309 } 02310 02311 if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture, 02312 (LPVOID*) &((*metafile)->image.picture)) != S_OK) 02313 { 02314 retval = GenericError; 02315 goto err; 02316 } 02317 02318 02319 (*metafile)->image.type = ImageTypeMetafile; 02320 memcpy(&(*metafile)->image.format, &ImageFormatWMF, sizeof(GUID)); 02321 (*metafile)->image.palette_flags = 0; 02322 (*metafile)->image.palette_count = 0; 02323 (*metafile)->image.palette_size = 0; 02324 (*metafile)->image.palette_entries = NULL; 02325 (*metafile)->image.xres = (REAL)copy->szlDevice.cx; 02326 (*metafile)->image.yres = (REAL)copy->szlDevice.cy; 02327 (*metafile)->bounds.X = (REAL)copy->rclBounds.left; 02328 (*metafile)->bounds.Y = (REAL)copy->rclBounds.top; 02329 (*metafile)->bounds.Width = (REAL)(copy->rclBounds.right - copy->rclBounds.left); 02330 (*metafile)->bounds.Height = (REAL)(copy->rclBounds.bottom - copy->rclBounds.top); 02331 (*metafile)->unit = UnitPixel; 02332 02333 if(delete) 02334 DeleteEnhMetaFile(hemf); 02335 02336 TRACE("<-- %p\n", *metafile); 02337 02338 err: 02339 if (retval != Ok) 02340 GdipFree(*metafile); 02341 IStream_Release(stream); 02342 return retval; 02343 } 02344 02345 GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete, 02346 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile) 02347 { 02348 UINT read; 02349 BYTE *copy; 02350 HENHMETAFILE hemf; 02351 GpStatus retval = Ok; 02352 02353 TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile); 02354 02355 if(!hwmf || !metafile || !placeable) 02356 return InvalidParameter; 02357 02358 *metafile = NULL; 02359 read = GetMetaFileBitsEx(hwmf, 0, NULL); 02360 if(!read) 02361 return GenericError; 02362 copy = GdipAlloc(read); 02363 GetMetaFileBitsEx(hwmf, read, copy); 02364 02365 hemf = SetWinMetaFileBits(read, copy, NULL, NULL); 02366 GdipFree(copy); 02367 02368 retval = GdipCreateMetafileFromEmf(hemf, FALSE, metafile); 02369 02370 if (retval == Ok) 02371 { 02372 (*metafile)->image.xres = (REAL)placeable->Inch; 02373 (*metafile)->image.yres = (REAL)placeable->Inch; 02374 (*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch); 02375 (*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch); 02376 (*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right - 02377 placeable->BoundingBox.Left); 02378 (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom - 02379 placeable->BoundingBox.Top); 02380 02381 if (delete) DeleteMetaFile(hwmf); 02382 } 02383 return retval; 02384 } 02385 02386 GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file, 02387 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile) 02388 { 02389 HMETAFILE hmf = GetMetaFileW(file); 02390 02391 TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile); 02392 02393 if(!hmf) return InvalidParameter; 02394 02395 return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile); 02396 } 02397 02398 GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file, 02399 GpMetafile **metafile) 02400 { 02401 FIXME("(%p, %p): stub\n", file, metafile); 02402 return NotImplemented; 02403 } 02404 02405 GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream, 02406 GpMetafile **metafile) 02407 { 02408 FIXME("(%p, %p): stub\n", stream, metafile); 02409 return NotImplemented; 02410 } 02411 02412 GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR * filename, 02413 UINT access, IStream **stream) 02414 { 02415 DWORD dwMode; 02416 HRESULT ret; 02417 02418 TRACE("(%s, %u, %p)\n", debugstr_w(filename), access, stream); 02419 02420 if(!stream || !filename) 02421 return InvalidParameter; 02422 02423 if(access & GENERIC_WRITE) 02424 dwMode = STGM_SHARE_DENY_WRITE | STGM_WRITE | STGM_CREATE; 02425 else if(access & GENERIC_READ) 02426 dwMode = STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE; 02427 else 02428 return InvalidParameter; 02429 02430 ret = SHCreateStreamOnFileW(filename, dwMode, stream); 02431 02432 return hresult_to_status(ret); 02433 } 02434 02435 GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics) 02436 { 02437 GraphicsContainerItem *cont, *next; 02438 GpStatus stat; 02439 TRACE("(%p)\n", graphics); 02440 02441 if(!graphics) return InvalidParameter; 02442 if(graphics->busy) return ObjectBusy; 02443 02444 if (graphics->image && graphics->image->type == ImageTypeMetafile) 02445 { 02446 stat = METAFILE_GraphicsDeleted((GpMetafile*)graphics->image); 02447 if (stat != Ok) 02448 return stat; 02449 } 02450 02451 if(graphics->owndc) 02452 ReleaseDC(graphics->hwnd, graphics->hdc); 02453 02454 LIST_FOR_EACH_ENTRY_SAFE(cont, next, &graphics->containers, GraphicsContainerItem, entry){ 02455 list_remove(&cont->entry); 02456 delete_container(cont); 02457 } 02458 02459 GdipDeleteRegion(graphics->clip); 02460 GdipDeleteMatrix(graphics->worldtrans); 02461 GdipFree(graphics); 02462 02463 return Ok; 02464 } 02465 02466 GpStatus WINGDIPAPI GdipDrawArc(GpGraphics *graphics, GpPen *pen, REAL x, 02467 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle) 02468 { 02469 INT save_state, num_pts; 02470 GpPointF points[MAX_ARC_PTS]; 02471 GpStatus retval; 02472 02473 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, 02474 width, height, startAngle, sweepAngle); 02475 02476 if(!graphics || !pen || width <= 0 || height <= 0) 02477 return InvalidParameter; 02478 02479 if(graphics->busy) 02480 return ObjectBusy; 02481 02482 if (!graphics->hdc) 02483 { 02484 FIXME("graphics object has no HDC\n"); 02485 return Ok; 02486 } 02487 02488 num_pts = arc2polybezier(points, x, y, width, height, startAngle, sweepAngle); 02489 02490 save_state = prepare_dc(graphics, pen); 02491 02492 retval = draw_polybezier(graphics, pen, points, num_pts, TRUE); 02493 02494 restore_dc(graphics, save_state); 02495 02496 return retval; 02497 } 02498 02499 GpStatus WINGDIPAPI GdipDrawArcI(GpGraphics *graphics, GpPen *pen, INT x, 02500 INT y, INT width, INT height, REAL startAngle, REAL sweepAngle) 02501 { 02502 TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", graphics, pen, x, y, 02503 width, height, startAngle, sweepAngle); 02504 02505 return GdipDrawArc(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle); 02506 } 02507 02508 GpStatus WINGDIPAPI GdipDrawBezier(GpGraphics *graphics, GpPen *pen, REAL x1, 02509 REAL y1, REAL x2, REAL y2, REAL x3, REAL y3, REAL x4, REAL y4) 02510 { 02511 INT save_state; 02512 GpPointF pt[4]; 02513 GpStatus retval; 02514 02515 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x1, y1, 02516 x2, y2, x3, y3, x4, y4); 02517 02518 if(!graphics || !pen) 02519 return InvalidParameter; 02520 02521 if(graphics->busy) 02522 return ObjectBusy; 02523 02524 if (!graphics->hdc) 02525 { 02526 FIXME("graphics object has no HDC\n"); 02527 return Ok; 02528 } 02529 02530 pt[0].X = x1; 02531 pt[0].Y = y1; 02532 pt[1].X = x2; 02533 pt[1].Y = y2; 02534 pt[2].X = x3; 02535 pt[2].Y = y3; 02536 pt[3].X = x4; 02537 pt[3].Y = y4; 02538 02539 save_state = prepare_dc(graphics, pen); 02540 02541 retval = draw_polybezier(graphics, pen, pt, 4, TRUE); 02542 02543 restore_dc(graphics, save_state); 02544 02545 return retval; 02546 } 02547 02548 GpStatus WINGDIPAPI GdipDrawBezierI(GpGraphics *graphics, GpPen *pen, INT x1, 02549 INT y1, INT x2, INT y2, INT x3, INT y3, INT x4, INT y4) 02550 { 02551 INT save_state; 02552 GpPointF pt[4]; 02553 GpStatus retval; 02554 02555 TRACE("(%p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", graphics, pen, x1, y1, 02556 x2, y2, x3, y3, x4, y4); 02557 02558 if(!graphics || !pen) 02559 return InvalidParameter; 02560 02561 if(graphics->busy) 02562 return ObjectBusy; 02563 02564 if (!graphics->hdc) 02565 { 02566 FIXME("graphics object has no HDC\n"); 02567 return Ok; 02568 } 02569 02570 pt[0].X = x1; 02571 pt[0].Y = y1; 02572 pt[1].X = x2; 02573 pt[1].Y = y2; 02574 pt[2].X = x3; 02575 pt[2].Y = y3; 02576 pt[3].X = x4; 02577 pt[3].Y = y4; 02578 02579 save_state = prepare_dc(graphics, pen); 02580 02581 retval = draw_polybezier(graphics, pen, pt, 4, TRUE); 02582 02583 restore_dc(graphics, save_state); 02584 02585 return retval; 02586 } 02587 02588 GpStatus WINGDIPAPI GdipDrawBeziers(GpGraphics *graphics, GpPen *pen, 02589 GDIPCONST GpPointF *points, INT count) 02590 { 02591 INT i; 02592 GpStatus ret; 02593 02594 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 02595 02596 if(!graphics || !pen || !points || (count <= 0)) 02597 return InvalidParameter; 02598 02599 if(graphics->busy) 02600 return ObjectBusy; 02601 02602 for(i = 0; i < floor(count / 4); i++){ 02603 ret = GdipDrawBezier(graphics, pen, 02604 points[4*i].X, points[4*i].Y, 02605 points[4*i + 1].X, points[4*i + 1].Y, 02606 points[4*i + 2].X, points[4*i + 2].Y, 02607 points[4*i + 3].X, points[4*i + 3].Y); 02608 if(ret != Ok) 02609 return ret; 02610 } 02611 02612 return Ok; 02613 } 02614 02615 GpStatus WINGDIPAPI GdipDrawBeziersI(GpGraphics *graphics, GpPen *pen, 02616 GDIPCONST GpPoint *points, INT count) 02617 { 02618 GpPointF *pts; 02619 GpStatus ret; 02620 INT i; 02621 02622 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 02623 02624 if(!graphics || !pen || !points || (count <= 0)) 02625 return InvalidParameter; 02626 02627 if(graphics->busy) 02628 return ObjectBusy; 02629 02630 pts = GdipAlloc(sizeof(GpPointF) * count); 02631 if(!pts) 02632 return OutOfMemory; 02633 02634 for(i = 0; i < count; i++){ 02635 pts[i].X = (REAL)points[i].X; 02636 pts[i].Y = (REAL)points[i].Y; 02637 } 02638 02639 ret = GdipDrawBeziers(graphics,pen,pts,count); 02640 02641 GdipFree(pts); 02642 02643 return ret; 02644 } 02645 02646 GpStatus WINGDIPAPI GdipDrawClosedCurve(GpGraphics *graphics, GpPen *pen, 02647 GDIPCONST GpPointF *points, INT count) 02648 { 02649 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 02650 02651 return GdipDrawClosedCurve2(graphics, pen, points, count, 1.0); 02652 } 02653 02654 GpStatus WINGDIPAPI GdipDrawClosedCurveI(GpGraphics *graphics, GpPen *pen, 02655 GDIPCONST GpPoint *points, INT count) 02656 { 02657 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 02658 02659 return GdipDrawClosedCurve2I(graphics, pen, points, count, 1.0); 02660 } 02661 02662 GpStatus WINGDIPAPI GdipDrawClosedCurve2(GpGraphics *graphics, GpPen *pen, 02663 GDIPCONST GpPointF *points, INT count, REAL tension) 02664 { 02665 GpPath *path; 02666 GpStatus stat; 02667 02668 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension); 02669 02670 if(!graphics || !pen || !points || count <= 0) 02671 return InvalidParameter; 02672 02673 if(graphics->busy) 02674 return ObjectBusy; 02675 02676 if((stat = GdipCreatePath(FillModeAlternate, &path)) != Ok) 02677 return stat; 02678 02679 stat = GdipAddPathClosedCurve2(path, points, count, tension); 02680 if(stat != Ok){ 02681 GdipDeletePath(path); 02682 return stat; 02683 } 02684 02685 stat = GdipDrawPath(graphics, pen, path); 02686 02687 GdipDeletePath(path); 02688 02689 return stat; 02690 } 02691 02692 GpStatus WINGDIPAPI GdipDrawClosedCurve2I(GpGraphics *graphics, GpPen *pen, 02693 GDIPCONST GpPoint *points, INT count, REAL tension) 02694 { 02695 GpPointF *ptf; 02696 GpStatus stat; 02697 INT i; 02698 02699 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension); 02700 02701 if(!points || count <= 0) 02702 return InvalidParameter; 02703 02704 ptf = GdipAlloc(sizeof(GpPointF)*count); 02705 if(!ptf) 02706 return OutOfMemory; 02707 02708 for(i = 0; i < count; i++){ 02709 ptf[i].X = (REAL)points[i].X; 02710 ptf[i].Y = (REAL)points[i].Y; 02711 } 02712 02713 stat = GdipDrawClosedCurve2(graphics, pen, ptf, count, tension); 02714 02715 GdipFree(ptf); 02716 02717 return stat; 02718 } 02719 02720 GpStatus WINGDIPAPI GdipDrawCurve(GpGraphics *graphics, GpPen *pen, 02721 GDIPCONST GpPointF *points, INT count) 02722 { 02723 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 02724 02725 return GdipDrawCurve2(graphics,pen,points,count,1.0); 02726 } 02727 02728 GpStatus WINGDIPAPI GdipDrawCurveI(GpGraphics *graphics, GpPen *pen, 02729 GDIPCONST GpPoint *points, INT count) 02730 { 02731 GpPointF *pointsF; 02732 GpStatus ret; 02733 INT i; 02734 02735 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 02736 02737 if(!points) 02738 return InvalidParameter; 02739 02740 pointsF = GdipAlloc(sizeof(GpPointF)*count); 02741 if(!pointsF) 02742 return OutOfMemory; 02743 02744 for(i = 0; i < count; i++){ 02745 pointsF[i].X = (REAL)points[i].X; 02746 pointsF[i].Y = (REAL)points[i].Y; 02747 } 02748 02749 ret = GdipDrawCurve(graphics,pen,pointsF,count); 02750 GdipFree(pointsF); 02751 02752 return ret; 02753 } 02754 02755 /* Approximates cardinal spline with Bezier curves. */ 02756 GpStatus WINGDIPAPI GdipDrawCurve2(GpGraphics *graphics, GpPen *pen, 02757 GDIPCONST GpPointF *points, INT count, REAL tension) 02758 { 02759 /* PolyBezier expects count*3-2 points. */ 02760 INT i, len_pt = count*3-2, save_state; 02761 GpPointF *pt; 02762 REAL x1, x2, y1, y2; 02763 GpStatus retval; 02764 02765 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension); 02766 02767 if(!graphics || !pen) 02768 return InvalidParameter; 02769 02770 if(graphics->busy) 02771 return ObjectBusy; 02772 02773 if(count < 2) 02774 return InvalidParameter; 02775 02776 if (!graphics->hdc) 02777 { 02778 FIXME("graphics object has no HDC\n"); 02779 return Ok; 02780 } 02781 02782 pt = GdipAlloc(len_pt * sizeof(GpPointF)); 02783 if(!pt) 02784 return OutOfMemory; 02785 02786 tension = tension * TENSION_CONST; 02787 02788 calc_curve_bezier_endp(points[0].X, points[0].Y, points[1].X, points[1].Y, 02789 tension, &x1, &y1); 02790 02791 pt[0].X = points[0].X; 02792 pt[0].Y = points[0].Y; 02793 pt[1].X = x1; 02794 pt[1].Y = y1; 02795 02796 for(i = 0; i < count-2; i++){ 02797 calc_curve_bezier(&(points[i]), tension, &x1, &y1, &x2, &y2); 02798 02799 pt[3*i+2].X = x1; 02800 pt[3*i+2].Y = y1; 02801 pt[3*i+3].X = points[i+1].X; 02802 pt[3*i+3].Y = points[i+1].Y; 02803 pt[3*i+4].X = x2; 02804 pt[3*i+4].Y = y2; 02805 } 02806 02807 calc_curve_bezier_endp(points[count-1].X, points[count-1].Y, 02808 points[count-2].X, points[count-2].Y, tension, &x1, &y1); 02809 02810 pt[len_pt-2].X = x1; 02811 pt[len_pt-2].Y = y1; 02812 pt[len_pt-1].X = points[count-1].X; 02813 pt[len_pt-1].Y = points[count-1].Y; 02814 02815 save_state = prepare_dc(graphics, pen); 02816 02817 retval = draw_polybezier(graphics, pen, pt, len_pt, TRUE); 02818 02819 GdipFree(pt); 02820 restore_dc(graphics, save_state); 02821 02822 return retval; 02823 } 02824 02825 GpStatus WINGDIPAPI GdipDrawCurve2I(GpGraphics *graphics, GpPen *pen, 02826 GDIPCONST GpPoint *points, INT count, REAL tension) 02827 { 02828 GpPointF *pointsF; 02829 GpStatus ret; 02830 INT i; 02831 02832 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension); 02833 02834 if(!points) 02835 return InvalidParameter; 02836 02837 pointsF = GdipAlloc(sizeof(GpPointF)*count); 02838 if(!pointsF) 02839 return OutOfMemory; 02840 02841 for(i = 0; i < count; i++){ 02842 pointsF[i].X = (REAL)points[i].X; 02843 pointsF[i].Y = (REAL)points[i].Y; 02844 } 02845 02846 ret = GdipDrawCurve2(graphics,pen,pointsF,count,tension); 02847 GdipFree(pointsF); 02848 02849 return ret; 02850 } 02851 02852 GpStatus WINGDIPAPI GdipDrawCurve3(GpGraphics *graphics, GpPen *pen, 02853 GDIPCONST GpPointF *points, INT count, INT offset, INT numberOfSegments, 02854 REAL tension) 02855 { 02856 TRACE("(%p, %p, %p, %d, %d, %d, %.2f)\n", graphics, pen, points, count, offset, numberOfSegments, tension); 02857 02858 if(offset >= count || numberOfSegments > count - offset - 1 || numberOfSegments <= 0){ 02859 return InvalidParameter; 02860 } 02861 02862 return GdipDrawCurve2(graphics, pen, points + offset, numberOfSegments + 1, tension); 02863 } 02864 02865 GpStatus WINGDIPAPI GdipDrawCurve3I(GpGraphics *graphics, GpPen *pen, 02866 GDIPCONST GpPoint *points, INT count, INT offset, INT numberOfSegments, 02867 REAL tension) 02868 { 02869 TRACE("(%p, %p, %p, %d, %d, %d, %.2f)\n", graphics, pen, points, count, offset, numberOfSegments, tension); 02870 02871 if(count < 0){ 02872 return OutOfMemory; 02873 } 02874 02875 if(offset >= count || numberOfSegments > count - offset - 1 || numberOfSegments <= 0){ 02876 return InvalidParameter; 02877 } 02878 02879 return GdipDrawCurve2I(graphics, pen, points + offset, numberOfSegments + 1, tension); 02880 } 02881 02882 GpStatus WINGDIPAPI GdipDrawEllipse(GpGraphics *graphics, GpPen *pen, REAL x, 02883 REAL y, REAL width, REAL height) 02884 { 02885 INT save_state; 02886 GpPointF ptf[2]; 02887 POINT pti[2]; 02888 02889 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, width, height); 02890 02891 if(!graphics || !pen) 02892 return InvalidParameter; 02893 02894 if(graphics->busy) 02895 return ObjectBusy; 02896 02897 if (!graphics->hdc) 02898 { 02899 FIXME("graphics object has no HDC\n"); 02900 return Ok; 02901 } 02902 02903 ptf[0].X = x; 02904 ptf[0].Y = y; 02905 ptf[1].X = x + width; 02906 ptf[1].Y = y + height; 02907 02908 save_state = prepare_dc(graphics, pen); 02909 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH)); 02910 02911 transform_and_round_points(graphics, pti, ptf, 2); 02912 02913 Ellipse(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y); 02914 02915 restore_dc(graphics, save_state); 02916 02917 return Ok; 02918 } 02919 02920 GpStatus WINGDIPAPI GdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x, 02921 INT y, INT width, INT height) 02922 { 02923 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x, y, width, height); 02924 02925 return GdipDrawEllipse(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height); 02926 } 02927 02928 02929 GpStatus WINGDIPAPI GdipDrawImage(GpGraphics *graphics, GpImage *image, REAL x, REAL y) 02930 { 02931 UINT width, height; 02932 GpPointF points[3]; 02933 02934 TRACE("(%p, %p, %.2f, %.2f)\n", graphics, image, x, y); 02935 02936 if(!graphics || !image) 02937 return InvalidParameter; 02938 02939 GdipGetImageWidth(image, &width); 02940 GdipGetImageHeight(image, &height); 02941 02942 /* FIXME: we should use the graphics and image dpi, somehow */ 02943 02944 points[0].X = points[2].X = x; 02945 points[0].Y = points[1].Y = y; 02946 points[1].X = x + width; 02947 points[2].Y = y + height; 02948 02949 return GdipDrawImagePointsRect(graphics, image, points, 3, 0, 0, width, height, 02950 UnitPixel, NULL, NULL, NULL); 02951 } 02952 02953 GpStatus WINGDIPAPI GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x, 02954 INT y) 02955 { 02956 TRACE("(%p, %p, %d, %d)\n", graphics, image, x, y); 02957 02958 return GdipDrawImage(graphics, image, (REAL)x, (REAL)y); 02959 } 02960 02961 GpStatus WINGDIPAPI GdipDrawImagePointRect(GpGraphics *graphics, GpImage *image, 02962 REAL x, REAL y, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight, 02963 GpUnit srcUnit) 02964 { 02965 GpPointF points[3]; 02966 TRACE("(%p, %p, %f, %f, %f, %f, %f, %f, %d)\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit); 02967 02968 points[0].X = points[2].X = x; 02969 points[0].Y = points[1].Y = y; 02970 02971 /* FIXME: convert image coordinates to Graphics coordinates? */ 02972 points[1].X = x + srcwidth; 02973 points[2].Y = y + srcheight; 02974 02975 return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy, 02976 srcwidth, srcheight, srcUnit, NULL, NULL, NULL); 02977 } 02978 02979 GpStatus WINGDIPAPI GdipDrawImagePointRectI(GpGraphics *graphics, GpImage *image, 02980 INT x, INT y, INT srcx, INT srcy, INT srcwidth, INT srcheight, 02981 GpUnit srcUnit) 02982 { 02983 return GdipDrawImagePointRect(graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit); 02984 } 02985 02986 GpStatus WINGDIPAPI GdipDrawImagePoints(GpGraphics *graphics, GpImage *image, 02987 GDIPCONST GpPointF *dstpoints, INT count) 02988 { 02989 UINT width, height; 02990 02991 TRACE("(%p, %p, %p, %d)\n", graphics, image, dstpoints, count); 02992 02993 if(!image) 02994 return InvalidParameter; 02995 02996 GdipGetImageWidth(image, &width); 02997 GdipGetImageHeight(image, &height); 02998 02999 return GdipDrawImagePointsRect(graphics, image, dstpoints, count, 0, 0, 03000 width, height, UnitPixel, NULL, NULL, NULL); 03001 } 03002 03003 GpStatus WINGDIPAPI GdipDrawImagePointsI(GpGraphics *graphics, GpImage *image, 03004 GDIPCONST GpPoint *dstpoints, INT count) 03005 { 03006 GpPointF ptf[3]; 03007 03008 TRACE("(%p, %p, %p, %d)\n", graphics, image, dstpoints, count); 03009 03010 if (count != 3 || !dstpoints) 03011 return InvalidParameter; 03012 03013 ptf[0].X = (REAL)dstpoints[0].X; 03014 ptf[0].Y = (REAL)dstpoints[0].Y; 03015 ptf[1].X = (REAL)dstpoints[1].X; 03016 ptf[1].Y = (REAL)dstpoints[1].Y; 03017 ptf[2].X = (REAL)dstpoints[2].X; 03018 ptf[2].Y = (REAL)dstpoints[2].Y; 03019 03020 return GdipDrawImagePoints(graphics, image, ptf, count); 03021 } 03022 03023 GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image, 03024 GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth, 03025 REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, 03026 DrawImageAbort callback, VOID * callbackData) 03027 { 03028 GpPointF ptf[4]; 03029 POINT pti[4]; 03030 REAL dx, dy; 03031 GpStatus stat; 03032 03033 TRACE("(%p, %p, %p, %d, %f, %f, %f, %f, %d, %p, %p, %p)\n", graphics, image, points, 03034 count, srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback, 03035 callbackData); 03036 03037 if (count > 3) 03038 return NotImplemented; 03039 03040 if(!graphics || !image || !points || count != 3) 03041 return InvalidParameter; 03042 03043 TRACE("%s %s %s\n", debugstr_pointf(&points[0]), debugstr_pointf(&points[1]), 03044 debugstr_pointf(&points[2])); 03045 03046 memcpy(ptf, points, 3 * sizeof(GpPointF)); 03047 ptf[3].X = ptf[2].X + ptf[1].X - ptf[0].X; 03048 ptf[3].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y; 03049 if (!srcwidth || !srcheight || ptf[3].X == ptf[0].X || ptf[3].Y == ptf[0].Y) 03050 return Ok; 03051 transform_and_round_points(graphics, pti, ptf, 4); 03052 03053 if (image->picture) 03054 { 03055 if (!graphics->hdc) 03056 { 03057 FIXME("graphics object has no HDC\n"); 03058 } 03059 03060 /* FIXME: partially implemented (only works for rectangular parallelograms) */ 03061 if(srcUnit == UnitInch) 03062 dx = dy = (REAL) INCH_HIMETRIC; 03063 else if(srcUnit == UnitPixel){ 03064 dx = ((REAL) INCH_HIMETRIC) / 03065 ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSX)); 03066 dy = ((REAL) INCH_HIMETRIC) / 03067 ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSY)); 03068 } 03069 else 03070 return NotImplemented; 03071 03072 if(IPicture_Render(image->picture, graphics->hdc, 03073 pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y, 03074 srcx * dx, srcy * dy, 03075 srcwidth * dx, srcheight * dy, 03076 NULL) != S_OK){ 03077 if(callback) 03078 callback(callbackData); 03079 return GenericError; 03080 } 03081 } 03082 else if (image->type == ImageTypeBitmap) 03083 { 03084 GpBitmap* bitmap = (GpBitmap*)image; 03085 int use_software=0; 03086 03087 if (srcUnit == UnitInch) 03088 dx = dy = 96.0; /* FIXME: use the image resolution */ 03089 else if (srcUnit == UnitPixel) 03090 dx = dy = 1.0; 03091 else 03092 return NotImplemented; 03093 03094 srcx = srcx * dx; 03095 srcy = srcy * dy; 03096 srcwidth = srcwidth * dx; 03097 srcheight = srcheight * dy; 03098 03099 if (imageAttributes || 03100 (graphics->image && graphics->image->type == ImageTypeBitmap) || 03101 !((GpBitmap*)image)->hbitmap || 03102 ptf[1].Y != ptf[0].Y || ptf[2].X != ptf[0].X || 03103 ptf[1].X - ptf[0].X != srcwidth || ptf[2].Y - ptf[0].Y != srcheight || 03104 srcx < 0 || srcy < 0 || 03105 srcx + srcwidth > bitmap->width || srcy + srcheight > bitmap->height) 03106 use_software = 1; 03107 03108 if (use_software) 03109 { 03110 RECT dst_area; 03111 GpRect src_area; 03112 int i, x, y, src_stride, dst_stride; 03113 GpMatrix *dst_to_src; 03114 REAL m11, m12, m21, m22, mdx, mdy; 03115 LPBYTE src_data, dst_data; 03116 BitmapData lockeddata; 03117 InterpolationMode interpolation = graphics->interpolation; 03118 GpPointF dst_to_src_points[3] = {{0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}}; 03119 REAL x_dx, x_dy, y_dx, y_dy; 03120 static const GpImageAttributes defaultImageAttributes = {WrapModeClamp, 0, FALSE}; 03121 03122 if (!imageAttributes) 03123 imageAttributes = &defaultImageAttributes; 03124 03125 dst_area.left = dst_area.right = pti[0].x; 03126 dst_area.top = dst_area.bottom = pti[0].y; 03127 for (i=1; i<4; i++) 03128 { 03129 if (dst_area.left > pti[i].x) dst_area.left = pti[i].x; 03130 if (dst_area.right < pti[i].x) dst_area.right = pti[i].x; 03131 if (dst_area.top > pti[i].y) dst_area.top = pti[i].y; 03132 if (dst_area.bottom < pti[i].y) dst_area.bottom = pti[i].y; 03133 } 03134 03135 m11 = (ptf[1].X - ptf[0].X) / srcwidth; 03136 m21 = (ptf[2].X - ptf[0].X) / srcheight; 03137 mdx = ptf[0].X - m11 * srcx - m21 * srcy; 03138 m12 = (ptf[1].Y - ptf[0].Y) / srcwidth; 03139 m22 = (ptf[2].Y - ptf[0].Y) / srcheight; 03140 mdy = ptf[0].Y - m12 * srcx - m22 * srcy; 03141 03142 stat = GdipCreateMatrix2(m11, m12, m21, m22, mdx, mdy, &dst_to_src); 03143 if (stat != Ok) return stat; 03144 03145 stat = GdipInvertMatrix(dst_to_src); 03146 if (stat != Ok) 03147 { 03148 GdipDeleteMatrix(dst_to_src); 03149 return stat; 03150 } 03151 03152 dst_data = GdipAlloc(sizeof(ARGB) * (dst_area.right - dst_area.left) * (dst_area.bottom - dst_area.top)); 03153 if (!dst_data) 03154 { 03155 GdipDeleteMatrix(dst_to_src); 03156 return OutOfMemory; 03157 } 03158 03159 dst_stride = sizeof(ARGB) * (dst_area.right - dst_area.left); 03160 03161 get_bitmap_sample_size(interpolation, imageAttributes->wrap, 03162 bitmap, srcx, srcy, srcwidth, srcheight, &src_area); 03163 03164 src_data = GdipAlloc(sizeof(ARGB) * src_area.Width * src_area.Height); 03165 if (!src_data) 03166 { 03167 GdipFree(dst_data); 03168 GdipDeleteMatrix(dst_to_src); 03169 return OutOfMemory; 03170 } 03171 src_stride = sizeof(ARGB) * src_area.Width; 03172 03173 /* Read the bits we need from the source bitmap into an ARGB buffer. */ 03174 lockeddata.Width = src_area.Width; 03175 lockeddata.Height = src_area.Height; 03176 lockeddata.Stride = src_stride; 03177 lockeddata.PixelFormat = PixelFormat32bppARGB; 03178 lockeddata.Scan0 = src_data; 03179 03180 stat = GdipBitmapLockBits(bitmap, &src_area, ImageLockModeRead|ImageLockModeUserInputBuf, 03181 PixelFormat32bppARGB, &lockeddata); 03182 03183 if (stat == Ok) 03184 stat = GdipBitmapUnlockBits(bitmap, &lockeddata); 03185 03186 if (stat != Ok) 03187 { 03188 if (src_data != dst_data) 03189 GdipFree(src_data); 03190 GdipFree(dst_data); 03191 GdipDeleteMatrix(dst_to_src); 03192 return OutOfMemory; 03193 } 03194 03195 apply_image_attributes(imageAttributes, src_data, 03196 src_area.Width, src_area.Height, 03197 src_stride, ColorAdjustTypeBitmap); 03198 03199 /* Transform the bits as needed to the destination. */ 03200 GdipTransformMatrixPoints(dst_to_src, dst_to_src_points, 3); 03201 03202 x_dx = dst_to_src_points[1].X - dst_to_src_points[0].X; 03203 x_dy = dst_to_src_points[1].Y - dst_to_src_points[0].Y; 03204 y_dx = dst_to_src_points[2].X - dst_to_src_points[0].X; 03205 y_dy = dst_to_src_points[2].Y - dst_to_src_points[0].Y; 03206 03207 for (x=dst_area.left; x<dst_area.right; x++) 03208 { 03209 for (y=dst_area.top; y<dst_area.bottom; y++) 03210 { 03211 GpPointF src_pointf; 03212 ARGB *dst_color; 03213 03214 src_pointf.X = dst_to_src_points[0].X + x * x_dx + y * y_dx; 03215 src_pointf.Y = dst_to_src_points[0].Y + x * x_dy + y * y_dy; 03216 03217 dst_color = (ARGB*)(dst_data + dst_stride * (y - dst_area.top) + sizeof(ARGB) * (x - dst_area.left)); 03218 03219 if (src_pointf.X >= srcx && src_pointf.X < srcx + srcwidth && src_pointf.Y >= srcy && src_pointf.Y < srcy+srcheight) 03220 *dst_color = resample_bitmap_pixel(&src_area, src_data, bitmap->width, bitmap->height, &src_pointf, imageAttributes, interpolation); 03221 else 03222 *dst_color = 0; 03223 } 03224 } 03225 03226 GdipDeleteMatrix(dst_to_src); 03227 03228 GdipFree(src_data); 03229 03230 stat = alpha_blend_pixels(graphics, dst_area.left, dst_area.top, 03231 dst_data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, dst_stride); 03232 03233 GdipFree(dst_data); 03234 03235 return stat; 03236 } 03237 else 03238 { 03239 HDC hdc; 03240 int temp_hdc=0, temp_bitmap=0; 03241 HBITMAP hbitmap, old_hbm=NULL; 03242 03243 if (!(bitmap->format == PixelFormat16bppRGB555 || 03244 bitmap->format == PixelFormat24bppRGB || 03245 bitmap->format == PixelFormat32bppRGB || 03246 bitmap->format == PixelFormat32bppPARGB)) 03247 { 03248 BITMAPINFOHEADER bih; 03249 BYTE *temp_bits; 03250 PixelFormat dst_format; 03251 03252 /* we can't draw a bitmap of this format directly */ 03253 hdc = CreateCompatibleDC(0); 03254 temp_hdc = 1; 03255 temp_bitmap = 1; 03256 03257 bih.biSize = sizeof(BITMAPINFOHEADER); 03258 bih.biWidth = bitmap->width; 03259 bih.biHeight = -bitmap->height; 03260 bih.biPlanes = 1; 03261 bih.biBitCount = 32; 03262 bih.biCompression = BI_RGB; 03263 bih.biSizeImage = 0; 03264 bih.biXPelsPerMeter = 0; 03265 bih.biYPelsPerMeter = 0; 03266 bih.biClrUsed = 0; 03267 bih.biClrImportant = 0; 03268 03269 hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, 03270 (void**)&temp_bits, NULL, 0); 03271 03272 if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha)) 03273 dst_format = PixelFormat32bppPARGB; 03274 else 03275 dst_format = PixelFormat32bppRGB; 03276 03277 convert_pixels(bitmap->width, bitmap->height, 03278 bitmap->width*4, temp_bits, dst_format, 03279 bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette_entries); 03280 } 03281 else 03282 { 03283 hbitmap = bitmap->hbitmap; 03284 hdc = bitmap->hdc; 03285 temp_hdc = (hdc == 0); 03286 } 03287 03288 if (temp_hdc) 03289 { 03290 if (!hdc) hdc = CreateCompatibleDC(0); 03291 old_hbm = SelectObject(hdc, hbitmap); 03292 } 03293 03294 if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha)) 03295 { 03296 gdi_alpha_blend(graphics, pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y, 03297 hdc, srcx, srcy, srcwidth, srcheight); 03298 } 03299 else 03300 { 03301 StretchBlt(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y, 03302 hdc, srcx, srcy, srcwidth, srcheight, SRCCOPY); 03303 } 03304 03305 if (temp_hdc) 03306 { 03307 SelectObject(hdc, old_hbm); 03308 DeleteDC(hdc); 03309 } 03310 03311 if (temp_bitmap) 03312 DeleteObject(hbitmap); 03313 } 03314 } 03315 else 03316 { 03317 ERR("GpImage with no IPicture or HBITMAP?!\n"); 03318 return NotImplemented; 03319 } 03320 03321 return Ok; 03322 } 03323 03324 GpStatus WINGDIPAPI GdipDrawImagePointsRectI(GpGraphics *graphics, GpImage *image, 03325 GDIPCONST GpPoint *points, INT count, INT srcx, INT srcy, INT srcwidth, 03326 INT srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, 03327 DrawImageAbort callback, VOID * callbackData) 03328 { 03329 GpPointF pointsF[3]; 03330 INT i; 03331 03332 TRACE("(%p, %p, %p, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n", graphics, image, points, count, 03333 srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback, 03334 callbackData); 03335 03336 if(!points || count!=3) 03337 return InvalidParameter; 03338 03339 for(i = 0; i < count; i++){ 03340 pointsF[i].X = (REAL)points[i].X; 03341 pointsF[i].Y = (REAL)points[i].Y; 03342 } 03343 03344 return GdipDrawImagePointsRect(graphics, image, pointsF, count, (REAL)srcx, (REAL)srcy, 03345 (REAL)srcwidth, (REAL)srcheight, srcUnit, imageAttributes, 03346 callback, callbackData); 03347 } 03348 03349 GpStatus WINGDIPAPI GdipDrawImageRectRect(GpGraphics *graphics, GpImage *image, 03350 REAL dstx, REAL dsty, REAL dstwidth, REAL dstheight, REAL srcx, REAL srcy, 03351 REAL srcwidth, REAL srcheight, GpUnit srcUnit, 03352 GDIPCONST GpImageAttributes* imageattr, DrawImageAbort callback, 03353 VOID * callbackData) 03354 { 03355 GpPointF points[3]; 03356 03357 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p, %p, %p)\n", 03358 graphics, image, dstx, dsty, dstwidth, dstheight, srcx, srcy, 03359 srcwidth, srcheight, srcUnit, imageattr, callback, callbackData); 03360 03361 points[0].X = dstx; 03362 points[0].Y = dsty; 03363 points[1].X = dstx + dstwidth; 03364 points[1].Y = dsty; 03365 points[2].X = dstx; 03366 points[2].Y = dsty + dstheight; 03367 03368 return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy, 03369 srcwidth, srcheight, srcUnit, imageattr, callback, callbackData); 03370 } 03371 03372 GpStatus WINGDIPAPI GdipDrawImageRectRectI(GpGraphics *graphics, GpImage *image, 03373 INT dstx, INT dsty, INT dstwidth, INT dstheight, INT srcx, INT srcy, 03374 INT srcwidth, INT srcheight, GpUnit srcUnit, 03375 GDIPCONST GpImageAttributes* imageAttributes, DrawImageAbort callback, 03376 VOID * callbackData) 03377 { 03378 GpPointF points[3]; 03379 03380 TRACE("(%p, %p, %d, %d, %d, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n", 03381 graphics, image, dstx, dsty, dstwidth, dstheight, srcx, srcy, 03382 srcwidth, srcheight, srcUnit, imageAttributes, callback, callbackData); 03383 03384 points[0].X = dstx; 03385 points[0].Y = dsty; 03386 points[1].X = dstx + dstwidth; 03387 points[1].Y = dsty; 03388 points[2].X = dstx; 03389 points[2].Y = dsty + dstheight; 03390 03391 return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy, 03392 srcwidth, srcheight, srcUnit, imageAttributes, callback, callbackData); 03393 } 03394 03395 GpStatus WINGDIPAPI GdipDrawImageRect(GpGraphics *graphics, GpImage *image, 03396 REAL x, REAL y, REAL width, REAL height) 03397 { 03398 RectF bounds; 03399 GpUnit unit; 03400 GpStatus ret; 03401 03402 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, image, x, y, width, height); 03403 03404 if(!graphics || !image) 03405 return InvalidParameter; 03406 03407 ret = GdipGetImageBounds(image, &bounds, &unit); 03408 if(ret != Ok) 03409 return ret; 03410 03411 return GdipDrawImageRectRect(graphics, image, x, y, width, height, 03412 bounds.X, bounds.Y, bounds.Width, bounds.Height, 03413 unit, NULL, NULL, NULL); 03414 } 03415 03416 GpStatus WINGDIPAPI GdipDrawImageRectI(GpGraphics *graphics, GpImage *image, 03417 INT x, INT y, INT width, INT height) 03418 { 03419 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, image, x, y, width, height); 03420 03421 return GdipDrawImageRect(graphics, image, (REAL)x, (REAL)y, (REAL)width, (REAL)height); 03422 } 03423 03424 GpStatus WINGDIPAPI GdipDrawLine(GpGraphics *graphics, GpPen *pen, REAL x1, 03425 REAL y1, REAL x2, REAL y2) 03426 { 03427 INT save_state; 03428 GpPointF pt[2]; 03429 GpStatus retval; 03430 03431 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x1, y1, x2, y2); 03432 03433 if(!pen || !graphics) 03434 return InvalidParameter; 03435 03436 if(graphics->busy) 03437 return ObjectBusy; 03438 03439 if (!graphics->hdc) 03440 { 03441 FIXME("graphics object has no HDC\n"); 03442 return Ok; 03443 } 03444 03445 pt[0].X = x1; 03446 pt[0].Y = y1; 03447 pt[1].X = x2; 03448 pt[1].Y = y2; 03449 03450 save_state = prepare_dc(graphics, pen); 03451 03452 retval = draw_polyline(graphics, pen, pt, 2, TRUE); 03453 03454 restore_dc(graphics, save_state); 03455 03456 return retval; 03457 } 03458 03459 GpStatus WINGDIPAPI GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1, 03460 INT y1, INT x2, INT y2) 03461 { 03462 INT save_state; 03463 GpPointF pt[2]; 03464 GpStatus retval; 03465 03466 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x1, y1, x2, y2); 03467 03468 if(!pen || !graphics) 03469 return InvalidParameter; 03470 03471 if(graphics->busy) 03472 return ObjectBusy; 03473 03474 if (!graphics->hdc) 03475 { 03476 FIXME("graphics object has no HDC\n"); 03477 return Ok; 03478 } 03479 03480 pt[0].X = (REAL)x1; 03481 pt[0].Y = (REAL)y1; 03482 pt[1].X = (REAL)x2; 03483 pt[1].Y = (REAL)y2; 03484 03485 save_state = prepare_dc(graphics, pen); 03486 03487 retval = draw_polyline(graphics, pen, pt, 2, TRUE); 03488 03489 restore_dc(graphics, save_state); 03490 03491 return retval; 03492 } 03493 03494 GpStatus WINGDIPAPI GdipDrawLines(GpGraphics *graphics, GpPen *pen, GDIPCONST 03495 GpPointF *points, INT count) 03496 { 03497 INT save_state; 03498 GpStatus retval; 03499 03500 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 03501 03502 if(!pen || !graphics || (count < 2)) 03503 return InvalidParameter; 03504 03505 if(graphics->busy) 03506 return ObjectBusy; 03507 03508 if (!graphics->hdc) 03509 { 03510 FIXME("graphics object has no HDC\n"); 03511 return Ok; 03512 } 03513 03514 save_state = prepare_dc(graphics, pen); 03515 03516 retval = draw_polyline(graphics, pen, points, count, TRUE); 03517 03518 restore_dc(graphics, save_state); 03519 03520 return retval; 03521 } 03522 03523 GpStatus WINGDIPAPI GdipDrawLinesI(GpGraphics *graphics, GpPen *pen, GDIPCONST 03524 GpPoint *points, INT count) 03525 { 03526 INT save_state; 03527 GpStatus retval; 03528 GpPointF *ptf = NULL; 03529 int i; 03530 03531 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 03532 03533 if(!pen || !graphics || (count < 2)) 03534 return InvalidParameter; 03535 03536 if(graphics->busy) 03537 return ObjectBusy; 03538 03539 if (!graphics->hdc) 03540 { 03541 FIXME("graphics object has no HDC\n"); 03542 return Ok; 03543 } 03544 03545 ptf = GdipAlloc(count * sizeof(GpPointF)); 03546 if(!ptf) return OutOfMemory; 03547 03548 for(i = 0; i < count; i ++){ 03549 ptf[i].X = (REAL) points[i].X; 03550 ptf[i].Y = (REAL) points[i].Y; 03551 } 03552 03553 save_state = prepare_dc(graphics, pen); 03554 03555 retval = draw_polyline(graphics, pen, ptf, count, TRUE); 03556 03557 restore_dc(graphics, save_state); 03558 03559 GdipFree(ptf); 03560 return retval; 03561 } 03562 03563 GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path) 03564 { 03565 INT save_state; 03566 GpStatus retval; 03567 03568 TRACE("(%p, %p, %p)\n", graphics, pen, path); 03569 03570 if(!pen || !graphics) 03571 return InvalidParameter; 03572 03573 if(graphics->busy) 03574 return ObjectBusy; 03575 03576 if (!graphics->hdc) 03577 { 03578 FIXME("graphics object has no HDC\n"); 03579 return Ok; 03580 } 03581 03582 save_state = prepare_dc(graphics, pen); 03583 03584 retval = draw_poly(graphics, pen, path->pathdata.Points, 03585 path->pathdata.Types, path->pathdata.Count, TRUE); 03586 03587 restore_dc(graphics, save_state); 03588 03589 return retval; 03590 } 03591 03592 GpStatus WINGDIPAPI GdipDrawPie(GpGraphics *graphics, GpPen *pen, REAL x, 03593 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle) 03594 { 03595 INT save_state; 03596 03597 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, 03598 width, height, startAngle, sweepAngle); 03599 03600 if(!graphics || !pen) 03601 return InvalidParameter; 03602 03603 if(graphics->busy) 03604 return ObjectBusy; 03605 03606 if (!graphics->hdc) 03607 { 03608 FIXME("graphics object has no HDC\n"); 03609 return Ok; 03610 } 03611 03612 save_state = prepare_dc(graphics, pen); 03613 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH)); 03614 03615 draw_pie(graphics, x, y, width, height, startAngle, sweepAngle); 03616 03617 restore_dc(graphics, save_state); 03618 03619 return Ok; 03620 } 03621 03622 GpStatus WINGDIPAPI GdipDrawPieI(GpGraphics *graphics, GpPen *pen, INT x, 03623 INT y, INT width, INT height, REAL startAngle, REAL sweepAngle) 03624 { 03625 TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", graphics, pen, x, y, 03626 width, height, startAngle, sweepAngle); 03627 03628 return GdipDrawPie(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle); 03629 } 03630 03631 GpStatus WINGDIPAPI GdipDrawRectangle(GpGraphics *graphics, GpPen *pen, REAL x, 03632 REAL y, REAL width, REAL height) 03633 { 03634 INT save_state; 03635 GpPointF ptf[4]; 03636 POINT pti[4]; 03637 03638 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, width, height); 03639 03640 if(!pen || !graphics) 03641 return InvalidParameter; 03642 03643 if(graphics->busy) 03644 return ObjectBusy; 03645 03646 if (!graphics->hdc) 03647 { 03648 FIXME("graphics object has no HDC\n"); 03649 return Ok; 03650 } 03651 03652 ptf[0].X = x; 03653 ptf[0].Y = y; 03654 ptf[1].X = x + width; 03655 ptf[1].Y = y; 03656 ptf[2].X = x + width; 03657 ptf[2].Y = y + height; 03658 ptf[3].X = x; 03659 ptf[3].Y = y + height; 03660 03661 save_state = prepare_dc(graphics, pen); 03662 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH)); 03663 03664 transform_and_round_points(graphics, pti, ptf, 4); 03665 Polygon(graphics->hdc, pti, 4); 03666 03667 restore_dc(graphics, save_state); 03668 03669 return Ok; 03670 } 03671 03672 GpStatus WINGDIPAPI GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x, 03673 INT y, INT width, INT height) 03674 { 03675 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x, y, width, height); 03676 03677 return GdipDrawRectangle(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height); 03678 } 03679 03680 GpStatus WINGDIPAPI GdipDrawRectangles(GpGraphics *graphics, GpPen *pen, 03681 GDIPCONST GpRectF* rects, INT count) 03682 { 03683 GpPointF *ptf; 03684 POINT *pti; 03685 INT save_state, i; 03686 03687 TRACE("(%p, %p, %p, %d)\n", graphics, pen, rects, count); 03688 03689 if(!graphics || !pen || !rects || count < 1) 03690 return InvalidParameter; 03691 03692 if(graphics->busy) 03693 return ObjectBusy; 03694 03695 if (!graphics->hdc) 03696 { 03697 FIXME("graphics object has no HDC\n"); 03698 return Ok; 03699 } 03700 03701 ptf = GdipAlloc(4 * count * sizeof(GpPointF)); 03702 pti = GdipAlloc(4 * count * sizeof(POINT)); 03703 03704 if(!ptf || !pti){ 03705 GdipFree(ptf); 03706 GdipFree(pti); 03707 return OutOfMemory; 03708 } 03709 03710 for(i = 0; i < count; i++){ 03711 ptf[4 * i + 3].X = ptf[4 * i].X = rects[i].X; 03712 ptf[4 * i + 1].Y = ptf[4 * i].Y = rects[i].Y; 03713 ptf[4 * i + 2].X = ptf[4 * i + 1].X = rects[i].X + rects[i].Width; 03714 ptf[4 * i + 3].Y = ptf[4 * i + 2].Y = rects[i].Y + rects[i].Height; 03715 } 03716 03717 save_state = prepare_dc(graphics, pen); 03718 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH)); 03719 03720 transform_and_round_points(graphics, pti, ptf, 4 * count); 03721 03722 for(i = 0; i < count; i++) 03723 Polygon(graphics->hdc, &pti[4 * i], 4); 03724 03725 restore_dc(graphics, save_state); 03726 03727 GdipFree(ptf); 03728 GdipFree(pti); 03729 03730 return Ok; 03731 } 03732 03733 GpStatus WINGDIPAPI GdipDrawRectanglesI(GpGraphics *graphics, GpPen *pen, 03734 GDIPCONST GpRect* rects, INT count) 03735 { 03736 GpRectF *rectsF; 03737 GpStatus ret; 03738 INT i; 03739 03740 TRACE("(%p, %p, %p, %d)\n", graphics, pen, rects, count); 03741 03742 if(!rects || count<=0) 03743 return InvalidParameter; 03744 03745 rectsF = GdipAlloc(sizeof(GpRectF) * count); 03746 if(!rectsF) 03747 return OutOfMemory; 03748 03749 for(i = 0;i < count;i++){ 03750 rectsF[i].X = (REAL)rects[i].X; 03751 rectsF[i].Y = (REAL)rects[i].Y; 03752 rectsF[i].Width = (REAL)rects[i].Width; 03753 rectsF[i].Height = (REAL)rects[i].Height; 03754 } 03755 03756 ret = GdipDrawRectangles(graphics, pen, rectsF, count); 03757 GdipFree(rectsF); 03758 03759 return ret; 03760 } 03761 03762 GpStatus WINGDIPAPI GdipFillClosedCurve2(GpGraphics *graphics, GpBrush *brush, 03763 GDIPCONST GpPointF *points, INT count, REAL tension, GpFillMode fill) 03764 { 03765 GpPath *path; 03766 GpStatus stat; 03767 03768 TRACE("(%p, %p, %p, %d, %.2f, %d)\n", graphics, brush, points, 03769 count, tension, fill); 03770 03771 if(!graphics || !brush || !points) 03772 return InvalidParameter; 03773 03774 if(graphics->busy) 03775 return ObjectBusy; 03776 03777 if(count == 1) /* Do nothing */ 03778 return Ok; 03779 03780 stat = GdipCreatePath(fill, &path); 03781 if(stat != Ok) 03782 return stat; 03783 03784 stat = GdipAddPathClosedCurve2(path, points, count, tension); 03785 if(stat != Ok){ 03786 GdipDeletePath(path); 03787 return stat; 03788 } 03789 03790 stat = GdipFillPath(graphics, brush, path); 03791 if(stat != Ok){ 03792 GdipDeletePath(path); 03793 return stat; 03794 } 03795 03796 GdipDeletePath(path); 03797 03798 return Ok; 03799 } 03800 03801 GpStatus WINGDIPAPI GdipFillClosedCurve2I(GpGraphics *graphics, GpBrush *brush, 03802 GDIPCONST GpPoint *points, INT count, REAL tension, GpFillMode fill) 03803 { 03804 GpPointF *ptf; 03805 GpStatus stat; 03806 INT i; 03807 03808 TRACE("(%p, %p, %p, %d, %.2f, %d)\n", graphics, brush, points, 03809 count, tension, fill); 03810 03811 if(!points || count == 0) 03812 return InvalidParameter; 03813 03814 if(count == 1) /* Do nothing */ 03815 return Ok; 03816 03817 ptf = GdipAlloc(sizeof(GpPointF)*count); 03818 if(!ptf) 03819 return OutOfMemory; 03820 03821 for(i = 0;i < count;i++){ 03822 ptf[i].X = (REAL)points[i].X; 03823 ptf[i].Y = (REAL)points[i].Y; 03824 } 03825 03826 stat = GdipFillClosedCurve2(graphics, brush, ptf, count, tension, fill); 03827 03828 GdipFree(ptf); 03829 03830 return stat; 03831 } 03832 03833 GpStatus WINGDIPAPI GdipFillClosedCurve(GpGraphics *graphics, GpBrush *brush, 03834 GDIPCONST GpPointF *points, INT count) 03835 { 03836 TRACE("(%p, %p, %p, %d)\n", graphics, brush, points, count); 03837 return GdipFillClosedCurve2(graphics, brush, points, count, 03838 0.5f, FillModeAlternate); 03839 } 03840 03841 GpStatus WINGDIPAPI GdipFillClosedCurveI(GpGraphics *graphics, GpBrush *brush, 03842 GDIPCONST GpPoint *points, INT count) 03843 { 03844 TRACE("(%p, %p, %p, %d)\n", graphics, brush, points, count); 03845 return GdipFillClosedCurve2I(graphics, brush, points, count, 03846 0.5f, FillModeAlternate); 03847 } 03848 03849 GpStatus WINGDIPAPI GdipFillEllipse(GpGraphics *graphics, GpBrush *brush, REAL x, 03850 REAL y, REAL width, REAL height) 03851 { 03852 GpStatus stat; 03853 GpPath *path; 03854 03855 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height); 03856 03857 if(!graphics || !brush) 03858 return InvalidParameter; 03859 03860 if(graphics->busy) 03861 return ObjectBusy; 03862 03863 stat = GdipCreatePath(FillModeAlternate, &path); 03864 03865 if (stat == Ok) 03866 { 03867 stat = GdipAddPathEllipse(path, x, y, width, height); 03868 03869 if (stat == Ok) 03870 stat = GdipFillPath(graphics, brush, path); 03871 03872 GdipDeletePath(path); 03873 } 03874 03875 return stat; 03876 } 03877 03878 GpStatus WINGDIPAPI GdipFillEllipseI(GpGraphics *graphics, GpBrush *brush, INT x, 03879 INT y, INT width, INT height) 03880 { 03881 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height); 03882 03883 return GdipFillEllipse(graphics,brush,(REAL)x,(REAL)y,(REAL)width,(REAL)height); 03884 } 03885 03886 static GpStatus GDI32_GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *path) 03887 { 03888 INT save_state; 03889 GpStatus retval; 03890 03891 if(!graphics->hdc || !brush_can_fill_path(brush)) 03892 return NotImplemented; 03893 03894 save_state = SaveDC(graphics->hdc); 03895 EndPath(graphics->hdc); 03896 SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE 03897 : WINDING)); 03898 03899 BeginPath(graphics->hdc); 03900 retval = draw_poly(graphics, NULL, path->pathdata.Points, 03901 path->pathdata.Types, path->pathdata.Count, FALSE); 03902 03903 if(retval != Ok) 03904 goto end; 03905 03906 EndPath(graphics->hdc); 03907 brush_fill_path(graphics, brush); 03908 03909 retval = Ok; 03910 03911 end: 03912 RestoreDC(graphics->hdc, save_state); 03913 03914 return retval; 03915 } 03916 03917 static GpStatus SOFTWARE_GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *path) 03918 { 03919 GpStatus stat; 03920 GpRegion *rgn; 03921 03922 if (!brush_can_fill_pixels(brush)) 03923 return NotImplemented; 03924 03925 /* FIXME: This could probably be done more efficiently without regions. */ 03926 03927 stat = GdipCreateRegionPath(path, &rgn); 03928 03929 if (stat == Ok) 03930 { 03931 stat = GdipFillRegion(graphics, brush, rgn); 03932 03933 GdipDeleteRegion(rgn); 03934 } 03935 03936 return stat; 03937 } 03938 03939 GpStatus WINGDIPAPI GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *path) 03940 { 03941 GpStatus stat = NotImplemented; 03942 03943 TRACE("(%p, %p, %p)\n", graphics, brush, path); 03944 03945 if(!brush || !graphics || !path) 03946 return InvalidParameter; 03947 03948 if(graphics->busy) 03949 return ObjectBusy; 03950 03951 if (!graphics->image) 03952 stat = GDI32_GdipFillPath(graphics, brush, path); 03953 03954 if (stat == NotImplemented) 03955 stat = SOFTWARE_GdipFillPath(graphics, brush, path); 03956 03957 if (stat == NotImplemented) 03958 { 03959 FIXME("Not implemented for brushtype %i\n", brush->bt); 03960 stat = Ok; 03961 } 03962 03963 return stat; 03964 } 03965 03966 GpStatus WINGDIPAPI GdipFillPie(GpGraphics *graphics, GpBrush *brush, REAL x, 03967 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle) 03968 { 03969 GpStatus stat; 03970 GpPath *path; 03971 03972 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", 03973 graphics, brush, x, y, width, height, startAngle, sweepAngle); 03974 03975 if(!graphics || !brush) 03976 return InvalidParameter; 03977 03978 if(graphics->busy) 03979 return ObjectBusy; 03980 03981 stat = GdipCreatePath(FillModeAlternate, &path); 03982 03983 if (stat == Ok) 03984 { 03985 stat = GdipAddPathPie(path, x, y, width, height, startAngle, sweepAngle); 03986 03987 if (stat == Ok) 03988 stat = GdipFillPath(graphics, brush, path); 03989 03990 GdipDeletePath(path); 03991 } 03992 03993 return stat; 03994 } 03995 03996 GpStatus WINGDIPAPI GdipFillPieI(GpGraphics *graphics, GpBrush *brush, INT x, 03997 INT y, INT width, INT height, REAL startAngle, REAL sweepAngle) 03998 { 03999 TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", 04000 graphics, brush, x, y, width, height, startAngle, sweepAngle); 04001 04002 return GdipFillPie(graphics,brush,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle); 04003 } 04004 04005 GpStatus WINGDIPAPI GdipFillPolygon(GpGraphics *graphics, GpBrush *brush, 04006 GDIPCONST GpPointF *points, INT count, GpFillMode fillMode) 04007 { 04008 GpStatus stat; 04009 GpPath *path; 04010 04011 TRACE("(%p, %p, %p, %d, %d)\n", graphics, brush, points, count, fillMode); 04012 04013 if(!graphics || !brush || !points || !count) 04014 return InvalidParameter; 04015 04016 if(graphics->busy) 04017 return ObjectBusy; 04018 04019 stat = GdipCreatePath(fillMode, &path); 04020 04021 if (stat == Ok) 04022 { 04023 stat = GdipAddPathPolygon(path, points, count); 04024 04025 if (stat == Ok) 04026 stat = GdipFillPath(graphics, brush, path); 04027 04028 GdipDeletePath(path); 04029 } 04030 04031 return stat; 04032 } 04033 04034 GpStatus WINGDIPAPI GdipFillPolygonI(GpGraphics *graphics, GpBrush *brush, 04035 GDIPCONST GpPoint *points, INT count, GpFillMode fillMode) 04036 { 04037 GpStatus stat; 04038 GpPath *path; 04039 04040 TRACE("(%p, %p, %p, %d, %d)\n", graphics, brush, points, count, fillMode); 04041 04042 if(!graphics || !brush || !points || !count) 04043 return InvalidParameter; 04044 04045 if(graphics->busy) 04046 return ObjectBusy; 04047 04048 stat = GdipCreatePath(fillMode, &path); 04049 04050 if (stat == Ok) 04051 { 04052 stat = GdipAddPathPolygonI(path, points, count); 04053 04054 if (stat == Ok) 04055 stat = GdipFillPath(graphics, brush, path); 04056 04057 GdipDeletePath(path); 04058 } 04059 04060 return stat; 04061 } 04062 04063 GpStatus WINGDIPAPI GdipFillPolygon2(GpGraphics *graphics, GpBrush *brush, 04064 GDIPCONST GpPointF *points, INT count) 04065 { 04066 TRACE("(%p, %p, %p, %d)\n", graphics, brush, points, count); 04067 04068 return GdipFillPolygon(graphics, brush, points, count, FillModeAlternate); 04069 } 04070 04071 GpStatus WINGDIPAPI GdipFillPolygon2I(GpGraphics *graphics, GpBrush *brush, 04072 GDIPCONST GpPoint *points, INT count) 04073 { 04074 TRACE("(%p, %p, %p, %d)\n", graphics, brush, points, count); 04075 04076 return GdipFillPolygonI(graphics, brush, points, count, FillModeAlternate); 04077 } 04078 04079 GpStatus WINGDIPAPI GdipFillRectangle(GpGraphics *graphics, GpBrush *brush, 04080 REAL x, REAL y, REAL width, REAL height) 04081 { 04082 GpStatus stat; 04083 GpPath *path; 04084 04085 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height); 04086 04087 if(!graphics || !brush) 04088 return InvalidParameter; 04089 04090 if(graphics->busy) 04091 return ObjectBusy; 04092 04093 stat = GdipCreatePath(FillModeAlternate, &path); 04094 04095 if (stat == Ok) 04096 { 04097 stat = GdipAddPathRectangle(path, x, y, width, height); 04098 04099 if (stat == Ok) 04100 stat = GdipFillPath(graphics, brush, path); 04101 04102 GdipDeletePath(path); 04103 } 04104 04105 return stat; 04106 } 04107 04108 GpStatus WINGDIPAPI GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush, 04109 INT x, INT y, INT width, INT height) 04110 { 04111 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height); 04112 04113 return GdipFillRectangle(graphics, brush, x, y, width, height); 04114 } 04115 04116 GpStatus WINGDIPAPI GdipFillRectangles(GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRectF *rects, 04117 INT count) 04118 { 04119 GpStatus ret; 04120 INT i; 04121 04122 TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count); 04123 04124 if(!rects) 04125 return InvalidParameter; 04126 04127 for(i = 0; i < count; i++){ 04128 ret = GdipFillRectangle(graphics, brush, rects[i].X, rects[i].Y, rects[i].Width, rects[i].Height); 04129 if(ret != Ok) return ret; 04130 } 04131 04132 return Ok; 04133 } 04134 04135 GpStatus WINGDIPAPI GdipFillRectanglesI(GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRect *rects, 04136 INT count) 04137 { 04138 GpRectF *rectsF; 04139 GpStatus ret; 04140 INT i; 04141 04142 TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count); 04143 04144 if(!rects || count <= 0) 04145 return InvalidParameter; 04146 04147 rectsF = GdipAlloc(sizeof(GpRectF)*count); 04148 if(!rectsF) 04149 return OutOfMemory; 04150 04151 for(i = 0; i < count; i++){ 04152 rectsF[i].X = (REAL)rects[i].X; 04153 rectsF[i].Y = (REAL)rects[i].Y; 04154 rectsF[i].X = (REAL)rects[i].Width; 04155 rectsF[i].Height = (REAL)rects[i].Height; 04156 } 04157 04158 ret = GdipFillRectangles(graphics,brush,rectsF,count); 04159 GdipFree(rectsF); 04160 04161 return ret; 04162 } 04163 04164 static GpStatus GDI32_GdipFillRegion(GpGraphics* graphics, GpBrush* brush, 04165 GpRegion* region) 04166 { 04167 INT save_state; 04168 GpStatus status; 04169 HRGN hrgn; 04170 RECT rc; 04171 04172 if(!graphics->hdc || !brush_can_fill_path(brush)) 04173 return NotImplemented; 04174 04175 status = GdipGetRegionHRgn(region, graphics, &hrgn); 04176 if(status != Ok) 04177 return status; 04178 04179 save_state = SaveDC(graphics->hdc); 04180 EndPath(graphics->hdc); 04181 04182 ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND); 04183 04184 if (GetClipBox(graphics->hdc, &rc) != NULLREGION) 04185 { 04186 BeginPath(graphics->hdc); 04187 Rectangle(graphics->hdc, rc.left, rc.top, rc.right, rc.bottom); 04188 EndPath(graphics->hdc); 04189 04190 brush_fill_path(graphics, brush); 04191 } 04192 04193 RestoreDC(graphics->hdc, save_state); 04194 04195 DeleteObject(hrgn); 04196 04197 return Ok; 04198 } 04199 04200 static GpStatus SOFTWARE_GdipFillRegion(GpGraphics *graphics, GpBrush *brush, 04201 GpRegion* region) 04202 { 04203 GpStatus stat; 04204 GpRegion *temp_region; 04205 GpMatrix *world_to_device; 04206 GpRectF graphics_bounds; 04207 DWORD *pixel_data; 04208 HRGN hregion; 04209 RECT bound_rect; 04210 GpRect gp_bound_rect; 04211 04212 if (!brush_can_fill_pixels(brush)) 04213 return NotImplemented; 04214 04215 stat = get_graphics_bounds(graphics, &graphics_bounds); 04216 04217 if (stat == Ok) 04218 stat = GdipCloneRegion(region, &temp_region); 04219 04220 if (stat == Ok) 04221 { 04222 stat = get_graphics_transform(graphics, CoordinateSpaceDevice, 04223 CoordinateSpaceWorld, &world_to_device); 04224 04225 if (stat == Ok) 04226 { 04227 stat = GdipTransformRegion(temp_region, world_to_device); 04228 04229 GdipDeleteMatrix(world_to_device); 04230 } 04231 04232 if (stat == Ok) 04233 stat = GdipCombineRegionRect(temp_region, &graphics_bounds, CombineModeIntersect); 04234 04235 if (stat == Ok) 04236 stat = GdipGetRegionHRgn(temp_region, NULL, &hregion); 04237 04238 GdipDeleteRegion(temp_region); 04239 } 04240 04241 if (stat == Ok && GetRgnBox(hregion, &bound_rect) == NULLREGION) 04242 { 04243 DeleteObject(hregion); 04244 return Ok; 04245 } 04246 04247 if (stat == Ok) 04248 { 04249 gp_bound_rect.X = bound_rect.left; 04250 gp_bound_rect.Y = bound_rect.top; 04251 gp_bound_rect.Width = bound_rect.right - bound_rect.left; 04252 gp_bound_rect.Height = bound_rect.bottom - bound_rect.top; 04253 04254 pixel_data = GdipAlloc(sizeof(*pixel_data) * gp_bound_rect.Width * gp_bound_rect.Height); 04255 if (!pixel_data) 04256 stat = OutOfMemory; 04257 04258 if (stat == Ok) 04259 { 04260 stat = brush_fill_pixels(graphics, brush, pixel_data, 04261 &gp_bound_rect, gp_bound_rect.Width); 04262 04263 if (stat == Ok) 04264 stat = alpha_blend_pixels_hrgn(graphics, gp_bound_rect.X, 04265 gp_bound_rect.Y, (BYTE*)pixel_data, gp_bound_rect.Width, 04266 gp_bound_rect.Height, gp_bound_rect.Width * 4, hregion); 04267 04268 GdipFree(pixel_data); 04269 } 04270 04271 DeleteObject(hregion); 04272 } 04273 04274 return stat; 04275 } 04276 04277 /***************************************************************************** 04278 * GdipFillRegion [GDIPLUS.@] 04279 */ 04280 GpStatus WINGDIPAPI GdipFillRegion(GpGraphics* graphics, GpBrush* brush, 04281 GpRegion* region) 04282 { 04283 GpStatus stat = NotImplemented; 04284 04285 TRACE("(%p, %p, %p)\n", graphics, brush, region); 04286 04287 if (!(graphics && brush && region)) 04288 return InvalidParameter; 04289 04290 if(graphics->busy) 04291 return ObjectBusy; 04292 04293 if (!graphics->image) 04294 stat = GDI32_GdipFillRegion(graphics, brush, region); 04295 04296 if (stat == NotImplemented) 04297 stat = SOFTWARE_GdipFillRegion(graphics, brush, region); 04298 04299 if (stat == NotImplemented) 04300 { 04301 FIXME("not implemented for brushtype %i\n", brush->bt); 04302 stat = Ok; 04303 } 04304 04305 return stat; 04306 } 04307 04308 GpStatus WINGDIPAPI GdipFlush(GpGraphics *graphics, GpFlushIntention intention) 04309 { 04310 TRACE("(%p,%u)\n", graphics, intention); 04311 04312 if(!graphics) 04313 return InvalidParameter; 04314 04315 if(graphics->busy) 04316 return ObjectBusy; 04317 04318 /* We have no internal operation queue, so there's no need to clear it. */ 04319 04320 if (graphics->hdc) 04321 GdiFlush(); 04322 04323 return Ok; 04324 } 04325 04326 /***************************************************************************** 04327 * GdipGetClipBounds [GDIPLUS.@] 04328 */ 04329 GpStatus WINGDIPAPI GdipGetClipBounds(GpGraphics *graphics, GpRectF *rect) 04330 { 04331 TRACE("(%p, %p)\n", graphics, rect); 04332 04333 if(!graphics) 04334 return InvalidParameter; 04335 04336 if(graphics->busy) 04337 return ObjectBusy; 04338 04339 return GdipGetRegionBounds(graphics->clip, graphics, rect); 04340 } 04341 04342 /***************************************************************************** 04343 * GdipGetClipBoundsI [GDIPLUS.@] 04344 */ 04345 GpStatus WINGDIPAPI GdipGetClipBoundsI(GpGraphics *graphics, GpRect *rect) 04346 { 04347 TRACE("(%p, %p)\n", graphics, rect); 04348 04349 if(!graphics) 04350 return InvalidParameter; 04351 04352 if(graphics->busy) 04353 return ObjectBusy; 04354 04355 return GdipGetRegionBoundsI(graphics->clip, graphics, rect); 04356 } 04357 04358 /* FIXME: Compositing mode is not used anywhere except the getter/setter. */ 04359 GpStatus WINGDIPAPI GdipGetCompositingMode(GpGraphics *graphics, 04360 CompositingMode *mode) 04361 { 04362 TRACE("(%p, %p)\n", graphics, mode); 04363 04364 if(!graphics || !mode) 04365 return InvalidParameter; 04366 04367 if(graphics->busy) 04368 return ObjectBusy; 04369 04370 *mode = graphics->compmode; 04371 04372 return Ok; 04373 } 04374 04375 /* FIXME: Compositing quality is not used anywhere except the getter/setter. */ 04376 GpStatus WINGDIPAPI GdipGetCompositingQuality(GpGraphics *graphics, 04377 CompositingQuality *quality) 04378 { 04379 TRACE("(%p, %p)\n", graphics, quality); 04380 04381 if(!graphics || !quality) 04382 return InvalidParameter; 04383 04384 if(graphics->busy) 04385 return ObjectBusy; 04386 04387 *quality = graphics->compqual; 04388 04389 return Ok; 04390 } 04391 04392 /* FIXME: Interpolation mode is not used anywhere except the getter/setter. */ 04393 GpStatus WINGDIPAPI GdipGetInterpolationMode(GpGraphics *graphics, 04394 InterpolationMode *mode) 04395 { 04396 TRACE("(%p, %p)\n", graphics, mode); 04397 04398 if(!graphics || !mode) 04399 return InvalidParameter; 04400 04401 if(graphics->busy) 04402 return ObjectBusy; 04403 04404 *mode = graphics->interpolation; 04405 04406 return Ok; 04407 } 04408 04409 /* FIXME: Need to handle color depths less than 24bpp */ 04410 GpStatus WINGDIPAPI GdipGetNearestColor(GpGraphics *graphics, ARGB* argb) 04411 { 04412 FIXME("(%p, %p): Passing color unmodified\n", graphics, argb); 04413 04414 if(!graphics || !argb) 04415 return InvalidParameter; 04416 04417 if(graphics->busy) 04418 return ObjectBusy; 04419 04420 return Ok; 04421 } 04422 04423 GpStatus WINGDIPAPI GdipGetPageScale(GpGraphics *graphics, REAL *scale) 04424 { 04425 TRACE("(%p, %p)\n", graphics, scale); 04426 04427 if(!graphics || !scale) 04428 return InvalidParameter; 04429 04430 if(graphics->busy) 04431 return ObjectBusy; 04432 04433 *scale = graphics->scale; 04434 04435 return Ok; 04436 } 04437 04438 GpStatus WINGDIPAPI GdipGetPageUnit(GpGraphics *graphics, GpUnit *unit) 04439 { 04440 TRACE("(%p, %p)\n", graphics, unit); 04441 04442 if(!graphics || !unit) 04443 return InvalidParameter; 04444 04445 if(graphics->busy) 04446 return ObjectBusy; 04447 04448 *unit = graphics->unit; 04449 04450 return Ok; 04451 } 04452 04453 /* FIXME: Pixel offset mode is not used anywhere except the getter/setter. */ 04454 GpStatus WINGDIPAPI GdipGetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode 04455 *mode) 04456 { 04457 TRACE("(%p, %p)\n", graphics, mode); 04458 04459 if(!graphics || !mode) 04460 return InvalidParameter; 04461 04462 if(graphics->busy) 04463 return ObjectBusy; 04464 04465 *mode = graphics->pixeloffset; 04466 04467 return Ok; 04468 } 04469 04470 /* FIXME: Smoothing mode is not used anywhere except the getter/setter. */ 04471 GpStatus WINGDIPAPI GdipGetSmoothingMode(GpGraphics *graphics, SmoothingMode *mode) 04472 { 04473 TRACE("(%p, %p)\n", graphics, mode); 04474 04475 if(!graphics || !mode) 04476 return InvalidParameter; 04477 04478 if(graphics->busy) 04479 return ObjectBusy; 04480 04481 *mode = graphics->smoothing; 04482 04483 return Ok; 04484 } 04485 04486 GpStatus WINGDIPAPI GdipGetTextContrast(GpGraphics *graphics, UINT *contrast) 04487 { 04488 TRACE("(%p, %p)\n", graphics, contrast); 04489 04490 if(!graphics || !contrast) 04491 return InvalidParameter; 04492 04493 *contrast = graphics->textcontrast; 04494 04495 return Ok; 04496 } 04497 04498 /* FIXME: Text rendering hint is not used anywhere except the getter/setter. */ 04499 GpStatus WINGDIPAPI GdipGetTextRenderingHint(GpGraphics *graphics, 04500 TextRenderingHint *hint) 04501 { 04502 TRACE("(%p, %p)\n", graphics, hint); 04503 04504 if(!graphics || !hint) 04505 return InvalidParameter; 04506 04507 if(graphics->busy) 04508 return ObjectBusy; 04509 04510 *hint = graphics->texthint; 04511 04512 return Ok; 04513 } 04514 04515 GpStatus WINGDIPAPI GdipGetVisibleClipBounds(GpGraphics *graphics, GpRectF *rect) 04516 { 04517 GpRegion *clip_rgn; 04518 GpStatus stat; 04519 04520 TRACE("(%p, %p)\n", graphics, rect); 04521 04522 if(!graphics || !rect) 04523 return InvalidParameter; 04524 04525 if(graphics->busy) 04526 return ObjectBusy; 04527 04528 /* intersect window and graphics clipping regions */ 04529 if((stat = GdipCreateRegion(&clip_rgn)) != Ok) 04530 return stat; 04531 04532 if((stat = get_visible_clip_region(graphics, clip_rgn)) != Ok) 04533 goto cleanup; 04534 04535 /* get bounds of the region */ 04536 stat = GdipGetRegionBounds(clip_rgn, graphics, rect); 04537 04538 cleanup: 04539 GdipDeleteRegion(clip_rgn); 04540 04541 return stat; 04542 } 04543 04544 GpStatus WINGDIPAPI GdipGetVisibleClipBoundsI(GpGraphics *graphics, GpRect *rect) 04545 { 04546 GpRectF rectf; 04547 GpStatus stat; 04548 04549 TRACE("(%p, %p)\n", graphics, rect); 04550 04551 if(!graphics || !rect) 04552 return InvalidParameter; 04553 04554 if((stat = GdipGetVisibleClipBounds(graphics, &rectf)) == Ok) 04555 { 04556 rect->X = roundr(rectf.X); 04557 rect->Y = roundr(rectf.Y); 04558 rect->Width = roundr(rectf.Width); 04559 rect->Height = roundr(rectf.Height); 04560 } 04561 04562 return stat; 04563 } 04564 04565 GpStatus WINGDIPAPI GdipGetWorldTransform(GpGraphics *graphics, GpMatrix *matrix) 04566 { 04567 TRACE("(%p, %p)\n", graphics, matrix); 04568 04569 if(!graphics || !matrix) 04570 return InvalidParameter; 04571 04572 if(graphics->busy) 04573 return ObjectBusy; 04574 04575 *matrix = *graphics->worldtrans; 04576 return Ok; 04577 } 04578 04579 GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics *graphics, ARGB color) 04580 { 04581 GpSolidFill *brush; 04582 GpStatus stat; 04583 GpRectF wnd_rect; 04584 04585 TRACE("(%p, %x)\n", graphics, color); 04586 04587 if(!graphics) 04588 return InvalidParameter; 04589 04590 if(graphics->busy) 04591 return ObjectBusy; 04592 04593 if((stat = GdipCreateSolidFill(color, &brush)) != Ok) 04594 return stat; 04595 04596 if((stat = get_graphics_bounds(graphics, &wnd_rect)) != Ok){ 04597 GdipDeleteBrush((GpBrush*)brush); 04598 return stat; 04599 } 04600 04601 GdipFillRectangle(graphics, (GpBrush*)brush, wnd_rect.X, wnd_rect.Y, 04602 wnd_rect.Width, wnd_rect.Height); 04603 04604 GdipDeleteBrush((GpBrush*)brush); 04605 04606 return Ok; 04607 } 04608 04609 GpStatus WINGDIPAPI GdipIsClipEmpty(GpGraphics *graphics, BOOL *res) 04610 { 04611 TRACE("(%p, %p)\n", graphics, res); 04612 04613 if(!graphics || !res) 04614 return InvalidParameter; 04615 04616 return GdipIsEmptyRegion(graphics->clip, graphics, res); 04617 } 04618 04619 GpStatus WINGDIPAPI GdipIsVisiblePoint(GpGraphics *graphics, REAL x, REAL y, BOOL *result) 04620 { 04621 GpStatus stat; 04622 GpRegion* rgn; 04623 GpPointF pt; 04624 04625 TRACE("(%p, %.2f, %.2f, %p)\n", graphics, x, y, result); 04626 04627 if(!graphics || !result) 04628 return InvalidParameter; 04629 04630 if(graphics->busy) 04631 return ObjectBusy; 04632 04633 pt.X = x; 04634 pt.Y = y; 04635 if((stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, 04636 CoordinateSpaceWorld, &pt, 1)) != Ok) 04637 return stat; 04638 04639 if((stat = GdipCreateRegion(&rgn)) != Ok) 04640 return stat; 04641 04642 if((stat = get_visible_clip_region(graphics, rgn)) != Ok) 04643 goto cleanup; 04644 04645 stat = GdipIsVisibleRegionPoint(rgn, pt.X, pt.Y, graphics, result); 04646 04647 cleanup: 04648 GdipDeleteRegion(rgn); 04649 return stat; 04650 } 04651 04652 GpStatus WINGDIPAPI GdipIsVisiblePointI(GpGraphics *graphics, INT x, INT y, BOOL *result) 04653 { 04654 return GdipIsVisiblePoint(graphics, (REAL)x, (REAL)y, result); 04655 } 04656 04657 GpStatus WINGDIPAPI GdipIsVisibleRect(GpGraphics *graphics, REAL x, REAL y, REAL width, REAL height, BOOL *result) 04658 { 04659 GpStatus stat; 04660 GpRegion* rgn; 04661 GpPointF pts[2]; 04662 04663 TRACE("(%p %.2f %.2f %.2f %.2f %p)\n", graphics, x, y, width, height, result); 04664 04665 if(!graphics || !result) 04666 return InvalidParameter; 04667 04668 if(graphics->busy) 04669 return ObjectBusy; 04670 04671 pts[0].X = x; 04672 pts[0].Y = y; 04673 pts[1].X = x + width; 04674 pts[1].Y = y + height; 04675 04676 if((stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, 04677 CoordinateSpaceWorld, pts, 2)) != Ok) 04678 return stat; 04679 04680 pts[1].X -= pts[0].X; 04681 pts[1].Y -= pts[0].Y; 04682 04683 if((stat = GdipCreateRegion(&rgn)) != Ok) 04684 return stat; 04685 04686 if((stat = get_visible_clip_region(graphics, rgn)) != Ok) 04687 goto cleanup; 04688 04689 stat = GdipIsVisibleRegionRect(rgn, pts[0].X, pts[0].Y, pts[1].X, pts[1].Y, graphics, result); 04690 04691 cleanup: 04692 GdipDeleteRegion(rgn); 04693 return stat; 04694 } 04695 04696 GpStatus WINGDIPAPI GdipIsVisibleRectI(GpGraphics *graphics, INT x, INT y, INT width, INT height, BOOL *result) 04697 { 04698 return GdipIsVisibleRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, result); 04699 } 04700 04701 GpStatus gdip_format_string(HDC hdc, 04702 GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, 04703 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, 04704 gdip_format_string_callback callback, void *user_data) 04705 { 04706 WCHAR* stringdup; 04707 int sum = 0, height = 0, fit, fitcpy, i, j, lret, nwidth, 04708 nheight, lineend, lineno = 0; 04709 RectF bounds; 04710 StringAlignment halign; 04711 GpStatus stat = Ok; 04712 SIZE size; 04713 HotkeyPrefix hkprefix; 04714 INT *hotkeyprefix_offsets=NULL; 04715 INT hotkeyprefix_count=0; 04716 INT hotkeyprefix_pos=0, hotkeyprefix_end_pos=0; 04717 int seen_prefix=0; 04718 04719 if(length == -1) length = lstrlenW(string); 04720 04721 stringdup = GdipAlloc((length + 1) * sizeof(WCHAR)); 04722 if(!stringdup) return OutOfMemory; 04723 04724 nwidth = roundr(rect->Width); 04725 nheight = roundr(rect->Height); 04726 04727 if (rect->Width >= INT_MAX || rect->Width < 0.5) nwidth = INT_MAX; 04728 if (rect->Height >= INT_MAX || rect->Height < 0.5) nheight = INT_MAX; 04729 04730 if (format) 04731 hkprefix = format->hkprefix; 04732 else 04733 hkprefix = HotkeyPrefixNone; 04734 04735 if (hkprefix == HotkeyPrefixShow) 04736 { 04737 for (i=0; i<length; i++) 04738 { 04739 if (string[i] == '&') 04740 hotkeyprefix_count++; 04741 } 04742 } 04743 04744 if (hotkeyprefix_count) 04745 hotkeyprefix_offsets = GdipAlloc(sizeof(INT) * hotkeyprefix_count); 04746 04747 hotkeyprefix_count = 0; 04748 04749 for(i = 0, j = 0; i < length; i++){ 04750 /* FIXME: This makes the indexes passed to callback inaccurate. */ 04751 if(!isprintW(string[i]) && (string[i] != '\n')) 04752 continue; 04753 04754 if (seen_prefix && hkprefix == HotkeyPrefixShow && string[i] != '&') 04755 hotkeyprefix_offsets[hotkeyprefix_count++] = j; 04756 else if (!seen_prefix && hkprefix != HotkeyPrefixNone && string[i] == '&') 04757 { 04758 seen_prefix = 1; 04759 continue; 04760 } 04761 04762 seen_prefix = 0; 04763 04764 stringdup[j] = string[i]; 04765 j++; 04766 } 04767 04768 length = j; 04769 04770 if (format) halign = format->align; 04771 else halign = StringAlignmentNear; 04772 04773 while(sum < length){ 04774 GetTextExtentExPointW(hdc, stringdup + sum, length - sum, 04775 nwidth, &fit, NULL, &size); 04776 fitcpy = fit; 04777 04778 if(fit == 0) 04779 break; 04780 04781 for(lret = 0; lret < fit; lret++) 04782 if(*(stringdup + sum + lret) == '\n') 04783 break; 04784 04785 /* Line break code (may look strange, but it imitates windows). */ 04786 if(lret < fit) 04787 lineend = fit = lret; /* this is not an off-by-one error */ 04788 else if(fit < (length - sum)){ 04789 if(*(stringdup + sum + fit) == ' ') 04790 while(*(stringdup + sum + fit) == ' ') 04791 fit++; 04792 else 04793 while(*(stringdup + sum + fit - 1) != ' '){ 04794 fit--; 04795 04796 if(*(stringdup + sum + fit) == '\t') 04797 break; 04798 04799 if(fit == 0){ 04800 fit = fitcpy; 04801 break; 04802 } 04803 } 04804 lineend = fit; 04805 while(*(stringdup + sum + lineend - 1) == ' ' || 04806 *(stringdup + sum + lineend - 1) == '\t') 04807 lineend--; 04808 } 04809 else 04810 lineend = fit; 04811 04812 GetTextExtentExPointW(hdc, stringdup + sum, lineend, 04813 nwidth, &j, NULL, &size); 04814 04815 bounds.Width = size.cx; 04816 04817 if(height + size.cy > nheight) 04818 bounds.Height = nheight - (height + size.cy); 04819 else 04820 bounds.Height = size.cy; 04821 04822 bounds.Y = rect->Y + height; 04823 04824 switch (halign) 04825 { 04826 case StringAlignmentNear: 04827 default: 04828 bounds.X = rect->X; 04829 break; 04830 case StringAlignmentCenter: 04831 bounds.X = rect->X + (rect->Width/2) - (bounds.Width/2); 04832 break; 04833 case StringAlignmentFar: 04834 bounds.X = rect->X + rect->Width - bounds.Width; 04835 break; 04836 } 04837 04838 for (hotkeyprefix_end_pos=hotkeyprefix_pos; hotkeyprefix_end_pos<hotkeyprefix_count; hotkeyprefix_end_pos++) 04839 if (hotkeyprefix_offsets[hotkeyprefix_end_pos] >= sum + lineend) 04840 break; 04841 04842 stat = callback(hdc, stringdup, sum, lineend, 04843 font, rect, format, lineno, &bounds, 04844 &hotkeyprefix_offsets[hotkeyprefix_pos], 04845 hotkeyprefix_end_pos-hotkeyprefix_pos, user_data); 04846 04847 if (stat != Ok) 04848 break; 04849 04850 sum += fit + (lret < fitcpy ? 1 : 0); 04851 height += size.cy; 04852 lineno++; 04853 04854 hotkeyprefix_pos = hotkeyprefix_end_pos; 04855 04856 if(height > nheight) 04857 break; 04858 04859 /* Stop if this was a linewrap (but not if it was a linebreak). */ 04860 if((lret == fitcpy) && format && (format->attr & StringFormatFlagsNoWrap)) 04861 break; 04862 } 04863 04864 GdipFree(stringdup); 04865 GdipFree(hotkeyprefix_offsets); 04866 04867 return stat; 04868 } 04869 04870 struct measure_ranges_args { 04871 GpRegion **regions; 04872 }; 04873 04874 static GpStatus measure_ranges_callback(HDC hdc, 04875 GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font, 04876 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, 04877 INT lineno, const RectF *bounds, INT *underlined_indexes, 04878 INT underlined_index_count, void *user_data) 04879 { 04880 int i; 04881 GpStatus stat = Ok; 04882 struct measure_ranges_args *args = user_data; 04883 04884 for (i=0; i<format->range_count; i++) 04885 { 04886 INT range_start = max(index, format->character_ranges[i].First); 04887 INT range_end = min(index+length, format->character_ranges[i].First+format->character_ranges[i].Length); 04888 if (range_start < range_end) 04889 { 04890 GpRectF range_rect; 04891 SIZE range_size; 04892 04893 range_rect.Y = bounds->Y; 04894 range_rect.Height = bounds->Height; 04895 04896 GetTextExtentExPointW(hdc, string + index, range_start - index, 04897 INT_MAX, NULL, NULL, &range_size); 04898 range_rect.X = bounds->X + range_size.cx; 04899 04900 GetTextExtentExPointW(hdc, string + index, range_end - index, 04901 INT_MAX, NULL, NULL, &range_size); 04902 range_rect.Width = (bounds->X + range_size.cx) - range_rect.X; 04903 04904 stat = GdipCombineRegionRect(args->regions[i], &range_rect, CombineModeUnion); 04905 if (stat != Ok) 04906 break; 04907 } 04908 } 04909 04910 return stat; 04911 } 04912 04913 GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics, 04914 GDIPCONST WCHAR* string, INT length, GDIPCONST GpFont* font, 04915 GDIPCONST RectF* layoutRect, GDIPCONST GpStringFormat *stringFormat, 04916 INT regionCount, GpRegion** regions) 04917 { 04918 GpStatus stat; 04919 int i; 04920 LOGFONTW lfw; 04921 HFONT oldfont; 04922 struct measure_ranges_args args; 04923 HDC hdc, temp_hdc=NULL; 04924 04925 TRACE("(%p %s %d %p %s %p %d %p)\n", graphics, debugstr_w(string), 04926 length, font, debugstr_rectf(layoutRect), stringFormat, regionCount, regions); 04927 04928 if (!(graphics && string && font && layoutRect && stringFormat && regions)) 04929 return InvalidParameter; 04930 04931 if (regionCount < stringFormat->range_count) 04932 return InvalidParameter; 04933 04934 stat = GdipGetLogFontW((GpFont *)font, graphics, &lfw); 04935 if (stat != Ok) return stat; 04936 04937 if(!graphics->hdc) 04938 { 04939 hdc = temp_hdc = CreateCompatibleDC(0); 04940 if (!temp_hdc) return OutOfMemory; 04941 } 04942 else 04943 hdc = graphics->hdc; 04944 04945 if (stringFormat->attr) 04946 TRACE("may be ignoring some format flags: attr %x\n", stringFormat->attr); 04947 04948 oldfont = SelectObject(hdc, CreateFontIndirectW(&lfw)); 04949 04950 for (i=0; i<stringFormat->range_count; i++) 04951 { 04952 stat = GdipSetEmpty(regions[i]); 04953 if (stat != Ok) 04954 return stat; 04955 } 04956 04957 args.regions = regions; 04958 04959 stat = gdip_format_string(hdc, string, length, font, layoutRect, stringFormat, 04960 measure_ranges_callback, &args); 04961 04962 DeleteObject(SelectObject(hdc, oldfont)); 04963 04964 if (temp_hdc) 04965 DeleteDC(temp_hdc); 04966 04967 return stat; 04968 } 04969 04970 struct measure_string_args { 04971 RectF *bounds; 04972 INT *codepointsfitted; 04973 INT *linesfilled; 04974 REAL rel_width, rel_height; 04975 }; 04976 04977 static GpStatus measure_string_callback(HDC hdc, 04978 GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font, 04979 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, 04980 INT lineno, const RectF *bounds, INT *underlined_indexes, 04981 INT underlined_index_count, void *user_data) 04982 { 04983 struct measure_string_args *args = user_data; 04984 REAL new_width, new_height; 04985 04986 new_width = bounds->Width / args->rel_width; 04987 new_height = (bounds->Height + bounds->Y - args->bounds->Y) / args->rel_height; 04988 04989 if (new_width > args->bounds->Width) 04990 args->bounds->Width = new_width; 04991 04992 if (new_height > args->bounds->Height) 04993 args->bounds->Height = new_height; 04994 04995 if (args->codepointsfitted) 04996 *args->codepointsfitted = index + length; 04997 04998 if (args->linesfilled) 04999 (*args->linesfilled)++; 05000 05001 return Ok; 05002 } 05003 05004 /* Find the smallest rectangle that bounds the text when it is printed in rect 05005 * according to the format options listed in format. If rect has 0 width and 05006 * height, then just find the smallest rectangle that bounds the text when it's 05007 * printed at location (rect->X, rect-Y). */ 05008 GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics, 05009 GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, 05010 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, RectF *bounds, 05011 INT *codepointsfitted, INT *linesfilled) 05012 { 05013 HFONT oldfont, gdifont; 05014 struct measure_string_args args; 05015 HDC temp_hdc=NULL, hdc; 05016 GpPointF pt[3]; 05017 05018 TRACE("(%p, %s, %i, %p, %s, %p, %p, %p, %p)\n", graphics, 05019 debugstr_wn(string, length), length, font, debugstr_rectf(rect), format, 05020 bounds, codepointsfitted, linesfilled); 05021 05022 if(!graphics || !string || !font || !rect || !bounds) 05023 return InvalidParameter; 05024 05025 if(!graphics->hdc) 05026 { 05027 hdc = temp_hdc = CreateCompatibleDC(0); 05028 if (!temp_hdc) return OutOfMemory; 05029 } 05030 else 05031 hdc = graphics->hdc; 05032 05033 if(linesfilled) *linesfilled = 0; 05034 if(codepointsfitted) *codepointsfitted = 0; 05035 05036 if(format) 05037 TRACE("may be ignoring some format flags: attr %x\n", format->attr); 05038 05039 pt[0].X = 0.0; 05040 pt[0].Y = 0.0; 05041 pt[1].X = 1.0; 05042 pt[1].Y = 0.0; 05043 pt[2].X = 0.0; 05044 pt[2].Y = 1.0; 05045 GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3); 05046 args.rel_width = sqrt((pt[1].Y-pt[0].Y)*(pt[1].Y-pt[0].Y)+ 05047 (pt[1].X-pt[0].X)*(pt[1].X-pt[0].X)); 05048 args.rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+ 05049 (pt[2].X-pt[0].X)*(pt[2].X-pt[0].X)); 05050 05051 get_font_hfont(graphics, font, &gdifont); 05052 oldfont = SelectObject(hdc, gdifont); 05053 05054 bounds->X = rect->X; 05055 bounds->Y = rect->Y; 05056 bounds->Width = 0.0; 05057 bounds->Height = 0.0; 05058 05059 args.bounds = bounds; 05060 args.codepointsfitted = codepointsfitted; 05061 args.linesfilled = linesfilled; 05062 05063 gdip_format_string(hdc, string, length, font, rect, format, 05064 measure_string_callback, &args); 05065 05066 SelectObject(hdc, oldfont); 05067 DeleteObject(gdifont); 05068 05069 if (temp_hdc) 05070 DeleteDC(temp_hdc); 05071 05072 return Ok; 05073 } 05074 05075 struct draw_string_args { 05076 GpGraphics *graphics; 05077 GDIPCONST GpBrush *brush; 05078 REAL x, y, rel_width, rel_height, ascent; 05079 }; 05080 05081 static GpStatus draw_string_callback(HDC hdc, 05082 GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font, 05083 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, 05084 INT lineno, const RectF *bounds, INT *underlined_indexes, 05085 INT underlined_index_count, void *user_data) 05086 { 05087 struct draw_string_args *args = user_data; 05088 PointF position; 05089 GpStatus stat; 05090 05091 position.X = args->x + bounds->X / args->rel_width; 05092 position.Y = args->y + bounds->Y / args->rel_height + args->ascent; 05093 05094 stat = GdipDrawDriverString(args->graphics, &string[index], length, font, 05095 args->brush, &position, 05096 DriverStringOptionsCmapLookup|DriverStringOptionsRealizedAdvance, NULL); 05097 05098 if (stat == Ok && underlined_index_count) 05099 { 05100 OUTLINETEXTMETRICW otm; 05101 REAL underline_y, underline_height; 05102 int i; 05103 05104 GetOutlineTextMetricsW(hdc, sizeof(otm), &otm); 05105 05106 underline_height = otm.otmsUnderscoreSize / args->rel_height; 05107 underline_y = position.Y - otm.otmsUnderscorePosition / args->rel_height - underline_height / 2; 05108 05109 for (i=0; i<underlined_index_count; i++) 05110 { 05111 REAL start_x, end_x; 05112 SIZE text_size; 05113 INT ofs = underlined_indexes[i] - index; 05114 05115 GetTextExtentExPointW(hdc, string + index, ofs, INT_MAX, NULL, NULL, &text_size); 05116 start_x = text_size.cx / args->rel_width; 05117 05118 GetTextExtentExPointW(hdc, string + index, ofs+1, INT_MAX, NULL, NULL, &text_size); 05119 end_x = text_size.cx / args->rel_width; 05120 05121 GdipFillRectangle(args->graphics, (GpBrush*)args->brush, position.X+start_x, underline_y, end_x-start_x, underline_height); 05122 } 05123 } 05124 05125 return stat; 05126 } 05127 05128 GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string, 05129 INT length, GDIPCONST GpFont *font, GDIPCONST RectF *rect, 05130 GDIPCONST GpStringFormat *format, GDIPCONST GpBrush *brush) 05131 { 05132 HRGN rgn = NULL; 05133 HFONT gdifont; 05134 GpPointF pt[3], rectcpy[4]; 05135 POINT corners[4]; 05136 REAL rel_width, rel_height; 05137 INT save_state; 05138 REAL offsety = 0.0; 05139 struct draw_string_args args; 05140 RectF scaled_rect; 05141 HDC hdc, temp_hdc=NULL; 05142 TEXTMETRICW textmetric; 05143 05144 TRACE("(%p, %s, %i, %p, %s, %p, %p)\n", graphics, debugstr_wn(string, length), 05145 length, font, debugstr_rectf(rect), format, brush); 05146 05147 if(!graphics || !string || !font || !brush || !rect) 05148 return InvalidParameter; 05149 05150 if(graphics->hdc) 05151 { 05152 hdc = graphics->hdc; 05153 } 05154 else 05155 { 05156 hdc = temp_hdc = CreateCompatibleDC(0); 05157 } 05158 05159 if(format){ 05160 TRACE("may be ignoring some format flags: attr %x\n", format->attr); 05161 05162 /* Should be no need to explicitly test for StringAlignmentNear as 05163 * that is default behavior if no alignment is passed. */ 05164 if(format->vertalign != StringAlignmentNear){ 05165 RectF bounds; 05166 GdipMeasureString(graphics, string, length, font, rect, format, &bounds, 0, 0); 05167 05168 if(format->vertalign == StringAlignmentCenter) 05169 offsety = (rect->Height - bounds.Height) / 2; 05170 else if(format->vertalign == StringAlignmentFar) 05171 offsety = (rect->Height - bounds.Height); 05172 } 05173 } 05174 05175 save_state = SaveDC(hdc); 05176 05177 pt[0].X = 0.0; 05178 pt[0].Y = 0.0; 05179 pt[1].X = 1.0; 05180 pt[1].Y = 0.0; 05181 pt[2].X = 0.0; 05182 pt[2].Y = 1.0; 05183 GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3); 05184 rel_width = sqrt((pt[1].Y-pt[0].Y)*(pt[1].Y-pt[0].Y)+ 05185 (pt[1].X-pt[0].X)*(pt[1].X-pt[0].X)); 05186 rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+ 05187 (pt[2].X-pt[0].X)*(pt[2].X-pt[0].X)); 05188 05189 rectcpy[3].X = rectcpy[0].X = rect->X; 05190 rectcpy[1].Y = rectcpy[0].Y = rect->Y + offsety; 05191 rectcpy[2].X = rectcpy[1].X = rect->X + rect->Width; 05192 rectcpy[3].Y = rectcpy[2].Y = rect->Y + offsety + rect->Height; 05193 transform_and_round_points(graphics, corners, rectcpy, 4); 05194 05195 scaled_rect.X = 0.0; 05196 scaled_rect.Y = 0.0; 05197 scaled_rect.Width = rel_width * rect->Width; 05198 scaled_rect.Height = rel_height * rect->Height; 05199 05200 if (roundr(scaled_rect.Width) != 0 && roundr(scaled_rect.Height) != 0) 05201 { 05202 /* FIXME: If only the width or only the height is 0, we should probably still clip */ 05203 rgn = CreatePolygonRgn(corners, 4, ALTERNATE); 05204 SelectClipRgn(hdc, rgn); 05205 } 05206 05207 get_font_hfont(graphics, font, &gdifont); 05208 SelectObject(hdc, gdifont); 05209 05210 args.graphics = graphics; 05211 args.brush = brush; 05212 05213 args.x = rect->X; 05214 args.y = rect->Y + offsety; 05215 05216 args.rel_width = rel_width; 05217 args.rel_height = rel_height; 05218 05219 GetTextMetricsW(hdc, &textmetric); 05220 args.ascent = textmetric.tmAscent / rel_height; 05221 05222 gdip_format_string(hdc, string, length, font, &scaled_rect, format, 05223 draw_string_callback, &args); 05224 05225 DeleteObject(rgn); 05226 DeleteObject(gdifont); 05227 05228 RestoreDC(hdc, save_state); 05229 05230 DeleteDC(temp_hdc); 05231 05232 return Ok; 05233 } 05234 05235 GpStatus WINGDIPAPI GdipResetClip(GpGraphics *graphics) 05236 { 05237 TRACE("(%p)\n", graphics); 05238 05239 if(!graphics) 05240 return InvalidParameter; 05241 05242 if(graphics->busy) 05243 return ObjectBusy; 05244 05245 return GdipSetInfinite(graphics->clip); 05246 } 05247 05248 GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics *graphics) 05249 { 05250 TRACE("(%p)\n", graphics); 05251 05252 if(!graphics) 05253 return InvalidParameter; 05254 05255 if(graphics->busy) 05256 return ObjectBusy; 05257 05258 graphics->worldtrans->matrix[0] = 1.0; 05259 graphics->worldtrans->matrix[1] = 0.0; 05260 graphics->worldtrans->matrix[2] = 0.0; 05261 graphics->worldtrans->matrix[3] = 1.0; 05262 graphics->worldtrans->matrix[4] = 0.0; 05263 graphics->worldtrans->matrix[5] = 0.0; 05264 05265 return Ok; 05266 } 05267 05268 GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState state) 05269 { 05270 return GdipEndContainer(graphics, state); 05271 } 05272 05273 GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle, 05274 GpMatrixOrder order) 05275 { 05276 TRACE("(%p, %.2f, %d)\n", graphics, angle, order); 05277 05278 if(!graphics) 05279 return InvalidParameter; 05280 05281 if(graphics->busy) 05282 return ObjectBusy; 05283 05284 return GdipRotateMatrix(graphics->worldtrans, angle, order); 05285 } 05286 05287 GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics *graphics, GraphicsState *state) 05288 { 05289 return GdipBeginContainer2(graphics, state); 05290 } 05291 05292 GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics, 05293 GraphicsContainer *state) 05294 { 05295 GraphicsContainerItem *container; 05296 GpStatus sts; 05297 05298 TRACE("(%p, %p)\n", graphics, state); 05299 05300 if(!graphics || !state) 05301 return InvalidParameter; 05302 05303 sts = init_container(&container, graphics); 05304 if(sts != Ok) 05305 return sts; 05306 05307 list_add_head(&graphics->containers, &container->entry); 05308 *state = graphics->contid = container->contid; 05309 05310 return Ok; 05311 } 05312 05313 GpStatus WINGDIPAPI GdipBeginContainer(GpGraphics *graphics, GDIPCONST GpRectF *dstrect, GDIPCONST GpRectF *srcrect, GpUnit unit, GraphicsContainer *state) 05314 { 05315 FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state); 05316 return NotImplemented; 05317 } 05318 05319 GpStatus WINGDIPAPI GdipBeginContainerI(GpGraphics *graphics, GDIPCONST GpRect *dstrect, GDIPCONST GpRect *srcrect, GpUnit unit, GraphicsContainer *state) 05320 { 05321 FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state); 05322 return NotImplemented; 05323 } 05324 05325 GpStatus WINGDIPAPI GdipComment(GpGraphics *graphics, UINT sizeData, GDIPCONST BYTE *data) 05326 { 05327 FIXME("(%p, %d, %p): stub\n", graphics, sizeData, data); 05328 return NotImplemented; 05329 } 05330 05331 GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsContainer state) 05332 { 05333 GpStatus sts; 05334 GraphicsContainerItem *container, *container2; 05335 05336 TRACE("(%p, %x)\n", graphics, state); 05337 05338 if(!graphics) 05339 return InvalidParameter; 05340 05341 LIST_FOR_EACH_ENTRY(container, &graphics->containers, GraphicsContainerItem, entry){ 05342 if(container->contid == state) 05343 break; 05344 } 05345 05346 /* did not find a matching container */ 05347 if(&container->entry == &graphics->containers) 05348 return Ok; 05349 05350 sts = restore_container(graphics, container); 05351 if(sts != Ok) 05352 return sts; 05353 05354 /* remove all of the containers on top of the found container */ 05355 LIST_FOR_EACH_ENTRY_SAFE(container, container2, &graphics->containers, GraphicsContainerItem, entry){ 05356 if(container->contid == state) 05357 break; 05358 list_remove(&container->entry); 05359 delete_container(container); 05360 } 05361 05362 list_remove(&container->entry); 05363 delete_container(container); 05364 05365 return Ok; 05366 } 05367 05368 GpStatus WINGDIPAPI GdipScaleWorldTransform(GpGraphics *graphics, REAL sx, 05369 REAL sy, GpMatrixOrder order) 05370 { 05371 TRACE("(%p, %.2f, %.2f, %d)\n", graphics, sx, sy, order); 05372 05373 if(!graphics) 05374 return InvalidParameter; 05375 05376 if(graphics->busy) 05377 return ObjectBusy; 05378 05379 return GdipScaleMatrix(graphics->worldtrans, sx, sy, order); 05380 } 05381 05382 GpStatus WINGDIPAPI GdipSetClipGraphics(GpGraphics *graphics, GpGraphics *srcgraphics, 05383 CombineMode mode) 05384 { 05385 TRACE("(%p, %p, %d)\n", graphics, srcgraphics, mode); 05386 05387 if(!graphics || !srcgraphics) 05388 return InvalidParameter; 05389 05390 return GdipCombineRegionRegion(graphics->clip, srcgraphics->clip, mode); 05391 } 05392 05393 GpStatus WINGDIPAPI GdipSetCompositingMode(GpGraphics *graphics, 05394 CompositingMode mode) 05395 { 05396 TRACE("(%p, %d)\n", graphics, mode); 05397 05398 if(!graphics) 05399 return InvalidParameter; 05400 05401 if(graphics->busy) 05402 return ObjectBusy; 05403 05404 graphics->compmode = mode; 05405 05406 return Ok; 05407 } 05408 05409 GpStatus WINGDIPAPI GdipSetCompositingQuality(GpGraphics *graphics, 05410 CompositingQuality quality) 05411 { 05412 TRACE("(%p, %d)\n", graphics, quality); 05413 05414 if(!graphics) 05415 return InvalidParameter; 05416 05417 if(graphics->busy) 05418 return ObjectBusy; 05419 05420 graphics->compqual = quality; 05421 05422 return Ok; 05423 } 05424 05425 GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics *graphics, 05426 InterpolationMode mode) 05427 { 05428 TRACE("(%p, %d)\n", graphics, mode); 05429 05430 if(!graphics || mode == InterpolationModeInvalid || mode > InterpolationModeHighQualityBicubic) 05431 return InvalidParameter; 05432 05433 if(graphics->busy) 05434 return ObjectBusy; 05435 05436 if (mode == InterpolationModeDefault || mode == InterpolationModeLowQuality) 05437 mode = InterpolationModeBilinear; 05438 05439 if (mode == InterpolationModeHighQuality) 05440 mode = InterpolationModeHighQualityBicubic; 05441 05442 graphics->interpolation = mode; 05443 05444 return Ok; 05445 } 05446 05447 GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale) 05448 { 05449 TRACE("(%p, %.2f)\n", graphics, scale); 05450 05451 if(!graphics || (scale <= 0.0)) 05452 return InvalidParameter; 05453 05454 if(graphics->busy) 05455 return ObjectBusy; 05456 05457 graphics->scale = scale; 05458 05459 return Ok; 05460 } 05461 05462 GpStatus WINGDIPAPI GdipSetPageUnit(GpGraphics *graphics, GpUnit unit) 05463 { 05464 TRACE("(%p, %d)\n", graphics, unit); 05465 05466 if(!graphics) 05467 return InvalidParameter; 05468 05469 if(graphics->busy) 05470 return ObjectBusy; 05471 05472 if(unit == UnitWorld) 05473 return InvalidParameter; 05474 05475 graphics->unit = unit; 05476 05477 return Ok; 05478 } 05479 05480 GpStatus WINGDIPAPI GdipSetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode 05481 mode) 05482 { 05483 TRACE("(%p, %d)\n", graphics, mode); 05484 05485 if(!graphics) 05486 return InvalidParameter; 05487 05488 if(graphics->busy) 05489 return ObjectBusy; 05490 05491 graphics->pixeloffset = mode; 05492 05493 return Ok; 05494 } 05495 05496 GpStatus WINGDIPAPI GdipSetRenderingOrigin(GpGraphics *graphics, INT x, INT y) 05497 { 05498 static int calls; 05499 05500 TRACE("(%p,%i,%i)\n", graphics, x, y); 05501 05502 if (!(calls++)) 05503 FIXME("value is unused in rendering\n"); 05504 05505 if (!graphics) 05506 return InvalidParameter; 05507 05508 graphics->origin_x = x; 05509 graphics->origin_y = y; 05510 05511 return Ok; 05512 } 05513 05514 GpStatus WINGDIPAPI GdipGetRenderingOrigin(GpGraphics *graphics, INT *x, INT *y) 05515 { 05516 TRACE("(%p,%p,%p)\n", graphics, x, y); 05517 05518 if (!graphics || !x || !y) 05519 return InvalidParameter; 05520 05521 *x = graphics->origin_x; 05522 *y = graphics->origin_y; 05523 05524 return Ok; 05525 } 05526 05527 GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode mode) 05528 { 05529 TRACE("(%p, %d)\n", graphics, mode); 05530 05531 if(!graphics) 05532 return InvalidParameter; 05533 05534 if(graphics->busy) 05535 return ObjectBusy; 05536 05537 graphics->smoothing = mode; 05538 05539 return Ok; 05540 } 05541 05542 GpStatus WINGDIPAPI GdipSetTextContrast(GpGraphics *graphics, UINT contrast) 05543 { 05544 TRACE("(%p, %d)\n", graphics, contrast); 05545 05546 if(!graphics) 05547 return InvalidParameter; 05548 05549 graphics->textcontrast = contrast; 05550 05551 return Ok; 05552 } 05553 05554 GpStatus WINGDIPAPI GdipSetTextRenderingHint(GpGraphics *graphics, 05555 TextRenderingHint hint) 05556 { 05557 TRACE("(%p, %d)\n", graphics, hint); 05558 05559 if(!graphics || hint > TextRenderingHintClearTypeGridFit) 05560 return InvalidParameter; 05561 05562 if(graphics->busy) 05563 return ObjectBusy; 05564 05565 graphics->texthint = hint; 05566 05567 return Ok; 05568 } 05569 05570 GpStatus WINGDIPAPI GdipSetWorldTransform(GpGraphics *graphics, GpMatrix *matrix) 05571 { 05572 TRACE("(%p, %p)\n", graphics, matrix); 05573 05574 if(!graphics || !matrix) 05575 return InvalidParameter; 05576 05577 if(graphics->busy) 05578 return ObjectBusy; 05579 05580 GdipDeleteMatrix(graphics->worldtrans); 05581 return GdipCloneMatrix(matrix, &graphics->worldtrans); 05582 } 05583 05584 GpStatus WINGDIPAPI GdipTranslateWorldTransform(GpGraphics *graphics, REAL dx, 05585 REAL dy, GpMatrixOrder order) 05586 { 05587 TRACE("(%p, %.2f, %.2f, %d)\n", graphics, dx, dy, order); 05588 05589 if(!graphics) 05590 return InvalidParameter; 05591 05592 if(graphics->busy) 05593 return ObjectBusy; 05594 05595 return GdipTranslateMatrix(graphics->worldtrans, dx, dy, order); 05596 } 05597 05598 /***************************************************************************** 05599 * GdipSetClipHrgn [GDIPLUS.@] 05600 */ 05601 GpStatus WINGDIPAPI GdipSetClipHrgn(GpGraphics *graphics, HRGN hrgn, CombineMode mode) 05602 { 05603 GpRegion *region; 05604 GpStatus status; 05605 05606 TRACE("(%p, %p, %d)\n", graphics, hrgn, mode); 05607 05608 if(!graphics) 05609 return InvalidParameter; 05610 05611 status = GdipCreateRegionHrgn(hrgn, ®ion); 05612 if(status != Ok) 05613 return status; 05614 05615 status = GdipSetClipRegion(graphics, region, mode); 05616 05617 GdipDeleteRegion(region); 05618 return status; 05619 } 05620 05621 GpStatus WINGDIPAPI GdipSetClipPath(GpGraphics *graphics, GpPath *path, CombineMode mode) 05622 { 05623 TRACE("(%p, %p, %d)\n", graphics, path, mode); 05624 05625 if(!graphics) 05626 return InvalidParameter; 05627 05628 if(graphics->busy) 05629 return ObjectBusy; 05630 05631 return GdipCombineRegionPath(graphics->clip, path, mode); 05632 } 05633 05634 GpStatus WINGDIPAPI GdipSetClipRect(GpGraphics *graphics, REAL x, REAL y, 05635 REAL width, REAL height, 05636 CombineMode mode) 05637 { 05638 GpRectF rect; 05639 05640 TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %d)\n", graphics, x, y, width, height, mode); 05641 05642 if(!graphics) 05643 return InvalidParameter; 05644 05645 if(graphics->busy) 05646 return ObjectBusy; 05647 05648 rect.X = x; 05649 rect.Y = y; 05650 rect.Width = width; 05651 rect.Height = height; 05652 05653 return GdipCombineRegionRect(graphics->clip, &rect, mode); 05654 } 05655 05656 GpStatus WINGDIPAPI GdipSetClipRectI(GpGraphics *graphics, INT x, INT y, 05657 INT width, INT height, 05658 CombineMode mode) 05659 { 05660 TRACE("(%p, %d, %d, %d, %d, %d)\n", graphics, x, y, width, height, mode); 05661 05662 if(!graphics) 05663 return InvalidParameter; 05664 05665 if(graphics->busy) 05666 return ObjectBusy; 05667 05668 return GdipSetClipRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, mode); 05669 } 05670 05671 GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region, 05672 CombineMode mode) 05673 { 05674 TRACE("(%p, %p, %d)\n", graphics, region, mode); 05675 05676 if(!graphics || !region) 05677 return InvalidParameter; 05678 05679 if(graphics->busy) 05680 return ObjectBusy; 05681 05682 return GdipCombineRegionRegion(graphics->clip, region, mode); 05683 } 05684 05685 GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile, 05686 UINT limitDpi) 05687 { 05688 static int calls; 05689 05690 TRACE("(%p,%u)\n", metafile, limitDpi); 05691 05692 if(!(calls++)) 05693 FIXME("not implemented\n"); 05694 05695 return NotImplemented; 05696 } 05697 05698 GpStatus WINGDIPAPI GdipDrawPolygon(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPointF *points, 05699 INT count) 05700 { 05701 INT save_state; 05702 POINT *pti; 05703 05704 TRACE("(%p, %p, %d)\n", graphics, points, count); 05705 05706 if(!graphics || !pen || count<=0) 05707 return InvalidParameter; 05708 05709 if(graphics->busy) 05710 return ObjectBusy; 05711 05712 if (!graphics->hdc) 05713 { 05714 FIXME("graphics object has no HDC\n"); 05715 return Ok; 05716 } 05717 05718 pti = GdipAlloc(sizeof(POINT) * count); 05719 05720 save_state = prepare_dc(graphics, pen); 05721 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH)); 05722 05723 transform_and_round_points(graphics, pti, (GpPointF*)points, count); 05724 Polygon(graphics->hdc, pti, count); 05725 05726 restore_dc(graphics, save_state); 05727 GdipFree(pti); 05728 05729 return Ok; 05730 } 05731 05732 GpStatus WINGDIPAPI GdipDrawPolygonI(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPoint *points, 05733 INT count) 05734 { 05735 GpStatus ret; 05736 GpPointF *ptf; 05737 INT i; 05738 05739 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 05740 05741 if(count<=0) return InvalidParameter; 05742 ptf = GdipAlloc(sizeof(GpPointF) * count); 05743 05744 for(i = 0;i < count; i++){ 05745 ptf[i].X = (REAL)points[i].X; 05746 ptf[i].Y = (REAL)points[i].Y; 05747 } 05748 05749 ret = GdipDrawPolygon(graphics,pen,ptf,count); 05750 GdipFree(ptf); 05751 05752 return ret; 05753 } 05754 05755 GpStatus WINGDIPAPI GdipGetDpiX(GpGraphics *graphics, REAL* dpi) 05756 { 05757 TRACE("(%p, %p)\n", graphics, dpi); 05758 05759 if(!graphics || !dpi) 05760 return InvalidParameter; 05761 05762 if(graphics->busy) 05763 return ObjectBusy; 05764 05765 if (graphics->image) 05766 *dpi = graphics->image->xres; 05767 else 05768 *dpi = (REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSX); 05769 05770 return Ok; 05771 } 05772 05773 GpStatus WINGDIPAPI GdipGetDpiY(GpGraphics *graphics, REAL* dpi) 05774 { 05775 TRACE("(%p, %p)\n", graphics, dpi); 05776 05777 if(!graphics || !dpi) 05778 return InvalidParameter; 05779 05780 if(graphics->busy) 05781 return ObjectBusy; 05782 05783 if (graphics->image) 05784 *dpi = graphics->image->yres; 05785 else 05786 *dpi = (REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSY); 05787 05788 return Ok; 05789 } 05790 05791 GpStatus WINGDIPAPI GdipMultiplyWorldTransform(GpGraphics *graphics, GDIPCONST GpMatrix *matrix, 05792 GpMatrixOrder order) 05793 { 05794 GpMatrix m; 05795 GpStatus ret; 05796 05797 TRACE("(%p, %p, %d)\n", graphics, matrix, order); 05798 05799 if(!graphics || !matrix) 05800 return InvalidParameter; 05801 05802 if(graphics->busy) 05803 return ObjectBusy; 05804 05805 m = *(graphics->worldtrans); 05806 05807 ret = GdipMultiplyMatrix(&m, matrix, order); 05808 if(ret == Ok) 05809 *(graphics->worldtrans) = m; 05810 05811 return ret; 05812 } 05813 05814 /* Color used to fill bitmaps so we can tell which parts have been drawn over by gdi32. */ 05815 static const COLORREF DC_BACKGROUND_KEY = 0x0c0b0d; 05816 05817 GpStatus WINGDIPAPI GdipGetDC(GpGraphics *graphics, HDC *hdc) 05818 { 05819 GpStatus stat=Ok; 05820 05821 TRACE("(%p, %p)\n", graphics, hdc); 05822 05823 if(!graphics || !hdc) 05824 return InvalidParameter; 05825 05826 if(graphics->busy) 05827 return ObjectBusy; 05828 05829 if (graphics->image && graphics->image->type == ImageTypeMetafile) 05830 { 05831 stat = METAFILE_GetDC((GpMetafile*)graphics->image, hdc); 05832 } 05833 else if (!graphics->hdc || 05834 (graphics->image && graphics->image->type == ImageTypeBitmap && ((GpBitmap*)graphics->image)->format & PixelFormatAlpha)) 05835 { 05836 /* Create a fake HDC and fill it with a constant color. */ 05837 HDC temp_hdc; 05838 HBITMAP hbitmap; 05839 GpRectF bounds; 05840 BITMAPINFOHEADER bmih; 05841 int i; 05842 05843 stat = get_graphics_bounds(graphics, &bounds); 05844 if (stat != Ok) 05845 return stat; 05846 05847 graphics->temp_hbitmap_width = bounds.Width; 05848 graphics->temp_hbitmap_height = bounds.Height; 05849 05850 bmih.biSize = sizeof(bmih); 05851 bmih.biWidth = graphics->temp_hbitmap_width; 05852 bmih.biHeight = -graphics->temp_hbitmap_height; 05853 bmih.biPlanes = 1; 05854 bmih.biBitCount = 32; 05855 bmih.biCompression = BI_RGB; 05856 bmih.biSizeImage = 0; 05857 bmih.biXPelsPerMeter = 0; 05858 bmih.biYPelsPerMeter = 0; 05859 bmih.biClrUsed = 0; 05860 bmih.biClrImportant = 0; 05861 05862 hbitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, 05863 (void**)&graphics->temp_bits, NULL, 0); 05864 if (!hbitmap) 05865 return GenericError; 05866 05867 temp_hdc = CreateCompatibleDC(0); 05868 if (!temp_hdc) 05869 { 05870 DeleteObject(hbitmap); 05871 return GenericError; 05872 } 05873 05874 for (i=0; i<(graphics->temp_hbitmap_width * graphics->temp_hbitmap_height); i++) 05875 ((DWORD*)graphics->temp_bits)[i] = DC_BACKGROUND_KEY; 05876 05877 SelectObject(temp_hdc, hbitmap); 05878 05879 graphics->temp_hbitmap = hbitmap; 05880 *hdc = graphics->temp_hdc = temp_hdc; 05881 } 05882 else 05883 { 05884 *hdc = graphics->hdc; 05885 } 05886 05887 if (stat == Ok) 05888 graphics->busy = TRUE; 05889 05890 return stat; 05891 } 05892 05893 GpStatus WINGDIPAPI GdipReleaseDC(GpGraphics *graphics, HDC hdc) 05894 { 05895 GpStatus stat=Ok; 05896 05897 TRACE("(%p, %p)\n", graphics, hdc); 05898 05899 if(!graphics || !hdc || !graphics->busy) 05900 return InvalidParameter; 05901 05902 if (graphics->image && graphics->image->type == ImageTypeMetafile) 05903 { 05904 stat = METAFILE_ReleaseDC((GpMetafile*)graphics->image, hdc); 05905 } 05906 else if (graphics->temp_hdc == hdc) 05907 { 05908 DWORD* pos; 05909 int i; 05910 05911 /* Find the pixels that have changed, and mark them as opaque. */ 05912 pos = (DWORD*)graphics->temp_bits; 05913 for (i=0; i<(graphics->temp_hbitmap_width * graphics->temp_hbitmap_height); i++) 05914 { 05915 if (*pos != DC_BACKGROUND_KEY) 05916 { 05917 *pos |= 0xff000000; 05918 } 05919 pos++; 05920 } 05921 05922 /* Write the changed pixels to the real target. */ 05923 alpha_blend_pixels(graphics, 0, 0, graphics->temp_bits, 05924 graphics->temp_hbitmap_width, graphics->temp_hbitmap_height, 05925 graphics->temp_hbitmap_width * 4); 05926 05927 /* Clean up. */ 05928 DeleteDC(graphics->temp_hdc); 05929 DeleteObject(graphics->temp_hbitmap); 05930 graphics->temp_hdc = NULL; 05931 graphics->temp_hbitmap = NULL; 05932 } 05933 else if (hdc != graphics->hdc) 05934 { 05935 stat = InvalidParameter; 05936 } 05937 05938 if (stat == Ok) 05939 graphics->busy = FALSE; 05940 05941 return stat; 05942 } 05943 05944 GpStatus WINGDIPAPI GdipGetClip(GpGraphics *graphics, GpRegion *region) 05945 { 05946 GpRegion *clip; 05947 GpStatus status; 05948 05949 TRACE("(%p, %p)\n", graphics, region); 05950 05951 if(!graphics || !region) 05952 return InvalidParameter; 05953 05954 if(graphics->busy) 05955 return ObjectBusy; 05956 05957 if((status = GdipCloneRegion(graphics->clip, &clip)) != Ok) 05958 return status; 05959 05960 /* free everything except root node and header */ 05961 delete_element(®ion->node); 05962 memcpy(region, clip, sizeof(GpRegion)); 05963 GdipFree(clip); 05964 05965 return Ok; 05966 } 05967 05968 static GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space, 05969 GpCoordinateSpace src_space, GpMatrix **matrix) 05970 { 05971 GpStatus stat = GdipCreateMatrix(matrix); 05972 REAL unitscale; 05973 05974 if (dst_space != src_space && stat == Ok) 05975 { 05976 unitscale = convert_unit(graphics_res(graphics), graphics->unit); 05977 05978 if(graphics->unit != UnitDisplay) 05979 unitscale *= graphics->scale; 05980 05981 /* transform from src_space to CoordinateSpacePage */ 05982 switch (src_space) 05983 { 05984 case CoordinateSpaceWorld: 05985 GdipMultiplyMatrix(*matrix, graphics->worldtrans, MatrixOrderAppend); 05986 break; 05987 case CoordinateSpacePage: 05988 break; 05989 case CoordinateSpaceDevice: 05990 GdipScaleMatrix(*matrix, 1.0/unitscale, 1.0/unitscale, MatrixOrderAppend); 05991 break; 05992 } 05993 05994 /* transform from CoordinateSpacePage to dst_space */ 05995 switch (dst_space) 05996 { 05997 case CoordinateSpaceWorld: 05998 { 05999 GpMatrix *inverted_transform; 06000 stat = GdipCloneMatrix(graphics->worldtrans, &inverted_transform); 06001 if (stat == Ok) 06002 { 06003 stat = GdipInvertMatrix(inverted_transform); 06004 if (stat == Ok) 06005 GdipMultiplyMatrix(*matrix, inverted_transform, MatrixOrderAppend); 06006 GdipDeleteMatrix(inverted_transform); 06007 } 06008 break; 06009 } 06010 case CoordinateSpacePage: 06011 break; 06012 case CoordinateSpaceDevice: 06013 GdipScaleMatrix(*matrix, unitscale, unitscale, MatrixOrderAppend); 06014 break; 06015 } 06016 } 06017 return stat; 06018 } 06019 06020 GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace dst_space, 06021 GpCoordinateSpace src_space, GpPointF *points, INT count) 06022 { 06023 GpMatrix *matrix; 06024 GpStatus stat; 06025 06026 if(!graphics || !points || count <= 0) 06027 return InvalidParameter; 06028 06029 if(graphics->busy) 06030 return ObjectBusy; 06031 06032 TRACE("(%p, %d, %d, %p, %d)\n", graphics, dst_space, src_space, points, count); 06033 06034 if (src_space == dst_space) return Ok; 06035 06036 stat = get_graphics_transform(graphics, dst_space, src_space, &matrix); 06037 06038 if (stat == Ok) 06039 { 06040 stat = GdipTransformMatrixPoints(matrix, points, count); 06041 06042 GdipDeleteMatrix(matrix); 06043 } 06044 06045 return stat; 06046 } 06047 06048 GpStatus WINGDIPAPI GdipTransformPointsI(GpGraphics *graphics, GpCoordinateSpace dst_space, 06049 GpCoordinateSpace src_space, GpPoint *points, INT count) 06050 { 06051 GpPointF *pointsF; 06052 GpStatus ret; 06053 INT i; 06054 06055 TRACE("(%p, %d, %d, %p, %d)\n", graphics, dst_space, src_space, points, count); 06056 06057 if(count <= 0) 06058 return InvalidParameter; 06059 06060 pointsF = GdipAlloc(sizeof(GpPointF) * count); 06061 if(!pointsF) 06062 return OutOfMemory; 06063 06064 for(i = 0; i < count; i++){ 06065 pointsF[i].X = (REAL)points[i].X; 06066 pointsF[i].Y = (REAL)points[i].Y; 06067 } 06068 06069 ret = GdipTransformPoints(graphics, dst_space, src_space, pointsF, count); 06070 06071 if(ret == Ok) 06072 for(i = 0; i < count; i++){ 06073 points[i].X = roundr(pointsF[i].X); 06074 points[i].Y = roundr(pointsF[i].Y); 06075 } 06076 GdipFree(pointsF); 06077 06078 return ret; 06079 } 06080 06081 HPALETTE WINGDIPAPI GdipCreateHalftonePalette(void) 06082 { 06083 static int calls; 06084 06085 TRACE("\n"); 06086 06087 if (!calls++) 06088 FIXME("stub\n"); 06089 06090 return NULL; 06091 } 06092 06093 /***************************************************************************** 06094 * GdipTranslateClip [GDIPLUS.@] 06095 */ 06096 GpStatus WINGDIPAPI GdipTranslateClip(GpGraphics *graphics, REAL dx, REAL dy) 06097 { 06098 TRACE("(%p, %.2f, %.2f)\n", graphics, dx, dy); 06099 06100 if(!graphics) 06101 return InvalidParameter; 06102 06103 if(graphics->busy) 06104 return ObjectBusy; 06105 06106 return GdipTranslateRegion(graphics->clip, dx, dy); 06107 } 06108 06109 /***************************************************************************** 06110 * GdipTranslateClipI [GDIPLUS.@] 06111 */ 06112 GpStatus WINGDIPAPI GdipTranslateClipI(GpGraphics *graphics, INT dx, INT dy) 06113 { 06114 TRACE("(%p, %d, %d)\n", graphics, dx, dy); 06115 06116 if(!graphics) 06117 return InvalidParameter; 06118 06119 if(graphics->busy) 06120 return ObjectBusy; 06121 06122 return GdipTranslateRegion(graphics->clip, (REAL)dx, (REAL)dy); 06123 } 06124 06125 06126 /***************************************************************************** 06127 * GdipMeasureDriverString [GDIPLUS.@] 06128 */ 06129 GpStatus WINGDIPAPI GdipMeasureDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length, 06130 GDIPCONST GpFont *font, GDIPCONST PointF *positions, 06131 INT flags, GDIPCONST GpMatrix *matrix, RectF *boundingBox) 06132 { 06133 static const INT unsupported_flags = ~(DriverStringOptionsCmapLookup|DriverStringOptionsRealizedAdvance); 06134 HFONT hfont; 06135 HDC hdc; 06136 REAL min_x, min_y, max_x, max_y, x, y; 06137 int i; 06138 TEXTMETRICW textmetric; 06139 const WORD *glyph_indices; 06140 WORD *dynamic_glyph_indices=NULL; 06141 REAL rel_width, rel_height, ascent, descent; 06142 GpPointF pt[3]; 06143 06144 TRACE("(%p %p %d %p %p %d %p %p)\n", graphics, text, length, font, positions, flags, matrix, boundingBox); 06145 06146 if (!graphics || !text || !font || !positions || !boundingBox) 06147 return InvalidParameter; 06148 06149 if (length == -1) 06150 length = strlenW(text); 06151 06152 if (length == 0) 06153 { 06154 boundingBox->X = 0.0; 06155 boundingBox->Y = 0.0; 06156 boundingBox->Width = 0.0; 06157 boundingBox->Height = 0.0; 06158 } 06159 06160 if (flags & unsupported_flags) 06161 FIXME("Ignoring flags %x\n", flags & unsupported_flags); 06162 06163 if (matrix) 06164 FIXME("Ignoring matrix\n"); 06165 06166 get_font_hfont(graphics, font, &hfont); 06167 06168 hdc = CreateCompatibleDC(0); 06169 SelectObject(hdc, hfont); 06170 06171 GetTextMetricsW(hdc, &textmetric); 06172 06173 pt[0].X = 0.0; 06174 pt[0].Y = 0.0; 06175 pt[1].X = 1.0; 06176 pt[1].Y = 0.0; 06177 pt[2].X = 0.0; 06178 pt[2].Y = 1.0; 06179 GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3); 06180 rel_width = sqrt((pt[1].Y-pt[0].Y)*(pt[1].Y-pt[0].Y)+ 06181 (pt[1].X-pt[0].X)*(pt[1].X-pt[0].X)); 06182 rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+ 06183 (pt[2].X-pt[0].X)*(pt[2].X-pt[0].X)); 06184 06185 if (flags & DriverStringOptionsCmapLookup) 06186 { 06187 glyph_indices = dynamic_glyph_indices = GdipAlloc(sizeof(WORD) * length); 06188 if (!glyph_indices) 06189 { 06190 DeleteDC(hdc); 06191 DeleteObject(hfont); 06192 return OutOfMemory; 06193 } 06194 06195 GetGlyphIndicesW(hdc, text, length, dynamic_glyph_indices, 0); 06196 } 06197 else 06198 glyph_indices = text; 06199 06200 min_x = max_x = x = positions[0].X; 06201 min_y = max_y = y = positions[0].Y; 06202 06203 ascent = textmetric.tmAscent / rel_height; 06204 descent = textmetric.tmDescent / rel_height; 06205 06206 for (i=0; i<length; i++) 06207 { 06208 int char_width; 06209 ABC abc; 06210 06211 if (!(flags & DriverStringOptionsRealizedAdvance)) 06212 { 06213 x = positions[i].X; 06214 y = positions[i].Y; 06215 } 06216 06217 GetCharABCWidthsW(hdc, glyph_indices[i], glyph_indices[i], &abc); 06218 char_width = abc.abcA + abc.abcB + abc.abcB; 06219 06220 if (min_y > y - ascent) min_y = y - ascent; 06221 if (max_y < y + descent) max_y = y + descent; 06222 if (min_x > x) min_x = x; 06223 06224 x += char_width / rel_width; 06225 06226 if (max_x < x) max_x = x; 06227 } 06228 06229 GdipFree(dynamic_glyph_indices); 06230 DeleteDC(hdc); 06231 DeleteObject(hfont); 06232 06233 boundingBox->X = min_x; 06234 boundingBox->Y = min_y; 06235 boundingBox->Width = max_x - min_x; 06236 boundingBox->Height = max_y - min_y; 06237 06238 return Ok; 06239 } 06240 06241 static GpStatus GDI32_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length, 06242 GDIPCONST GpFont *font, GDIPCONST GpBrush *brush, 06243 GDIPCONST PointF *positions, INT flags, 06244 GDIPCONST GpMatrix *matrix ) 06245 { 06246 static const INT unsupported_flags = ~(DriverStringOptionsRealizedAdvance|DriverStringOptionsCmapLookup); 06247 INT save_state; 06248 GpPointF pt; 06249 HFONT hfont; 06250 UINT eto_flags=0; 06251 06252 if (flags & unsupported_flags) 06253 FIXME("Ignoring flags %x\n", flags & unsupported_flags); 06254 06255 if (matrix) 06256 FIXME("Ignoring matrix\n"); 06257 06258 if (!(flags & DriverStringOptionsCmapLookup)) 06259 eto_flags |= ETO_GLYPH_INDEX; 06260 06261 save_state = SaveDC(graphics->hdc); 06262 SetBkMode(graphics->hdc, TRANSPARENT); 06263 SetTextColor(graphics->hdc, get_gdi_brush_color(brush)); 06264 06265 pt = positions[0]; 06266 GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &pt, 1); 06267 06268 get_font_hfont(graphics, font, &hfont); 06269 SelectObject(graphics->hdc, hfont); 06270 06271 SetTextAlign(graphics->hdc, TA_BASELINE|TA_LEFT); 06272 06273 ExtTextOutW(graphics->hdc, roundr(pt.X), roundr(pt.Y), eto_flags, NULL, text, length, NULL); 06274 06275 RestoreDC(graphics->hdc, save_state); 06276 06277 DeleteObject(hfont); 06278 06279 return Ok; 06280 } 06281 06282 static GpStatus SOFTWARE_GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length, 06283 GDIPCONST GpFont *font, GDIPCONST GpBrush *brush, 06284 GDIPCONST PointF *positions, INT flags, 06285 GDIPCONST GpMatrix *matrix ) 06286 { 06287 static const INT unsupported_flags = ~(DriverStringOptionsCmapLookup|DriverStringOptionsRealizedAdvance); 06288 GpStatus stat; 06289 PointF *real_positions, real_position; 06290 POINT *pti; 06291 HFONT hfont; 06292 HDC hdc; 06293 int min_x=INT_MAX, min_y=INT_MAX, max_x=INT_MIN, max_y=INT_MIN, i, x, y; 06294 DWORD max_glyphsize=0; 06295 GLYPHMETRICS glyphmetrics; 06296 static const MAT2 identity = {{0,1}, {0,0}, {0,0}, {0,1}}; 06297 BYTE *glyph_mask; 06298 BYTE *text_mask; 06299 int text_mask_stride; 06300 BYTE *pixel_data; 06301 int pixel_data_stride; 06302 GpRect pixel_area; 06303 UINT ggo_flags = GGO_GRAY8_BITMAP; 06304 06305 if (length <= 0) 06306 return Ok; 06307 06308 if (!(flags & DriverStringOptionsCmapLookup)) 06309 ggo_flags |= GGO_GLYPH_INDEX; 06310 06311 if (flags & unsupported_flags) 06312 FIXME("Ignoring flags %x\n", flags & unsupported_flags); 06313 06314 if (matrix) 06315 FIXME("Ignoring matrix\n"); 06316 06317 pti = GdipAlloc(sizeof(POINT) * length); 06318 if (!pti) 06319 return OutOfMemory; 06320 06321 if (flags & DriverStringOptionsRealizedAdvance) 06322 { 06323 real_position = positions[0]; 06324 06325 transform_and_round_points(graphics, pti, &real_position, 1); 06326 } 06327 else 06328 { 06329 real_positions = GdipAlloc(sizeof(PointF) * length); 06330 if (!real_positions) 06331 { 06332 GdipFree(pti); 06333 return OutOfMemory; 06334 } 06335 06336 memcpy(real_positions, positions, sizeof(PointF) * length); 06337 06338 transform_and_round_points(graphics, pti, real_positions, length); 06339 06340 GdipFree(real_positions); 06341 } 06342 06343 get_font_hfont(graphics, font, &hfont); 06344 06345 hdc = CreateCompatibleDC(0); 06346 SelectObject(hdc, hfont); 06347 06348 /* Get the boundaries of the text to be drawn */ 06349 for (i=0; i<length; i++) 06350 { 06351 DWORD glyphsize; 06352 int left, top, right, bottom; 06353 06354 glyphsize = GetGlyphOutlineW(hdc, text[i], ggo_flags, 06355 &glyphmetrics, 0, NULL, &identity); 06356 06357 if (glyphsize == GDI_ERROR) 06358 { 06359 ERR("GetGlyphOutlineW failed\n"); 06360 GdipFree(pti); 06361 DeleteDC(hdc); 06362 DeleteObject(hfont); 06363 return GenericError; 06364 } 06365 06366 if (glyphsize > max_glyphsize) 06367 max_glyphsize = glyphsize; 06368 06369 left = pti[i].x + glyphmetrics.gmptGlyphOrigin.x; 06370 top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y; 06371 right = pti[i].x + glyphmetrics.gmptGlyphOrigin.x + glyphmetrics.gmBlackBoxX; 06372 bottom = pti[i].y - glyphmetrics.gmptGlyphOrigin.y + glyphmetrics.gmBlackBoxY; 06373 06374 if (left < min_x) min_x = left; 06375 if (top < min_y) min_y = top; 06376 if (right > max_x) max_x = right; 06377 if (bottom > max_y) max_y = bottom; 06378 06379 if (i+1 < length && (flags & DriverStringOptionsRealizedAdvance) == DriverStringOptionsRealizedAdvance) 06380 { 06381 pti[i+1].x = pti[i].x + glyphmetrics.gmCellIncX; 06382 pti[i+1].y = pti[i].y + glyphmetrics.gmCellIncY; 06383 } 06384 } 06385 06386 glyph_mask = GdipAlloc(max_glyphsize); 06387 text_mask = GdipAlloc((max_x - min_x) * (max_y - min_y)); 06388 text_mask_stride = max_x - min_x; 06389 06390 if (!(glyph_mask && text_mask)) 06391 { 06392 GdipFree(glyph_mask); 06393 GdipFree(text_mask); 06394 GdipFree(pti); 06395 DeleteDC(hdc); 06396 DeleteObject(hfont); 06397 return OutOfMemory; 06398 } 06399 06400 /* Generate a mask for the text */ 06401 for (i=0; i<length; i++) 06402 { 06403 int left, top, stride; 06404 06405 GetGlyphOutlineW(hdc, text[i], ggo_flags, 06406 &glyphmetrics, max_glyphsize, glyph_mask, &identity); 06407 06408 left = pti[i].x + glyphmetrics.gmptGlyphOrigin.x; 06409 top = pti[i].y - glyphmetrics.gmptGlyphOrigin.y; 06410 stride = (glyphmetrics.gmBlackBoxX + 3) & (~3); 06411 06412 for (y=0; y<glyphmetrics.gmBlackBoxY; y++) 06413 { 06414 BYTE *glyph_val = glyph_mask + y * stride; 06415 BYTE *text_val = text_mask + (left - min_x) + (top - min_y + y) * text_mask_stride; 06416 for (x=0; x<glyphmetrics.gmBlackBoxX; x++) 06417 { 06418 *text_val = min(64, *text_val + *glyph_val); 06419 glyph_val++; 06420 text_val++; 06421 } 06422 } 06423 } 06424 06425 GdipFree(pti); 06426 DeleteDC(hdc); 06427 DeleteObject(hfont); 06428 GdipFree(glyph_mask); 06429 06430 /* get the brush data */ 06431 pixel_data = GdipAlloc(4 * (max_x - min_x) * (max_y - min_y)); 06432 if (!pixel_data) 06433 { 06434 GdipFree(text_mask); 06435 return OutOfMemory; 06436 } 06437 06438 pixel_area.X = min_x; 06439 pixel_area.Y = min_y; 06440 pixel_area.Width = max_x - min_x; 06441 pixel_area.Height = max_y - min_y; 06442 pixel_data_stride = pixel_area.Width * 4; 06443 06444 stat = brush_fill_pixels(graphics, (GpBrush*)brush, (DWORD*)pixel_data, &pixel_area, pixel_area.Width); 06445 if (stat != Ok) 06446 { 06447 GdipFree(text_mask); 06448 GdipFree(pixel_data); 06449 return stat; 06450 } 06451 06452 /* multiply the brush data by the mask */ 06453 for (y=0; y<pixel_area.Height; y++) 06454 { 06455 BYTE *text_val = text_mask + text_mask_stride * y; 06456 BYTE *pixel_val = pixel_data + pixel_data_stride * y + 3; 06457 for (x=0; x<pixel_area.Width; x++) 06458 { 06459 *pixel_val = (*pixel_val) * (*text_val) / 64; 06460 text_val++; 06461 pixel_val+=4; 06462 } 06463 } 06464 06465 GdipFree(text_mask); 06466 06467 /* draw the result */ 06468 stat = alpha_blend_pixels(graphics, min_x, min_y, pixel_data, pixel_area.Width, 06469 pixel_area.Height, pixel_data_stride); 06470 06471 GdipFree(pixel_data); 06472 06473 return stat; 06474 } 06475 06476 /***************************************************************************** 06477 * GdipDrawDriverString [GDIPLUS.@] 06478 */ 06479 GpStatus WINGDIPAPI GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length, 06480 GDIPCONST GpFont *font, GDIPCONST GpBrush *brush, 06481 GDIPCONST PointF *positions, INT flags, 06482 GDIPCONST GpMatrix *matrix ) 06483 { 06484 GpStatus stat=NotImplemented; 06485 06486 TRACE("(%p %s %p %p %p %d %p)\n", graphics, debugstr_wn(text, length), font, brush, positions, flags, matrix); 06487 06488 if (!graphics || !text || !font || !brush || !positions) 06489 return InvalidParameter; 06490 06491 if (length == -1) 06492 length = strlenW(text); 06493 06494 if (graphics->hdc && 06495 ((flags & DriverStringOptionsRealizedAdvance) || length <= 1) && 06496 brush->bt == BrushTypeSolidColor && 06497 (((GpSolidFill*)brush)->color & 0xff000000) == 0xff000000) 06498 stat = GDI32_GdipDrawDriverString(graphics, text, length, font, brush, 06499 positions, flags, matrix); 06500 06501 if (stat == NotImplemented) 06502 stat = SOFTWARE_GdipDrawDriverString(graphics, text, length, font, brush, 06503 positions, flags, matrix); 06504 06505 return stat; 06506 } 06507 06508 GpStatus WINGDIPAPI GdipRecordMetafileStream(IStream *stream, HDC hdc, EmfType type, GDIPCONST GpRect *frameRect, 06509 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile) 06510 { 06511 FIXME("(%p %p %d %p %d %p %p): stub\n", stream, hdc, type, frameRect, frameUnit, desc, metafile); 06512 return NotImplemented; 06513 } 06514 06515 /***************************************************************************** 06516 * GdipIsVisibleClipEmpty [GDIPLUS.@] 06517 */ 06518 GpStatus WINGDIPAPI GdipIsVisibleClipEmpty(GpGraphics *graphics, BOOL *res) 06519 { 06520 GpStatus stat; 06521 GpRegion* rgn; 06522 06523 TRACE("(%p, %p)\n", graphics, res); 06524 06525 if((stat = GdipCreateRegion(&rgn)) != Ok) 06526 return stat; 06527 06528 if((stat = get_visible_clip_region(graphics, rgn)) != Ok) 06529 goto cleanup; 06530 06531 stat = GdipIsEmptyRegion(rgn, graphics, res); 06532 06533 cleanup: 06534 GdipDeleteRegion(rgn); 06535 return stat; 06536 } 06537 06538 GpStatus WINGDIPAPI GdipResetPageTransform(GpGraphics *graphics) 06539 { 06540 static int calls; 06541 06542 TRACE("(%p) stub\n", graphics); 06543 06544 if(!(calls++)) 06545 FIXME("not implemented\n"); 06546 06547 return NotImplemented; 06548 } Generated on Sat May 26 2012 04:22:10 for ReactOS by
1.7.6.1
|