1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Pen functiona 5 * FILE: win32ss/gdi/ntgdi/pen.c 6 * PROGRAMER: 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 /* PRIVATE FUNCTIONS **********************************************************/ 15 16 static 17 VOID 18 PEN_vInit( 19 PPEN ppen) 20 { 21 /* Start with kmode brush attribute */ 22 ppen->pBrushAttr = &ppen->BrushAttr; 23 } 24 25 PBRUSH 26 NTAPI 27 PEN_AllocPenWithHandle( 28 VOID) 29 { 30 PPEN ppen; 31 32 ppen = (PBRUSH)GDIOBJ_AllocObjWithHandle(GDILoObjType_LO_PEN_TYPE, sizeof(PEN)); 33 if (ppen == NULL) 34 { 35 return NULL; 36 } 37 38 PEN_vInit(ppen); 39 return ppen; 40 } 41 42 PBRUSH 43 NTAPI 44 PEN_AllocExtPenWithHandle( 45 VOID) 46 { 47 PPEN ppen; 48 49 ppen = (PBRUSH)GDIOBJ_AllocObjWithHandle(GDILoObjType_LO_EXTPEN_TYPE, sizeof(PEN)); 50 if (ppen == NULL) 51 { 52 return NULL; 53 } 54 55 PEN_vInit(ppen); 56 return ppen; 57 } 58 59 PBRUSH 60 FASTCALL 61 PEN_ShareLockPen(HPEN hobj) 62 { 63 if ((GDI_HANDLE_GET_TYPE(hobj) != GDILoObjType_LO_PEN_TYPE) && 64 (GDI_HANDLE_GET_TYPE(hobj) != GDILoObjType_LO_EXTPEN_TYPE)) 65 { 66 return NULL; 67 } 68 69 return (PBRUSH)GDIOBJ_ReferenceObjectByHandle(hobj, GDIObjType_BRUSH_TYPE); 70 } 71 72 HPEN 73 APIENTRY 74 IntGdiExtCreatePen( 75 DWORD dwPenStyle, 76 DWORD dwWidth, 77 IN ULONG ulBrushStyle, 78 IN ULONG ulColor, 79 IN ULONG_PTR ulClientHatch, 80 IN ULONG_PTR ulHatch, 81 DWORD dwStyleCount, 82 PULONG pStyle, 83 IN ULONG cjDIB, 84 IN BOOL bOldStylePen, 85 IN OPTIONAL HBRUSH hbrush) 86 { 87 HPEN hPen; 88 PBRUSH pbrushPen; 89 static ULONG aulStyleAlternate[] = { 1, 1 }; 90 static ULONG aulStyleDash[] = { 6, 2 }; 91 static ULONG aulStyleDot[] = { 1, 1 }; 92 static ULONG aulStyleDashDot[] = { 3, 2, 1, 2 }; 93 static ULONG aulStyleDashDotDot[] = { 3, 1, 1, 1, 1, 1 }; 94 ULONG i; 95 96 dwWidth = abs(dwWidth); 97 98 if ( (dwPenStyle & PS_STYLE_MASK) == PS_NULL) 99 { 100 return StockObjects[NULL_PEN]; 101 } 102 103 if (bOldStylePen) 104 { 105 pbrushPen = PEN_AllocPenWithHandle(); 106 } 107 else 108 { 109 pbrushPen = PEN_AllocExtPenWithHandle(); 110 } 111 112 if (!pbrushPen) 113 { 114 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 115 DPRINT("Can't allocate pen\n"); 116 return 0; 117 } 118 119 hPen = pbrushPen->BaseObject.hHmgr; 120 121 if (bOldStylePen) 122 { 123 // If nWidth is zero, the pen is a single pixel wide, regardless of the current transformation. 124 if (!dwWidth && (dwPenStyle & PS_STYLE_MASK) != PS_SOLID) 125 dwWidth = 1; 126 } 127 else 128 { 129 switch (dwPenStyle & PS_ENDCAP_MASK) 130 { 131 case PS_ENDCAP_ROUND: 132 case PS_ENDCAP_SQUARE: 133 case PS_ENDCAP_FLAT: 134 break; 135 136 default: 137 goto ExitCleanup; 138 } 139 140 switch (dwPenStyle & PS_JOIN_MASK) 141 { 142 case PS_JOIN_ROUND: 143 case PS_JOIN_BEVEL: 144 case PS_JOIN_MITER: 145 break; 146 147 default: 148 goto ExitCleanup; 149 } 150 151 switch (dwPenStyle & PS_TYPE_MASK) 152 { 153 case PS_COSMETIC: 154 if (dwWidth != 1 || ulBrushStyle != BS_SOLID) 155 goto ExitCleanup; 156 157 break; 158 159 case PS_GEOMETRIC: 160 break; 161 162 default: 163 goto ExitCleanup; 164 } 165 } 166 167 pbrushPen->lWidth = dwWidth; 168 FLOATOBJ_SetLong(&pbrushPen->eWidth, pbrushPen->lWidth); 169 pbrushPen->ulPenStyle = dwPenStyle; 170 pbrushPen->BrushAttr.lbColor = ulColor; 171 pbrushPen->iBrushStyle = ulBrushStyle; 172 // FIXME: Copy the bitmap first ? 173 pbrushPen->hbmClient = (HANDLE)ulClientHatch; 174 pbrushPen->dwStyleCount = 0; 175 pbrushPen->pStyle = NULL; 176 pbrushPen->ulStyleSize = 0; 177 pbrushPen->flAttrs = bOldStylePen ? BR_IS_OLDSTYLEPEN : BR_IS_PEN; 178 179 switch (dwPenStyle & PS_STYLE_MASK) 180 { 181 case PS_NULL: 182 pbrushPen->flAttrs |= BR_IS_NULL; 183 break; 184 185 case PS_SOLID: 186 pbrushPen->flAttrs |= BR_IS_SOLID; 187 break; 188 189 case PS_ALTERNATE: 190 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE; 191 pbrushPen->pStyle = aulStyleAlternate; 192 pbrushPen->dwStyleCount = _countof(aulStyleAlternate); 193 break; 194 195 case PS_DOT: 196 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE; 197 pbrushPen->pStyle = aulStyleDot; 198 pbrushPen->dwStyleCount = _countof(aulStyleDot); 199 break; 200 201 case PS_DASH: 202 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE; 203 pbrushPen->pStyle = aulStyleDash; 204 pbrushPen->dwStyleCount = _countof(aulStyleDash); 205 break; 206 207 case PS_DASHDOT: 208 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE; 209 pbrushPen->pStyle = aulStyleDashDot; 210 pbrushPen->dwStyleCount = _countof(aulStyleDashDot); 211 break; 212 213 case PS_DASHDOTDOT: 214 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE; 215 pbrushPen->pStyle = aulStyleDashDotDot; 216 pbrushPen->dwStyleCount = _countof(aulStyleDashDotDot); 217 break; 218 219 case PS_INSIDEFRAME: 220 pbrushPen->flAttrs |= (BR_IS_SOLID | BR_IS_INSIDEFRAME); 221 break; 222 223 case PS_USERSTYLE: 224 { 225 UINT i; 226 BOOL has_neg = FALSE, all_zero = TRUE; 227 228 for(i = 0; (i < dwStyleCount) && !has_neg; i++) 229 { 230 has_neg = has_neg || (((INT)(pStyle[i])) < 0); 231 all_zero = all_zero && (pStyle[i] == 0); 232 } 233 234 if(all_zero || has_neg) 235 { 236 goto ExitCleanup; 237 } 238 } 239 /* FIXME: What style here? */ 240 pbrushPen->flAttrs |= BR_IS_SOLID; 241 pbrushPen->dwStyleCount = dwStyleCount; 242 pbrushPen->pStyle = pStyle; 243 break; 244 245 default: 246 DPRINT1("IntGdiExtCreatePen unknown penstyle %x\n", dwPenStyle); 247 goto ExitCleanup; 248 } 249 250 if (pbrushPen->pStyle != NULL) 251 { 252 for (i = 0; i < pbrushPen->dwStyleCount; i++) 253 { 254 pbrushPen->ulStyleSize += pbrushPen->pStyle[i]; 255 } 256 } 257 258 NT_ASSERT((pbrushPen->dwStyleCount == 0) || (pbrushPen->pStyle != NULL)); 259 260 PEN_UnlockPen(pbrushPen); 261 return hPen; 262 263 ExitCleanup: 264 EngSetLastError(ERROR_INVALID_PARAMETER); 265 pbrushPen->pStyle = NULL; 266 GDIOBJ_vDeleteObject(&pbrushPen->BaseObject); 267 268 return NULL; 269 } 270 271 VOID 272 FASTCALL 273 IntGdiSetSolidPenColor(HPEN hPen, COLORREF Color) 274 { 275 PBRUSH pbrPen; 276 277 pbrPen = PEN_ShareLockPen(hPen); 278 if (pbrPen) 279 { 280 if (pbrPen->flAttrs & BR_IS_SOLID) 281 { 282 pbrPen->BrushAttr.lbColor = Color & 0xFFFFFF; 283 } 284 PEN_ShareUnlockPen(pbrPen); 285 } 286 } 287 288 INT 289 APIENTRY 290 PEN_GetObject(PBRUSH pbrushPen, INT cbCount, PLOGPEN pBuffer) 291 { 292 PLOGPEN pLogPen; 293 PEXTLOGPEN pExtLogPen; 294 INT cbRetCount; 295 296 if (pbrushPen->flAttrs & BR_IS_OLDSTYLEPEN) 297 { 298 cbRetCount = sizeof(LOGPEN); 299 if (pBuffer) 300 { 301 if (cbCount < cbRetCount) return 0; 302 303 if (((pbrushPen->ulPenStyle & PS_STYLE_MASK) == PS_NULL) && 304 (cbCount == sizeof(EXTLOGPEN))) 305 { 306 pExtLogPen = (PEXTLOGPEN)pBuffer; 307 pExtLogPen->elpPenStyle = pbrushPen->ulPenStyle; 308 pExtLogPen->elpWidth = 0; 309 pExtLogPen->elpBrushStyle = pbrushPen->iBrushStyle; 310 pExtLogPen->elpColor = pbrushPen->BrushAttr.lbColor; 311 pExtLogPen->elpHatch = 0; 312 pExtLogPen->elpNumEntries = 0; 313 cbRetCount = sizeof(EXTLOGPEN); 314 } 315 else 316 { 317 pLogPen = (PLOGPEN)pBuffer; 318 pLogPen->lopnWidth.x = pbrushPen->lWidth; 319 pLogPen->lopnWidth.y = 0; 320 pLogPen->lopnStyle = pbrushPen->ulPenStyle; 321 pLogPen->lopnColor = pbrushPen->BrushAttr.lbColor; 322 } 323 } 324 } 325 else 326 { 327 DWORD dwStyleCount = (pbrushPen->flAttrs & BR_IS_DEFAULTSTYLE) ? 328 0 : pbrushPen->dwStyleCount; 329 cbRetCount = sizeof(EXTLOGPEN) - sizeof(DWORD) + dwStyleCount * sizeof(DWORD); 330 if (pBuffer) 331 { 332 ULONG i; 333 334 if (cbCount < cbRetCount) return 0; 335 pExtLogPen = (PEXTLOGPEN)pBuffer; 336 pExtLogPen->elpPenStyle = pbrushPen->ulPenStyle; 337 pExtLogPen->elpWidth = pbrushPen->lWidth; 338 pExtLogPen->elpBrushStyle = pbrushPen->iBrushStyle; 339 pExtLogPen->elpColor = pbrushPen->BrushAttr.lbColor; 340 pExtLogPen->elpHatch = (ULONG_PTR)pbrushPen->hbmClient; 341 pExtLogPen->elpNumEntries = dwStyleCount; 342 for (i = 0; i < dwStyleCount; i++) 343 { 344 pExtLogPen->elpStyleEntry[i] = pbrushPen->pStyle[i]; 345 } 346 } 347 } 348 349 return cbRetCount; 350 } 351 352 353 /* PUBLIC FUNCTIONS ***********************************************************/ 354 355 HPEN 356 APIENTRY 357 NtGdiCreatePen( 358 INT PenStyle, 359 INT Width, 360 COLORREF Color, 361 IN HBRUSH hbr) 362 { 363 if ((PenStyle < PS_SOLID) ||( PenStyle > PS_INSIDEFRAME)) 364 { 365 EngSetLastError(ERROR_INVALID_PARAMETER); 366 return NULL; 367 } 368 369 return IntGdiExtCreatePen(PenStyle, 370 Width, 371 BS_SOLID, 372 Color, 373 0, 374 0, 375 0, 376 NULL, 377 0, 378 TRUE, 379 hbr); 380 } 381 382 HPEN 383 APIENTRY 384 NtGdiExtCreatePen( 385 DWORD dwPenStyle, 386 DWORD ulWidth, 387 IN ULONG ulBrushStyle, 388 IN ULONG ulColor, 389 IN ULONG_PTR ulClientHatch, 390 IN ULONG_PTR ulHatch, 391 DWORD dwStyleCount, 392 PULONG pUnsafeStyle, 393 IN ULONG cjDIB, 394 IN BOOL bOldStylePen, 395 IN OPTIONAL HBRUSH hBrush) 396 { 397 NTSTATUS Status = STATUS_SUCCESS; 398 DWORD* pSafeStyle = NULL; 399 HPEN hPen; 400 401 if ((int)dwStyleCount < 0) return 0; 402 if (dwStyleCount > 16) 403 { 404 EngSetLastError(ERROR_INVALID_PARAMETER); 405 return 0; 406 } 407 408 if (((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC) && 409 (ulBrushStyle != BS_SOLID)) 410 { 411 EngSetLastError(ERROR_INVALID_PARAMETER); 412 return 0; 413 } 414 415 if (((dwPenStyle & PS_STYLE_MASK) == PS_NULL) || 416 (ulBrushStyle == BS_NULL)) 417 { 418 return StockObjects[NULL_PEN]; 419 } 420 421 422 if ((ulBrushStyle == BS_PATTERN) || 423 (ulBrushStyle == BS_DIBPATTERN) || 424 (ulBrushStyle == BS_DIBPATTERNPT)) 425 { 426 ulColor = 0; 427 } 428 else if ((ulBrushStyle != BS_SOLID) && 429 (ulBrushStyle != BS_HATCHED)) 430 { 431 EngSetLastError(ERROR_INVALID_PARAMETER); 432 return 0; 433 } 434 435 if ((dwPenStyle & PS_STYLE_MASK) != PS_USERSTYLE) 436 { 437 dwStyleCount = 0; 438 pUnsafeStyle = NULL; 439 } 440 441 if (dwStyleCount > 0) 442 { 443 if (pUnsafeStyle == NULL) 444 { 445 EngSetLastError(ERROR_INVALID_PARAMETER); 446 return 0; 447 } 448 449 pSafeStyle = ExAllocatePoolWithTag(NonPagedPool, 450 dwStyleCount * sizeof(DWORD), 451 GDITAG_PENSTYLE); 452 if (!pSafeStyle) 453 { 454 SetLastNtError(ERROR_NOT_ENOUGH_MEMORY); 455 return 0; 456 } 457 _SEH2_TRY 458 { 459 ProbeForRead(pUnsafeStyle, dwStyleCount * sizeof(DWORD), 1); 460 RtlCopyMemory(pSafeStyle, 461 pUnsafeStyle, 462 dwStyleCount * sizeof(DWORD)); 463 } 464 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 465 { 466 Status = _SEH2_GetExceptionCode(); 467 } 468 _SEH2_END 469 if(!NT_SUCCESS(Status)) 470 { 471 SetLastNtError(Status); 472 ExFreePoolWithTag(pSafeStyle, GDITAG_PENSTYLE); 473 return 0; 474 } 475 } 476 477 if (ulBrushStyle == BS_PATTERN) 478 { 479 _SEH2_TRY 480 { 481 ProbeForRead((PVOID)ulHatch, cjDIB, 1); 482 } 483 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 484 { 485 Status = _SEH2_GetExceptionCode(); 486 } 487 _SEH2_END 488 if(!NT_SUCCESS(Status)) 489 { 490 SetLastNtError(Status); 491 if (pSafeStyle) ExFreePoolWithTag(pSafeStyle, GDITAG_PENSTYLE); 492 return 0; 493 } 494 } 495 496 hPen = IntGdiExtCreatePen(dwPenStyle, 497 ulWidth, 498 ulBrushStyle, 499 ulColor, 500 ulClientHatch, 501 ulHatch, 502 dwStyleCount, 503 pSafeStyle, 504 cjDIB, 505 bOldStylePen, 506 hBrush); 507 508 if (!hPen && pSafeStyle) 509 { 510 ExFreePoolWithTag(pSafeStyle, GDITAG_PENSTYLE); 511 } 512 513 return hPen; 514 } 515 516 /* EOF */ 517