diff --git a/dlls/gdi32/pen.c b/dlls/gdi32/pen.c index 2f693751288..569c2b296ca 100644 --- a/dlls/gdi32/pen.c +++ b/dlls/gdi32/pen.c @@ -36,8 +36,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdi); /* GDI logical pen object */ typedef struct { - GDIOBJHDR header; - EXTLOGPEN logpen; + GDIOBJHDR header; + struct brush_pattern pattern; + EXTLOGPEN logpen; } PENOBJ; @@ -87,15 +88,12 @@ HPEN WINAPI CreatePenIndirect( const LOGPEN * pen ) if (hpen) return hpen; } - if (!(penPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*penPtr) ))) return 0; + if (!(penPtr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*penPtr) ))) return 0; penPtr->logpen.elpPenStyle = pen->lopnStyle; penPtr->logpen.elpWidth = abs(pen->lopnWidth.x); penPtr->logpen.elpColor = pen->lopnColor; penPtr->logpen.elpBrushStyle = BS_SOLID; - penPtr->logpen.elpHatch = 0; - penPtr->logpen.elpNumEntries = 0; - penPtr->logpen.elpStyleEntry[0] = 0; switch (pen->lopnStyle) { @@ -128,14 +126,12 @@ HPEN WINAPI ExtCreatePen( DWORD style, DWORD width, const LOGBRUSH * brush, DWORD style_count, const DWORD *style_bits ) { - PENOBJ * penPtr; + PENOBJ *penPtr = NULL; HPEN hpen; + LOGBRUSH logbrush; if ((style_count || style_bits) && (style & PS_STYLE_MASK) != PS_USERSTYLE) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } + goto invalid; switch (style & PS_STYLE_MASK) { @@ -152,11 +148,7 @@ HPEN WINAPI ExtCreatePen( DWORD style, DWORD width, case PS_USERSTYLE: if (((INT)style_count) <= 0) return 0; - if ((style_count > 16) || !style_bits) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } + if ((style_count > 16) || !style_bits) goto invalid; if ((style & PS_TYPE_MASK) == PS_GEOMETRIC) { @@ -169,28 +161,16 @@ HPEN WINAPI ExtCreatePen( DWORD style, DWORD width, all_zero = all_zero && (style_bits[i] == 0); } - if(all_zero || has_neg) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } + if (all_zero || has_neg) goto invalid; } break; case PS_INSIDEFRAME: /* applicable only for geometric pens */ - if ((style & PS_TYPE_MASK) != PS_GEOMETRIC) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } + if ((style & PS_TYPE_MASK) != PS_GEOMETRIC) goto invalid; break; case PS_ALTERNATE: /* applicable only for cosmetic pens */ - if ((style & PS_TYPE_MASK) == PS_GEOMETRIC) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } + if ((style & PS_TYPE_MASK) == PS_GEOMETRIC) goto invalid; break; default: @@ -200,35 +180,40 @@ HPEN WINAPI ExtCreatePen( DWORD style, DWORD width, if ((style & PS_TYPE_MASK) == PS_GEOMETRIC) { - if (brush->lbHatch && ((brush->lbStyle != BS_SOLID) && (brush->lbStyle != BS_HOLLOW))) - { - static int fixme_hatches_shown; - if (!fixme_hatches_shown++) FIXME("Hatches not implemented\n"); - } + if (brush->lbStyle == BS_NULL) return CreatePen( PS_NULL, 0, 0 ); } else { - if (width != 1) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } + if (width != 1) goto invalid; + if (brush->lbStyle != BS_SOLID) goto invalid; } if (!(penPtr = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(PENOBJ,logpen.elpStyleEntry[style_count])))) return 0; + logbrush = *brush; + if (!store_brush_pattern( &logbrush, &penPtr->pattern )) goto invalid; + if (logbrush.lbStyle == BS_DIBPATTERN) logbrush.lbStyle = BS_DIBPATTERNPT; + penPtr->logpen.elpPenStyle = style; penPtr->logpen.elpWidth = abs(width); - penPtr->logpen.elpBrushStyle = brush->lbStyle; - penPtr->logpen.elpColor = brush->lbColor; + penPtr->logpen.elpBrushStyle = logbrush.lbStyle; + penPtr->logpen.elpColor = logbrush.lbColor; penPtr->logpen.elpHatch = brush->lbHatch; penPtr->logpen.elpNumEntries = style_count; memcpy(penPtr->logpen.elpStyleEntry, style_bits, style_count * sizeof(DWORD)); if (!(hpen = alloc_gdi_handle( &penPtr->header, OBJ_EXTPEN, &pen_funcs ))) + { + free_brush_pattern( &penPtr->pattern ); HeapFree( GetProcessHeap(), 0, penPtr ); + } return hpen; + +invalid: + HeapFree( GetProcessHeap(), 0, penPtr ); + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; } /*********************************************************************** @@ -276,6 +261,7 @@ static BOOL PEN_DeleteObject( HGDIOBJ handle ) PENOBJ *pen = free_gdi_handle( handle ); if (!pen) return FALSE; + free_brush_pattern( &pen->pattern ); return HeapFree( GetProcessHeap(), 0, pen ); } diff --git a/dlls/gdi32/tests/pen.c b/dlls/gdi32/tests/pen.c index 9b626698158..ed7927a3343 100644 --- a/dlls/gdi32/tests/pen.c +++ b/dlls/gdi32/tests/pen.c @@ -570,9 +570,130 @@ static void test_ps_userstyle(void) DeleteObject(pen); } +static void test_brush_pens(void) +{ + char buffer[sizeof(EXTLOGPEN) + 15 * sizeof(DWORD)]; + EXTLOGPEN *elp = (EXTLOGPEN *)buffer; + LOGBRUSH lb; + HPEN pen = 0; + DWORD size; + HBITMAP bmp = CreateBitmap( 8, 8, 1, 1, NULL ); + BITMAPINFO *info; + HGLOBAL hmem; + + hmem = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(*info) + 16 * 16 * 4 ); + info = GlobalLock( hmem ); + info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biWidth = 16; + info->bmiHeader.biHeight = 16; + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = 32; + info->bmiHeader.biCompression = BI_RGB; + + for (lb.lbStyle = BS_SOLID; lb.lbStyle <= BS_MONOPATTERN + 1; lb.lbStyle++) + { + SetLastError( 0xdeadbeef ); + memset( buffer, 0xcc, sizeof(buffer) ); + trace( "testing brush style %u\n", lb.lbStyle ); + + switch (lb.lbStyle) + { + case BS_SOLID: + case BS_HATCHED: + lb.lbColor = RGB(12,34,56); + lb.lbHatch = HS_CROSS; + pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL ); + ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() ); + size = GetObject( pen, sizeof(buffer), elp ); + ok( size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size ); + ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle ); + ok( elp->elpBrushStyle == lb.lbStyle, "wrong brush style %x\n", elp->elpBrushStyle ); + ok( elp->elpColor == RGB(12,34,56), "wrong color %x\n", elp->elpColor ); + ok( elp->elpHatch == HS_CROSS, "wrong hatch %lx\n", elp->elpHatch ); + ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries ); + break; + + case BS_NULL: + pen = ExtCreatePen( PS_SOLID | PS_GEOMETRIC, 3, &lb, 0, NULL ); + ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() ); + size = GetObject( pen, sizeof(buffer), elp ); + ok( size == sizeof(LOGPEN), "wrong size %u\n", size ); + ok( ((LOGPEN *)elp)->lopnStyle == PS_NULL, + "wrong pen style %x\n", ((LOGPEN *)elp)->lopnStyle ); + ok( ((LOGPEN *)elp)->lopnColor == 0, + "wrong color %x\n", ((LOGPEN *)elp)->lopnColor ); + break; + + case BS_PATTERN: + lb.lbColor = RGB(12,34,56); + lb.lbHatch = (ULONG_PTR)bmp; + pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL ); + ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() ); + size = GetObject( pen, sizeof(buffer), elp ); + ok( size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size ); + ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle ); + ok( elp->elpBrushStyle == BS_PATTERN, "wrong brush style %x\n", elp->elpBrushStyle ); + ok( elp->elpColor == 0, "wrong color %x\n", elp->elpColor ); + ok( elp->elpHatch == (ULONG_PTR)bmp, "wrong hatch %lx/%p\n", elp->elpHatch, bmp ); + ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries ); + break; + + case BS_DIBPATTERN: + case BS_DIBPATTERNPT: + lb.lbColor = DIB_PAL_COLORS; + lb.lbHatch = lb.lbStyle == BS_DIBPATTERN ? (ULONG_PTR)hmem : (ULONG_PTR)info; + pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL ); + ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() ); + size = GetObject( pen, sizeof(buffer), elp ); + ok( size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size ); + ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle ); + ok( elp->elpBrushStyle == BS_DIBPATTERNPT, "wrong brush style %x\n", elp->elpBrushStyle ); + ok( elp->elpColor == 0, "wrong color %x\n", elp->elpColor ); + ok( elp->elpHatch == lb.lbHatch || broken(elp->elpHatch != lb.lbHatch), /* <= w2k */ + "wrong hatch %lx/%lx\n", elp->elpHatch, lb.lbHatch ); + ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries ); + break; + + default: + pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL ); + ok( !pen, "ExtCreatePen succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + break; + } + + if (pen) DeleteObject( pen ); + else continue; + + /* cosmetic pens require BS_SOLID */ + SetLastError( 0xdeadbeef ); + pen = ExtCreatePen( PS_DOT, 1, &lb, 0, NULL ); + if (lb.lbStyle == BS_SOLID) + { + ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() ); + size = GetObject( pen, sizeof(buffer), elp ); + ok( size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size ); + ok( elp->elpPenStyle == PS_DOT, "wrong pen style %x\n", elp->elpPenStyle ); + ok( elp->elpBrushStyle == BS_SOLID, "wrong brush style %x\n", elp->elpBrushStyle ); + ok( elp->elpColor == RGB(12,34,56), "wrong color %x\n", elp->elpColor ); + ok( elp->elpHatch == HS_CROSS, "wrong hatch %lx\n", elp->elpHatch ); + DeleteObject( pen ); + } + else + { + ok( !pen, "ExtCreatePen succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + } + } + + GlobalUnlock( hmem ); + GlobalFree( hmem ); + DeleteObject( bmp ); +} + START_TEST(pen) { test_logpen(); + test_brush_pens(); test_ps_alternate(); test_ps_userstyle(); }