/* WIN32GState - Implements graphic state drawing for MSWindows Copyright (C) 2002 Free Software Foundation, Inc. Written by: Fred Kiefer Additions by: Christopher Armstrong Date: March 2002 This file is part of the GNU Objective C User Interface Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. */ // Currently the use of alpha blending is switched off by default. #define USE_ALPHABLEND // Define this so we pick up AlphaBlend, when loading windows.h #ifdef USE_ALPHABLEND #define WINVER 0x0500 #endif #include #include #include #include #include #include "winlib/WIN32GState.h" #include "winlib/WIN32Context.h" #include "winlib/WIN32FontInfo.h" #include "win32/WIN32Server.h" #include #ifndef AC_SRC_ALPHA // Missing definitions from wingdi.h #define AC_SRC_ALPHA 0x01 #endif // There is a bug in Win32 GDI drawing with lines wider than 0 // before and after a bezier path forming an oblique // angle. The solution is to insert extra MoveToEx()'s // before and after the PolyBezierTo(). // FK: I switched this off, as I think the treatment is worse than the illness. #define GDI_WIDELINE_BEZIERPATH_BUG 0 static inline int WindowHeight(HWND window) { RECT rect; if (!window) { NSLog(@"No window for coordinate transformation."); return 0; } if (!GetClientRect(window, &rect)) { NSLog(@"No window rectangle for coordinate transformation."); return 0; } return rect.bottom - rect.top; } static inline POINT GSWindowPointToMS(WIN32GState *s, NSPoint p) { POINT p1; p1.x = p.x - s->offset.x; p1.y = s->offset.y - p.y; return p1; } static inline RECT GSWindowRectToMS(WIN32GState *s, NSRect r) { RECT r1; r1.left = r.origin.x - s->offset.x; r1.bottom = s->offset.y - r.origin.y; r1.right = r1.left + r.size.width; r1.top = r1.bottom - r.size.height; return r1; } static inline POINT GSViewPointToWin(WIN32GState *s, NSPoint p) { p = [s->ctm transformPoint: p]; return GSWindowPointToMS(s, p); } static inline RECT GSViewRectToWin(WIN32GState *s, NSRect r) { r = [s->ctm rectInMatrixSpace: r]; return GSWindowRectToMS(s, r); } @interface WIN32GState (WinOps) - (void) setStyle: (HDC)hDC; - (void) restoreStyle: (HDC)hDC; - (HDC) getHDC; - (void) releaseHDC: (HDC)hDC; @end @implementation WIN32GState - (id) deepen { [super deepen]; if (clipRegion) { HRGN newClipRegion; newClipRegion = CreateRectRgn(0, 0, 1, 1); CombineRgn(newClipRegion, clipRegion, NULL, RGN_COPY); clipRegion = newClipRegion; } oldBrush = NULL; oldPen = NULL; oldClipRegion = NULL; return self; } - (void) dealloc { DeleteObject(clipRegion); [super dealloc]; } - (void) setWindow: (HWND)number { window = number; } - (HWND) window { return window; } - (void) setColor: (device_color_t *)acolor state: (color_state_t)cState { device_color_t color; [super setColor: acolor state: cState]; color = *acolor; gsColorToRGB(&color); if (cState & COLOR_FILL) wfcolor = RGB(color.field[0]*255, color.field[1]*255, color.field[2]*255); if (cState & COLOR_STROKE) wscolor = RGB(color.field[0]*255, color.field[1]*255, color.field[2]*255); } static inline RECT GSXWindowRectToMS(WIN32GState *s, NSRect r) { RECT r1; int h; h = WindowHeight([s window]); // r.origin.x += s->offset.x; // r.origin.y += s->offset.y; r1.left = r.origin.x; r1.right = r.origin.x + r.size.width; r1.bottom = h - r.origin.y; r1.top = h - r.origin.y - r.size.height; return r1; } - (void) compositeGState: (WIN32GState *) source fromRect: (NSRect) sourceRect toPoint: (NSPoint) destPoint op: (NSCompositingOperation) op fraction: (float)delta { NSAffineTransformStruct sctms; NSAffineTransformStruct ctms; HDC sourceDC; HDC hDC; RECT rectFrom; RECT rectTo; int h; int x; int y; NSRect destRect; BOOL success = NO; NSDebugLLog(@"WIN32GState", @"compositeGState: fromRect: %@ toPoint: %@ op: %d", NSStringFromRect(sourceRect), NSStringFromPoint(destPoint), op); rectFrom = GSViewRectToWin(source, sourceRect); //rectFrom = GSXWindowRectToMS(sourceRect); h = rectFrom.bottom - rectFrom.top; destRect.size = sourceRect.size; destRect.origin = destPoint; rectTo = GSViewRectToWin(self, destRect); x = rectTo.left; y = rectTo.top; sctms = [source->ctm transformStruct]; ctms = [ctm transformStruct]; if (sctms.m22 < 0 && ctms.m22 > 0) y += h; if (sctms.m22 > 0 && ctms.m22 < 0) y -= h; sourceDC = [source getHDC]; if (!sourceDC) { return; } if (self == source) { hDC = sourceDC; } else { hDC = [self getHDC]; if (!hDC) { [source releaseHDC: sourceDC]; return; } } switch (op) { case NSCompositeSourceOver: { #ifdef USE_ALPHABLEND // Use (0..1) fraction to set a (0..255) alpha constant value BYTE SourceConstantAlpha = (BYTE)(delta * 255); BLENDFUNCTION blendFunc = {AC_SRC_OVER, 0, SourceConstantAlpha, AC_SRC_ALPHA}; success = AlphaBlend(hDC, x, y, (rectFrom.right - rectFrom.left), h, sourceDC, rectFrom.left, rectFrom.top, (rectFrom.right - rectFrom.left), h, blendFunc); /* There is actually a very real chance this could fail, even on computers that supposedly support it. It's not known why it fails though... */ if (success) break; #endif } case NSCompositeCopy: { success = BitBlt(hDC, x, y, (rectFrom.right - rectFrom.left), h, sourceDC, rectFrom.left, rectFrom.top, SRCCOPY); break; } case NSCompositeClear: { break; } default: success = BitBlt(hDC, x, y, (rectFrom.right - rectFrom.left), h, sourceDC, rectFrom.left, rectFrom.top, SRCCOPY); break; } if (!success) { NSLog(@"Blit operation failed %d", GetLastError()); NSLog(@"Orig Copy Bits to %@ from %@", NSStringFromPoint(destPoint), NSStringFromRect(destRect)); NSLog(@"Copy bits to {%d, %d} from {%d, %d} size {%d, %d}", x, y, rectFrom.left, rectFrom.top, (rectFrom.right - rectFrom.left), h); } if (self != source) { [self releaseHDC: hDC]; } [source releaseHDC: sourceDC]; } - (void) compositeGState: (GSGState *)source fromRect: (NSRect)aRect toPoint: (NSPoint)aPoint op: (NSCompositingOperation)op { [self compositeGState: (WIN32GState *) source fromRect: aRect toPoint: aPoint op: op fraction: 1]; } - (void) dissolveGState: (GSGState *)source fromRect: (NSRect)aRect toPoint: (NSPoint)aPoint delta: (float)delta { [self compositeGState: (WIN32GState *) source fromRect: aRect toPoint: aPoint op: NSCompositeSourceOver fraction: delta]; } - (void) compositerect: (NSRect)aRect op: (NSCompositingOperation)op { float gray; [self DPScurrentgray: &gray]; if (fabs(gray - 0.667) < 0.005) [self DPSsetgray: 0.333]; else [self DPSsetrgbcolor: 0.121 : 0.121 : 0]; switch (op) { case NSCompositeClear: break; case NSCompositeHighlight: { HDC hDC; RECT rect = GSViewRectToWin(self, aRect); hDC = [self getHDC]; if (!hDC) { return; } InvertRect(hDC, &rect); [self releaseHDC: hDC]; break; } case NSCompositeCopy: // FIXME case NSCompositeSourceOver: case NSCompositeSourceIn: case NSCompositeSourceOut: case NSCompositeSourceAtop: case NSCompositeDestinationOver: case NSCompositeDestinationIn: case NSCompositeDestinationOut: case NSCompositeDestinationAtop: case NSCompositeXOR: case NSCompositePlusDarker: case NSCompositePlusLighter: default: [self DPSrectfill: NSMinX(aRect) : NSMinY(aRect) : NSWidth(aRect) : NSHeight(aRect)]; break; } } static HBITMAP GSCreateBitmap(HDC hDC, int pixelsWide, int pixelsHigh, int bitsPerSample, int samplesPerPixel, int bitsPerPixel, int bytesPerRow, BOOL isPlanar, BOOL hasAlpha, NSString *colorSpaceName, const unsigned char *const data[5]) { const unsigned char *bits = data[0]; HBITMAP hbitmap; BITMAPINFO *bitmap; BITMAPINFOHEADER *bmih; int xres, yres; UINT fuColorUse; if (isPlanar || !([colorSpaceName isEqualToString: NSDeviceRGBColorSpace] || [colorSpaceName isEqualToString: NSCalibratedRGBColorSpace])) { NSLog(@"Bitmap type currently not supported %d %@", isPlanar, colorSpaceName); return NULL; } // default is 8 bit grayscale if (!bitsPerSample) bitsPerSample = 8; if (!samplesPerPixel) samplesPerPixel = 1; // FIXME - does this work if we are passed a planar image but no hints ? if (!bitsPerPixel) bitsPerPixel = bitsPerSample * samplesPerPixel; if (!bytesPerRow) bytesPerRow = (bitsPerPixel * pixelsWide) / 8; // make sure its sane - also handles row padding if hint missing while ((bytesPerRow * 8) < (bitsPerPixel * pixelsWide)) bytesPerRow++; if (!(GetDeviceCaps(hDC, RASTERCAPS) & RC_DI_BITMAP)) { return NULL; } hbitmap = CreateCompatibleBitmap(hDC, pixelsWide, pixelsHigh); if (!hbitmap) { return NULL; } if (bitsPerPixel > 8) { bitmap = objc_malloc(sizeof(BITMAPV4HEADER)); } else { bitmap = objc_malloc(sizeof(BITMAPINFOHEADER) + (1 << bitsPerPixel) * sizeof(RGBQUAD)); } bmih = (BITMAPINFOHEADER*)bitmap; bmih->biSize = sizeof(BITMAPINFOHEADER); bmih->biWidth = pixelsWide; bmih->biHeight = -pixelsHigh; bmih->biPlanes = 1; bmih->biBitCount = bitsPerPixel; bmih->biCompression = BI_RGB; bmih->biSizeImage = 0; xres = GetDeviceCaps(hDC, HORZRES) / GetDeviceCaps(hDC, HORZSIZE); yres = GetDeviceCaps(hDC, VERTRES) / GetDeviceCaps(hDC, VERTSIZE); bmih->biXPelsPerMeter = xres; bmih->biYPelsPerMeter = yres; bmih->biClrUsed = 0; bmih->biClrImportant = 0; fuColorUse = 0; if (bitsPerPixel <= 8) { // FIXME How to get a colour palette? NSLog(@"Need to define colour map for images with %d bits", bitsPerPixel); //bitmap->bmiColors; fuColorUse = DIB_RGB_COLORS; } else if (bitsPerPixel == 32) { BITMAPV4HEADER *bmih; unsigned char *tmp; unsigned int pixels = pixelsHigh * pixelsWide; unsigned int i = 0; bmih = (BITMAPV4HEADER*)bitmap; bmih->bV4Size = sizeof(BITMAPV4HEADER); bmih->bV4V4Compression = BI_BITFIELDS; bmih->bV4BlueMask = 0x000000FF; bmih->bV4GreenMask = 0x0000FF00; bmih->bV4RedMask = 0x00FF0000; bmih->bV4AlphaMask = 0xFF000000; tmp = objc_malloc(pixels * 4); while (i < pixels*4) { tmp[i+0] = bits[i+2]; tmp[i+1] = bits[i+1]; tmp[i+2] = bits[i+0]; tmp[i+3] = bits[i+3]; i += 4; } bits = tmp; } else if (bitsPerPixel == 24) { unsigned char* tmp; unsigned int pixels = pixelsHigh * pixelsWide; unsigned int i = 0, j = 0; bmih->biBitCount = 32; NSDebugLLog(@"WIN32GState", @"24bit picure with pixelsWide:%d " @"pixelsHigh:%d", pixelsWide, pixelsHigh); tmp = objc_malloc(pixels * 4); //memset(tmp, 0xFF, pixels*4); while (i < (pixels*4)) { // We expand the bytes in a 24bit image into 32bits as Windows // seems to handle it better (and I can't figure out the correct // rearrangement for 24bit images anyway). tmp[i+0] = bits[j+2]; tmp[i+1] = bits[j+1]; tmp[i+2] = bits[j+0]; tmp[i+3] = 0xFF; i+=4; j+=3; } bits = tmp; } else if (bitsPerPixel == 16) { /* BITMAPV4HEADER *bmih; bmih = (BITMAPV4HEADER*)bitmap; bmih->bV4Size = sizeof(BITMAPV4HEADER); bmih->bV4V4Compression = BI_BITFIELDS; bmih->bV4RedMask = 0xF000; bmih->bV4GreenMask = 0x0F00; bmih->bV4BlueMask = 0x00F0; bmih->bV4AlphaMask = 0x000F; */ NSLog(@"Unsure how to handle images with %d bits", bitsPerPixel); } if (!SetDIBits(hDC, hbitmap, 0, pixelsHigh, bits, bitmap, fuColorUse)) { DeleteObject(hbitmap); hbitmap = NULL; } if (bits != data[0]) { /* cast bits to Void Pointer to fix warning in compile */ objc_free((void *)(bits)); } objc_free(bitmap); return hbitmap; } - (void)DPSimage: (NSAffineTransform*) matrix : (int) pixelsWide : (int) pixelsHigh : (int) bitsPerSample : (int) samplesPerPixel : (int) bitsPerPixel : (int) bytesPerRow : (BOOL) isPlanar : (BOOL) hasAlpha : (NSString *) colorSpaceName : (const unsigned char *const [5]) data { NSAffineTransform *old_ctm = nil; HDC hDC; HBITMAP hbitmap; HGDIOBJ old; HDC hDC2; POINT p; int h; int y1; /* NSDebugLLog(@"WIN32GState", @"DPSImage : pixelsWide = %d : pixelsHigh = %d" ": bitsPerSample = %d : samplesPerPixel = %d" ": bitsPerPixel = %d : bytesPerRow = %d " ": isPlanar = %d" ": hasAlpha = %d : colorSpaceName = %@", pixelsWide, pixelsHigh, bitsPerSample, samplesPerPixel, bitsPerPixel, bytesPerRow, isPlanar, hasAlpha, colorSpaceName); */ if (window == NULL) { NSLog(@"No window in DPSImage"); return; } hDC = GetDC((HWND)window); if (!hDC) { NSLog(@"No DC for window %d in DPSImage. Error %d", (int)window, GetLastError()); } hbitmap = GSCreateBitmap(hDC, pixelsWide, pixelsHigh, bitsPerSample, samplesPerPixel, bitsPerPixel, bytesPerRow, isPlanar, hasAlpha, colorSpaceName, data); if (!hbitmap) { NSLog(@"Created bitmap failed %d", GetLastError()); } hDC2 = CreateCompatibleDC(hDC); if (!hDC2) { NSLog(@"No Compatible DC for window %d in DPSImage. Error %d", (int)window, GetLastError()); } old = SelectObject(hDC2, hbitmap); if (!old) { NSLog(@"SelectObject failed for window %d in DPSImage. Error %d", (int)window, GetLastError()); } //SetMapMode(hDC2, GetMapMode(hDC)); ReleaseDC((HWND)window, hDC); hDC = [self getHDC]; h = pixelsHigh; // Apply the additional transformation if (matrix) { old_ctm = [ctm copy]; [ctm prependTransform: matrix]; } p = GSViewPointToWin(self, NSMakePoint(0, 0)); if (old_ctm != nil) { RELEASE(ctm); // old_ctm is already retained ctm = old_ctm; } if (viewIsFlipped) y1 = p.y; else y1 = p.y - h; if (!BitBlt(hDC, p.x, y1, pixelsWide, pixelsHigh, hDC2, 0, 0, SRCCOPY)) { NSLog(@"Copy bitmap failed %d", GetLastError()); NSLog(@"DPSimage with %d %d %d %d to %d, %d", pixelsWide, pixelsHigh, bytesPerRow, bitsPerPixel, p.x, y1); } [self releaseHDC: hDC]; SelectObject(hDC2, old); DeleteDC(hDC2); DeleteObject(hbitmap); } @end @implementation WIN32GState (PathOps) - (void) _paintPath: (ctxt_object_t) drawType { unsigned count; HDC hDC; hDC = [self getHDC]; if (!hDC) { return; } count = [path elementCount]; if (count) { NSBezierPathElement type; NSPoint points[3]; unsigned j, i = 0; POINT p; BeginPath(hDC); for (j = 0; j < count; j++) { type = [path elementAtIndex: j associatedPoints: points]; switch(type) { case NSMoveToBezierPathElement: p = GSWindowPointToMS(self, points[0]); MoveToEx(hDC, p.x, p.y, NULL); break; case NSLineToBezierPathElement: p = GSWindowPointToMS(self, points[0]); // FIXME This gives one pixel too few LineTo(hDC, p.x, p.y); break; case NSCurveToBezierPathElement: { POINT bp[3]; #if GDI_WIDELINE_BEZIERPATH_BUG if (drawType == path_stroke && lineWidth > 1) { if (j != 0) { NSPoint movePoints[3]; [path elementAtIndex: j-1 associatedPoints: movePoints]; p = GSWindowPointToMS(self, movePoints[0]); MoveToEx(hDC, p.x, p.y, NULL); } } #endif for (i = 0; i < 3; i++) { bp[i] = GSWindowPointToMS(self, points[i]); } PolyBezierTo(hDC, bp, 3); #if GDI_WIDELINE_BEZIERPATH_BUG if (drawType == path_stroke && lineWidth > 1) MoveToEx(hDC, bp[2].x, bp[2].y, NULL); #endif } break; case NSClosePathBezierPathElement: #if GDI_WIDELINE_BEZIERPATH_BUG // CloseFigure works from the last MoveTo point which is // a problem when we need to insert gratuitious moves // before and after bezier curves to fix draw problems. [path elementAtIndex: 0 associatedPoints: points]; p = GSWindowPointToMS(self, points[0]); // FIXME This may also give one pixel too few LineTo(hDC, p.x, p.y); #else CloseFigure(hDC); #endif break; default: break; } } EndPath(hDC); // Now operate on the path switch (drawType) { case path_stroke: StrokePath(hDC); break; case path_eofill: SetPolyFillMode(hDC, ALTERNATE); FillPath(hDC); break; case path_fill: SetPolyFillMode(hDC, WINDING); FillPath(hDC); break; case path_eoclip: { HRGN region; SetPolyFillMode(hDC, ALTERNATE); region = PathToRegion(hDC); if (clipRegion) { CombineRgn(clipRegion, clipRegion, region, RGN_AND); DeleteObject(region); } else { clipRegion = region; } break; } case path_clip: { HRGN region; SetPolyFillMode(hDC, WINDING); region = PathToRegion(hDC); if (clipRegion) { CombineRgn(clipRegion, clipRegion, region, RGN_AND); DeleteObject(region); } else { clipRegion = region; } break; } default: break; } } [self releaseHDC: hDC]; /* * clip does not delete the current path, so we only clear the path if the * operation was not a clipping operation. */ if ((drawType != path_clip) && (drawType != path_eoclip)) { [path removeAllPoints]; } } - (void)DPSclip { [self _paintPath: path_clip]; } - (void)DPSeoclip { [self _paintPath: path_eoclip]; } - (void)DPSeofill { [self _paintPath: path_eofill]; } - (void)DPSfill { [self _paintPath: path_fill]; } - (void)DPSstroke { [self _paintPath: path_stroke]; } - (void) DPSinitclip; { if (clipRegion) { DeleteObject(clipRegion); clipRegion = NULL; } } - (void)DPSrectfill: (float)x : (float)y : (float)w : (float)h { HDC hDC; HBRUSH brush; RECT rect; hDC = [self getHDC]; if (!hDC) { return; } brush = GetCurrentObject(hDC, OBJ_BRUSH); rect = GSViewRectToWin(self, NSMakeRect(x, y, w, h)); FillRect(hDC, &rect, brush); [self releaseHDC: hDC]; } - (void)DPSrectstroke: (float)x : (float)y : (float)w : (float)h { NSRect rect = [ctm rectInMatrixSpace: NSMakeRect(x, y, w, h)]; /* // Samll adjustment so that the line is visible if (rect.size.width > 0) rect.size.width--; if (rect.size.height > 0) rect.size.height--; rect.origin.y += 1; */ [path appendBezierPathWithRect: rect]; [self DPSstroke]; } - (void)DPSrectclip: (float)x : (float)y : (float)w : (float)h { RECT rect; HRGN region; rect = GSViewRectToWin(self, NSMakeRect(x, y, w, h)); region = CreateRectRgnIndirect(&rect); if (clipRegion) { CombineRgn(clipRegion, clipRegion, region, RGN_AND); DeleteObject(region); } else { clipRegion = region; } [self DPSnewpath]; } - (void)DPSshow: (const char *)s { NSPoint current = [path currentPoint]; POINT p; HDC hDC; hDC = [self getHDC]; if (!hDC) { return; } p = GSWindowPointToMS(self, current); [(WIN32FontInfo*)font draw: s length: strlen(s) onDC: hDC at: p]; [self releaseHDC: hDC]; } - (void) GSShowGlyphs: (const NSGlyph *)glyphs : (size_t)length { NSPoint current = [path currentPoint]; POINT p; HDC hDC; hDC = [self getHDC]; if (!hDC) { return; } p = GSWindowPointToMS(self, current); [(WIN32FontInfo*)font drawGlyphs: glyphs length: length onDC: hDC at: p]; [self releaseHDC: hDC]; } @end @implementation WIN32GState (GStateOps) - (void)DPSinitgraphics { [super DPSinitgraphics]; } - (void) DPSsetdash: (const float*)thePattern : (int)count : (float)phase { if (!path) { path = [NSBezierPath new]; } [path setLineDash: thePattern count: count phase: phase]; } - (void)DPScurrentmiterlimit: (float *)limit { *limit = miterlimit; } - (void)DPSsetmiterlimit: (float)limit { miterlimit = limit; } - (void)DPScurrentlinecap: (int *)linecap { *linecap = lineCap; } - (void)DPSsetlinecap: (int)linecap { lineCap = linecap; } - (void)DPScurrentlinejoin: (int *)linejoin { *linejoin = joinStyle; } - (void)DPSsetlinejoin: (int)linejoin { joinStyle = linejoin; } - (void)DPScurrentlinewidth: (float *)width { *width = lineWidth; } - (void)DPSsetlinewidth: (float)width { lineWidth = width; } - (void)DPScurrentstrokeadjust: (int *)b { } - (void)DPSsetstrokeadjust: (int)b { } @end @implementation WIN32GState (WinOps) - (void) setStyle: (HDC)hDC { HPEN pen; HBRUSH brush; LOGBRUSH br; int join; int cap; DWORD penStyle; // Temporary variables for gathering pen information float* thePattern = NULL; DWORD* iPattern = NULL; int patternCount = 0; float phase = 0.0; SetBkMode(hDC, TRANSPARENT); br.lbStyle = BS_SOLID; br.lbColor = wfcolor; br.lbHatch = 0; /* brush = CreateBrushIndirect(&br); */ brush = CreateSolidBrush(wfcolor); oldBrush = SelectObject(hDC, brush); switch (joinStyle) { case NSBevelLineJoinStyle: join = PS_JOIN_BEVEL; break; case NSMiterLineJoinStyle: join = PS_JOIN_MITER; break; case NSRoundLineJoinStyle: join = PS_JOIN_ROUND; break; default: join = PS_JOIN_MITER; break; } switch (lineCap) { case NSButtLineCapStyle: cap = PS_ENDCAP_FLAT; break; case NSSquareLineCapStyle: cap = PS_ENDCAP_SQUARE; break; case NSRoundLineCapStyle: cap = PS_ENDCAP_ROUND; break; default: cap = PS_ENDCAP_SQUARE; break; } // Get the size of the pen line dash [path getLineDash: NULL count: &patternCount phase: NULL]; if (patternCount > 0) { penStyle = PS_GEOMETRIC | PS_USERSTYLE; // The user has defined a dash pattern for stroking on // the path. Note that we lose the floating point information // here, as windows only supports DWORD elements, not float. thePattern = objc_malloc(sizeof(float) * patternCount); [path getLineDash: thePattern count: &patternCount phase: &phase]; iPattern = objc_malloc(sizeof(DWORD) * patternCount); int i = 0; for (i = 0 ; i < patternCount; i ++) iPattern[i] = (DWORD)thePattern[i]; objc_free(thePattern); thePattern = NULL; } else { penStyle = PS_GEOMETRIC | PS_SOLID; } pen = ExtCreatePen(penStyle | join | cap, lineWidth, &br, patternCount, iPattern); if (iPattern) { objc_free(iPattern); iPattern = NULL; } oldPen = SelectObject(hDC, pen); SetMiterLimit(hDC, miterlimit, NULL); SetTextColor(hDC, wfcolor); oldClipRegion = CreateRectRgn(0, 0, 1, 1); if (1 != GetClipRgn(hDC, oldClipRegion)) { DeleteObject(oldClipRegion); oldClipRegion = NULL; } SelectClipRgn(hDC, clipRegion); } - (void) restoreStyle: (HDC)hDC { HGDIOBJ old; SelectClipRgn(hDC, oldClipRegion); DeleteObject(oldClipRegion); oldClipRegion = NULL; old = SelectObject(hDC, oldBrush); DeleteObject(old); old = SelectObject(hDC, oldPen); DeleteObject(old); } - (HDC) getHDC { WIN_INTERN *win; HDC hDC; if (NULL == window) { //NSLog(@"No window in getHDC"); return NULL; } win = (WIN_INTERN *)GetWindowLong((HWND)window, GWL_USERDATA); if (win && win->useHDC) { hDC = win->hdc; //NSLog(@"getHDC found DC %d", hDC); } else { hDC = GetDC((HWND)window); //NSLog(@"getHDC using window DC %d", hDC); } if (!hDC) { //NSLog(@"No DC in getHDC"); return NULL; } [self setStyle: hDC]; return hDC; } - (void) releaseHDC: (HDC)hDC { WIN_INTERN *win; if (NULL == window || NULL == hDC) { return; } [self restoreStyle: hDC]; win = (WIN_INTERN *)GetWindowLong((HWND)window, GWL_USERDATA); if (win && !win->useHDC) ReleaseDC((HWND)window, hDC); } @end