1 /* 2 * Copyright (C) 2007 Google (Evan Stade) 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include <stdarg.h> 20 #include <math.h> 21 #include <limits.h> 22 23 #include "windef.h" 24 #include "winbase.h" 25 #include "winuser.h" 26 #include "wingdi.h" 27 #include "wine/unicode.h" 28 29 #define COBJMACROS 30 #include "objbase.h" 31 #include "ocidl.h" 32 #include "olectl.h" 33 #include "ole2.h" 34 35 #include "winreg.h" 36 #include "shlwapi.h" 37 38 #include "gdiplus.h" 39 #include "gdiplus_private.h" 40 #include "wine/debug.h" 41 #include "wine/list.h" 42 43 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus); 44 45 /* looks-right constants */ 46 #define ANCHOR_WIDTH (2.0) 47 #define MAX_ITERS (50) 48 49 /* Converts angle (in degrees) to x/y coordinates */ 50 static void deg2xy(REAL angle, REAL x_0, REAL y_0, REAL *x, REAL *y) 51 { 52 REAL radAngle, hypotenuse; 53 54 radAngle = deg2rad(angle); 55 hypotenuse = 50.0; /* arbitrary */ 56 57 *x = x_0 + cos(radAngle) * hypotenuse; 58 *y = y_0 + sin(radAngle) * hypotenuse; 59 } 60 61 /* Converts from gdiplus path point type to gdi path point type. */ 62 static BYTE convert_path_point_type(BYTE type) 63 { 64 BYTE ret; 65 66 switch(type & PathPointTypePathTypeMask){ 67 case PathPointTypeBezier: 68 ret = PT_BEZIERTO; 69 break; 70 case PathPointTypeLine: 71 ret = PT_LINETO; 72 break; 73 case PathPointTypeStart: 74 ret = PT_MOVETO; 75 break; 76 default: 77 ERR("Bad point type\n"); 78 return 0; 79 } 80 81 if(type & PathPointTypeCloseSubpath) 82 ret |= PT_CLOSEFIGURE; 83 84 return ret; 85 } 86 87 static INT prepare_dc(GpGraphics *graphics, GpPen *pen) 88 { 89 HPEN gdipen; 90 REAL width; 91 INT save_state = SaveDC(graphics->hdc), i, numdashes; 92 GpPointF pt[2]; 93 DWORD dash_array[MAX_DASHLEN]; 94 95 EndPath(graphics->hdc); 96 97 if(pen->unit == UnitPixel){ 98 width = pen->width; 99 } 100 else{ 101 /* Get an estimate for the amount the pen width is affected by the world 102 * transform. (This is similar to what some of the wine drivers do.) */ 103 pt[0].X = 0.0; 104 pt[0].Y = 0.0; 105 pt[1].X = 1.0; 106 pt[1].Y = 1.0; 107 GdipTransformMatrixPoints(graphics->worldtrans, pt, 2); 108 width = sqrt((pt[1].X - pt[0].X) * (pt[1].X - pt[0].X) + 109 (pt[1].Y - pt[0].Y) * (pt[1].Y - pt[0].Y)) / sqrt(2.0); 110 111 width *= pen->width * convert_unit(graphics->hdc, 112 pen->unit == UnitWorld ? graphics->unit : pen->unit); 113 } 114 115 if(pen->dash == DashStyleCustom){ 116 numdashes = min(pen->numdashes, MAX_DASHLEN); 117 118 TRACE("dashes are: "); 119 for(i = 0; i < numdashes; i++){ 120 dash_array[i] = roundr(width * pen->dashes[i]); 121 TRACE("%d, ", dash_array[i]); 122 } 123 TRACE("\n and the pen style is %x\n", pen->style); 124 125 gdipen = ExtCreatePen(pen->style, roundr(width), &pen->brush->lb, 126 numdashes, dash_array); 127 } 128 else 129 gdipen = ExtCreatePen(pen->style, roundr(width), &pen->brush->lb, 0, NULL); 130 131 SelectObject(graphics->hdc, gdipen); 132 133 return save_state; 134 } 135 136 static void restore_dc(GpGraphics *graphics, INT state) 137 { 138 DeleteObject(SelectObject(graphics->hdc, GetStockObject(NULL_PEN))); 139 RestoreDC(graphics->hdc, state); 140 } 141 142 /* This helper applies all the changes that the points listed in ptf need in 143 * order to be drawn on the device context. In the end, this should include at 144 * least: 145 * -scaling by page unit 146 * -applying world transformation 147 * -converting from float to int 148 * Native gdiplus uses gdi32 to do all this (via SetMapMode, SetViewportExtEx, 149 * SetWindowExtEx, SetWorldTransform, etc.) but we cannot because we are using 150 * gdi to draw, and these functions would irreparably mess with line widths. 151 */ 152 static void transform_and_round_points(GpGraphics *graphics, POINT *pti, 153 GpPointF *ptf, INT count) 154 { 155 REAL unitscale; 156 GpMatrix *matrix; 157 int i; 158 159 unitscale = convert_unit(graphics->hdc, graphics->unit); 160 161 /* apply page scale */ 162 if(graphics->unit != UnitDisplay) 163 unitscale *= graphics->scale; 164 165 GdipCloneMatrix(graphics->worldtrans, &matrix); 166 GdipScaleMatrix(matrix, unitscale, unitscale, MatrixOrderAppend); 167 GdipTransformMatrixPoints(matrix, ptf, count); 168 GdipDeleteMatrix(matrix); 169 170 for(i = 0; i < count; i++){ 171 pti[i].x = roundr(ptf[i].X); 172 pti[i].y = roundr(ptf[i].Y); 173 } 174 } 175 176 /* Draw non-premultiplied ARGB data to the given graphics object */ 177 static GpStatus alpha_blend_pixels(GpGraphics *graphics, INT dst_x, INT dst_y, 178 const BYTE *src, INT src_width, INT src_height, INT src_stride) 179 { 180 if (graphics->image && graphics->image->type == ImageTypeBitmap) 181 { 182 GpBitmap *dst_bitmap = (GpBitmap*)graphics->image; 183 INT x, y; 184 185 for (x=0; x<src_width; x++) 186 { 187 for (y=0; y<src_height; y++) 188 { 189 ARGB dst_color, src_color; 190 GdipBitmapGetPixel(dst_bitmap, x+dst_x, y+dst_y, &dst_color); 191 src_color = ((ARGB*)(src + src_stride * y))[x]; 192 GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over(dst_color, src_color)); 193 } 194 } 195 196 return Ok; 197 } 198 else 199 { 200 HDC hdc; 201 HBITMAP hbitmap, old_hbm=NULL; 202 BITMAPINFOHEADER bih; 203 BYTE *temp_bits; 204 BLENDFUNCTION bf; 205 206 hdc = CreateCompatibleDC(0); 207 208 bih.biSize = sizeof(BITMAPINFOHEADER); 209 bih.biWidth = src_width; 210 bih.biHeight = -src_height; 211 bih.biPlanes = 1; 212 bih.biBitCount = 32; 213 bih.biCompression = BI_RGB; 214 bih.biSizeImage = 0; 215 bih.biXPelsPerMeter = 0; 216 bih.biYPelsPerMeter = 0; 217 bih.biClrUsed = 0; 218 bih.biClrImportant = 0; 219 220 hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, 221 (void**)&temp_bits, NULL, 0); 222 223 convert_32bppARGB_to_32bppPARGB(src_width, src_height, temp_bits, 224 4 * src_width, src, src_stride); 225 226 old_hbm = SelectObject(hdc, hbitmap); 227 228 bf.BlendOp = AC_SRC_OVER; 229 bf.BlendFlags = 0; 230 bf.SourceConstantAlpha = 255; 231 bf.AlphaFormat = AC_SRC_ALPHA; 232 233 GdiAlphaBlend(graphics->hdc, dst_x, dst_y, src_width, src_height, 234 hdc, 0, 0, src_width, src_height, bf); 235 236 SelectObject(hdc, old_hbm); 237 DeleteDC(hdc); 238 DeleteObject(hbitmap); 239 240 return Ok; 241 } 242 } 243 244 static ARGB blend_colors(ARGB start, ARGB end, REAL position) 245 { 246 ARGB result=0; 247 ARGB i; 248 for (i=0xff; i<=0xff0000; i = i << 8) 249 result |= (int)((start&i)*(1.0f - position)+(end&i)*(position))&i; 250 return result; 251 } 252 253 static ARGB blend_line_gradient(GpLineGradient* brush, REAL position) 254 { 255 REAL blendfac; 256 257 /* clamp to between 0.0 and 1.0, using the wrap mode */ 258 if (brush->wrap == WrapModeTile) 259 { 260 position = fmodf(position, 1.0f); 261 if (position < 0.0f) position += 1.0f; 262 } 263 else /* WrapModeFlip* */ 264 { 265 position = fmodf(position, 2.0f); 266 if (position < 0.0f) position += 2.0f; 267 if (position > 1.0f) position = 2.0f - position; 268 } 269 270 if (brush->blendcount == 1) 271 blendfac = position; 272 else 273 { 274 int i=1; 275 REAL left_blendpos, left_blendfac, right_blendpos, right_blendfac; 276 REAL range; 277 278 /* locate the blend positions surrounding this position */ 279 while (position > brush->blendpos[i]) 280 i++; 281 282 /* interpolate between the blend positions */ 283 left_blendpos = brush->blendpos[i-1]; 284 left_blendfac = brush->blendfac[i-1]; 285 right_blendpos = brush->blendpos[i]; 286 right_blendfac = brush->blendfac[i]; 287 range = right_blendpos - left_blendpos; 288 blendfac = (left_blendfac * (right_blendpos - position) + 289 right_blendfac * (position - left_blendpos)) / range; 290 } 291 292 if (brush->pblendcount == 0) 293 return blend_colors(brush->startcolor, brush->endcolor, blendfac); 294 else 295 { 296 int i=1; 297 ARGB left_blendcolor, right_blendcolor; 298 REAL left_blendpos, right_blendpos; 299 300 /* locate the blend colors surrounding this position */ 301 while (blendfac > brush->pblendpos[i]) 302 i++; 303 304 /* interpolate between the blend colors */ 305 left_blendpos = brush->pblendpos[i-1]; 306 left_blendcolor = brush->pblendcolor[i-1]; 307 right_blendpos = brush->pblendpos[i]; 308 right_blendcolor = brush->pblendcolor[i]; 309 blendfac = (blendfac - left_blendpos) / (right_blendpos - left_blendpos); 310 return blend_colors(left_blendcolor, right_blendcolor, blendfac); 311 } 312 } 313 314 static void brush_fill_path(GpGraphics *graphics, GpBrush* brush) 315 { 316 switch (brush->bt) 317 { 318 case BrushTypeLinearGradient: 319 { 320 GpLineGradient *line = (GpLineGradient*)brush; 321 RECT rc; 322 323 SelectClipPath(graphics->hdc, RGN_AND); 324 if (GetClipBox(graphics->hdc, &rc) != NULLREGION) 325 { 326 GpPointF endpointsf[2]; 327 POINT endpointsi[2]; 328 POINT poly[4]; 329 330 SelectObject(graphics->hdc, GetStockObject(NULL_PEN)); 331 332 endpointsf[0] = line->startpoint; 333 endpointsf[1] = line->endpoint; 334 transform_and_round_points(graphics, endpointsi, endpointsf, 2); 335 336 if (abs(endpointsi[0].x-endpointsi[1].x) > abs(endpointsi[0].y-endpointsi[1].y)) 337 { 338 /* vertical-ish gradient */ 339 int startx, endx; /* x co-ordinates of endpoints shifted to intersect the top of the visible rectangle */ 340 int startbottomx; /* x co-ordinate of start point shifted to intersect the bottom of the visible rectangle */ 341 int width; 342 COLORREF col; 343 HBRUSH hbrush, hprevbrush; 344 int leftx, rightx; /* x co-ordinates where the leftmost and rightmost gradient lines hit the top of the visible rectangle */ 345 int x; 346 int tilt; /* horizontal distance covered by a gradient line */ 347 348 startx = roundr((rc.top - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X); 349 endx = roundr((rc.top - endpointsf[1].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[1].X); 350 width = endx - startx; 351 startbottomx = roundr((rc.bottom - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X); 352 tilt = startx - startbottomx; 353 354 if (startx >= startbottomx) 355 { 356 leftx = rc.left; 357 rightx = rc.right + tilt; 358 } 359 else 360 { 361 leftx = rc.left + tilt; 362 rightx = rc.right; 363 } 364 365 poly[0].y = rc.bottom; 366 poly[1].y = rc.top; 367 poly[2].y = rc.top; 368 poly[3].y = rc.bottom; 369 370 for (x=leftx; x<=rightx; x++) 371 { 372 ARGB argb = blend_line_gradient(line, (x-startx)/(REAL)width); 373 col = ARGB2COLORREF(argb); 374 hbrush = CreateSolidBrush(col); 375 hprevbrush = SelectObject(graphics->hdc, hbrush); 376 poly[0].x = x - tilt - 1; 377 poly[1].x = x - 1; 378 poly[2].x = x; 379 poly[3].x = x - tilt; 380 Polygon(graphics->hdc, poly, 4); 381 SelectObject(graphics->hdc, hprevbrush); 382 DeleteObject(hbrush); 383 } 384 } 385 else if (endpointsi[0].y != endpointsi[1].y) 386 { 387 /* horizontal-ish gradient */ 388 int starty, endy; /* y co-ordinates of endpoints shifted to intersect the left of the visible rectangle */ 389 int startrighty; /* y co-ordinate of start point shifted to intersect the right of the visible rectangle */ 390 int height; 391 COLORREF col; 392 HBRUSH hbrush, hprevbrush; 393 int topy, bottomy; /* y co-ordinates where the topmost and bottommost gradient lines hit the left of the visible rectangle */ 394 int y; 395 int tilt; /* vertical distance covered by a gradient line */ 396 397 starty = roundr((rc.left - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y); 398 endy = roundr((rc.left - endpointsf[1].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[1].Y); 399 height = endy - starty; 400 startrighty = roundr((rc.right - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y); 401 tilt = starty - startrighty; 402 403 if (starty >= startrighty) 404 { 405 topy = rc.top; 406 bottomy = rc.bottom + tilt; 407 } 408 else 409 { 410 topy = rc.top + tilt; 411 bottomy = rc.bottom; 412 } 413 414 poly[0].x = rc.right; 415 poly[1].x = rc.left; 416 poly[2].x = rc.left; 417 poly[3].x = rc.right; 418 419 for (y=topy; y<=bottomy; y++) 420 { 421 ARGB argb = blend_line_gradient(line, (y-starty)/(REAL)height); 422 col = ARGB2COLORREF(argb); 423 hbrush = CreateSolidBrush(col); 424 hprevbrush = SelectObject(graphics->hdc, hbrush); 425 poly[0].y = y - tilt - 1; 426 poly[1].y = y - 1; 427 poly[2].y = y; 428 poly[3].y = y - tilt; 429 Polygon(graphics->hdc, poly, 4); 430 SelectObject(graphics->hdc, hprevbrush); 431 DeleteObject(hbrush); 432 } 433 } 434 /* else startpoint == endpoint */ 435 } 436 break; 437 } 438 case BrushTypeSolidColor: 439 { 440 GpSolidFill *fill = (GpSolidFill*)brush; 441 if (fill->bmp) 442 { 443 RECT rc; 444 /* partially transparent fill */ 445 446 SelectClipPath(graphics->hdc, RGN_AND); 447 if (GetClipBox(graphics->hdc, &rc) != NULLREGION) 448 { 449 HDC hdc = CreateCompatibleDC(NULL); 450 HBITMAP oldbmp; 451 BLENDFUNCTION bf; 452 453 if (!hdc) break; 454 455 oldbmp = SelectObject(hdc, fill->bmp); 456 457 bf.BlendOp = AC_SRC_OVER; 458 bf.BlendFlags = 0; 459 bf.SourceConstantAlpha = 255; 460 bf.AlphaFormat = AC_SRC_ALPHA; 461 462 GdiAlphaBlend(graphics->hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, hdc, 0, 0, 1, 1, bf); 463 464 SelectObject(hdc, oldbmp); 465 DeleteDC(hdc); 466 } 467 468 break; 469 } 470 /* else fall through */ 471 } 472 default: 473 SelectObject(graphics->hdc, brush->gdibrush); 474 FillPath(graphics->hdc); 475 break; 476 } 477 } 478 479 /* GdipDrawPie/GdipFillPie helper function */ 480 static void draw_pie(GpGraphics *graphics, REAL x, REAL y, REAL width, 481 REAL height, REAL startAngle, REAL sweepAngle) 482 { 483 GpPointF ptf[4]; 484 POINT pti[4]; 485 486 ptf[0].X = x; 487 ptf[0].Y = y; 488 ptf[1].X = x + width; 489 ptf[1].Y = y + height; 490 491 deg2xy(startAngle+sweepAngle, x + width / 2.0, y + width / 2.0, &ptf[2].X, &ptf[2].Y); 492 deg2xy(startAngle, x + width / 2.0, y + width / 2.0, &ptf[3].X, &ptf[3].Y); 493 494 transform_and_round_points(graphics, pti, ptf, 4); 495 496 Pie(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y, pti[2].x, 497 pti[2].y, pti[3].x, pti[3].y); 498 } 499 500 /* Draws the linecap the specified color and size on the hdc. The linecap is in 501 * direction of the line from x1, y1 to x2, y2 and is anchored on x2, y2. Probably 502 * should not be called on an hdc that has a path you care about. */ 503 static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL size, 504 const GpCustomLineCap *custom, REAL x1, REAL y1, REAL x2, REAL y2) 505 { 506 HGDIOBJ oldbrush = NULL, oldpen = NULL; 507 GpMatrix *matrix = NULL; 508 HBRUSH brush = NULL; 509 HPEN pen = NULL; 510 PointF ptf[4], *custptf = NULL; 511 POINT pt[4], *custpt = NULL; 512 BYTE *tp = NULL; 513 REAL theta, dsmall, dbig, dx, dy = 0.0; 514 INT i, count; 515 LOGBRUSH lb; 516 BOOL customstroke; 517 518 if((x1 == x2) && (y1 == y2)) 519 return; 520 521 theta = gdiplus_atan2(y2 - y1, x2 - x1); 522 523 customstroke = (cap == LineCapCustom) && custom && (!custom->fill); 524 if(!customstroke){ 525 brush = CreateSolidBrush(color); 526 lb.lbStyle = BS_SOLID; 527 lb.lbColor = color; 528 lb.lbHatch = 0; 529 pen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT | 530 PS_JOIN_MITER, 1, &lb, 0, 531 NULL); 532 oldbrush = SelectObject(graphics->hdc, brush); 533 oldpen = SelectObject(graphics->hdc, pen); 534 } 535 536 switch(cap){ 537 case LineCapFlat: 538 break; 539 case LineCapSquare: 540 case LineCapSquareAnchor: 541 case LineCapDiamondAnchor: 542 size = size * (cap & LineCapNoAnchor ? ANCHOR_WIDTH : 1.0) / 2.0; 543 if(cap == LineCapDiamondAnchor){ 544 dsmall = cos(theta + M_PI_2) * size; 545 dbig = sin(theta + M_PI_2) * size; 546 } 547 else{ 548 dsmall = cos(theta + M_PI_4) * size; 549 dbig = sin(theta + M_PI_4) * size; 550 } 551 552 ptf[0].X = x2 - dsmall; 553 ptf[1].X = x2 + dbig; 554 555 ptf[0].Y = y2 - dbig; 556 ptf[3].Y = y2 + dsmall; 557 558 ptf[1].Y = y2 - dsmall; 559 ptf[2].Y = y2 + dbig; 560 561 ptf[3].X = x2 - dbig; 562 ptf[2].X = x2 + dsmall; 563 564 transform_and_round_points(graphics, pt, ptf, 4); 565 Polygon(graphics->hdc, pt, 4); 566 567 break; 568 case LineCapArrowAnchor: 569 size = size * 4.0 / sqrt(3.0); 570 571 dx = cos(M_PI / 6.0 + theta) * size; 572 dy = sin(M_PI / 6.0 + theta) * size; 573 574 ptf[0].X = x2 - dx; 575 ptf[0].Y = y2 - dy; 576 577 dx = cos(- M_PI / 6.0 + theta) * size; 578 dy = sin(- M_PI / 6.0 + theta) * size; 579 580 ptf[1].X = x2 - dx; 581 ptf[1].Y = y2 - dy; 582 583 ptf[2].X = x2; 584 ptf[2].Y = y2; 585 586 transform_and_round_points(graphics, pt, ptf, 3); 587 Polygon(graphics->hdc, pt, 3); 588 589 break; 590 case LineCapRoundAnchor: 591 dx = dy = ANCHOR_WIDTH * size / 2.0; 592 593 ptf[0].X = x2 - dx; 594 ptf[0].Y = y2 - dy; 595 ptf[1].X = x2 + dx; 596 ptf[1].Y = y2 + dy; 597 598 transform_and_round_points(graphics, pt, ptf, 2); 599 Ellipse(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y); 600 601 break; 602 case LineCapTriangle: 603 size = size / 2.0; 604 dx = cos(M_PI_2 + theta) * size; 605 dy = sin(M_PI_2 + theta) * size; 606 607 ptf[0].X = x2 - dx; 608 ptf[0].Y = y2 - dy; 609 ptf[1].X = x2 + dx; 610 ptf[1].Y = y2 + dy; 611 612 dx = cos(theta) * size; 613 dy = sin(theta) * size; 614 615 ptf[2].X = x2 + dx; 616 ptf[2].Y = y2 + dy; 617 618 transform_and_round_points(graphics, pt, ptf, 3); 619 Polygon(graphics->hdc, pt, 3); 620 621 break; 622 case LineCapRound: 623 dx = dy = size / 2.0; 624 625 ptf[0].X = x2 - dx; 626 ptf[0].Y = y2 - dy; 627 ptf[1].X = x2 + dx; 628 ptf[1].Y = y2 + dy; 629 630 dx = -cos(M_PI_2 + theta) * size; 631 dy = -sin(M_PI_2 + theta) * size; 632 633 ptf[2].X = x2 - dx; 634 ptf[2].Y = y2 - dy; 635 ptf[3].X = x2 + dx; 636 ptf[3].Y = y2 + dy; 637 638 transform_and_round_points(graphics, pt, ptf, 4); 639 Pie(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y, pt[2].x, 640 pt[2].y, pt[3].x, pt[3].y); 641 642 break; 643 case LineCapCustom: 644 if(!custom) 645 break; 646 647 count = custom->pathdata.Count; 648 custptf = GdipAlloc(count * sizeof(PointF)); 649 custpt = GdipAlloc(count * sizeof(POINT)); 650 tp = GdipAlloc(count); 651 652 if(!custptf || !custpt || !tp || (GdipCreateMatrix(&matrix) != Ok)) 653 goto custend; 654 655 memcpy(custptf, custom->pathdata.Points, count * sizeof(PointF)); 656 657 GdipScaleMatrix(matrix, size, size, MatrixOrderAppend); 658 GdipRotateMatrix(matrix, (180.0 / M_PI) * (theta - M_PI_2), 659 MatrixOrderAppend); 660 GdipTranslateMatrix(matrix, x2, y2, MatrixOrderAppend); 661 GdipTransformMatrixPoints(matrix, custptf, count); 662 663 transform_and_round_points(graphics, custpt, custptf, count); 664 665 for(i = 0; i < count; i++) 666 tp[i] = convert_path_point_type(custom->pathdata.Types[i]); 667 668 if(custom->fill){ 669 BeginPath(graphics->hdc); 670 PolyDraw(graphics->hdc, custpt, tp, count); 671 EndPath(graphics->hdc); 672 StrokeAndFillPath(graphics->hdc); 673 } 674 else 675 PolyDraw(graphics->hdc, custpt, tp, count); 676 677 custend: 678 GdipFree(custptf); 679 GdipFree(custpt); 680 GdipFree(tp); 681 GdipDeleteMatrix(matrix); 682 break; 683 default: 684 break; 685 } 686 687 if(!customstroke){ 688 SelectObject(graphics->hdc, oldbrush); 689 SelectObject(graphics->hdc, oldpen); 690 DeleteObject(brush); 691 DeleteObject(pen); 692 } 693 } 694 695 /* Shortens the line by the given percent by changing x2, y2. 696 * If percent is > 1.0 then the line will change direction. 697 * If percent is negative it can lengthen the line. */ 698 static void shorten_line_percent(REAL x1, REAL y1, REAL *x2, REAL *y2, REAL percent) 699 { 700 REAL dist, theta, dx, dy; 701 702 if((y1 == *y2) && (x1 == *x2)) 703 return; 704 705 dist = sqrt((*x2 - x1) * (*x2 - x1) + (*y2 - y1) * (*y2 - y1)) * -percent; 706 theta = gdiplus_atan2((*y2 - y1), (*x2 - x1)); 707 dx = cos(theta) * dist; 708 dy = sin(theta) * dist; 709 710 *x2 = *x2 + dx; 711 *y2 = *y2 + dy; 712 } 713 714 /* Shortens the line by the given amount by changing x2, y2. 715 * If the amount is greater than the distance, the line will become length 0. 716 * If the amount is negative, it can lengthen the line. */ 717 static void shorten_line_amt(REAL x1, REAL y1, REAL *x2, REAL *y2, REAL amt) 718 { 719 REAL dx, dy, percent; 720 721 dx = *x2 - x1; 722 dy = *y2 - y1; 723 if(dx == 0 && dy == 0) 724 return; 725 726 percent = amt / sqrt(dx * dx + dy * dy); 727 if(percent >= 1.0){ 728 *x2 = x1; 729 *y2 = y1; 730 return; 731 } 732 733 shorten_line_percent(x1, y1, x2, y2, percent); 734 } 735 736 /* Draws lines between the given points, and if caps is true then draws an endcap 737 * at the end of the last line. */ 738 static GpStatus draw_polyline(GpGraphics *graphics, GpPen *pen, 739 GDIPCONST GpPointF * pt, INT count, BOOL caps) 740 { 741 POINT *pti = NULL; 742 GpPointF *ptcopy = NULL; 743 GpStatus status = GenericError; 744 745 if(!count) 746 return Ok; 747 748 pti = GdipAlloc(count * sizeof(POINT)); 749 ptcopy = GdipAlloc(count * sizeof(GpPointF)); 750 751 if(!pti || !ptcopy){ 752 status = OutOfMemory; 753 goto end; 754 } 755 756 memcpy(ptcopy, pt, count * sizeof(GpPointF)); 757 758 if(caps){ 759 if(pen->endcap == LineCapArrowAnchor) 760 shorten_line_amt(ptcopy[count-2].X, ptcopy[count-2].Y, 761 &ptcopy[count-1].X, &ptcopy[count-1].Y, pen->width); 762 else if((pen->endcap == LineCapCustom) && pen->customend) 763 shorten_line_amt(ptcopy[count-2].X, ptcopy[count-2].Y, 764 &ptcopy[count-1].X, &ptcopy[count-1].Y, 765 pen->customend->inset * pen->width); 766 767 if(pen->startcap == LineCapArrowAnchor) 768 shorten_line_amt(ptcopy[1].X, ptcopy[1].Y, 769 &ptcopy[0].X, &ptcopy[0].Y, pen->width); 770 else if((pen->startcap == LineCapCustom) && pen->customstart) 771 shorten_line_amt(ptcopy[1].X, ptcopy[1].Y, 772 &ptcopy[0].X, &ptcopy[0].Y, 773 pen->customstart->inset * pen->width); 774 775 draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend, 776 pt[count - 2].X, pt[count - 2].Y, pt[count - 1].X, pt[count - 1].Y); 777 draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart, 778 pt[1].X, pt[1].Y, pt[0].X, pt[0].Y); 779 } 780 781 transform_and_round_points(graphics, pti, ptcopy, count); 782 783 if(Polyline(graphics->hdc, pti, count)) 784 status = Ok; 785 786 end: 787 GdipFree(pti); 788 GdipFree(ptcopy); 789 790 return status; 791 } 792 793 /* Conducts a linear search to find the bezier points that will back off 794 * the endpoint of the curve by a distance of amt. Linear search works 795 * better than binary in this case because there are multiple solutions, 796 * and binary searches often find a bad one. I don't think this is what 797 * Windows does but short of rendering the bezier without GDI's help it's 798 * the best we can do. If rev then work from the start of the passed points 799 * instead of the end. */ 800 static void shorten_bezier_amt(GpPointF * pt, REAL amt, BOOL rev) 801 { 802 GpPointF origpt[4]; 803 REAL percent = 0.00, dx, dy, origx, origy, diff = -1.0; 804 INT i, first = 0, second = 1, third = 2, fourth = 3; 805 806 if(rev){ 807 first = 3; 808 second = 2; 809 third = 1; 810 fourth = 0; 811 } 812 813 origx = pt[fourth].X; 814 origy = pt[fourth].Y; 815 memcpy(origpt, pt, sizeof(GpPointF) * 4); 816 817 for(i = 0; (i < MAX_ITERS) && (diff < amt); i++){ 818 /* reset bezier points to original values */ 819 memcpy(pt, origpt, sizeof(GpPointF) * 4); 820 /* Perform magic on bezier points. Order is important here.*/ 821 shorten_line_percent(pt[third].X, pt[third].Y, &pt[fourth].X, &pt[fourth].Y, percent); 822 shorten_line_percent(pt[second].X, pt[second].Y, &pt[third].X, &pt[third].Y, percent); 823 shorten_line_percent(pt[third].X, pt[third].Y, &pt[fourth].X, &pt[fourth].Y, percent); 824 shorten_line_percent(pt[first].X, pt[first].Y, &pt[second].X, &pt[second].Y, percent); 825 shorten_line_percent(pt[second].X, pt[second].Y, &pt[third].X, &pt[third].Y, percent); 826 shorten_line_percent(pt[third].X, pt[third].Y, &pt[fourth].X, &pt[fourth].Y, percent); 827 828 dx = pt[fourth].X - origx; 829 dy = pt[fourth].Y - origy; 830 831 diff = sqrt(dx * dx + dy * dy); 832 percent += 0.0005 * amt; 833 } 834 } 835 836 /* Draws bezier curves between given points, and if caps is true then draws an 837 * endcap at the end of the last line. */ 838 static GpStatus draw_polybezier(GpGraphics *graphics, GpPen *pen, 839 GDIPCONST GpPointF * pt, INT count, BOOL caps) 840 { 841 POINT *pti; 842 GpPointF *ptcopy; 843 GpStatus status = GenericError; 844 845 if(!count) 846 return Ok; 847 848 pti = GdipAlloc(count * sizeof(POINT)); 849 ptcopy = GdipAlloc(count * sizeof(GpPointF)); 850 851 if(!pti || !ptcopy){ 852 status = OutOfMemory; 853 goto end; 854 } 855 856 memcpy(ptcopy, pt, count * sizeof(GpPointF)); 857 858 if(caps){ 859 if(pen->endcap == LineCapArrowAnchor) 860 shorten_bezier_amt(&ptcopy[count-4], pen->width, FALSE); 861 else if((pen->endcap == LineCapCustom) && pen->customend) 862 shorten_bezier_amt(&ptcopy[count-4], pen->width * pen->customend->inset, 863 FALSE); 864 865 if(pen->startcap == LineCapArrowAnchor) 866 shorten_bezier_amt(ptcopy, pen->width, TRUE); 867 else if((pen->startcap == LineCapCustom) && pen->customstart) 868 shorten_bezier_amt(ptcopy, pen->width * pen->customstart->inset, TRUE); 869 870 /* the direction of the line cap is parallel to the direction at the 871 * end of the bezier (which, if it has been shortened, is not the same 872 * as the direction from pt[count-2] to pt[count-1]) */ 873 draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend, 874 pt[count - 1].X - (ptcopy[count - 1].X - ptcopy[count - 2].X), 875 pt[count - 1].Y - (ptcopy[count - 1].Y - ptcopy[count - 2].Y), 876 pt[count - 1].X, pt[count - 1].Y); 877 878 draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart, 879 pt[0].X - (ptcopy[0].X - ptcopy[1].X), 880 pt[0].Y - (ptcopy[0].Y - ptcopy[1].Y), pt[0].X, pt[0].Y); 881 } 882 883 transform_and_round_points(graphics, pti, ptcopy, count); 884 885 PolyBezier(graphics->hdc, pti, count); 886 887 status = Ok; 888 889 end: 890 GdipFree(pti); 891 GdipFree(ptcopy); 892 893 return status; 894 } 895 896 /* Draws a combination of bezier curves and lines between points. */ 897 static GpStatus draw_poly(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF * pt, 898 GDIPCONST BYTE * types, INT count, BOOL caps) 899 { 900 POINT *pti = GdipAlloc(count * sizeof(POINT)); 901 BYTE *tp = GdipAlloc(count); 902 GpPointF *ptcopy = GdipAlloc(count * sizeof(GpPointF)); 903 INT i, j; 904 GpStatus status = GenericError; 905 906 if(!count){ 907 status = Ok; 908 goto end; 909 } 910 if(!pti || !tp || !ptcopy){ 911 status = OutOfMemory; 912 goto end; 913 } 914 915 for(i = 1; i < count; i++){ 916 if((types[i] & PathPointTypePathTypeMask) == PathPointTypeBezier){ 917 if((i + 2 >= count) || !(types[i + 1] & PathPointTypeBezier) 918 || !(types[i + 1] & PathPointTypeBezier)){ 919 ERR("Bad bezier points\n"); 920 goto end; 921 } 922 i += 2; 923 } 924 } 925 926 memcpy(ptcopy, pt, count * sizeof(GpPointF)); 927 928 /* If we are drawing caps, go through the points and adjust them accordingly, 929 * and draw the caps. */ 930 if(caps){ 931 switch(types[count - 1] & PathPointTypePathTypeMask){ 932 case PathPointTypeBezier: 933 if(pen->endcap == LineCapArrowAnchor) 934 shorten_bezier_amt(&ptcopy[count - 4], pen->width, FALSE); 935 else if((pen->endcap == LineCapCustom) && pen->customend) 936 shorten_bezier_amt(&ptcopy[count - 4], 937 pen->width * pen->customend->inset, FALSE); 938 939 draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend, 940 pt[count - 1].X - (ptcopy[count - 1].X - ptcopy[count - 2].X), 941 pt[count - 1].Y - (ptcopy[count - 1].Y - ptcopy[count - 2].Y), 942 pt[count - 1].X, pt[count - 1].Y); 943 944 break; 945 case PathPointTypeLine: 946 if(pen->endcap == LineCapArrowAnchor) 947 shorten_line_amt(ptcopy[count - 2].X, ptcopy[count - 2].Y, 948 &ptcopy[count - 1].X, &ptcopy[count - 1].Y, 949 pen->width); 950 else if((pen->endcap == LineCapCustom) && pen->customend) 951 shorten_line_amt(ptcopy[count - 2].X, ptcopy[count - 2].Y, 952 &ptcopy[count - 1].X, &ptcopy[count - 1].Y, 953 pen->customend->inset * pen->width); 954 955 draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend, 956 pt[count - 2].X, pt[count - 2].Y, pt[count - 1].X, 957 pt[count - 1].Y); 958 959 break; 960 default: 961 ERR("Bad path last point\n"); 962 goto end; 963 } 964 965 /* Find start of points */ 966 for(j = 1; j < count && ((types[j] & PathPointTypePathTypeMask) 967 == PathPointTypeStart); j++); 968 969 switch(types[j] & PathPointTypePathTypeMask){ 970 case PathPointTypeBezier: 971 if(pen->startcap == LineCapArrowAnchor) 972 shorten_bezier_amt(&ptcopy[j - 1], pen->width, TRUE); 973 else if((pen->startcap == LineCapCustom) && pen->customstart) 974 shorten_bezier_amt(&ptcopy[j - 1], 975 pen->width * pen->customstart->inset, TRUE); 976 977 draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart, 978 pt[j - 1].X - (ptcopy[j - 1].X - ptcopy[j].X), 979 pt[j - 1].Y - (ptcopy[j - 1].Y - ptcopy[j].Y), 980 pt[j - 1].X, pt[j - 1].Y); 981 982 break; 983 case PathPointTypeLine: 984 if(pen->startcap == LineCapArrowAnchor) 985 shorten_line_amt(ptcopy[j].X, ptcopy[j].Y, 986 &ptcopy[j - 1].X, &ptcopy[j - 1].Y, 987 pen->width); 988 else if((pen->startcap == LineCapCustom) && pen->customstart) 989 shorten_line_amt(ptcopy[j].X, ptcopy[j].Y, 990 &ptcopy[j - 1].X, &ptcopy[j - 1].Y, 991 pen->customstart->inset * pen->width); 992 993 draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart, 994 pt[j].X, pt[j].Y, pt[j - 1].X, 995 pt[j - 1].Y); 996 997 break; 998 default: 999 ERR("Bad path points\n"); 1000 goto end; 1001 } 1002 } 1003 1004 transform_and_round_points(graphics, pti, ptcopy, count); 1005 1006 for(i = 0; i < count; i++){ 1007 tp[i] = convert_path_point_type(types[i]); 1008 } 1009 1010 PolyDraw(graphics->hdc, pti, tp, count); 1011 1012 status = Ok; 1013 1014 end: 1015 GdipFree(pti); 1016 GdipFree(ptcopy); 1017 GdipFree(tp); 1018 1019 return status; 1020 } 1021 1022 GpStatus trace_path(GpGraphics *graphics, GpPath *path) 1023 { 1024 GpStatus result; 1025 1026 BeginPath(graphics->hdc); 1027 result = draw_poly(graphics, NULL, path->pathdata.Points, 1028 path->pathdata.Types, path->pathdata.Count, FALSE); 1029 EndPath(graphics->hdc); 1030 return result; 1031 } 1032 1033 typedef struct _GraphicsContainerItem { 1034 struct list entry; 1035 GraphicsContainer contid; 1036 1037 SmoothingMode smoothing; 1038 CompositingQuality compqual; 1039 InterpolationMode interpolation; 1040 CompositingMode compmode; 1041 TextRenderingHint texthint; 1042 REAL scale; 1043 GpUnit unit; 1044 PixelOffsetMode pixeloffset; 1045 UINT textcontrast; 1046 GpMatrix* worldtrans; 1047 GpRegion* clip; 1048 } GraphicsContainerItem; 1049 1050 static GpStatus init_container(GraphicsContainerItem** container, 1051 GDIPCONST GpGraphics* graphics){ 1052 GpStatus sts; 1053 1054 *container = GdipAlloc(sizeof(GraphicsContainerItem)); 1055 if(!(*container)) 1056 return OutOfMemory; 1057 1058 (*container)->contid = graphics->contid + 1; 1059 1060 (*container)->smoothing = graphics->smoothing; 1061 (*container)->compqual = graphics->compqual; 1062 (*container)->interpolation = graphics->interpolation; 1063 (*container)->compmode = graphics->compmode; 1064 (*container)->texthint = graphics->texthint; 1065 (*container)->scale = graphics->scale; 1066 (*container)->unit = graphics->unit; 1067 (*container)->textcontrast = graphics->textcontrast; 1068 (*container)->pixeloffset = graphics->pixeloffset; 1069 1070 sts = GdipCloneMatrix(graphics->worldtrans, &(*container)->worldtrans); 1071 if(sts != Ok){ 1072 GdipFree(*container); 1073 *container = NULL; 1074 return sts; 1075 } 1076 1077 sts = GdipCloneRegion(graphics->clip, &(*container)->clip); 1078 if(sts != Ok){ 1079 GdipDeleteMatrix((*container)->worldtrans); 1080 GdipFree(*container); 1081 *container = NULL; 1082 return sts; 1083 } 1084 1085 return Ok; 1086 } 1087 1088 static void delete_container(GraphicsContainerItem* container){ 1089 GdipDeleteMatrix(container->worldtrans); 1090 GdipDeleteRegion(container->clip); 1091 GdipFree(container); 1092 } 1093 1094 static GpStatus restore_container(GpGraphics* graphics, 1095 GDIPCONST GraphicsContainerItem* container){ 1096 GpStatus sts; 1097 GpMatrix *newTrans; 1098 GpRegion *newClip; 1099 1100 sts = GdipCloneMatrix(container->worldtrans, &newTrans); 1101 if(sts != Ok) 1102 return sts; 1103 1104 sts = GdipCloneRegion(container->clip, &newClip); 1105 if(sts != Ok){ 1106 GdipDeleteMatrix(newTrans); 1107 return sts; 1108 } 1109 1110 GdipDeleteMatrix(graphics->worldtrans); 1111 graphics->worldtrans = newTrans; 1112 1113 GdipDeleteRegion(graphics->clip); 1114 graphics->clip = newClip; 1115 1116 graphics->contid = container->contid - 1; 1117 1118 graphics->smoothing = container->smoothing; 1119 graphics->compqual = container->compqual; 1120 graphics->interpolation = container->interpolation; 1121 graphics->compmode = container->compmode; 1122 graphics->texthint = container->texthint; 1123 graphics->scale = container->scale; 1124 graphics->unit = container->unit; 1125 graphics->textcontrast = container->textcontrast; 1126 graphics->pixeloffset = container->pixeloffset; 1127 1128 return Ok; 1129 } 1130 1131 static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect) 1132 { 1133 RECT wnd_rect; 1134 1135 if(graphics->hwnd) { 1136 if(!GetClientRect(graphics->hwnd, &wnd_rect)) 1137 return GenericError; 1138 1139 rect->X = wnd_rect.left; 1140 rect->Y = wnd_rect.top; 1141 rect->Width = wnd_rect.right - wnd_rect.left; 1142 rect->Height = wnd_rect.bottom - wnd_rect.top; 1143 }else{ 1144 rect->X = 0; 1145 rect->Y = 0; 1146 rect->Width = GetDeviceCaps(graphics->hdc, HORZRES); 1147 rect->Height = GetDeviceCaps(graphics->hdc, VERTRES); 1148 } 1149 1150 return Ok; 1151 } 1152 1153 /* on success, rgn will contain the region of the graphics object which 1154 * is visible after clipping has been applied */ 1155 static GpStatus get_visible_clip_region(GpGraphics *graphics, GpRegion *rgn) 1156 { 1157 GpStatus stat; 1158 GpRectF rectf; 1159 GpRegion* tmp; 1160 1161 if((stat = get_graphics_bounds(graphics, &rectf)) != Ok) 1162 return stat; 1163 1164 if((stat = GdipCreateRegion(&tmp)) != Ok) 1165 return stat; 1166 1167 if((stat = GdipCombineRegionRect(tmp, &rectf, CombineModeReplace)) != Ok) 1168 goto end; 1169 1170 if((stat = GdipCombineRegionRegion(tmp, graphics->clip, CombineModeIntersect)) != Ok) 1171 goto end; 1172 1173 stat = GdipCombineRegionRegion(rgn, tmp, CombineModeReplace); 1174 1175 end: 1176 GdipDeleteRegion(tmp); 1177 return stat; 1178 } 1179 1180 GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics) 1181 { 1182 TRACE("(%p, %p)\n", hdc, graphics); 1183 1184 return GdipCreateFromHDC2(hdc, NULL, graphics); 1185 } 1186 1187 GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **graphics) 1188 { 1189 GpStatus retval; 1190 1191 TRACE("(%p, %p, %p)\n", hdc, hDevice, graphics); 1192 1193 if(hDevice != NULL) { 1194 FIXME("Don't know how to handle parameter hDevice\n"); 1195 return NotImplemented; 1196 } 1197 1198 if(hdc == NULL) 1199 return OutOfMemory; 1200 1201 if(graphics == NULL) 1202 return InvalidParameter; 1203 1204 *graphics = GdipAlloc(sizeof(GpGraphics)); 1205 if(!*graphics) return OutOfMemory; 1206 1207 if((retval = GdipCreateMatrix(&(*graphics)->worldtrans)) != Ok){ 1208 GdipFree(*graphics); 1209 return retval; 1210 } 1211 1212 if((retval = GdipCreateRegion(&(*graphics)->clip)) != Ok){ 1213 GdipFree((*graphics)->worldtrans); 1214 GdipFree(*graphics); 1215 return retval; 1216 } 1217 1218 (*graphics)->hdc = hdc; 1219 (*graphics)->hwnd = WindowFromDC(hdc); 1220 (*graphics)->owndc = FALSE; 1221 (*graphics)->smoothing = SmoothingModeDefault; 1222 (*graphics)->compqual = CompositingQualityDefault; 1223 (*graphics)->interpolation = InterpolationModeDefault; 1224 (*graphics)->pixeloffset = PixelOffsetModeDefault; 1225 (*graphics)->compmode = CompositingModeSourceOver; 1226 (*graphics)->unit = UnitDisplay; 1227 (*graphics)->scale = 1.0; 1228 (*graphics)->busy = FALSE; 1229 (*graphics)->textcontrast = 4; 1230 list_init(&(*graphics)->containers); 1231 (*graphics)->contid = 0; 1232 1233 TRACE("<-- %p\n", *graphics); 1234 1235 return Ok; 1236 } 1237 1238 GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics) 1239 { 1240 GpStatus ret; 1241 HDC hdc; 1242 1243 TRACE("(%p, %p)\n", hwnd, graphics); 1244 1245 hdc = GetDC(hwnd); 1246 1247 if((ret = GdipCreateFromHDC(hdc, graphics)) != Ok) 1248 { 1249 ReleaseDC(hwnd, hdc); 1250 return ret; 1251 } 1252 1253 (*graphics)->hwnd = hwnd; 1254 (*graphics)->owndc = TRUE; 1255 1256 return Ok; 1257 } 1258 1259 /* FIXME: no icm handling */ 1260 GpStatus WINGDIPAPI GdipCreateFromHWNDICM(HWND hwnd, GpGraphics **graphics) 1261 { 1262 TRACE("(%p, %p)\n", hwnd, graphics); 1263 1264 return GdipCreateFromHWND(hwnd, graphics); 1265 } 1266 1267 GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete, 1268 GpMetafile **metafile) 1269 { 1270 static int calls; 1271 1272 TRACE("(%p,%i,%p)\n", hemf, delete, metafile); 1273 1274 if(!hemf || !metafile) 1275 return InvalidParameter; 1276 1277 if(!(calls++)) 1278 FIXME("not implemented\n"); 1279 1280 return NotImplemented; 1281 } 1282 1283 GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete, 1284 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile) 1285 { 1286 IStream *stream = NULL; 1287 UINT read; 1288 BYTE* copy; 1289 HENHMETAFILE hemf; 1290 GpStatus retval = Ok; 1291 1292 TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile); 1293 1294 if(!hwmf || !metafile || !placeable) 1295 return InvalidParameter; 1296 1297 *metafile = NULL; 1298 read = GetMetaFileBitsEx(hwmf, 0, NULL); 1299 if(!read) 1300 return GenericError; 1301 copy = GdipAlloc(read); 1302 GetMetaFileBitsEx(hwmf, read, copy); 1303 1304 hemf = SetWinMetaFileBits(read, copy, NULL, NULL); 1305 GdipFree(copy); 1306 1307 read = GetEnhMetaFileBits(hemf, 0, NULL); 1308 copy = GdipAlloc(read); 1309 GetEnhMetaFileBits(hemf, read, copy); 1310 DeleteEnhMetaFile(hemf); 1311 1312 if(CreateStreamOnHGlobal(copy, TRUE, &stream) != S_OK){ 1313 ERR("could not make stream\n"); 1314 GdipFree(copy); 1315 retval = GenericError; 1316 goto err; 1317 } 1318 1319 *metafile = GdipAlloc(sizeof(GpMetafile)); 1320 if(!*metafile){ 1321 retval = OutOfMemory; 1322 goto err; 1323 } 1324 1325 if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture, 1326 (LPVOID*) &((*metafile)->image.picture)) != S_OK) 1327 { 1328 retval = GenericError; 1329 goto err; 1330 } 1331 1332 1333 (*metafile)->image.type = ImageTypeMetafile; 1334 memcpy(&(*metafile)->image.format, &ImageFormatWMF, sizeof(GUID)); 1335 (*metafile)->image.palette_flags = 0; 1336 (*metafile)->image.palette_count = 0; 1337 (*metafile)->image.palette_size = 0; 1338 (*metafile)->image.palette_entries = NULL; 1339 (*metafile)->image.xres = (REAL)placeable->Inch; 1340 (*metafile)->image.yres = (REAL)placeable->Inch; 1341 (*metafile)->bounds.X = ((REAL) placeable->BoundingBox.Left) / ((REAL) placeable->Inch); 1342 (*metafile)->bounds.Y = ((REAL) placeable->BoundingBox.Top) / ((REAL) placeable->Inch); 1343 (*metafile)->bounds.Width = ((REAL) (placeable->BoundingBox.Right 1344 - placeable->BoundingBox.Left)); 1345 (*metafile)->bounds.Height = ((REAL) (placeable->BoundingBox.Bottom 1346 - placeable->BoundingBox.Top)); 1347 (*metafile)->unit = UnitPixel; 1348 1349 if(delete) 1350 DeleteMetaFile(hwmf); 1351 1352 TRACE("<-- %p\n", *metafile); 1353 1354 err: 1355 if (retval != Ok) 1356 GdipFree(*metafile); 1357 IStream_Release(stream); 1358 return retval; 1359 } 1360 1361 GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file, 1362 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile) 1363 { 1364 HMETAFILE hmf = GetMetaFileW(file); 1365 1366 TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile); 1367 1368 if(!hmf) return InvalidParameter; 1369 1370 return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile); 1371 } 1372 1373 GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file, 1374 GpMetafile **metafile) 1375 { 1376 FIXME("(%p, %p): stub\n", file, metafile); 1377 return NotImplemented; 1378 } 1379 1380 GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream, 1381 GpMetafile **metafile) 1382 { 1383 FIXME("(%p, %p): stub\n", stream, metafile); 1384 return NotImplemented; 1385 } 1386 1387 GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR * filename, 1388 UINT access, IStream **stream) 1389 { 1390 DWORD dwMode; 1391 HRESULT ret; 1392 1393 TRACE("(%s, %u, %p)\n", debugstr_w(filename), access, stream); 1394 1395 if(!stream || !filename) 1396 return InvalidParameter; 1397 1398 if(access & GENERIC_WRITE) 1399 dwMode = STGM_SHARE_DENY_WRITE | STGM_WRITE | STGM_CREATE; 1400 else if(access & GENERIC_READ) 1401 dwMode = STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE; 1402 else 1403 return InvalidParameter; 1404 1405 ret = SHCreateStreamOnFileW(filename, dwMode, stream); 1406 1407 return hresult_to_status(ret); 1408 } 1409 1410 GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics) 1411 { 1412 GraphicsContainerItem *cont, *next; 1413 TRACE("(%p)\n", graphics); 1414 1415 if(!graphics) return InvalidParameter; 1416 if(graphics->busy) return ObjectBusy; 1417 1418 if(graphics->owndc) 1419 ReleaseDC(graphics->hwnd, graphics->hdc); 1420 1421 LIST_FOR_EACH_ENTRY_SAFE(cont, next, &graphics->containers, GraphicsContainerItem, entry){ 1422 list_remove(&cont->entry); 1423 delete_container(cont); 1424 } 1425 1426 GdipDeleteRegion(graphics->clip); 1427 GdipDeleteMatrix(graphics->worldtrans); 1428 GdipFree(graphics); 1429 1430 return Ok; 1431 } 1432 1433 GpStatus WINGDIPAPI GdipDrawArc(GpGraphics *graphics, GpPen *pen, REAL x, 1434 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle) 1435 { 1436 INT save_state, num_pts; 1437 GpPointF points[MAX_ARC_PTS]; 1438 GpStatus retval; 1439 1440 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, 1441 width, height, startAngle, sweepAngle); 1442 1443 if(!graphics || !pen || width <= 0 || height <= 0) 1444 return InvalidParameter; 1445 1446 if(graphics->busy) 1447 return ObjectBusy; 1448 1449 num_pts = arc2polybezier(points, x, y, width, height, startAngle, sweepAngle); 1450 1451 save_state = prepare_dc(graphics, pen); 1452 1453 retval = draw_polybezier(graphics, pen, points, num_pts, TRUE); 1454 1455 restore_dc(graphics, save_state); 1456 1457 return retval; 1458 } 1459 1460 GpStatus WINGDIPAPI GdipDrawArcI(GpGraphics *graphics, GpPen *pen, INT x, 1461 INT y, INT width, INT height, REAL startAngle, REAL sweepAngle) 1462 { 1463 TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", graphics, pen, x, y, 1464 width, height, startAngle, sweepAngle); 1465 1466 return GdipDrawArc(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle); 1467 } 1468 1469 GpStatus WINGDIPAPI GdipDrawBezier(GpGraphics *graphics, GpPen *pen, REAL x1, 1470 REAL y1, REAL x2, REAL y2, REAL x3, REAL y3, REAL x4, REAL y4) 1471 { 1472 INT save_state; 1473 GpPointF pt[4]; 1474 GpStatus retval; 1475 1476 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x1, y1, 1477 x2, y2, x3, y3, x4, y4); 1478 1479 if(!graphics || !pen) 1480 return InvalidParameter; 1481 1482 if(graphics->busy) 1483 return ObjectBusy; 1484 1485 pt[0].X = x1; 1486 pt[0].Y = y1; 1487 pt[1].X = x2; 1488 pt[1].Y = y2; 1489 pt[2].X = x3; 1490 pt[2].Y = y3; 1491 pt[3].X = x4; 1492 pt[3].Y = y4; 1493 1494 save_state = prepare_dc(graphics, pen); 1495 1496 retval = draw_polybezier(graphics, pen, pt, 4, TRUE); 1497 1498 restore_dc(graphics, save_state); 1499 1500 return retval; 1501 } 1502 1503 GpStatus WINGDIPAPI GdipDrawBezierI(GpGraphics *graphics, GpPen *pen, INT x1, 1504 INT y1, INT x2, INT y2, INT x3, INT y3, INT x4, INT y4) 1505 { 1506 INT save_state; 1507 GpPointF pt[4]; 1508 GpStatus retval; 1509 1510 TRACE("(%p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", graphics, pen, x1, y1, 1511 x2, y2, x3, y3, x4, y4); 1512 1513 if(!graphics || !pen) 1514 return InvalidParameter; 1515 1516 if(graphics->busy) 1517 return ObjectBusy; 1518 1519 pt[0].X = x1; 1520 pt[0].Y = y1; 1521 pt[1].X = x2; 1522 pt[1].Y = y2; 1523 pt[2].X = x3; 1524 pt[2].Y = y3; 1525 pt[3].X = x4; 1526 pt[3].Y = y4; 1527 1528 save_state = prepare_dc(graphics, pen); 1529 1530 retval = draw_polybezier(graphics, pen, pt, 4, TRUE); 1531 1532 restore_dc(graphics, save_state); 1533 1534 return retval; 1535 } 1536 1537 GpStatus WINGDIPAPI GdipDrawBeziers(GpGraphics *graphics, GpPen *pen, 1538 GDIPCONST GpPointF *points, INT count) 1539 { 1540 INT i; 1541 GpStatus ret; 1542 1543 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 1544 1545 if(!graphics || !pen || !points || (count <= 0)) 1546 return InvalidParameter; 1547 1548 if(graphics->busy) 1549 return ObjectBusy; 1550 1551 for(i = 0; i < floor(count / 4); i++){ 1552 ret = GdipDrawBezier(graphics, pen, 1553 points[4*i].X, points[4*i].Y, 1554 points[4*i + 1].X, points[4*i + 1].Y, 1555 points[4*i + 2].X, points[4*i + 2].Y, 1556 points[4*i + 3].X, points[4*i + 3].Y); 1557 if(ret != Ok) 1558 return ret; 1559 } 1560 1561 return Ok; 1562 } 1563 1564 GpStatus WINGDIPAPI GdipDrawBeziersI(GpGraphics *graphics, GpPen *pen, 1565 GDIPCONST GpPoint *points, INT count) 1566 { 1567 GpPointF *pts; 1568 GpStatus ret; 1569 INT i; 1570 1571 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 1572 1573 if(!graphics || !pen || !points || (count <= 0)) 1574 return InvalidParameter; 1575 1576 if(graphics->busy) 1577 return ObjectBusy; 1578 1579 pts = GdipAlloc(sizeof(GpPointF) * count); 1580 if(!pts) 1581 return OutOfMemory; 1582 1583 for(i = 0; i < count; i++){ 1584 pts[i].X = (REAL)points[i].X; 1585 pts[i].Y = (REAL)points[i].Y; 1586 } 1587 1588 ret = GdipDrawBeziers(graphics,pen,pts,count); 1589 1590 GdipFree(pts); 1591 1592 return ret; 1593 } 1594 1595 GpStatus WINGDIPAPI GdipDrawClosedCurve(GpGraphics *graphics, GpPen *pen, 1596 GDIPCONST GpPointF *points, INT count) 1597 { 1598 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 1599 1600 return GdipDrawClosedCurve2(graphics, pen, points, count, 1.0); 1601 } 1602 1603 GpStatus WINGDIPAPI GdipDrawClosedCurveI(GpGraphics *graphics, GpPen *pen, 1604 GDIPCONST GpPoint *points, INT count) 1605 { 1606 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 1607 1608 return GdipDrawClosedCurve2I(graphics, pen, points, count, 1.0); 1609 } 1610 1611 GpStatus WINGDIPAPI GdipDrawClosedCurve2(GpGraphics *graphics, GpPen *pen, 1612 GDIPCONST GpPointF *points, INT count, REAL tension) 1613 { 1614 GpPath *path; 1615 GpStatus stat; 1616 1617 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension); 1618 1619 if(!graphics || !pen || !points || count <= 0) 1620 return InvalidParameter; 1621 1622 if(graphics->busy) 1623 return ObjectBusy; 1624 1625 if((stat = GdipCreatePath(FillModeAlternate, &path)) != Ok) 1626 return stat; 1627 1628 stat = GdipAddPathClosedCurve2(path, points, count, tension); 1629 if(stat != Ok){ 1630 GdipDeletePath(path); 1631 return stat; 1632 } 1633 1634 stat = GdipDrawPath(graphics, pen, path); 1635 1636 GdipDeletePath(path); 1637 1638 return stat; 1639 } 1640 1641 GpStatus WINGDIPAPI GdipDrawClosedCurve2I(GpGraphics *graphics, GpPen *pen, 1642 GDIPCONST GpPoint *points, INT count, REAL tension) 1643 { 1644 GpPointF *ptf; 1645 GpStatus stat; 1646 INT i; 1647 1648 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension); 1649 1650 if(!points || count <= 0) 1651 return InvalidParameter; 1652 1653 ptf = GdipAlloc(sizeof(GpPointF)*count); 1654 if(!ptf) 1655 return OutOfMemory; 1656 1657 for(i = 0; i < count; i++){ 1658 ptf[i].X = (REAL)points[i].X; 1659 ptf[i].Y = (REAL)points[i].Y; 1660 } 1661 1662 stat = GdipDrawClosedCurve2(graphics, pen, ptf, count, tension); 1663 1664 GdipFree(ptf); 1665 1666 return stat; 1667 } 1668 1669 GpStatus WINGDIPAPI GdipDrawCurve(GpGraphics *graphics, GpPen *pen, 1670 GDIPCONST GpPointF *points, INT count) 1671 { 1672 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 1673 1674 return GdipDrawCurve2(graphics,pen,points,count,1.0); 1675 } 1676 1677 GpStatus WINGDIPAPI GdipDrawCurveI(GpGraphics *graphics, GpPen *pen, 1678 GDIPCONST GpPoint *points, INT count) 1679 { 1680 GpPointF *pointsF; 1681 GpStatus ret; 1682 INT i; 1683 1684 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 1685 1686 if(!points) 1687 return InvalidParameter; 1688 1689 pointsF = GdipAlloc(sizeof(GpPointF)*count); 1690 if(!pointsF) 1691 return OutOfMemory; 1692 1693 for(i = 0; i < count; i++){ 1694 pointsF[i].X = (REAL)points[i].X; 1695 pointsF[i].Y = (REAL)points[i].Y; 1696 } 1697 1698 ret = GdipDrawCurve(graphics,pen,pointsF,count); 1699 GdipFree(pointsF); 1700 1701 return ret; 1702 } 1703 1704 /* Approximates cardinal spline with Bezier curves. */ 1705 GpStatus WINGDIPAPI GdipDrawCurve2(GpGraphics *graphics, GpPen *pen, 1706 GDIPCONST GpPointF *points, INT count, REAL tension) 1707 { 1708 /* PolyBezier expects count*3-2 points. */ 1709 INT i, len_pt = count*3-2, save_state; 1710 GpPointF *pt; 1711 REAL x1, x2, y1, y2; 1712 GpStatus retval; 1713 1714 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension); 1715 1716 if(!graphics || !pen) 1717 return InvalidParameter; 1718 1719 if(graphics->busy) 1720 return ObjectBusy; 1721 1722 if(count < 2) 1723 return InvalidParameter; 1724 1725 pt = GdipAlloc(len_pt * sizeof(GpPointF)); 1726 if(!pt) 1727 return OutOfMemory; 1728 1729 tension = tension * TENSION_CONST; 1730 1731 calc_curve_bezier_endp(points[0].X, points[0].Y, points[1].X, points[1].Y, 1732 tension, &x1, &y1); 1733 1734 pt[0].X = points[0].X; 1735 pt[0].Y = points[0].Y; 1736 pt[1].X = x1; 1737 pt[1].Y = y1; 1738 1739 for(i = 0; i < count-2; i++){ 1740 calc_curve_bezier(&(points[i]), tension, &x1, &y1, &x2, &y2); 1741 1742 pt[3*i+2].X = x1; 1743 pt[3*i+2].Y = y1; 1744 pt[3*i+3].X = points[i+1].X; 1745 pt[3*i+3].Y = points[i+1].Y; 1746 pt[3*i+4].X = x2; 1747 pt[3*i+4].Y = y2; 1748 } 1749 1750 calc_curve_bezier_endp(points[count-1].X, points[count-1].Y, 1751 points[count-2].X, points[count-2].Y, tension, &x1, &y1); 1752 1753 pt[len_pt-2].X = x1; 1754 pt[len_pt-2].Y = y1; 1755 pt[len_pt-1].X = points[count-1].X; 1756 pt[len_pt-1].Y = points[count-1].Y; 1757 1758 save_state = prepare_dc(graphics, pen); 1759 1760 retval = draw_polybezier(graphics, pen, pt, len_pt, TRUE); 1761 1762 GdipFree(pt); 1763 restore_dc(graphics, save_state); 1764 1765 return retval; 1766 } 1767 1768 GpStatus WINGDIPAPI GdipDrawCurve2I(GpGraphics *graphics, GpPen *pen, 1769 GDIPCONST GpPoint *points, INT count, REAL tension) 1770 { 1771 GpPointF *pointsF; 1772 GpStatus ret; 1773 INT i; 1774 1775 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension); 1776 1777 if(!points) 1778 return InvalidParameter; 1779 1780 pointsF = GdipAlloc(sizeof(GpPointF)*count); 1781 if(!pointsF) 1782 return OutOfMemory; 1783 1784 for(i = 0; i < count; i++){ 1785 pointsF[i].X = (REAL)points[i].X; 1786 pointsF[i].Y = (REAL)points[i].Y; 1787 } 1788 1789 ret = GdipDrawCurve2(graphics,pen,pointsF,count,tension); 1790 GdipFree(pointsF); 1791 1792 return ret; 1793 } 1794 1795 GpStatus WINGDIPAPI GdipDrawCurve3(GpGraphics *graphics, GpPen *pen, 1796 GDIPCONST GpPointF *points, INT count, INT offset, INT numberOfSegments, 1797 REAL tension) 1798 { 1799 TRACE("(%p, %p, %p, %d, %d, %d, %.2f)\n", graphics, pen, points, count, offset, numberOfSegments, tension); 1800 1801 if(offset >= count || numberOfSegments > count - offset - 1 || numberOfSegments <= 0){ 1802 return InvalidParameter; 1803 } 1804 1805 return GdipDrawCurve2(graphics, pen, points + offset, numberOfSegments + 1, tension); 1806 } 1807 1808 GpStatus WINGDIPAPI GdipDrawCurve3I(GpGraphics *graphics, GpPen *pen, 1809 GDIPCONST GpPoint *points, INT count, INT offset, INT numberOfSegments, 1810 REAL tension) 1811 { 1812 TRACE("(%p, %p, %p, %d, %d, %d, %.2f)\n", graphics, pen, points, count, offset, numberOfSegments, tension); 1813 1814 if(count < 0){ 1815 return OutOfMemory; 1816 } 1817 1818 if(offset >= count || numberOfSegments > count - offset - 1 || numberOfSegments <= 0){ 1819 return InvalidParameter; 1820 } 1821 1822 return GdipDrawCurve2I(graphics, pen, points + offset, numberOfSegments + 1, tension); 1823 } 1824 1825 GpStatus WINGDIPAPI GdipDrawEllipse(GpGraphics *graphics, GpPen *pen, REAL x, 1826 REAL y, REAL width, REAL height) 1827 { 1828 INT save_state; 1829 GpPointF ptf[2]; 1830 POINT pti[2]; 1831 1832 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, width, height); 1833 1834 if(!graphics || !pen) 1835 return InvalidParameter; 1836 1837 if(graphics->busy) 1838 return ObjectBusy; 1839 1840 ptf[0].X = x; 1841 ptf[0].Y = y; 1842 ptf[1].X = x + width; 1843 ptf[1].Y = y + height; 1844 1845 save_state = prepare_dc(graphics, pen); 1846 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH)); 1847 1848 transform_and_round_points(graphics, pti, ptf, 2); 1849 1850 Ellipse(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y); 1851 1852 restore_dc(graphics, save_state); 1853 1854 return Ok; 1855 } 1856 1857 GpStatus WINGDIPAPI GdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x, 1858 INT y, INT width, INT height) 1859 { 1860 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x, y, width, height); 1861 1862 return GdipDrawEllipse(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height); 1863 } 1864 1865 1866 GpStatus WINGDIPAPI GdipDrawImage(GpGraphics *graphics, GpImage *image, REAL x, REAL y) 1867 { 1868 UINT width, height; 1869 GpPointF points[3]; 1870 1871 TRACE("(%p, %p, %.2f, %.2f)\n", graphics, image, x, y); 1872 1873 if(!graphics || !image) 1874 return InvalidParameter; 1875 1876 GdipGetImageWidth(image, &width); 1877 GdipGetImageHeight(image, &height); 1878 1879 /* FIXME: we should use the graphics and image dpi, somehow */ 1880 1881 points[0].X = points[2].X = x; 1882 points[0].Y = points[1].Y = y; 1883 points[1].X = x + width; 1884 points[2].Y = y + height; 1885 1886 return GdipDrawImagePointsRect(graphics, image, points, 3, 0, 0, width, height, 1887 UnitPixel, NULL, NULL, NULL); 1888 } 1889 1890 GpStatus WINGDIPAPI GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x, 1891 INT y) 1892 { 1893 TRACE("(%p, %p, %d, %d)\n", graphics, image, x, y); 1894 1895 return GdipDrawImage(graphics, image, (REAL)x, (REAL)y); 1896 } 1897 1898 GpStatus WINGDIPAPI GdipDrawImagePointRect(GpGraphics *graphics, GpImage *image, 1899 REAL x, REAL y, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight, 1900 GpUnit srcUnit) 1901 { 1902 GpPointF points[3]; 1903 TRACE("(%p, %p, %f, %f, %f, %f, %f, %f, %d)\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit); 1904 1905 points[0].X = points[2].X = x; 1906 points[0].Y = points[1].Y = y; 1907 1908 /* FIXME: convert image coordinates to Graphics coordinates? */ 1909 points[1].X = x + srcwidth; 1910 points[2].Y = y + srcheight; 1911 1912 return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy, 1913 srcwidth, srcheight, srcUnit, NULL, NULL, NULL); 1914 } 1915 1916 GpStatus WINGDIPAPI GdipDrawImagePointRectI(GpGraphics *graphics, GpImage *image, 1917 INT x, INT y, INT srcx, INT srcy, INT srcwidth, INT srcheight, 1918 GpUnit srcUnit) 1919 { 1920 return GdipDrawImagePointRect(graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit); 1921 } 1922 1923 GpStatus WINGDIPAPI GdipDrawImagePoints(GpGraphics *graphics, GpImage *image, 1924 GDIPCONST GpPointF *dstpoints, INT count) 1925 { 1926 FIXME("(%p, %p, %p, %d): stub\n", graphics, image, dstpoints, count); 1927 return NotImplemented; 1928 } 1929 1930 GpStatus WINGDIPAPI GdipDrawImagePointsI(GpGraphics *graphics, GpImage *image, 1931 GDIPCONST GpPoint *dstpoints, INT count) 1932 { 1933 FIXME("(%p, %p, %p, %d): stub\n", graphics, image, dstpoints, count); 1934 return NotImplemented; 1935 } 1936 1937 GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image, 1938 GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth, 1939 REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, 1940 DrawImageAbort callback, VOID * callbackData) 1941 { 1942 GpPointF ptf[4]; 1943 POINT pti[4]; 1944 REAL dx, dy; 1945 GpStatus stat; 1946 1947 TRACE("(%p, %p, %p, %d, %f, %f, %f, %f, %d, %p, %p, %p)\n", graphics, image, points, 1948 count, srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback, 1949 callbackData); 1950 1951 if(!graphics || !image || !points || count != 3) 1952 return InvalidParameter; 1953 1954 TRACE("%s %s %s\n", debugstr_pointf(&points[0]), debugstr_pointf(&points[1]), 1955 debugstr_pointf(&points[2])); 1956 1957 memcpy(ptf, points, 3 * sizeof(GpPointF)); 1958 ptf[3].X = ptf[2].X + ptf[1].X - ptf[0].X; 1959 ptf[3].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y; 1960 transform_and_round_points(graphics, pti, ptf, 4); 1961 1962 if (image->picture) 1963 { 1964 /* FIXME: partially implemented (only works for rectangular parallelograms) */ 1965 if(srcUnit == UnitInch) 1966 dx = dy = (REAL) INCH_HIMETRIC; 1967 else if(srcUnit == UnitPixel){ 1968 dx = ((REAL) INCH_HIMETRIC) / 1969 ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSX)); 1970 dy = ((REAL) INCH_HIMETRIC) / 1971 ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSY)); 1972 } 1973 else 1974 return NotImplemented; 1975 1976 if(IPicture_Render(image->picture, graphics->hdc, 1977 pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y, 1978 srcx * dx, srcy * dy, 1979 srcwidth * dx, srcheight * dy, 1980 NULL) != S_OK){ 1981 if(callback) 1982 callback(callbackData); 1983 return GenericError; 1984 } 1985 } 1986 else if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap) 1987 { 1988 GpBitmap* bitmap = (GpBitmap*)image; 1989 int use_software=0; 1990 1991 if (srcUnit == UnitInch) 1992 dx = dy = 96.0; /* FIXME: use the image resolution */ 1993 else if (srcUnit == UnitPixel) 1994 dx = dy = 1.0; 1995 else 1996 return NotImplemented; 1997 1998 if (imageAttributes || 1999 (graphics->image && graphics->image->type == ImageTypeBitmap) || 2000 ptf[1].Y != ptf[0].Y || ptf[2].X != ptf[0].X) 2001 use_software = 1; 2002 2003 if (use_software) 2004 { 2005 RECT src_area, dst_area; 2006 int i, x, y, stride; 2007 GpMatrix *dst_to_src; 2008 REAL m11, m12, m21, m22, mdx, mdy; 2009 LPBYTE data; 2010 2011 src_area.left = srcx*dx; 2012 src_area.top = srcy*dy; 2013 src_area.right = (srcx+srcwidth)*dx; 2014 src_area.bottom = (srcy+srcheight)*dy; 2015 2016 dst_area.left = dst_area.right = pti[0].x; 2017 dst_area.top = dst_area.bottom = pti[0].y; 2018 for (i=1; i<4; i++) 2019 { 2020 if (dst_area.left > pti[i].x) dst_area.left = pti[i].x; 2021 if (dst_area.right < pti[i].x) dst_area.right = pti[i].x; 2022 if (dst_area.top > pti[i].y) dst_area.top = pti[i].y; 2023 if (dst_area.bottom < pti[i].y) dst_area.bottom = pti[i].y; 2024 } 2025 2026 m11 = (ptf[1].X - ptf[0].X) / srcwidth; 2027 m21 = (ptf[2].X - ptf[0].X) / srcheight; 2028 mdx = ptf[0].X - m11 * srcx - m21 * srcy; 2029 m12 = (ptf[1].Y - ptf[0].Y) / srcwidth; 2030 m22 = (ptf[2].Y - ptf[0].Y) / srcheight; 2031 mdy = ptf[0].Y - m12 * srcx - m22 * srcy; 2032 2033 stat = GdipCreateMatrix2(m11, m12, m21, m22, mdx, mdy, &dst_to_src); 2034 if (stat != Ok) return stat; 2035 2036 stat = GdipInvertMatrix(dst_to_src); 2037 if (stat != Ok) 2038 { 2039 GdipDeleteMatrix(dst_to_src); 2040 return stat; 2041 } 2042 2043 data = GdipAlloc(sizeof(ARGB) * (dst_area.right - dst_area.left) * (dst_area.bottom - dst_area.top)); 2044 if (!data) 2045 { 2046 GdipDeleteMatrix(dst_to_src); 2047 return OutOfMemory; 2048 } 2049 2050 stride = sizeof(ARGB) * (dst_area.right - dst_area.left); 2051 2052 if (imageAttributes && 2053 (imageAttributes->wrap != WrapModeClamp || 2054 imageAttributes->outside_color != 0x00000000 || 2055 imageAttributes->clamp)) 2056 { 2057 static int fixme; 2058 if (!fixme++) 2059 FIXME("Image wrap mode not implemented\n"); 2060 } 2061 2062 for (x=dst_area.left; x<dst_area.right; x++) 2063 { 2064 for (y=dst_area.top; y<dst_area.bottom; y++) 2065 { 2066 GpPointF src_pointf; 2067 int src_x, src_y; 2068 ARGB *src_color; 2069 2070 src_pointf.X = x; 2071 src_pointf.Y = y; 2072 2073 GdipTransformMatrixPoints(dst_to_src, &src_pointf, 1); 2074 2075 src_x = roundr(src_pointf.X); 2076 src_y = roundr(src_pointf.Y); 2077 2078 src_color = (ARGB*)(data + stride * (y - dst_area.top) + sizeof(ARGB) * (x - dst_area.left)); 2079 2080 if (src_x < src_area.left || src_x >= src_area.right || 2081 src_y < src_area.top || src_y >= src_area.bottom) 2082 *src_color = 0; 2083 else 2084 GdipBitmapGetPixel(bitmap, src_x, src_y, src_color); 2085 } 2086 } 2087 2088 GdipDeleteMatrix(dst_to_src); 2089 2090 if (imageAttributes) 2091 { 2092 if (imageAttributes->colorkeys[ColorAdjustTypeBitmap].enabled || 2093 imageAttributes->colorkeys[ColorAdjustTypeDefault].enabled) 2094 { 2095 const struct color_key *key; 2096 BYTE min_blue, min_green, min_red; 2097 BYTE max_blue, max_green, max_red; 2098 2099 if (imageAttributes->colorkeys[ColorAdjustTypeBitmap].enabled) 2100 key = &imageAttributes->colorkeys[ColorAdjustTypeBitmap]; 2101 else 2102 key = &imageAttributes->colorkeys[ColorAdjustTypeDefault]; 2103 2104 min_blue = key->low&0xff; 2105 min_green = (key->low>>8)&0xff; 2106 min_red = (key->low>>16)&0xff; 2107 2108 max_blue = key->high&0xff; 2109 max_green = (key->high>>8)&0xff; 2110 max_red = (key->high>>16)&0xff; 2111 2112 for (x=dst_area.left; x<dst_area.right; x++) 2113 for (y=dst_area.top; y<dst_area.bottom; y++) 2114 { 2115 ARGB *src_color; 2116 BYTE blue, green, red; 2117 src_color = (ARGB*)(data + stride * (y - dst_area.top) + sizeof(ARGB) * (x - dst_area.left)); 2118 blue = *src_color&0xff; 2119 green = (*src_color>>8)&0xff; 2120 red = (*src_color>>16)&0xff; 2121 if (blue >= min_blue && green >= min_green && red >= min_red && 2122 blue <= max_blue && green <= max_green && red <= max_red) 2123 *src_color = 0x00000000; 2124 } 2125 } 2126 2127 if (imageAttributes->colorremaptables[ColorAdjustTypeBitmap].enabled || 2128 imageAttributes->colorremaptables[ColorAdjustTypeDefault].enabled) 2129 { 2130 const struct color_remap_table *table; 2131 2132 if (imageAttributes->colorremaptables[ColorAdjustTypeBitmap].enabled) 2133 table = &imageAttributes->colorremaptables[ColorAdjustTypeBitmap]; 2134 else 2135 table = &imageAttributes->colorremaptables[ColorAdjustTypeDefault]; 2136 2137 for (x=dst_area.left; x<dst_area.right; x++) 2138 for (y=dst_area.top; y<dst_area.bottom; y++) 2139 { 2140 ARGB *src_color; 2141 src_color = (ARGB*)(data + stride * (y - dst_area.top) + sizeof(ARGB) * (x - dst_area.left)); 2142 for (i=0; i<table->mapsize; i++) 2143 { 2144 if (*src_color == table->colormap[i].oldColor.Argb) 2145 { 2146 *src_color = table->colormap[i].newColor.Argb; 2147 break; 2148 } 2149 } 2150 } 2151 } 2152 2153 if (imageAttributes->colormatrices[ColorAdjustTypeBitmap].enabled || 2154 imageAttributes->colormatrices[ColorAdjustTypeDefault].enabled) 2155 { 2156 static int fixme; 2157 if (!fixme++) 2158 FIXME("Color transforms not implemented\n"); 2159 } 2160 2161 if (imageAttributes->gamma_enabled[ColorAdjustTypeBitmap] || 2162 imageAttributes->gamma_enabled[ColorAdjustTypeDefault]) 2163 { 2164 static int fixme; 2165 if (!fixme++) 2166 FIXME("Gamma adjustment not implemented\n"); 2167 } 2168 } 2169 2170 stat = alpha_blend_pixels(graphics, dst_area.left, dst_area.top, 2171 data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, stride); 2172 2173 GdipFree(data); 2174 2175 return stat; 2176 } 2177 else 2178 { 2179 HDC hdc; 2180 int temp_hdc=0, temp_bitmap=0; 2181 HBITMAP hbitmap, old_hbm=NULL; 2182 2183 if (!(bitmap->format == PixelFormat16bppRGB555 || 2184 bitmap->format == PixelFormat24bppRGB || 2185 bitmap->format == PixelFormat32bppRGB || 2186 bitmap->format == PixelFormat32bppPARGB)) 2187 { 2188 BITMAPINFOHEADER bih; 2189 BYTE *temp_bits; 2190 PixelFormat dst_format; 2191 2192 /* we can't draw a bitmap of this format directly */ 2193 hdc = CreateCompatibleDC(0); 2194 temp_hdc = 1; 2195 temp_bitmap = 1; 2196 2197 bih.biSize = sizeof(BITMAPINFOHEADER); 2198 bih.biWidth = bitmap->width; 2199 bih.biHeight = -bitmap->height; 2200 bih.biPlanes = 1; 2201 bih.biBitCount = 32; 2202 bih.biCompression = BI_RGB; 2203 bih.biSizeImage = 0; 2204 bih.biXPelsPerMeter = 0; 2205 bih.biYPelsPerMeter = 0; 2206 bih.biClrUsed = 0; 2207 bih.biClrImportant = 0; 2208 2209 hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, 2210 (void**)&temp_bits, NULL, 0); 2211 2212 if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha)) 2213 dst_format = PixelFormat32bppPARGB; 2214 else 2215 dst_format = PixelFormat32bppRGB; 2216 2217 convert_pixels(bitmap->width, bitmap->height, 2218 bitmap->width*4, temp_bits, dst_format, 2219 bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette_entries); 2220 } 2221 else 2222 { 2223 hbitmap = bitmap->hbitmap; 2224 hdc = bitmap->hdc; 2225 temp_hdc = (hdc == 0); 2226 } 2227 2228 if (temp_hdc) 2229 { 2230 if (!hdc) hdc = CreateCompatibleDC(0); 2231 old_hbm = SelectObject(hdc, hbitmap); 2232 } 2233 2234 if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha)) 2235 { 2236 BLENDFUNCTION bf; 2237 2238 bf.BlendOp = AC_SRC_OVER; 2239 bf.BlendFlags = 0; 2240 bf.SourceConstantAlpha = 255; 2241 bf.AlphaFormat = AC_SRC_ALPHA; 2242 2243 GdiAlphaBlend(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y, 2244 hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, bf); 2245 } 2246 else 2247 { 2248 StretchBlt(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y, 2249 hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, SRCCOPY); 2250 } 2251 2252 if (temp_hdc) 2253 { 2254 SelectObject(hdc, old_hbm); 2255 DeleteDC(hdc); 2256 } 2257 2258 if (temp_bitmap) 2259 DeleteObject(hbitmap); 2260 } 2261 } 2262 else 2263 { 2264 ERR("GpImage with no IPicture or HBITMAP?!\n"); 2265 return NotImplemented; 2266 } 2267 2268 return Ok; 2269 } 2270 2271 GpStatus WINGDIPAPI GdipDrawImagePointsRectI(GpGraphics *graphics, GpImage *image, 2272 GDIPCONST GpPoint *points, INT count, INT srcx, INT srcy, INT srcwidth, 2273 INT srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, 2274 DrawImageAbort callback, VOID * callbackData) 2275 { 2276 GpPointF pointsF[3]; 2277 INT i; 2278 2279 TRACE("(%p, %p, %p, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n", graphics, image, points, count, 2280 srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback, 2281 callbackData); 2282 2283 if(!points || count!=3) 2284 return InvalidParameter; 2285 2286 for(i = 0; i < count; i++){ 2287 pointsF[i].X = (REAL)points[i].X; 2288 pointsF[i].Y = (REAL)points[i].Y; 2289 } 2290 2291 return GdipDrawImagePointsRect(graphics, image, pointsF, count, (REAL)srcx, (REAL)srcy, 2292 (REAL)srcwidth, (REAL)srcheight, srcUnit, imageAttributes, 2293 callback, callbackData); 2294 } 2295 2296 GpStatus WINGDIPAPI GdipDrawImageRectRect(GpGraphics *graphics, GpImage *image, 2297 REAL dstx, REAL dsty, REAL dstwidth, REAL dstheight, REAL srcx, REAL srcy, 2298 REAL srcwidth, REAL srcheight, GpUnit srcUnit, 2299 GDIPCONST GpImageAttributes* imageattr, DrawImageAbort callback, 2300 VOID * callbackData) 2301 { 2302 GpPointF points[3]; 2303 2304 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p, %p, %p)\n", 2305 graphics, image, dstx, dsty, dstwidth, dstheight, srcx, srcy, 2306 srcwidth, srcheight, srcUnit, imageattr, callback, callbackData); 2307 2308 points[0].X = dstx; 2309 points[0].Y = dsty; 2310 points[1].X = dstx + dstwidth; 2311 points[1].Y = dsty; 2312 points[2].X = dstx; 2313 points[2].Y = dsty + dstheight; 2314 2315 return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy, 2316 srcwidth, srcheight, srcUnit, imageattr, callback, callbackData); 2317 } 2318 2319 GpStatus WINGDIPAPI GdipDrawImageRectRectI(GpGraphics *graphics, GpImage *image, 2320 INT dstx, INT dsty, INT dstwidth, INT dstheight, INT srcx, INT srcy, 2321 INT srcwidth, INT srcheight, GpUnit srcUnit, 2322 GDIPCONST GpImageAttributes* imageAttributes, DrawImageAbort callback, 2323 VOID * callbackData) 2324 { 2325 GpPointF points[3]; 2326 2327 TRACE("(%p, %p, %d, %d, %d, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n", 2328 graphics, image, dstx, dsty, dstwidth, dstheight, srcx, srcy, 2329 srcwidth, srcheight, srcUnit, imageAttributes, callback, callbackData); 2330 2331 points[0].X = dstx; 2332 points[0].Y = dsty; 2333 points[1].X = dstx + dstwidth; 2334 points[1].Y = dsty; 2335 points[2].X = dstx; 2336 points[2].Y = dsty + dstheight; 2337 2338 return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy, 2339 srcwidth, srcheight, srcUnit, imageAttributes, callback, callbackData); 2340 } 2341 2342 GpStatus WINGDIPAPI GdipDrawImageRect(GpGraphics *graphics, GpImage *image, 2343 REAL x, REAL y, REAL width, REAL height) 2344 { 2345 RectF bounds; 2346 GpUnit unit; 2347 GpStatus ret; 2348 2349 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, image, x, y, width, height); 2350 2351 if(!graphics || !image) 2352 return InvalidParameter; 2353 2354 ret = GdipGetImageBounds(image, &bounds, &unit); 2355 if(ret != Ok) 2356 return ret; 2357 2358 return GdipDrawImageRectRect(graphics, image, x, y, width, height, 2359 bounds.X, bounds.Y, bounds.Width, bounds.Height, 2360 unit, NULL, NULL, NULL); 2361 } 2362 2363 GpStatus WINGDIPAPI GdipDrawImageRectI(GpGraphics *graphics, GpImage *image, 2364 INT x, INT y, INT width, INT height) 2365 { 2366 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, image, x, y, width, height); 2367 2368 return GdipDrawImageRect(graphics, image, (REAL)x, (REAL)y, (REAL)width, (REAL)height); 2369 } 2370 2371 GpStatus WINGDIPAPI GdipDrawLine(GpGraphics *graphics, GpPen *pen, REAL x1, 2372 REAL y1, REAL x2, REAL y2) 2373 { 2374 INT save_state; 2375 GpPointF pt[2]; 2376 GpStatus retval; 2377 2378 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x1, y1, x2, y2); 2379 2380 if(!pen || !graphics) 2381 return InvalidParameter; 2382 2383 if(graphics->busy) 2384 return ObjectBusy; 2385 2386 pt[0].X = x1; 2387 pt[0].Y = y1; 2388 pt[1].X = x2; 2389 pt[1].Y = y2; 2390 2391 save_state = prepare_dc(graphics, pen); 2392 2393 retval = draw_polyline(graphics, pen, pt, 2, TRUE); 2394 2395 restore_dc(graphics, save_state); 2396 2397 return retval; 2398 } 2399 2400 GpStatus WINGDIPAPI GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1, 2401 INT y1, INT x2, INT y2) 2402 { 2403 INT save_state; 2404 GpPointF pt[2]; 2405 GpStatus retval; 2406 2407 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x1, y1, x2, y2); 2408 2409 if(!pen || !graphics) 2410 return InvalidParameter; 2411 2412 if(graphics->busy) 2413 return ObjectBusy; 2414 2415 pt[0].X = (REAL)x1; 2416 pt[0].Y = (REAL)y1; 2417 pt[1].X = (REAL)x2; 2418 pt[1].Y = (REAL)y2; 2419 2420 save_state = prepare_dc(graphics, pen); 2421 2422 retval = draw_polyline(graphics, pen, pt, 2, TRUE); 2423 2424 restore_dc(graphics, save_state); 2425 2426 return retval; 2427 } 2428 2429 GpStatus WINGDIPAPI GdipDrawLines(GpGraphics *graphics, GpPen *pen, GDIPCONST 2430 GpPointF *points, INT count) 2431 { 2432 INT save_state; 2433 GpStatus retval; 2434 2435 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 2436 2437 if(!pen || !graphics || (count < 2)) 2438 return InvalidParameter; 2439 2440 if(graphics->busy) 2441 return ObjectBusy; 2442 2443 save_state = prepare_dc(graphics, pen); 2444 2445 retval = draw_polyline(graphics, pen, points, count, TRUE); 2446 2447 restore_dc(graphics, save_state); 2448 2449 return retval; 2450 } 2451 2452 GpStatus WINGDIPAPI GdipDrawLinesI(GpGraphics *graphics, GpPen *pen, GDIPCONST 2453 GpPoint *points, INT count) 2454 { 2455 INT save_state; 2456 GpStatus retval; 2457 GpPointF *ptf = NULL; 2458 int i; 2459 2460 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 2461 2462 if(!pen || !graphics || (count < 2)) 2463 return InvalidParameter; 2464 2465 if(graphics->busy) 2466 return ObjectBusy; 2467 2468 ptf = GdipAlloc(count * sizeof(GpPointF)); 2469 if(!ptf) return OutOfMemory; 2470 2471 for(i = 0; i < count; i ++){ 2472 ptf[i].X = (REAL) points[i].X; 2473 ptf[i].Y = (REAL) points[i].Y; 2474 } 2475 2476 save_state = prepare_dc(graphics, pen); 2477 2478 retval = draw_polyline(graphics, pen, ptf, count, TRUE); 2479 2480 restore_dc(graphics, save_state); 2481 2482 GdipFree(ptf); 2483 return retval; 2484 } 2485 2486 GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path) 2487 { 2488 INT save_state; 2489 GpStatus retval; 2490 2491 TRACE("(%p, %p, %p)\n", graphics, pen, path); 2492 2493 if(!pen || !graphics) 2494 return InvalidParameter; 2495 2496 if(graphics->busy) 2497 return ObjectBusy; 2498 2499 save_state = prepare_dc(graphics, pen); 2500 2501 retval = draw_poly(graphics, pen, path->pathdata.Points, 2502 path->pathdata.Types, path->pathdata.Count, TRUE); 2503 2504 restore_dc(graphics, save_state); 2505 2506 return retval; 2507 } 2508 2509 GpStatus WINGDIPAPI GdipDrawPie(GpGraphics *graphics, GpPen *pen, REAL x, 2510 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle) 2511 { 2512 INT save_state; 2513 2514 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, 2515 width, height, startAngle, sweepAngle); 2516 2517 if(!graphics || !pen) 2518 return InvalidParameter; 2519 2520 if(graphics->busy) 2521 return ObjectBusy; 2522 2523 save_state = prepare_dc(graphics, pen); 2524 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH)); 2525 2526 draw_pie(graphics, x, y, width, height, startAngle, sweepAngle); 2527 2528 restore_dc(graphics, save_state); 2529 2530 return Ok; 2531 } 2532 2533 GpStatus WINGDIPAPI GdipDrawPieI(GpGraphics *graphics, GpPen *pen, INT x, 2534 INT y, INT width, INT height, REAL startAngle, REAL sweepAngle) 2535 { 2536 TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", graphics, pen, x, y, 2537 width, height, startAngle, sweepAngle); 2538 2539 return GdipDrawPie(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle); 2540 } 2541 2542 GpStatus WINGDIPAPI GdipDrawRectangle(GpGraphics *graphics, GpPen *pen, REAL x, 2543 REAL y, REAL width, REAL height) 2544 { 2545 INT save_state; 2546 GpPointF ptf[4]; 2547 POINT pti[4]; 2548 2549 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, width, height); 2550 2551 if(!pen || !graphics) 2552 return InvalidParameter; 2553 2554 if(graphics->busy) 2555 return ObjectBusy; 2556 2557 ptf[0].X = x; 2558 ptf[0].Y = y; 2559 ptf[1].X = x + width; 2560 ptf[1].Y = y; 2561 ptf[2].X = x + width; 2562 ptf[2].Y = y + height; 2563 ptf[3].X = x; 2564 ptf[3].Y = y + height; 2565 2566 save_state = prepare_dc(graphics, pen); 2567 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH)); 2568 2569 transform_and_round_points(graphics, pti, ptf, 4); 2570 Polygon(graphics->hdc, pti, 4); 2571 2572 restore_dc(graphics, save_state); 2573 2574 return Ok; 2575 } 2576 2577 GpStatus WINGDIPAPI GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x, 2578 INT y, INT width, INT height) 2579 { 2580 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x, y, width, height); 2581 2582 return GdipDrawRectangle(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height); 2583 } 2584 2585 GpStatus WINGDIPAPI GdipDrawRectangles(GpGraphics *graphics, GpPen *pen, 2586 GDIPCONST GpRectF* rects, INT count) 2587 { 2588 GpPointF *ptf; 2589 POINT *pti; 2590 INT save_state, i; 2591 2592 TRACE("(%p, %p, %p, %d)\n", graphics, pen, rects, count); 2593 2594 if(!graphics || !pen || !rects || count < 1) 2595 return InvalidParameter; 2596 2597 if(graphics->busy) 2598 return ObjectBusy; 2599 2600 ptf = GdipAlloc(4 * count * sizeof(GpPointF)); 2601 pti = GdipAlloc(4 * count * sizeof(POINT)); 2602 2603 if(!ptf || !pti){ 2604 GdipFree(ptf); 2605 GdipFree(pti); 2606 return OutOfMemory; 2607 } 2608 2609 for(i = 0; i < count; i++){ 2610 ptf[4 * i + 3].X = ptf[4 * i].X = rects[i].X; 2611 ptf[4 * i + 1].Y = ptf[4 * i].Y = rects[i].Y; 2612 ptf[4 * i + 2].X = ptf[4 * i + 1].X = rects[i].X + rects[i].Width; 2613 ptf[4 * i + 3].Y = ptf[4 * i + 2].Y = rects[i].Y + rects[i].Height; 2614 } 2615 2616 save_state = prepare_dc(graphics, pen); 2617 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH)); 2618 2619 transform_and_round_points(graphics, pti, ptf, 4 * count); 2620 2621 for(i = 0; i < count; i++) 2622 Polygon(graphics->hdc, &pti[4 * i], 4); 2623 2624 restore_dc(graphics, save_state); 2625 2626 GdipFree(ptf); 2627 GdipFree(pti); 2628 2629 return Ok; 2630 } 2631 2632 GpStatus WINGDIPAPI GdipDrawRectanglesI(GpGraphics *graphics, GpPen *pen, 2633 GDIPCONST GpRect* rects, INT count) 2634 { 2635 GpRectF *rectsF; 2636 GpStatus ret; 2637 INT i; 2638 2639 TRACE("(%p, %p, %p, %d)\n", graphics, pen, rects, count); 2640 2641 if(!rects || count<=0) 2642 return InvalidParameter; 2643 2644 rectsF = GdipAlloc(sizeof(GpRectF) * count); 2645 if(!rectsF) 2646 return OutOfMemory; 2647 2648 for(i = 0;i < count;i++){ 2649 rectsF[i].X = (REAL)rects[i].X; 2650 rectsF[i].Y = (REAL)rects[i].Y; 2651 rectsF[i].Width = (REAL)rects[i].Width; 2652 rectsF[i].Height = (REAL)rects[i].Height; 2653 } 2654 2655 ret = GdipDrawRectangles(graphics, pen, rectsF, count); 2656 GdipFree(rectsF); 2657 2658 return ret; 2659 } 2660 2661 GpStatus WINGDIPAPI GdipFillClosedCurve2(GpGraphics *graphics, GpBrush *brush, 2662 GDIPCONST GpPointF *points, INT count, REAL tension, GpFillMode fill) 2663 { 2664 GpPath *path; 2665 GpStatus stat; 2666 2667 TRACE("(%p, %p, %p, %d, %.2f, %d)\n", graphics, brush, points, 2668 count, tension, fill); 2669 2670 if(!graphics || !brush || !points) 2671 return InvalidParameter; 2672 2673 if(graphics->busy) 2674 return ObjectBusy; 2675 2676 stat = GdipCreatePath(fill, &path); 2677 if(stat != Ok) 2678 return stat; 2679 2680 stat = GdipAddPathClosedCurve2(path, points, count, tension); 2681 if(stat != Ok){ 2682 GdipDeletePath(path); 2683 return stat; 2684 } 2685 2686 stat = GdipFillPath(graphics, brush, path); 2687 if(stat != Ok){ 2688 GdipDeletePath(path); 2689 return stat; 2690 } 2691 2692 GdipDeletePath(path); 2693 2694 return Ok; 2695 } 2696 2697 GpStatus WINGDIPAPI GdipFillClosedCurve2I(GpGraphics *graphics, GpBrush *brush, 2698 GDIPCONST GpPoint *points, INT count, REAL tension, GpFillMode fill) 2699 { 2700 GpPointF *ptf; 2701 GpStatus stat; 2702 INT i; 2703 2704 TRACE("(%p, %p, %p, %d, %.2f, %d)\n", graphics, brush, points, 2705 count, tension, fill); 2706 2707 if(!points || count <= 0) 2708 return InvalidParameter; 2709 2710 ptf = GdipAlloc(sizeof(GpPointF)*count); 2711 if(!ptf) 2712 return OutOfMemory; 2713 2714 for(i = 0;i < count;i++){ 2715 ptf[i].X = (REAL)points[i].X; 2716 ptf[i].Y = (REAL)points[i].Y; 2717 } 2718 2719 stat = GdipFillClosedCurve2(graphics, brush, ptf, count, tension, fill); 2720 2721 GdipFree(ptf); 2722 2723 return stat; 2724 } 2725 2726 GpStatus WINGDIPAPI GdipFillEllipse(GpGraphics *graphics, GpBrush *brush, REAL x, 2727 REAL y, REAL width, REAL height) 2728 { 2729 INT save_state; 2730 GpPointF ptf[2]; 2731 POINT pti[2]; 2732 2733 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height); 2734 2735 if(!graphics || !brush) 2736 return InvalidParameter; 2737 2738 if(graphics->busy) 2739 return ObjectBusy; 2740 2741 ptf[0].X = x; 2742 ptf[0].Y = y; 2743 ptf[1].X = x + width; 2744 ptf[1].Y = y + height; 2745 2746 save_state = SaveDC(graphics->hdc); 2747 EndPath(graphics->hdc); 2748 2749 transform_and_round_points(graphics, pti, ptf, 2); 2750 2751 BeginPath(graphics->hdc); 2752 Ellipse(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y); 2753 EndPath(graphics->hdc); 2754 2755 brush_fill_path(graphics, brush); 2756 2757 RestoreDC(graphics->hdc, save_state); 2758 2759 return Ok; 2760 } 2761 2762 GpStatus WINGDIPAPI GdipFillEllipseI(GpGraphics *graphics, GpBrush *brush, INT x, 2763 INT y, INT width, INT height) 2764 { 2765 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height); 2766 2767 return GdipFillEllipse(graphics,brush,(REAL)x,(REAL)y,(REAL)width,(REAL)height); 2768 } 2769 2770 GpStatus WINGDIPAPI GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *path) 2771 { 2772 INT save_state; 2773 GpStatus retval; 2774 2775 TRACE("(%p, %p, %p)\n", graphics, brush, path); 2776 2777 if(!brush || !graphics || !path) 2778 return InvalidParameter; 2779 2780 if(graphics->busy) 2781 return ObjectBusy; 2782 2783 save_state = SaveDC(graphics->hdc); 2784 EndPath(graphics->hdc); 2785 SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE 2786 : WINDING)); 2787 2788 BeginPath(graphics->hdc); 2789 retval = draw_poly(graphics, NULL, path->pathdata.Points, 2790 path->pathdata.Types, path->pathdata.Count, FALSE); 2791 2792 if(retval != Ok) 2793 goto end; 2794 2795 EndPath(graphics->hdc); 2796 brush_fill_path(graphics, brush); 2797 2798 retval = Ok; 2799 2800 end: 2801 RestoreDC(graphics->hdc, save_state); 2802 2803 return retval; 2804 } 2805 2806 GpStatus WINGDIPAPI GdipFillPie(GpGraphics *graphics, GpBrush *brush, REAL x, 2807 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle) 2808 { 2809 INT save_state; 2810 2811 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", 2812 graphics, brush, x, y, width, height, startAngle, sweepAngle); 2813 2814 if(!graphics || !brush) 2815 return InvalidParameter; 2816 2817 if(graphics->busy) 2818 return ObjectBusy; 2819 2820 save_state = SaveDC(graphics->hdc); 2821 EndPath(graphics->hdc); 2822 2823 BeginPath(graphics->hdc); 2824 draw_pie(graphics, x, y, width, height, startAngle, sweepAngle); 2825 EndPath(graphics->hdc); 2826 2827 brush_fill_path(graphics, brush); 2828 2829 RestoreDC(graphics->hdc, save_state); 2830 2831 return Ok; 2832 } 2833 2834 GpStatus WINGDIPAPI GdipFillPieI(GpGraphics *graphics, GpBrush *brush, INT x, 2835 INT y, INT width, INT height, REAL startAngle, REAL sweepAngle) 2836 { 2837 TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", 2838 graphics, brush, x, y, width, height, startAngle, sweepAngle); 2839 2840 return GdipFillPie(graphics,brush,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle); 2841 } 2842 2843 GpStatus WINGDIPAPI GdipFillPolygon(GpGraphics *graphics, GpBrush *brush, 2844 GDIPCONST GpPointF *points, INT count, GpFillMode fillMode) 2845 { 2846 INT save_state; 2847 GpPointF *ptf = NULL; 2848 POINT *pti = NULL; 2849 GpStatus retval = Ok; 2850 2851 TRACE("(%p, %p, %p, %d, %d)\n", graphics, brush, points, count, fillMode); 2852 2853 if(!graphics || !brush || !points || !count) 2854 return InvalidParameter; 2855 2856 if(graphics->busy) 2857 return ObjectBusy; 2858 2859 ptf = GdipAlloc(count * sizeof(GpPointF)); 2860 pti = GdipAlloc(count * sizeof(POINT)); 2861 if(!ptf || !pti){ 2862 retval = OutOfMemory; 2863 goto end; 2864 } 2865 2866 memcpy(ptf, points, count * sizeof(GpPointF)); 2867 2868 save_state = SaveDC(graphics->hdc); 2869 EndPath(graphics->hdc); 2870 SetPolyFillMode(graphics->hdc, (fillMode == FillModeAlternate ? ALTERNATE 2871 : WINDING)); 2872 2873 transform_and_round_points(graphics, pti, ptf, count); 2874 2875 BeginPath(graphics->hdc); 2876 Polygon(graphics->hdc, pti, count); 2877 EndPath(graphics->hdc); 2878 2879 brush_fill_path(graphics, brush); 2880 2881 RestoreDC(graphics->hdc, save_state); 2882 2883 end: 2884 GdipFree(ptf); 2885 GdipFree(pti); 2886 2887 return retval; 2888 } 2889 2890 GpStatus WINGDIPAPI GdipFillPolygonI(GpGraphics *graphics, GpBrush *brush, 2891 GDIPCONST GpPoint *points, INT count, GpFillMode fillMode) 2892 { 2893 INT save_state, i; 2894 GpPointF *ptf = NULL; 2895 POINT *pti = NULL; 2896 GpStatus retval = Ok; 2897 2898 TRACE("(%p, %p, %p, %d, %d)\n", graphics, brush, points, count, fillMode); 2899 2900 if(!graphics || !brush || !points || !count) 2901 return InvalidParameter; 2902 2903 if(graphics->busy) 2904 return ObjectBusy; 2905 2906 ptf = GdipAlloc(count * sizeof(GpPointF)); 2907 pti = GdipAlloc(count * sizeof(POINT)); 2908 if(!ptf || !pti){ 2909 retval = OutOfMemory; 2910 goto end; 2911 } 2912 2913 for(i = 0; i < count; i ++){ 2914 ptf[i].X = (REAL) points[i].X; 2915 ptf[i].Y = (REAL) points[i].Y; 2916 } 2917 2918 save_state = SaveDC(graphics->hdc); 2919 EndPath(graphics->hdc); 2920 SetPolyFillMode(graphics->hdc, (fillMode == FillModeAlternate ? ALTERNATE 2921 : WINDING)); 2922 2923 transform_and_round_points(graphics, pti, ptf, count); 2924 2925 BeginPath(graphics->hdc); 2926 Polygon(graphics->hdc, pti, count); 2927 EndPath(graphics->hdc); 2928 2929 brush_fill_path(graphics, brush); 2930 2931 RestoreDC(graphics->hdc, save_state); 2932 2933 end: 2934 GdipFree(ptf); 2935 GdipFree(pti); 2936 2937 return retval; 2938 } 2939 2940 GpStatus WINGDIPAPI GdipFillPolygon2(GpGraphics *graphics, GpBrush *brush, 2941 GDIPCONST GpPointF *points, INT count) 2942 { 2943 TRACE("(%p, %p, %p, %d)\n", graphics, brush, points, count); 2944 2945 return GdipFillPolygon(graphics, brush, points, count, FillModeAlternate); 2946 } 2947 2948 GpStatus WINGDIPAPI GdipFillPolygon2I(GpGraphics *graphics, GpBrush *brush, 2949 GDIPCONST GpPoint *points, INT count) 2950 { 2951 TRACE("(%p, %p, %p, %d)\n", graphics, brush, points, count); 2952 2953 return GdipFillPolygonI(graphics, brush, points, count, FillModeAlternate); 2954 } 2955 2956 GpStatus WINGDIPAPI GdipFillRectangle(GpGraphics *graphics, GpBrush *brush, 2957 REAL x, REAL y, REAL width, REAL height) 2958 { 2959 INT save_state; 2960 GpPointF ptf[4]; 2961 POINT pti[4]; 2962 2963 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height); 2964 2965 if(!graphics || !brush) 2966 return InvalidParameter; 2967 2968 if(graphics->busy) 2969 return ObjectBusy; 2970 2971 ptf[0].X = x; 2972 ptf[0].Y = y; 2973 ptf[1].X = x + width; 2974 ptf[1].Y = y; 2975 ptf[2].X = x + width; 2976 ptf[2].Y = y + height; 2977 ptf[3].X = x; 2978 ptf[3].Y = y + height; 2979 2980 save_state = SaveDC(graphics->hdc); 2981 EndPath(graphics->hdc); 2982 2983 transform_and_round_points(graphics, pti, ptf, 4); 2984 2985 BeginPath(graphics->hdc); 2986 Polygon(graphics->hdc, pti, 4); 2987 EndPath(graphics->hdc); 2988 2989 brush_fill_path(graphics, brush); 2990 2991 RestoreDC(graphics->hdc, save_state); 2992 2993 return Ok; 2994 } 2995 2996 GpStatus WINGDIPAPI GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush, 2997 INT x, INT y, INT width, INT height) 2998 { 2999 INT save_state; 3000 GpPointF ptf[4]; 3001 POINT pti[4]; 3002 3003 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height); 3004 3005 if(!graphics || !brush) 3006 return InvalidParameter; 3007 3008 if(graphics->busy) 3009 return ObjectBusy; 3010 3011 ptf[0].X = x; 3012 ptf[0].Y = y; 3013 ptf[1].X = x + width; 3014 ptf[1].Y = y; 3015 ptf[2].X = x + width; 3016 ptf[2].Y = y + height; 3017 ptf[3].X = x; 3018 ptf[3].Y = y + height; 3019 3020 save_state = SaveDC(graphics->hdc); 3021 EndPath(graphics->hdc); 3022 3023 transform_and_round_points(graphics, pti, ptf, 4); 3024 3025 BeginPath(graphics->hdc); 3026 Polygon(graphics->hdc, pti, 4); 3027 EndPath(graphics->hdc); 3028 3029 brush_fill_path(graphics, brush); 3030 3031 RestoreDC(graphics->hdc, save_state); 3032 3033 return Ok; 3034 } 3035 3036 GpStatus WINGDIPAPI GdipFillRectangles(GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRectF *rects, 3037 INT count) 3038 { 3039 GpStatus ret; 3040 INT i; 3041 3042 TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count); 3043 3044 if(!rects) 3045 return InvalidParameter; 3046 3047 for(i = 0; i < count; i++){ 3048 ret = GdipFillRectangle(graphics, brush, rects[i].X, rects[i].Y, rects[i].Width, rects[i].Height); 3049 if(ret != Ok) return ret; 3050 } 3051 3052 return Ok; 3053 } 3054 3055 GpStatus WINGDIPAPI GdipFillRectanglesI(GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRect *rects, 3056 INT count) 3057 { 3058 GpRectF *rectsF; 3059 GpStatus ret; 3060 INT i; 3061 3062 TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count); 3063 3064 if(!rects || count <= 0) 3065 return InvalidParameter; 3066 3067 rectsF = GdipAlloc(sizeof(GpRectF)*count); 3068 if(!rectsF) 3069 return OutOfMemory; 3070 3071 for(i = 0; i < count; i++){ 3072 rectsF[i].X = (REAL)rects[i].X; 3073 rectsF[i].Y = (REAL)rects[i].Y; 3074 rectsF[i].X = (REAL)rects[i].Width; 3075 rectsF[i].Height = (REAL)rects[i].Height; 3076 } 3077 3078 ret = GdipFillRectangles(graphics,brush,rectsF,count); 3079 GdipFree(rectsF); 3080 3081 return ret; 3082 } 3083 3084 /***************************************************************************** 3085 * GdipFillRegion [GDIPLUS.@] 3086 */ 3087 GpStatus WINGDIPAPI GdipFillRegion(GpGraphics* graphics, GpBrush* brush, 3088 GpRegion* region) 3089 { 3090 INT save_state; 3091 GpStatus status; 3092 HRGN hrgn; 3093 RECT rc; 3094 3095 TRACE("(%p, %p, %p)\n", graphics, brush, region); 3096 3097 if (!(graphics && brush && region)) 3098 return InvalidParameter; 3099 3100 if(graphics->busy) 3101 return ObjectBusy; 3102 3103 status = GdipGetRegionHRgn(region, graphics, &hrgn); 3104 if(status != Ok) 3105 return status; 3106 3107 save_state = SaveDC(graphics->hdc); 3108 EndPath(graphics->hdc); 3109 3110 ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND); 3111 3112 if (GetClipBox(graphics->hdc, &rc) != NULLREGION) 3113 { 3114 BeginPath(graphics->hdc); 3115 Rectangle(graphics->hdc, rc.left, rc.top, rc.right, rc.bottom); 3116 EndPath(graphics->hdc); 3117 3118 brush_fill_path(graphics, brush); 3119 } 3120 3121 RestoreDC(graphics->hdc, save_state); 3122 3123 DeleteObject(hrgn); 3124 3125 return Ok; 3126 } 3127 3128 GpStatus WINGDIPAPI GdipFlush(GpGraphics *graphics, GpFlushIntention intention) 3129 { 3130 TRACE("(%p,%u)\n", graphics, intention); 3131 3132 if(!graphics) 3133 return InvalidParameter; 3134 3135 if(graphics->busy) 3136 return ObjectBusy; 3137 3138 /* We have no internal operation queue, so there's no need to clear it. */ 3139 3140 if (graphics->hdc) 3141 GdiFlush(); 3142 3143 return Ok; 3144 } 3145 3146 /***************************************************************************** 3147 * GdipGetClipBounds [GDIPLUS.@] 3148 */ 3149 GpStatus WINGDIPAPI GdipGetClipBounds(GpGraphics *graphics, GpRectF *rect) 3150 { 3151 TRACE("(%p, %p)\n", graphics, rect); 3152 3153 if(!graphics) 3154 return InvalidParameter; 3155 3156 if(graphics->busy) 3157 return ObjectBusy; 3158 3159 return GdipGetRegionBounds(graphics->clip, graphics, rect); 3160 } 3161 3162 /***************************************************************************** 3163 * GdipGetClipBoundsI [GDIPLUS.@] 3164 */ 3165 GpStatus WINGDIPAPI GdipGetClipBoundsI(GpGraphics *graphics, GpRect *rect) 3166 { 3167 TRACE("(%p, %p)\n", graphics, rect); 3168 3169 if(!graphics) 3170 return InvalidParameter; 3171 3172 if(graphics->busy) 3173 return ObjectBusy; 3174 3175 return GdipGetRegionBoundsI(graphics->clip, graphics, rect); 3176 } 3177 3178 /* FIXME: Compositing mode is not used anywhere except the getter/setter. */ 3179 GpStatus WINGDIPAPI GdipGetCompositingMode(GpGraphics *graphics, 3180 CompositingMode *mode) 3181 { 3182 TRACE("(%p, %p)\n", graphics, mode); 3183 3184 if(!graphics || !mode) 3185 return InvalidParameter; 3186 3187 if(graphics->busy) 3188 return ObjectBusy; 3189 3190 *mode = graphics->compmode; 3191 3192 return Ok; 3193 } 3194 3195 /* FIXME: Compositing quality is not used anywhere except the getter/setter. */ 3196 GpStatus WINGDIPAPI GdipGetCompositingQuality(GpGraphics *graphics, 3197 CompositingQuality *quality) 3198 { 3199 TRACE("(%p, %p)\n", graphics, quality); 3200 3201 if(!graphics || !quality) 3202 return InvalidParameter; 3203 3204 if(graphics->busy) 3205 return ObjectBusy; 3206 3207 *quality = graphics->compqual; 3208 3209 return Ok; 3210 } 3211 3212 /* FIXME: Interpolation mode is not used anywhere except the getter/setter. */ 3213 GpStatus WINGDIPAPI GdipGetInterpolationMode(GpGraphics *graphics, 3214 InterpolationMode *mode) 3215 { 3216 TRACE("(%p, %p)\n", graphics, mode); 3217 3218 if(!graphics || !mode) 3219 return InvalidParameter; 3220 3221 if(graphics->busy) 3222 return ObjectBusy; 3223 3224 *mode = graphics->interpolation; 3225 3226 return Ok; 3227 } 3228 3229 /* FIXME: Need to handle color depths less than 24bpp */ 3230 GpStatus WINGDIPAPI GdipGetNearestColor(GpGraphics *graphics, ARGB* argb) 3231 { 3232 FIXME("(%p, %p): Passing color unmodified\n", graphics, argb); 3233 3234 if(!graphics || !argb) 3235 return InvalidParameter; 3236 3237 if(graphics->busy) 3238 return ObjectBusy; 3239 3240 return Ok; 3241 } 3242 3243 GpStatus WINGDIPAPI GdipGetPageScale(GpGraphics *graphics, REAL *scale) 3244 { 3245 TRACE("(%p, %p)\n", graphics, scale); 3246 3247 if(!graphics || !scale) 3248 return InvalidParameter; 3249 3250 if(graphics->busy) 3251 return ObjectBusy; 3252 3253 *scale = graphics->scale; 3254 3255 return Ok; 3256 } 3257 3258 GpStatus WINGDIPAPI GdipGetPageUnit(GpGraphics *graphics, GpUnit *unit) 3259 { 3260 TRACE("(%p, %p)\n", graphics, unit); 3261 3262 if(!graphics || !unit) 3263 return InvalidParameter; 3264 3265 if(graphics->busy) 3266 return ObjectBusy; 3267 3268 *unit = graphics->unit; 3269 3270 return Ok; 3271 } 3272 3273 /* FIXME: Pixel offset mode is not used anywhere except the getter/setter. */ 3274 GpStatus WINGDIPAPI GdipGetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode 3275 *mode) 3276 { 3277 TRACE("(%p, %p)\n", graphics, mode); 3278 3279 if(!graphics || !mode) 3280 return InvalidParameter; 3281 3282 if(graphics->busy) 3283 return ObjectBusy; 3284 3285 *mode = graphics->pixeloffset; 3286 3287 return Ok; 3288 } 3289 3290 /* FIXME: Smoothing mode is not used anywhere except the getter/setter. */ 3291 GpStatus WINGDIPAPI GdipGetSmoothingMode(GpGraphics *graphics, SmoothingMode *mode) 3292 { 3293 TRACE("(%p, %p)\n", graphics, mode); 3294 3295 if(!graphics || !mode) 3296 return InvalidParameter; 3297 3298 if(graphics->busy) 3299 return ObjectBusy; 3300 3301 *mode = graphics->smoothing; 3302 3303 return Ok; 3304 } 3305 3306 GpStatus WINGDIPAPI GdipGetTextContrast(GpGraphics *graphics, UINT *contrast) 3307 { 3308 TRACE("(%p, %p)\n", graphics, contrast); 3309 3310 if(!graphics || !contrast) 3311 return InvalidParameter; 3312 3313 *contrast = graphics->textcontrast; 3314 3315 return Ok; 3316 } 3317 3318 /* FIXME: Text rendering hint is not used anywhere except the getter/setter. */ 3319 GpStatus WINGDIPAPI GdipGetTextRenderingHint(GpGraphics *graphics, 3320 TextRenderingHint *hint) 3321 { 3322 TRACE("(%p, %p)\n", graphics, hint); 3323 3324 if(!graphics || !hint) 3325 return InvalidParameter; 3326 3327 if(graphics->busy) 3328 return ObjectBusy; 3329 3330 *hint = graphics->texthint; 3331 3332 return Ok; 3333 } 3334 3335 GpStatus WINGDIPAPI GdipGetVisibleClipBounds(GpGraphics *graphics, GpRectF *rect) 3336 { 3337 GpRegion *clip_rgn; 3338 GpStatus stat; 3339 3340 TRACE("(%p, %p)\n", graphics, rect); 3341 3342 if(!graphics || !rect) 3343 return InvalidParameter; 3344 3345 if(graphics->busy) 3346 return ObjectBusy; 3347 3348 /* intersect window and graphics clipping regions */ 3349 if((stat = GdipCreateRegion(&clip_rgn)) != Ok) 3350 return stat; 3351 3352 if((stat = get_visible_clip_region(graphics, clip_rgn)) != Ok) 3353 goto cleanup; 3354 3355 /* get bounds of the region */ 3356 stat = GdipGetRegionBounds(clip_rgn, graphics, rect); 3357 3358 cleanup: 3359 GdipDeleteRegion(clip_rgn); 3360 3361 return stat; 3362 } 3363 3364 GpStatus WINGDIPAPI GdipGetVisibleClipBoundsI(GpGraphics *graphics, GpRect *rect) 3365 { 3366 GpRectF rectf; 3367 GpStatus stat; 3368 3369 TRACE("(%p, %p)\n", graphics, rect); 3370 3371 if(!graphics || !rect) 3372 return InvalidParameter; 3373 3374 if((stat = GdipGetVisibleClipBounds(graphics, &rectf)) == Ok) 3375 { 3376 rect->X = roundr(rectf.X); 3377 rect->Y = roundr(rectf.Y); 3378 rect->Width = roundr(rectf.Width); 3379 rect->Height = roundr(rectf.Height); 3380 } 3381 3382 return stat; 3383 } 3384 3385 GpStatus WINGDIPAPI GdipGetWorldTransform(GpGraphics *graphics, GpMatrix *matrix) 3386 { 3387 TRACE("(%p, %p)\n", graphics, matrix); 3388 3389 if(!graphics || !matrix) 3390 return InvalidParameter; 3391 3392 if(graphics->busy) 3393 return ObjectBusy; 3394 3395 *matrix = *graphics->worldtrans; 3396 return Ok; 3397 } 3398 3399 GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics *graphics, ARGB color) 3400 { 3401 GpSolidFill *brush; 3402 GpStatus stat; 3403 GpRectF wnd_rect; 3404 3405 TRACE("(%p, %x)\n", graphics, color); 3406 3407 if(!graphics) 3408 return InvalidParameter; 3409 3410 if(graphics->busy) 3411 return ObjectBusy; 3412 3413 if((stat = GdipCreateSolidFill(color, &brush)) != Ok) 3414 return stat; 3415 3416 if((stat = get_graphics_bounds(graphics, &wnd_rect)) != Ok){ 3417 GdipDeleteBrush((GpBrush*)brush); 3418 return stat; 3419 } 3420 3421 GdipFillRectangle(graphics, (GpBrush*)brush, wnd_rect.X, wnd_rect.Y, 3422 wnd_rect.Width, wnd_rect.Height); 3423 3424 GdipDeleteBrush((GpBrush*)brush); 3425 3426 return Ok; 3427 } 3428 3429 GpStatus WINGDIPAPI GdipIsClipEmpty(GpGraphics *graphics, BOOL *res) 3430 { 3431 TRACE("(%p, %p)\n", graphics, res); 3432 3433 if(!graphics || !res) 3434 return InvalidParameter; 3435 3436 return GdipIsEmptyRegion(graphics->clip, graphics, res); 3437 } 3438 3439 GpStatus WINGDIPAPI GdipIsVisiblePoint(GpGraphics *graphics, REAL x, REAL y, BOOL *result) 3440 { 3441 GpStatus stat; 3442 GpRegion* rgn; 3443 GpPointF pt; 3444 3445 TRACE("(%p, %.2f, %.2f, %p)\n", graphics, x, y, result); 3446 3447 if(!graphics || !result) 3448 return InvalidParameter; 3449 3450 if(graphics->busy) 3451 return ObjectBusy; 3452 3453 pt.X = x; 3454 pt.Y = y; 3455 if((stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, 3456 CoordinateSpaceWorld, &pt, 1)) != Ok) 3457 return stat; 3458 3459 if((stat = GdipCreateRegion(&rgn)) != Ok) 3460 return stat; 3461 3462 if((stat = get_visible_clip_region(graphics, rgn)) != Ok) 3463 goto cleanup; 3464 3465 stat = GdipIsVisibleRegionPoint(rgn, pt.X, pt.Y, graphics, result); 3466 3467 cleanup: 3468 GdipDeleteRegion(rgn); 3469 return stat; 3470 } 3471 3472 GpStatus WINGDIPAPI GdipIsVisiblePointI(GpGraphics *graphics, INT x, INT y, BOOL *result) 3473 { 3474 return GdipIsVisiblePoint(graphics, (REAL)x, (REAL)y, result); 3475 } 3476 3477 GpStatus WINGDIPAPI GdipIsVisibleRect(GpGraphics *graphics, REAL x, REAL y, REAL width, REAL height, BOOL *result) 3478 { 3479 GpStatus stat; 3480 GpRegion* rgn; 3481 GpPointF pts[2]; 3482 3483 TRACE("(%p %.2f %.2f %.2f %.2f %p)\n", graphics, x, y, width, height, result); 3484 3485 if(!graphics || !result) 3486 return InvalidParameter; 3487 3488 if(graphics->busy) 3489 return ObjectBusy; 3490 3491 pts[0].X = x; 3492 pts[0].Y = y; 3493 pts[1].X = x + width; 3494 pts[1].Y = y + height; 3495 3496 if((stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, 3497 CoordinateSpaceWorld, pts, 2)) != Ok) 3498 return stat; 3499 3500 pts[1].X -= pts[0].X; 3501 pts[1].Y -= pts[0].Y; 3502 3503 if((stat = GdipCreateRegion(&rgn)) != Ok) 3504 return stat; 3505 3506 if((stat = get_visible_clip_region(graphics, rgn)) != Ok) 3507 goto cleanup; 3508 3509 stat = GdipIsVisibleRegionRect(rgn, pts[0].X, pts[0].Y, pts[1].X, pts[1].Y, graphics, result); 3510 3511 cleanup: 3512 GdipDeleteRegion(rgn); 3513 return stat; 3514 } 3515 3516 GpStatus WINGDIPAPI GdipIsVisibleRectI(GpGraphics *graphics, INT x, INT y, INT width, INT height, BOOL *result) 3517 { 3518 return GdipIsVisibleRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, result); 3519 } 3520 3521 typedef GpStatus (*gdip_format_string_callback)(GpGraphics *graphics, 3522 GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font, 3523 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, 3524 INT lineno, const RectF *bounds, void *user_data); 3525 3526 static GpStatus gdip_format_string(GpGraphics *graphics, 3527 GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, 3528 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, 3529 gdip_format_string_callback callback, void *user_data) 3530 { 3531 WCHAR* stringdup; 3532 int sum = 0, height = 0, fit, fitcpy, i, j, lret, nwidth, 3533 nheight, lineend, lineno = 0; 3534 RectF bounds; 3535 StringAlignment halign; 3536 GpStatus stat = Ok; 3537 SIZE size; 3538 3539 if(length == -1) length = lstrlenW(string); 3540 3541 stringdup = GdipAlloc((length + 1) * sizeof(WCHAR)); 3542 if(!stringdup) return OutOfMemory; 3543 3544 nwidth = roundr(rect->Width); 3545 nheight = roundr(rect->Height); 3546 3547 if (rect->Width >= INT_MAX || rect->Width < 0.5) nwidth = INT_MAX; 3548 if (rect->Height >= INT_MAX || rect->Width < 0.5) nheight = INT_MAX; 3549 3550 for(i = 0, j = 0; i < length; i++){ 3551 /* FIXME: This makes the indexes passed to callback inaccurate. */ 3552 if(!isprintW(string[i]) && (string[i] != '\n')) 3553 continue; 3554 3555 stringdup[j] = string[i]; 3556 j++; 3557 } 3558 3559 length = j; 3560 3561 if (format) halign = format->align; 3562 else halign = StringAlignmentNear; 3563 3564 while(sum < length){ 3565 GetTextExtentExPointW(graphics->hdc, stringdup + sum, length - sum, 3566 nwidth, &fit, NULL, &size); 3567 fitcpy = fit; 3568 3569 if(fit == 0) 3570 break; 3571 3572 for(lret = 0; lret < fit; lret++) 3573 if(*(stringdup + sum + lret) == '\n') 3574 break; 3575 3576 /* Line break code (may look strange, but it imitates windows). */ 3577 if(lret < fit) 3578 lineend = fit = lret; /* this is not an off-by-one error */ 3579 else if(fit < (length - sum)){ 3580 if(*(stringdup + sum + fit) == ' ') 3581 while(*(stringdup + sum + fit) == ' ') 3582 fit++; 3583 else 3584 while(*(stringdup + sum + fit - 1) != ' '){ 3585 fit--; 3586 3587 if(*(stringdup + sum + fit) == '\t') 3588 break; 3589 3590 if(fit == 0){ 3591 fit = fitcpy; 3592 break; 3593 } 3594 } 3595 lineend = fit; 3596 while(*(stringdup + sum + lineend - 1) == ' ' || 3597 *(stringdup + sum + lineend - 1) == '\t') 3598 lineend--; 3599 } 3600 else 3601 lineend = fit; 3602 3603 GetTextExtentExPointW(graphics->hdc, stringdup + sum, lineend, 3604 nwidth, &j, NULL, &size); 3605 3606 bounds.Width = size.cx; 3607 3608 if(height + size.cy > nheight) 3609 bounds.Height = nheight - (height + size.cy); 3610 else 3611 bounds.Height = size.cy; 3612 3613 bounds.Y = rect->Y + height; 3614 3615 switch (halign) 3616 { 3617 case StringAlignmentNear: 3618 default: 3619 bounds.X = rect->X; 3620 break; 3621 case StringAlignmentCenter: 3622 bounds.X = rect->X + (rect->Width/2) - (bounds.Width/2); 3623 break; 3624 case StringAlignmentFar: 3625 bounds.X = rect->X + rect->Width - bounds.Width; 3626 break; 3627 } 3628 3629 stat = callback(graphics, stringdup, sum, lineend, 3630 font, rect, format, lineno, &bounds, user_data); 3631 3632 if (stat != Ok) 3633 break; 3634 3635 sum += fit + (lret < fitcpy ? 1 : 0); 3636 height += size.cy; 3637 lineno++; 3638 3639 if(height > nheight) 3640 break; 3641 3642 /* Stop if this was a linewrap (but not if it was a linebreak). */ 3643 if((lret == fitcpy) && format && (format->attr & StringFormatFlagsNoWrap)) 3644 break; 3645 } 3646 3647 GdipFree(stringdup); 3648 3649 return stat; 3650 } 3651 3652 struct measure_ranges_args { 3653 GpRegion **regions; 3654 }; 3655 3656 static GpStatus measure_ranges_callback(GpGraphics *graphics, 3657 GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font, 3658 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, 3659 INT lineno, const RectF *bounds, void *user_data) 3660 { 3661 int i; 3662 GpStatus stat = Ok; 3663 struct measure_ranges_args *args = user_data; 3664 3665 for (i=0; i<format->range_count; i++) 3666 { 3667 INT range_start = max(index, format->character_ranges[i].First); 3668 INT range_end = min(index+length, format->character_ranges[i].First+format->character_ranges[i].Length); 3669 if (range_start < range_end) 3670 { 3671 GpRectF range_rect; 3672 SIZE range_size; 3673 3674 range_rect.Y = bounds->Y; 3675 range_rect.Height = bounds->Height; 3676 3677 GetTextExtentExPointW(graphics->hdc, string + index, range_start - index, 3678 INT_MAX, NULL, NULL, &range_size); 3679 range_rect.X = bounds->X + range_size.cx; 3680 3681 GetTextExtentExPointW(graphics->hdc, string + index, range_end - index, 3682 INT_MAX, NULL, NULL, &range_size); 3683 range_rect.Width = (bounds->X + range_size.cx) - range_rect.X; 3684 3685 stat = GdipCombineRegionRect(args->regions[i], &range_rect, CombineModeUnion); 3686 if (stat != Ok) 3687 break; 3688 } 3689 } 3690 3691 return stat; 3692 } 3693 3694 GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics, 3695 GDIPCONST WCHAR* string, INT length, GDIPCONST GpFont* font, 3696 GDIPCONST RectF* layoutRect, GDIPCONST GpStringFormat *stringFormat, 3697 INT regionCount, GpRegion** regions) 3698 { 3699 GpStatus stat; 3700 int i; 3701 HFONT oldfont; 3702 struct measure_ranges_args args; 3703 3704 TRACE("(%p %s %d %p %s %p %d %p)\n", graphics, debugstr_w(string), 3705 length, font, debugstr_rectf(layoutRect), stringFormat, regionCount, regions); 3706 3707 if (!(graphics && string && font && layoutRect && stringFormat && regions)) 3708 return InvalidParameter; 3709 3710 if (regionCount < stringFormat->range_count) 3711 return InvalidParameter; 3712 3713 if (stringFormat->attr) 3714 TRACE("may be ignoring some format flags: attr %x\n", stringFormat->attr); 3715 3716 oldfont = SelectObject(graphics->hdc, CreateFontIndirectW(&font->lfw)); 3717 3718 for (i=0; i<stringFormat->range_count; i++) 3719 { 3720 stat = GdipSetEmpty(regions[i]); 3721 if (stat != Ok) 3722 return stat; 3723 } 3724 3725 args.regions = regions; 3726 3727 stat = gdip_format_string(graphics, string, length, font, layoutRect, stringFormat, 3728 measure_ranges_callback, &args); 3729 3730 DeleteObject(SelectObject(graphics->hdc, oldfont)); 3731 3732 return stat; 3733 } 3734 3735 struct measure_string_args { 3736 RectF *bounds; 3737 INT *codepointsfitted; 3738 INT *linesfilled; 3739 }; 3740 3741 static GpStatus measure_string_callback(GpGraphics *graphics, 3742 GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font, 3743 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, 3744 INT lineno, const RectF *bounds, void *user_data) 3745 { 3746 struct measure_string_args *args = user_data; 3747 3748 if (bounds->Width > args->bounds->Width) 3749 args->bounds->Width = bounds->Width; 3750 3751 if (bounds->Height + bounds->Y > args->bounds->Height + args->bounds->Y) 3752 args->bounds->Height = bounds->Height + bounds->Y - args->bounds->Y; 3753 3754 if (args->codepointsfitted) 3755 *args->codepointsfitted = index + length; 3756 3757 if (args->linesfilled) 3758 (*args->linesfilled)++; 3759 3760 return Ok; 3761 } 3762 3763 /* Find the smallest rectangle that bounds the text when it is printed in rect 3764 * according to the format options listed in format. If rect has 0 width and 3765 * height, then just find the smallest rectangle that bounds the text when it's 3766 * printed at location (rect->X, rect-Y). */ 3767 GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics, 3768 GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, 3769 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, RectF *bounds, 3770 INT *codepointsfitted, INT *linesfilled) 3771 { 3772 HFONT oldfont; 3773 struct measure_string_args args; 3774 3775 TRACE("(%p, %s, %i, %p, %s, %p, %p, %p, %p)\n", graphics, 3776 debugstr_wn(string, length), length, font, debugstr_rectf(rect), format, 3777 bounds, codepointsfitted, linesfilled); 3778 3779 if(!graphics || !string || !font || !rect || !bounds) 3780 return InvalidParameter; 3781 3782 if(linesfilled) *linesfilled = 0; 3783 if(codepointsfitted) *codepointsfitted = 0; 3784 3785 if(format) 3786 TRACE("may be ignoring some format flags: attr %x\n", format->attr); 3787 3788 oldfont = SelectObject(graphics->hdc, CreateFontIndirectW(&font->lfw)); 3789 3790 bounds->X = rect->X; 3791 bounds->Y = rect->Y; 3792 bounds->Width = 0.0; 3793 bounds->Height = 0.0; 3794 3795 args.bounds = bounds; 3796 args.codepointsfitted = codepointsfitted; 3797 args.linesfilled = linesfilled; 3798 3799 gdip_format_string(graphics, string, length, font, rect, format, 3800 measure_string_callback, &args); 3801 3802 DeleteObject(SelectObject(graphics->hdc, oldfont)); 3803 3804 return Ok; 3805 } 3806 3807 struct draw_string_args { 3808 POINT drawbase; 3809 UINT drawflags; 3810 REAL ang_cos, ang_sin; 3811 }; 3812 3813 static GpStatus draw_string_callback(GpGraphics *graphics, 3814 GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font, 3815 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, 3816 INT lineno, const RectF *bounds, void *user_data) 3817 { 3818 struct draw_string_args *args = user_data; 3819 RECT drawcoord; 3820 3821 drawcoord.left = drawcoord.right = args->drawbase.x + roundr(args->ang_sin * bounds->Y); 3822 drawcoord.top = drawcoord.bottom = args->drawbase.y + roundr(args->ang_cos * bounds->Y); 3823 3824 DrawTextW(graphics->hdc, string + index, length, &drawcoord, args->drawflags); 3825 3826 return Ok; 3827 } 3828 3829 GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string, 3830 INT length, GDIPCONST GpFont *font, GDIPCONST RectF *rect, 3831 GDIPCONST GpStringFormat *format, GDIPCONST GpBrush *brush) 3832 { 3833 HRGN rgn = NULL; 3834 HFONT gdifont; 3835 LOGFONTW lfw; 3836 TEXTMETRICW textmet; 3837 GpPointF pt[3], rectcpy[4]; 3838 POINT corners[4]; 3839 REAL angle, rel_width, rel_height; 3840 INT offsety = 0, save_state; 3841 struct draw_string_args args; 3842 RectF scaled_rect; 3843 3844 TRACE("(%p, %s, %i, %p, %s, %p, %p)\n", graphics, debugstr_wn(string, length), 3845 length, font, debugstr_rectf(rect), format, brush); 3846 3847 if(!graphics || !string || !font || !brush || !rect) 3848 return InvalidParameter; 3849 3850 if((brush->bt != BrushTypeSolidColor)){ 3851 FIXME("not implemented for given parameters\n"); 3852 return NotImplemented; 3853 } 3854 3855 if(format){ 3856 TRACE("may be ignoring some format flags: attr %x\n", format->attr); 3857 3858 /* Should be no need to explicitly test for StringAlignmentNear as 3859 * that is default behavior if no alignment is passed. */ 3860 if(format->vertalign != StringAlignmentNear){ 3861 RectF bounds; 3862 GdipMeasureString(graphics, string, length, font, rect, format, &bounds, 0, 0); 3863 3864 if(format->vertalign == StringAlignmentCenter) 3865 offsety = (rect->Height - bounds.Height) / 2; 3866 else if(format->vertalign == StringAlignmentFar) 3867 offsety = (rect->Height - bounds.Height); 3868 } 3869 } 3870 3871 save_state = SaveDC(graphics->hdc); 3872 SetBkMode(graphics->hdc, TRANSPARENT); 3873 SetTextColor(graphics->hdc, brush->lb.lbColor); 3874 3875 pt[0].X = 0.0; 3876 pt[0].Y = 0.0; 3877 pt[1].X = 1.0; 3878 pt[1].Y = 0.0; 3879 pt[2].X = 0.0; 3880 pt[2].Y = 1.0; 3881 GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3); 3882 angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X)); 3883 args.ang_cos = cos(angle); 3884 args.ang_sin = sin(angle); 3885 rel_width = sqrt((pt[1].Y-pt[0].Y)*(pt[1].Y-pt[0].Y)+ 3886 (pt[1].X-pt[0].X)*(pt[1].X-pt[0].X)); 3887 rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+ 3888 (pt[2].X-pt[0].X)*(pt[2].X-pt[0].X)); 3889 3890 rectcpy[3].X = rectcpy[0].X = rect->X; 3891 rectcpy[1].Y = rectcpy[0].Y = rect->Y + offsety; 3892 rectcpy[2].X = rectcpy[1].X = rect->X + rect->Width; 3893 rectcpy[3].Y = rectcpy[2].Y = rect->Y + offsety + rect->Height; 3894 transform_and_round_points(graphics, corners, rectcpy, 4); 3895 3896 scaled_rect.X = 0.0; 3897 scaled_rect.Y = 0.0; 3898 scaled_rect.Width = rel_width * rect->Width; 3899 scaled_rect.Height = rel_height * rect->Height; 3900 3901 if (roundr(scaled_rect.Width) != 0 && roundr(scaled_rect.Height) != 0) 3902 { 3903 /* FIXME: If only the width or only the height is 0, we should probably still clip */ 3904 rgn = CreatePolygonRgn(corners, 4, ALTERNATE); 3905 SelectClipRgn(graphics->hdc, rgn); 3906 } 3907 3908 /* Use gdi to find the font, then perform transformations on it (height, 3909 * width, angle). */ 3910 SelectObject(graphics->hdc, CreateFontIndirectW(&font->lfw)); 3911 GetTextMetricsW(graphics->hdc, &textmet); 3912 lfw = font->lfw; 3913 3914 lfw.lfHeight = roundr(((REAL)lfw.lfHeight) * rel_height); 3915 lfw.lfWidth = roundr(textmet.tmAveCharWidth * rel_width); 3916 3917 lfw.lfEscapement = lfw.lfOrientation = roundr((angle / M_PI) * 1800.0); 3918 3919 gdifont = CreateFontIndirectW(&lfw); 3920 DeleteObject(SelectObject(graphics->hdc, CreateFontIndirectW(&lfw))); 3921 3922 if (!format || format->align == StringAlignmentNear) 3923 { 3924 args.drawbase.x = corners[0].x; 3925 args.drawbase.y = corners[0].y; 3926 args.drawflags = DT_NOCLIP | DT_EXPANDTABS; 3927 } 3928 else if (format->align == StringAlignmentCenter) 3929 { 3930 args.drawbase.x = (corners[0].x + corners[1].x)/2; 3931 args.drawbase.y = (corners[0].y + corners[1].y)/2; 3932 args.drawflags = DT_NOCLIP | DT_EXPANDTABS | DT_CENTER; 3933 } 3934 else /* (format->align == StringAlignmentFar) */ 3935 { 3936 args.drawbase.x = corners[1].x; 3937 args.drawbase.y = corners[1].y; 3938 args.drawflags = DT_NOCLIP | DT_EXPANDTABS | DT_RIGHT; 3939 } 3940 3941 gdip_format_string(graphics, string, length, font, &scaled_rect, format, 3942 draw_string_callback, &args); 3943 3944 DeleteObject(rgn); 3945 DeleteObject(gdifont); 3946 3947 RestoreDC(graphics->hdc, save_state); 3948 3949 return Ok; 3950 } 3951 3952 GpStatus WINGDIPAPI GdipResetClip(GpGraphics *graphics) 3953 { 3954 TRACE("(%p)\n", graphics); 3955 3956 if(!graphics) 3957 return InvalidParameter; 3958 3959 if(graphics->busy) 3960 return ObjectBusy; 3961 3962 return GdipSetInfinite(graphics->clip); 3963 } 3964 3965 GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics *graphics) 3966 { 3967 TRACE("(%p)\n", graphics); 3968 3969 if(!graphics) 3970 return InvalidParameter; 3971 3972 if(graphics->busy) 3973 return ObjectBusy; 3974 3975 graphics->worldtrans->matrix[0] = 1.0; 3976 graphics->worldtrans->matrix[1] = 0.0; 3977 graphics->worldtrans->matrix[2] = 0.0; 3978 graphics->worldtrans->matrix[3] = 1.0; 3979 graphics->worldtrans->matrix[4] = 0.0; 3980 graphics->worldtrans->matrix[5] = 0.0; 3981 3982 return Ok; 3983 } 3984 3985 GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState state) 3986 { 3987 return GdipEndContainer(graphics, state); 3988 } 3989 3990 GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle, 3991 GpMatrixOrder order) 3992 { 3993 TRACE("(%p, %.2f, %d)\n", graphics, angle, order); 3994 3995 if(!graphics) 3996 return InvalidParameter; 3997 3998 if(graphics->busy) 3999 return ObjectBusy; 4000 4001 return GdipRotateMatrix(graphics->worldtrans, angle, order); 4002 } 4003 4004 GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics *graphics, GraphicsState *state) 4005 { 4006 return GdipBeginContainer2(graphics, state); 4007 } 4008 4009 GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics, 4010 GraphicsContainer *state) 4011 { 4012 GraphicsContainerItem *container; 4013 GpStatus sts; 4014 4015 TRACE("(%p, %p)\n", graphics, state); 4016 4017 if(!graphics || !state) 4018 return InvalidParameter; 4019 4020 sts = init_container(&container, graphics); 4021 if(sts != Ok) 4022 return sts; 4023 4024 list_add_head(&graphics->containers, &container->entry); 4025 *state = graphics->contid = container->contid; 4026 4027 return Ok; 4028 } 4029 4030 GpStatus WINGDIPAPI GdipBeginContainer(GpGraphics *graphics, GDIPCONST GpRectF *dstrect, GDIPCONST GpRectF *srcrect, GpUnit unit, GraphicsContainer *state) 4031 { 4032 FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state); 4033 return NotImplemented; 4034 } 4035 4036 GpStatus WINGDIPAPI GdipBeginContainerI(GpGraphics *graphics, GDIPCONST GpRect *dstrect, GDIPCONST GpRect *srcrect, GpUnit unit, GraphicsContainer *state) 4037 { 4038 FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state); 4039 return NotImplemented; 4040 } 4041 4042 GpStatus WINGDIPAPI GdipComment(GpGraphics *graphics, UINT sizeData, GDIPCONST BYTE *data) 4043 { 4044 FIXME("(%p, %d, %p): stub\n", graphics, sizeData, data); 4045 return NotImplemented; 4046 } 4047 4048 GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsContainer state) 4049 { 4050 GpStatus sts; 4051 GraphicsContainerItem *container, *container2; 4052 4053 TRACE("(%p, %x)\n", graphics, state); 4054 4055 if(!graphics) 4056 return InvalidParameter; 4057 4058 LIST_FOR_EACH_ENTRY(container, &graphics->containers, GraphicsContainerItem, entry){ 4059 if(container->contid == state) 4060 break; 4061 } 4062 4063 /* did not find a matching container */ 4064 if(&container->entry == &graphics->containers) 4065 return Ok; 4066 4067 sts = restore_container(graphics, container); 4068 if(sts != Ok) 4069 return sts; 4070 4071 /* remove all of the containers on top of the found container */ 4072 LIST_FOR_EACH_ENTRY_SAFE(container, container2, &graphics->containers, GraphicsContainerItem, entry){ 4073 if(container->contid == state) 4074 break; 4075 list_remove(&container->entry); 4076 delete_container(container); 4077 } 4078 4079 list_remove(&container->entry); 4080 delete_container(container); 4081 4082 return Ok; 4083 } 4084 4085 GpStatus WINGDIPAPI GdipScaleWorldTransform(GpGraphics *graphics, REAL sx, 4086 REAL sy, GpMatrixOrder order) 4087 { 4088 TRACE("(%p, %.2f, %.2f, %d)\n", graphics, sx, sy, order); 4089 4090 if(!graphics) 4091 return InvalidParameter; 4092 4093 if(graphics->busy) 4094 return ObjectBusy; 4095 4096 return GdipScaleMatrix(graphics->worldtrans, sx, sy, order); 4097 } 4098 4099 GpStatus WINGDIPAPI GdipSetClipGraphics(GpGraphics *graphics, GpGraphics *srcgraphics, 4100 CombineMode mode) 4101 { 4102 TRACE("(%p, %p, %d)\n", graphics, srcgraphics, mode); 4103 4104 if(!graphics || !srcgraphics) 4105 return InvalidParameter; 4106 4107 return GdipCombineRegionRegion(graphics->clip, srcgraphics->clip, mode); 4108 } 4109 4110 GpStatus WINGDIPAPI GdipSetCompositingMode(GpGraphics *graphics, 4111 CompositingMode mode) 4112 { 4113 TRACE("(%p, %d)\n", graphics, mode); 4114 4115 if(!graphics) 4116 return InvalidParameter; 4117 4118 if(graphics->busy) 4119 return ObjectBusy; 4120 4121 graphics->compmode = mode; 4122 4123 return Ok; 4124 } 4125 4126 GpStatus WINGDIPAPI GdipSetCompositingQuality(GpGraphics *graphics, 4127 CompositingQuality quality) 4128 { 4129 TRACE("(%p, %d)\n", graphics, quality); 4130 4131 if(!graphics) 4132 return InvalidParameter; 4133 4134 if(graphics->busy) 4135 return ObjectBusy; 4136 4137 graphics->compqual = quality; 4138 4139 return Ok; 4140 } 4141 4142 GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics *graphics, 4143 InterpolationMode mode) 4144 { 4145 TRACE("(%p, %d)\n", graphics, mode); 4146 4147 if(!graphics) 4148 return InvalidParameter; 4149 4150 if(graphics->busy) 4151 return ObjectBusy; 4152 4153 graphics->interpolation = mode; 4154 4155 return Ok; 4156 } 4157 4158 GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale) 4159 { 4160 TRACE("(%p, %.2f)\n", graphics, scale); 4161 4162 if(!graphics || (scale <= 0.0)) 4163 return InvalidParameter; 4164 4165 if(graphics->busy) 4166 return ObjectBusy; 4167 4168 graphics->scale = scale; 4169 4170 return Ok; 4171 } 4172 4173 GpStatus WINGDIPAPI GdipSetPageUnit(GpGraphics *graphics, GpUnit unit) 4174 { 4175 TRACE("(%p, %d)\n", graphics, unit); 4176 4177 if(!graphics) 4178 return InvalidParameter; 4179 4180 if(graphics->busy) 4181 return ObjectBusy; 4182 4183 if(unit == UnitWorld) 4184 return InvalidParameter; 4185 4186 graphics->unit = unit; 4187 4188 return Ok; 4189 } 4190 4191 GpStatus WINGDIPAPI GdipSetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode 4192 mode) 4193 { 4194 TRACE("(%p, %d)\n", graphics, mode); 4195 4196 if(!graphics) 4197 return InvalidParameter; 4198 4199 if(graphics->busy) 4200 return ObjectBusy; 4201 4202 graphics->pixeloffset = mode; 4203 4204 return Ok; 4205 } 4206 4207 GpStatus WINGDIPAPI GdipSetRenderingOrigin(GpGraphics *graphics, INT x, INT y) 4208 { 4209 static int calls; 4210 4211 TRACE("(%p,%i,%i)\n", graphics, x, y); 4212 4213 if (!(calls++)) 4214 FIXME("not implemented\n"); 4215 4216 return NotImplemented; 4217 } 4218 4219 GpStatus WINGDIPAPI GdipGetRenderingOrigin(GpGraphics *graphics, INT *x, INT *y) 4220 { 4221 static int calls; 4222 4223 TRACE("(%p,%p,%p)\n", graphics, x, y); 4224 4225 if (!(calls++)) 4226 FIXME("not implemented\n"); 4227 4228 *x = *y = 0; 4229 4230 return NotImplemented; 4231 } 4232 4233 GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode mode) 4234 { 4235 TRACE("(%p, %d)\n", graphics, mode); 4236 4237 if(!graphics) 4238 return InvalidParameter; 4239 4240 if(graphics->busy) 4241 return ObjectBusy; 4242 4243 graphics->smoothing = mode; 4244 4245 return Ok; 4246 } 4247 4248 GpStatus WINGDIPAPI GdipSetTextContrast(GpGraphics *graphics, UINT contrast) 4249 { 4250 TRACE("(%p, %d)\n", graphics, contrast); 4251 4252 if(!graphics) 4253 return InvalidParameter; 4254 4255 graphics->textcontrast = contrast; 4256 4257 return Ok; 4258 } 4259 4260 GpStatus WINGDIPAPI GdipSetTextRenderingHint(GpGraphics *graphics, 4261 TextRenderingHint hint) 4262 { 4263 TRACE("(%p, %d)\n", graphics, hint); 4264 4265 if(!graphics) 4266 return InvalidParameter; 4267 4268 if(graphics->busy) 4269 return ObjectBusy; 4270 4271 graphics->texthint = hint; 4272 4273 return Ok; 4274 } 4275 4276 GpStatus WINGDIPAPI GdipSetWorldTransform(GpGraphics *graphics, GpMatrix *matrix) 4277 { 4278 TRACE("(%p, %p)\n", graphics, matrix); 4279 4280 if(!graphics || !matrix) 4281 return InvalidParameter; 4282 4283 if(graphics->busy) 4284 return ObjectBusy; 4285 4286 GdipDeleteMatrix(graphics->worldtrans); 4287 return GdipCloneMatrix(matrix, &graphics->worldtrans); 4288 } 4289 4290 GpStatus WINGDIPAPI GdipTranslateWorldTransform(GpGraphics *graphics, REAL dx, 4291 REAL dy, GpMatrixOrder order) 4292 { 4293 TRACE("(%p, %.2f, %.2f, %d)\n", graphics, dx, dy, order); 4294 4295 if(!graphics) 4296 return InvalidParameter; 4297 4298 if(graphics->busy) 4299 return ObjectBusy; 4300 4301 return GdipTranslateMatrix(graphics->worldtrans, dx, dy, order); 4302 } 4303 4304 /***************************************************************************** 4305 * GdipSetClipHrgn [GDIPLUS.@] 4306 */ 4307 GpStatus WINGDIPAPI GdipSetClipHrgn(GpGraphics *graphics, HRGN hrgn, CombineMode mode) 4308 { 4309 GpRegion *region; 4310 GpStatus status; 4311 4312 TRACE("(%p, %p, %d)\n", graphics, hrgn, mode); 4313 4314 if(!graphics) 4315 return InvalidParameter; 4316 4317 status = GdipCreateRegionHrgn(hrgn, ®ion); 4318 if(status != Ok) 4319 return status; 4320 4321 status = GdipSetClipRegion(graphics, region, mode); 4322 4323 GdipDeleteRegion(region); 4324 return status; 4325 } 4326 4327 GpStatus WINGDIPAPI GdipSetClipPath(GpGraphics *graphics, GpPath *path, CombineMode mode) 4328 { 4329 TRACE("(%p, %p, %d)\n", graphics, path, mode); 4330 4331 if(!graphics) 4332 return InvalidParameter; 4333 4334 if(graphics->busy) 4335 return ObjectBusy; 4336 4337 return GdipCombineRegionPath(graphics->clip, path, mode); 4338 } 4339 4340 GpStatus WINGDIPAPI GdipSetClipRect(GpGraphics *graphics, REAL x, REAL y, 4341 REAL width, REAL height, 4342 CombineMode mode) 4343 { 4344 GpRectF rect; 4345 4346 TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %d)\n", graphics, x, y, width, height, mode); 4347 4348 if(!graphics) 4349 return InvalidParameter; 4350 4351 if(graphics->busy) 4352 return ObjectBusy; 4353 4354 rect.X = x; 4355 rect.Y = y; 4356 rect.Width = width; 4357 rect.Height = height; 4358 4359 return GdipCombineRegionRect(graphics->clip, &rect, mode); 4360 } 4361 4362 GpStatus WINGDIPAPI GdipSetClipRectI(GpGraphics *graphics, INT x, INT y, 4363 INT width, INT height, 4364 CombineMode mode) 4365 { 4366 TRACE("(%p, %d, %d, %d, %d, %d)\n", graphics, x, y, width, height, mode); 4367 4368 if(!graphics) 4369 return InvalidParameter; 4370 4371 if(graphics->busy) 4372 return ObjectBusy; 4373 4374 return GdipSetClipRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, mode); 4375 } 4376 4377 GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region, 4378 CombineMode mode) 4379 { 4380 TRACE("(%p, %p, %d)\n", graphics, region, mode); 4381 4382 if(!graphics || !region) 4383 return InvalidParameter; 4384 4385 if(graphics->busy) 4386 return ObjectBusy; 4387 4388 return GdipCombineRegionRegion(graphics->clip, region, mode); 4389 } 4390 4391 GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile, 4392 UINT limitDpi) 4393 { 4394 static int calls; 4395 4396 TRACE("(%p,%u)\n", metafile, limitDpi); 4397 4398 if(!(calls++)) 4399 FIXME("not implemented\n"); 4400 4401 return NotImplemented; 4402 } 4403 4404 GpStatus WINGDIPAPI GdipDrawPolygon(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPointF *points, 4405 INT count) 4406 { 4407 INT save_state; 4408 POINT *pti; 4409 4410 TRACE("(%p, %p, %d)\n", graphics, points, count); 4411 4412 if(!graphics || !pen || count<=0) 4413 return InvalidParameter; 4414 4415 if(graphics->busy) 4416 return ObjectBusy; 4417 4418 pti = GdipAlloc(sizeof(POINT) * count); 4419 4420 save_state = prepare_dc(graphics, pen); 4421 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH)); 4422 4423 transform_and_round_points(graphics, pti, (GpPointF*)points, count); 4424 Polygon(graphics->hdc, pti, count); 4425 4426 restore_dc(graphics, save_state); 4427 GdipFree(pti); 4428 4429 return Ok; 4430 } 4431 4432 GpStatus WINGDIPAPI GdipDrawPolygonI(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPoint *points, 4433 INT count) 4434 { 4435 GpStatus ret; 4436 GpPointF *ptf; 4437 INT i; 4438 4439 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count); 4440 4441 if(count<=0) return InvalidParameter; 4442 ptf = GdipAlloc(sizeof(GpPointF) * count); 4443 4444 for(i = 0;i < count; i++){ 4445 ptf[i].X = (REAL)points[i].X; 4446 ptf[i].Y = (REAL)points[i].Y; 4447 } 4448 4449 ret = GdipDrawPolygon(graphics,pen,ptf,count); 4450 GdipFree(ptf); 4451 4452 return ret; 4453 } 4454 4455 GpStatus WINGDIPAPI GdipGetDpiX(GpGraphics *graphics, REAL* dpi) 4456 { 4457 TRACE("(%p, %p)\n", graphics, dpi); 4458 4459 if(!graphics || !dpi) 4460 return InvalidParameter; 4461 4462 if(graphics->busy) 4463 return ObjectBusy; 4464 4465 *dpi = (REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSX); 4466 4467 return Ok; 4468 } 4469 4470 GpStatus WINGDIPAPI GdipGetDpiY(GpGraphics *graphics, REAL* dpi) 4471 { 4472 TRACE("(%p, %p)\n", graphics, dpi); 4473 4474 if(!graphics || !dpi) 4475 return InvalidParameter; 4476 4477 if(graphics->busy) 4478 return ObjectBusy; 4479 4480 *dpi = (REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSY); 4481 4482 return Ok; 4483 } 4484 4485 GpStatus WINGDIPAPI GdipMultiplyWorldTransform(GpGraphics *graphics, GDIPCONST GpMatrix *matrix, 4486 GpMatrixOrder order) 4487 { 4488 GpMatrix m; 4489 GpStatus ret; 4490 4491 TRACE("(%p, %p, %d)\n", graphics, matrix, order); 4492 4493 if(!graphics || !matrix) 4494 return InvalidParameter; 4495 4496 if(graphics->busy) 4497 return ObjectBusy; 4498 4499 m = *(graphics->worldtrans); 4500 4501 ret = GdipMultiplyMatrix(&m, matrix, order); 4502 if(ret == Ok) 4503 *(graphics->worldtrans) = m; 4504 4505 return ret; 4506 } 4507 4508 GpStatus WINGDIPAPI GdipGetDC(GpGraphics *graphics, HDC *hdc) 4509 { 4510 TRACE("(%p, %p)\n", graphics, hdc); 4511 4512 if(!graphics || !hdc) 4513 return InvalidParameter; 4514 4515 if(graphics->busy) 4516 return ObjectBusy; 4517 4518 *hdc = graphics->hdc; 4519 graphics->busy = TRUE; 4520 4521 return Ok; 4522 } 4523 4524 GpStatus WINGDIPAPI GdipReleaseDC(GpGraphics *graphics, HDC hdc) 4525 { 4526 TRACE("(%p, %p)\n", graphics, hdc); 4527 4528 if(!graphics) 4529 return InvalidParameter; 4530 4531 if(graphics->hdc != hdc || !(graphics->busy)) 4532 return InvalidParameter; 4533 4534 graphics->busy = FALSE; 4535 4536 return Ok; 4537 } 4538 4539 GpStatus WINGDIPAPI GdipGetClip(GpGraphics *graphics, GpRegion *region) 4540 { 4541 GpRegion *clip; 4542 GpStatus status; 4543 4544 TRACE("(%p, %p)\n", graphics, region); 4545 4546 if(!graphics || !region) 4547 return InvalidParameter; 4548 4549 if(graphics->busy) 4550 return ObjectBusy; 4551 4552 if((status = GdipCloneRegion(graphics->clip, &clip)) != Ok) 4553 return status; 4554 4555 /* free everything except root node and header */ 4556 delete_element(®ion->node); 4557 memcpy(region, clip, sizeof(GpRegion)); 4558 GdipFree(clip); 4559 4560 return Ok; 4561 } 4562 4563 GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace dst_space, 4564 GpCoordinateSpace src_space, GpPointF *points, INT count) 4565 { 4566 GpMatrix *matrix; 4567 GpStatus stat; 4568 REAL unitscale; 4569 4570 if(!graphics || !points || count <= 0) 4571 return InvalidParameter; 4572 4573 if(graphics->busy) 4574 return ObjectBusy; 4575 4576 TRACE("(%p, %d, %d, %p, %d)\n", graphics, dst_space, src_space, points, count); 4577 4578 if (src_space == dst_space) return Ok; 4579 4580 stat = GdipCreateMatrix(&matrix); 4581 if (stat == Ok) 4582 { 4583 unitscale = convert_unit(graphics->hdc, graphics->unit); 4584 4585 if(graphics->unit != UnitDisplay) 4586 unitscale *= graphics->scale; 4587 4588 /* transform from src_space to CoordinateSpacePage */ 4589 switch (src_space) 4590 { 4591 case CoordinateSpaceWorld: 4592 GdipMultiplyMatrix(matrix, graphics->worldtrans, MatrixOrderAppend); 4593 break; 4594 case CoordinateSpacePage: 4595 break; 4596 case CoordinateSpaceDevice: 4597 GdipScaleMatrix(matrix, 1.0/unitscale, 1.0/unitscale, MatrixOrderAppend); 4598 break; 4599 } 4600 4601 /* transform from CoordinateSpacePage to dst_space */ 4602 switch (dst_space) 4603 { 4604 case CoordinateSpaceWorld: 4605 { 4606 GpMatrix *inverted_transform; 4607 stat = GdipCloneMatrix(graphics->worldtrans, &inverted_transform); 4608 if (stat == Ok) 4609 { 4610 stat = GdipInvertMatrix(inverted_transform); 4611 if (stat == Ok) 4612 GdipMultiplyMatrix(matrix, inverted_transform, MatrixOrderAppend); 4613 GdipDeleteMatrix(inverted_transform); 4614 } 4615 break; 4616 } 4617 case CoordinateSpacePage: 4618 break; 4619 case CoordinateSpaceDevice: 4620 GdipScaleMatrix(matrix, unitscale, unitscale, MatrixOrderAppend); 4621 break; 4622 } 4623 4624 if (stat == Ok) 4625 stat = GdipTransformMatrixPoints(matrix, points, count); 4626 4627 GdipDeleteMatrix(matrix); 4628 } 4629 4630 return stat; 4631 } 4632 4633 GpStatus WINGDIPAPI GdipTransformPointsI(GpGraphics *graphics, GpCoordinateSpace dst_space, 4634 GpCoordinateSpace src_space, GpPoint *points, INT count) 4635 { 4636 GpPointF *pointsF; 4637 GpStatus ret; 4638 INT i; 4639 4640 TRACE("(%p, %d, %d, %p, %d)\n", graphics, dst_space, src_space, points, count); 4641 4642 if(count <= 0) 4643 return InvalidParameter; 4644 4645 pointsF = GdipAlloc(sizeof(GpPointF) * count); 4646 if(!pointsF) 4647 return OutOfMemory; 4648 4649 for(i = 0; i < count; i++){ 4650 pointsF[i].X = (REAL)points[i].X; 4651 pointsF[i].Y = (REAL)points[i].Y; 4652 } 4653 4654 ret = GdipTransformPoints(graphics, dst_space, src_space, pointsF, count); 4655 4656 if(ret == Ok) 4657 for(i = 0; i < count; i++){ 4658 points[i].X = roundr(pointsF[i].X); 4659 points[i].Y = roundr(pointsF[i].Y); 4660 } 4661 GdipFree(pointsF); 4662 4663 return ret; 4664 } 4665 4666 HPALETTE WINGDIPAPI GdipCreateHalftonePalette(void) 4667 { 4668 static int calls; 4669 4670 TRACE("\n"); 4671 4672 if (!calls++) 4673 FIXME("stub\n"); 4674 4675 return NULL; 4676 } 4677 4678 /***************************************************************************** 4679 * GdipTranslateClip [GDIPLUS.@] 4680 */ 4681 GpStatus WINGDIPAPI GdipTranslateClip(GpGraphics *graphics, REAL dx, REAL dy) 4682 { 4683 TRACE("(%p, %.2f, %.2f)\n", graphics, dx, dy); 4684 4685 if(!graphics) 4686 return InvalidParameter; 4687 4688 if(graphics->busy) 4689 return ObjectBusy; 4690 4691 return GdipTranslateRegion(graphics->clip, dx, dy); 4692 } 4693 4694 /***************************************************************************** 4695 * GdipTranslateClipI [GDIPLUS.@] 4696 */ 4697 GpStatus WINGDIPAPI GdipTranslateClipI(GpGraphics *graphics, INT dx, INT dy) 4698 { 4699 TRACE("(%p, %d, %d)\n", graphics, dx, dy); 4700 4701 if(!graphics) 4702 return InvalidParameter; 4703 4704 if(graphics->busy) 4705 return ObjectBusy; 4706 4707 return GdipTranslateRegion(graphics->clip, (REAL)dx, (REAL)dy); 4708 } 4709 4710 4711 /***************************************************************************** 4712 * GdipMeasureDriverString [GDIPLUS.@] 4713 */ 4714 GpStatus WINGDIPAPI GdipMeasureDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length, 4715 GDIPCONST GpFont *font, GDIPCONST PointF *positions, 4716 INT flags, GDIPCONST GpMatrix *matrix, RectF *boundingBox) 4717 { 4718 FIXME("(%p %p %d %p %p %d %p %p): stub\n", graphics, text, length, font, positions, flags, matrix, boundingBox); 4719 return NotImplemented; 4720 } 4721 4722 /***************************************************************************** 4723 * GdipDrawDriverString [GDIPLUS.@] 4724 */ 4725 GpStatus WINGDIPAPI GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length, 4726 GDIPCONST GpFont *font, GDIPCONST GpBrush *brush, 4727 GDIPCONST PointF *positions, INT flags, 4728 GDIPCONST GpMatrix *matrix ) 4729 { 4730 FIXME("(%p %p %d %p %p %p %d %p): stub\n", graphics, text, length, font, brush, positions, flags, matrix); 4731 return NotImplemented; 4732 } 4733 4734 GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect, 4735 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile) 4736 { 4737 FIXME("(%p %d %p %d %p %p): stub\n", hdc, type, frameRect, frameUnit, desc, metafile); 4738 return NotImplemented; 4739 } 4740 4741 /***************************************************************************** 4742 * GdipRecordMetafileI [GDIPLUS.@] 4743 */ 4744 GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect, 4745 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile) 4746 { 4747 FIXME("(%p %d %p %d %p %p): stub\n", hdc, type, frameRect, frameUnit, desc, metafile); 4748 return NotImplemented; 4749 } 4750 4751 GpStatus WINGDIPAPI GdipRecordMetafileStream(IStream *stream, HDC hdc, EmfType type, GDIPCONST GpRect *frameRect, 4752 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile) 4753 { 4754 FIXME("(%p %p %d %p %d %p %p): stub\n", stream, hdc, type, frameRect, frameUnit, desc, metafile); 4755 return NotImplemented; 4756 } 4757 4758 /***************************************************************************** 4759 * GdipIsVisibleClipEmpty [GDIPLUS.@] 4760 */ 4761 GpStatus WINGDIPAPI GdipIsVisibleClipEmpty(GpGraphics *graphics, BOOL *res) 4762 { 4763 GpStatus stat; 4764 GpRegion* rgn; 4765 4766 TRACE("(%p, %p)\n", graphics, res); 4767 4768 if((stat = GdipCreateRegion(&rgn)) != Ok) 4769 return stat; 4770 4771 if((stat = get_visible_clip_region(graphics, rgn)) != Ok) 4772 goto cleanup; 4773 4774 stat = GdipIsEmptyRegion(rgn, graphics, res); 4775 4776 cleanup: 4777 GdipDeleteRegion(rgn); 4778 return stat; 4779 } 4780