1 |
/* WIN32GState - Implements graphic state drawing for MSWindows |
2 |
|
3 |
Copyright (C) 2002 Free Software Foundation, Inc. |
4 |
|
5 |
Written by: <author name="Fred Kiefer><email>FredKiefer@gmx.de</email></author> |
6 |
Date: March 2002 |
7 |
|
8 |
This file is part of the GNU Objective C User Interface Library. |
9 |
|
10 |
This library is free software; you can redistribute it and/or |
11 |
modify it under the terms of the GNU Library General Public |
12 |
License as published by the Free Software Foundation; either |
13 |
version 2 of the License, or (at your option) any later version. |
14 |
|
15 |
This library is distributed in the hope that it will be useful, |
16 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 |
Library General Public License for more details. |
19 |
|
20 |
You should have received a copy of the GNU Library General Public |
21 |
License along with this library; if not, write to the Free |
22 |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. |
23 |
*/ |
24 |
|
25 |
#include <AppKit/NSAffineTransform.h> |
26 |
#include <AppKit/NSBezierPath.h> |
27 |
#include <AppKit/NSColor.h> |
28 |
#include <AppKit/NSFont.h> |
29 |
#include <AppKit/NSGraphics.h> |
30 |
|
31 |
#include "winlib/WIN32GState.h" |
32 |
#include "winlib/WIN32Context.h" |
33 |
#include "winlib/WIN32FontInfo.h" |
34 |
#include "win32/WIN32Server.h" |
35 |
|
36 |
#include <math.h> |
37 |
|
38 |
static inline |
39 |
int WindowHeight(HWND window) |
40 |
{ |
41 |
RECT rect; |
42 |
|
43 |
if (!window) |
44 |
{ |
45 |
NSLog(@"No window for coordinate transformation."); |
46 |
return 0; |
47 |
} |
48 |
|
49 |
if (!GetClientRect(window, &rect)) |
50 |
{ |
51 |
NSLog(@"No window rectangle for coordinate transformation."); |
52 |
return 0; |
53 |
} |
54 |
|
55 |
return rect.bottom - rect.top; |
56 |
} |
57 |
|
58 |
static inline |
59 |
POINT GSWindowPointToMS(WIN32GState *s, NSPoint p) |
60 |
{ |
61 |
POINT p1; |
62 |
int h; |
63 |
|
64 |
h = WindowHeight([s window]); |
65 |
|
66 |
p.x += s->offset.x; |
67 |
p.y += s->offset.y; |
68 |
p1.x = p.x; |
69 |
p1.y = h -p.y; |
70 |
|
71 |
return p1; |
72 |
} |
73 |
|
74 |
static inline |
75 |
RECT GSWindowRectToMS(WIN32GState *s, NSRect r) |
76 |
{ |
77 |
RECT r1; |
78 |
int h; |
79 |
|
80 |
h = WindowHeight([s window]); |
81 |
|
82 |
r.origin.x += s->offset.x; |
83 |
r.origin.y += s->offset.y; |
84 |
|
85 |
r1.left = r.origin.x; |
86 |
r1.right = r.origin.x + r.size.width; |
87 |
r1.bottom = h - r.origin.y; |
88 |
r1.top = h - r.origin.y - r.size.height; |
89 |
|
90 |
return r1; |
91 |
} |
92 |
|
93 |
static inline |
94 |
POINT GSViewPointToWin(WIN32GState *s, NSPoint p) |
95 |
{ |
96 |
p = [s->ctm pointInMatrixSpace: p]; |
97 |
return GSWindowPointToMS(s, p); |
98 |
} |
99 |
|
100 |
static inline |
101 |
RECT GSViewRectToWin(WIN32GState *s, NSRect r) |
102 |
{ |
103 |
r = [s->ctm rectInMatrixSpace: r]; |
104 |
return GSWindowRectToMS(s, r); |
105 |
} |
106 |
|
107 |
@interface WIN32GState (WinOps) |
108 |
- (void) setStyle: (HDC)hDC; |
109 |
- (void) restoreStyle: (HDC)hDC; |
110 |
- (HDC) getHDC; |
111 |
- (void) releaseHDC: (HDC)hDC; |
112 |
@end |
113 |
|
114 |
@implementation WIN32GState |
115 |
|
116 |
- (id) deepen |
117 |
{ |
118 |
[super deepen]; |
119 |
|
120 |
if (clipRegion) |
121 |
{ |
122 |
HRGN newClipRegion; |
123 |
|
124 |
newClipRegion = CreateRectRgn(0, 0, 1, 1); |
125 |
CombineRgn(newClipRegion, clipRegion, NULL, RGN_COPY); |
126 |
clipRegion = newClipRegion; |
127 |
} |
128 |
|
129 |
oldBrush = NULL; |
130 |
oldPen = NULL; |
131 |
oldClipRegion = NULL; |
132 |
|
133 |
return self; |
134 |
} |
135 |
|
136 |
- (void) dealloc |
137 |
{ |
138 |
DeleteObject(clipRegion); |
139 |
[super dealloc]; |
140 |
} |
141 |
|
142 |
- (void) setWindow: (HWND)number |
143 |
{ |
144 |
window = number; |
145 |
} |
146 |
|
147 |
- (HWND) window |
148 |
{ |
149 |
return window; |
150 |
} |
151 |
|
152 |
- (void) setColor: (device_color_t *)acolor state: (color_state_t)cState |
153 |
{ |
154 |
device_color_t color; |
155 |
[super setColor: acolor state: cState]; |
156 |
color = *acolor; |
157 |
gsColorToRGB(&color); |
158 |
if (cState & COLOR_FILL) |
159 |
wfcolor = RGB(color.field[0]*255, color.field[1]*255, color.field[2]*255); |
160 |
if (cState & COLOR_STROKE) |
161 |
wscolor = RGB(color.field[0]*255, color.field[1]*255, color.field[2]*255); |
162 |
} |
163 |
|
164 |
- (void) copyBits: (WIN32GState*)source |
165 |
fromRect: (NSRect)aRect |
166 |
toPoint: (NSPoint)aPoint |
167 |
{ |
168 |
HDC otherDC; |
169 |
HDC hDC; |
170 |
POINT p; |
171 |
RECT rect; |
172 |
int h; |
173 |
int y1; |
174 |
|
175 |
p = GSViewPointToWin(self, aPoint); |
176 |
rect = GSViewRectToWin(source, aRect); |
177 |
h = rect.bottom - rect.top; |
178 |
|
179 |
if (viewIsFlipped) |
180 |
y1 = p.y; |
181 |
else |
182 |
y1 = p.y - h; |
183 |
|
184 |
otherDC = [source getHDC]; |
185 |
if (!otherDC) |
186 |
{ |
187 |
return; |
188 |
} |
189 |
hDC = [self getHDC]; |
190 |
if (!hDC) |
191 |
{ |
192 |
[source releaseHDC: otherDC]; |
193 |
return; |
194 |
} |
195 |
|
196 |
if (!BitBlt(hDC, p.x, y1, (rect.right - rect.left), h, |
197 |
otherDC, rect.left, rect.top, SRCCOPY)) |
198 |
{ |
199 |
NSLog(@"Copy bitmap failed %d", GetLastError()); |
200 |
NSLog(@"Orig Copy Bits to %f, %f from %@", aPoint.x, aPoint.y, |
201 |
NSStringFromRect(aRect)); |
202 |
NSLog(@"Copy Bits to %d %d from %d %d size %d %d", p.x , y1, |
203 |
rect.left, rect.top, (rect.right - rect.left), h); |
204 |
} |
205 |
[self releaseHDC: hDC]; |
206 |
[source releaseHDC: otherDC]; |
207 |
} |
208 |
|
209 |
- (void) compositeGState: (GSGState *)source |
210 |
fromRect: (NSRect)aRect |
211 |
toPoint: (NSPoint)aPoint |
212 |
op: (NSCompositingOperation)op |
213 |
{ |
214 |
// FIXME |
215 |
[self copyBits: (WIN32GState *)source fromRect: aRect toPoint: aPoint]; |
216 |
} |
217 |
|
218 |
- (void) dissolveGState: (GSGState *)source |
219 |
fromRect: (NSRect)aRect |
220 |
toPoint: (NSPoint)aPoint |
221 |
delta: (float)delta |
222 |
{ |
223 |
// FIXME |
224 |
[self copyBits: (WIN32GState *)source fromRect: aRect toPoint: aPoint]; |
225 |
} |
226 |
|
227 |
- (void) compositerect: (NSRect)aRect |
228 |
op: (NSCompositingOperation)op |
229 |
{ |
230 |
float gray; |
231 |
|
232 |
[self DPScurrentgray: &gray]; |
233 |
if (fabs(gray - 0.667) < 0.005) |
234 |
[self DPSsetgray: 0.333]; |
235 |
else |
236 |
[self DPSsetrgbcolor: 0.121 : 0.121 : 0]; |
237 |
|
238 |
switch (op) |
239 |
{ |
240 |
case NSCompositeClear: |
241 |
break; |
242 |
case NSCompositeHighlight: |
243 |
{ |
244 |
HDC hDC; |
245 |
RECT rect = GSViewRectToWin(self, aRect); |
246 |
|
247 |
hDC = [self getHDC]; |
248 |
if (!hDC) |
249 |
{ |
250 |
return; |
251 |
} |
252 |
|
253 |
InvertRect(hDC, &rect); |
254 |
[self releaseHDC: hDC]; |
255 |
break; |
256 |
} |
257 |
case NSCompositeCopy: |
258 |
// FIXME |
259 |
case NSCompositeSourceOver: |
260 |
case NSCompositeSourceIn: |
261 |
case NSCompositeSourceOut: |
262 |
case NSCompositeSourceAtop: |
263 |
case NSCompositeDestinationOver: |
264 |
case NSCompositeDestinationIn: |
265 |
case NSCompositeDestinationOut: |
266 |
case NSCompositeDestinationAtop: |
267 |
case NSCompositeXOR: |
268 |
case NSCompositePlusDarker: |
269 |
case NSCompositePlusLighter: |
270 |
default: |
271 |
[self DPSrectfill: NSMinX(aRect) : NSMinY(aRect) |
272 |
: NSWidth(aRect) : NSHeight(aRect)]; |
273 |
break; |
274 |
} |
275 |
} |
276 |
|
277 |
|
278 |
static |
279 |
HBITMAP GSCreateBitmap(HDC hDC, int pixelsWide, int pixelsHigh, |
280 |
int bitsPerSample, int samplesPerPixel, |
281 |
int bitsPerPixel, int bytesPerRow, |
282 |
BOOL isPlanar, BOOL hasAlpha, |
283 |
NSString *colorSpaceName, |
284 |
const unsigned char *const data[5]) |
285 |
{ |
286 |
HBITMAP hbitmap; |
287 |
BITMAPINFO *bitmap; |
288 |
BITMAPINFOHEADER *bmih; |
289 |
int xres, yres; |
290 |
UINT fuColorUse; |
291 |
|
292 |
if (isPlanar || ![colorSpaceName isEqualToString: NSDeviceRGBColorSpace]) |
293 |
{ |
294 |
NSLog(@"Bitmap type currently not supported %d %@", isPlanar, colorSpaceName); |
295 |
return NULL; |
296 |
} |
297 |
|
298 |
// default is 8 bit grayscale |
299 |
if (!bitsPerSample) |
300 |
bitsPerSample = 8; |
301 |
if (!samplesPerPixel) |
302 |
samplesPerPixel = 1; |
303 |
|
304 |
// FIXME - does this work if we are passed a planar image but no hints ? |
305 |
if (!bitsPerPixel) |
306 |
bitsPerPixel = bitsPerSample * samplesPerPixel; |
307 |
if (!bytesPerRow) |
308 |
bytesPerRow = (bitsPerPixel * pixelsWide) / 8; |
309 |
|
310 |
// make sure its sane - also handles row padding if hint missing |
311 |
while((bytesPerRow * 8) < (bitsPerPixel * pixelsWide)) |
312 |
bytesPerRow++; |
313 |
|
314 |
if (!(GetDeviceCaps(hDC, RASTERCAPS) & RC_DI_BITMAP)) |
315 |
{ |
316 |
return NULL; |
317 |
} |
318 |
|
319 |
hbitmap = CreateCompatibleBitmap(hDC, pixelsWide, pixelsHigh); |
320 |
if (!hbitmap) |
321 |
{ |
322 |
return NULL; |
323 |
} |
324 |
|
325 |
if (bitsPerPixel > 8) |
326 |
{ |
327 |
bitmap = objc_malloc(sizeof(BITMAPV4HEADER)); |
328 |
} |
329 |
else |
330 |
{ |
331 |
bitmap = objc_malloc(sizeof(BITMAPINFOHEADER) + |
332 |
(1 << bitsPerPixel) * sizeof(RGBQUAD)); |
333 |
} |
334 |
bmih = (BITMAPINFOHEADER*)bitmap; |
335 |
|
336 |
bmih->biSize = sizeof(BITMAPINFOHEADER); |
337 |
bmih->biWidth = pixelsWide; |
338 |
bmih->biHeight = -pixelsHigh; |
339 |
bmih->biPlanes = 1; |
340 |
bmih->biBitCount = bitsPerPixel; |
341 |
bmih->biCompression = BI_RGB; |
342 |
bmih->biSizeImage = 0; |
343 |
xres = GetDeviceCaps(hDC, HORZRES) / GetDeviceCaps(hDC, HORZSIZE); |
344 |
yres = GetDeviceCaps(hDC, VERTRES) / GetDeviceCaps(hDC, VERTSIZE); |
345 |
bmih->biXPelsPerMeter = xres; |
346 |
bmih->biYPelsPerMeter = yres; |
347 |
bmih->biClrUsed = 0; |
348 |
bmih->biClrImportant = 0; |
349 |
fuColorUse = 0; |
350 |
|
351 |
if (bitsPerPixel <= 8) |
352 |
{ |
353 |
// FIXME How to get a colour palette? |
354 |
NSLog(@"Need to define colour map for images with %d bits", bitsPerPixel); |
355 |
//bitmap->bmiColors; |
356 |
fuColorUse = DIB_RGB_COLORS; |
357 |
} |
358 |
else if (bitsPerPixel == 32) |
359 |
{ |
360 |
BITMAPV4HEADER *bmih; |
361 |
|
362 |
bmih = (BITMAPV4HEADER*)bitmap; |
363 |
bmih->bV4Size = sizeof(BITMAPV4HEADER); |
364 |
bmih->bV4V4Compression = BI_BITFIELDS; |
365 |
bmih->bV4RedMask = 0x000000FF; |
366 |
bmih->bV4GreenMask = 0x0000FF00; |
367 |
bmih->bV4BlueMask = 0x00FF0000; |
368 |
bmih->bV4AlphaMask = 0xFF000000; |
369 |
} |
370 |
else if (bitsPerPixel == 16) |
371 |
{ |
372 |
/* |
373 |
BITMAPV4HEADER *bmih; |
374 |
|
375 |
bmih = (BITMAPV4HEADER*)bitmap; |
376 |
bmih->bV4Size = sizeof(BITMAPV4HEADER); |
377 |
bmih->bV4V4Compression = BI_BITFIELDS; |
378 |
bmih->bV4RedMask = 0xF000; |
379 |
bmih->bV4GreenMask = 0x0F00; |
380 |
bmih->bV4BlueMask = 0x00F0; |
381 |
bmih->bV4AlphaMask = 0x000F; |
382 |
*/ |
383 |
NSLog(@"Unsure how to handle images with %d bits", bitsPerPixel); |
384 |
} |
385 |
|
386 |
if (!SetDIBits(hDC, hbitmap, 0, pixelsHigh, data[0], |
387 |
bitmap, fuColorUse)) |
388 |
{ |
389 |
objc_free(bitmap); |
390 |
DeleteObject(hbitmap); |
391 |
return NULL; |
392 |
} |
393 |
|
394 |
objc_free(bitmap); |
395 |
return hbitmap; |
396 |
} |
397 |
|
398 |
- (void)DPSimage: (NSAffineTransform*) matrix |
399 |
: (int) pixelsWide : (int) pixelsHigh |
400 |
: (int) bitsPerSample : (int) samplesPerPixel |
401 |
: (int) bitsPerPixel : (int) bytesPerRow : (BOOL) isPlanar |
402 |
: (BOOL) hasAlpha : (NSString *) colorSpaceName |
403 |
: (const unsigned char *const [5]) data |
404 |
{ |
405 |
NSAffineTransform *old_ctm = nil; |
406 |
HDC hDC; |
407 |
HBITMAP hbitmap; |
408 |
HGDIOBJ old; |
409 |
HDC hDC2; |
410 |
POINT p; |
411 |
int h; |
412 |
int y1; |
413 |
|
414 |
if (window == NULL) |
415 |
{ |
416 |
NSLog(@"No window in DPSImage"); |
417 |
return; |
418 |
} |
419 |
|
420 |
hDC = GetDC((HWND)window); |
421 |
if (!hDC) |
422 |
{ |
423 |
NSLog(@"No DC for window %d in DPSImage. Error %d", |
424 |
(int)window, GetLastError()); |
425 |
} |
426 |
|
427 |
hbitmap = GSCreateBitmap(hDC, pixelsWide, pixelsHigh, |
428 |
bitsPerSample, samplesPerPixel, |
429 |
bitsPerPixel, bytesPerRow, |
430 |
isPlanar, hasAlpha, |
431 |
colorSpaceName, data); |
432 |
if (!hbitmap) |
433 |
{ |
434 |
NSLog(@"Created bitmap failed %d", GetLastError()); |
435 |
} |
436 |
|
437 |
hDC2 = CreateCompatibleDC(hDC); |
438 |
if (!hDC2) |
439 |
{ |
440 |
NSLog(@"No Compatible DC for window %d in DPSImage. Error %d", |
441 |
(int)window, GetLastError()); |
442 |
} |
443 |
old = SelectObject(hDC2, hbitmap); |
444 |
if (!old) |
445 |
{ |
446 |
NSLog(@"SelectObject failed for window %d in DPSImage. Error %d", |
447 |
(int)window, GetLastError()); |
448 |
} |
449 |
|
450 |
//SetMapMode(hDC2, GetMapMode(hDC)); |
451 |
ReleaseDC((HWND)window, hDC); |
452 |
|
453 |
hDC = [self getHDC]; |
454 |
|
455 |
h = pixelsHigh; |
456 |
// Apply the additional transformation |
457 |
if (matrix) |
458 |
{ |
459 |
old_ctm = [ctm copy]; |
460 |
[ctm appendTransform: matrix]; |
461 |
} |
462 |
p = GSViewPointToWin(self, NSMakePoint(0, 0)); |
463 |
if (old_ctm != nil) |
464 |
{ |
465 |
RELEASE(ctm); |
466 |
// old_ctm is already retained |
467 |
ctm = old_ctm; |
468 |
} |
469 |
if (viewIsFlipped) |
470 |
y1 = p.y; |
471 |
else |
472 |
y1 = p.y - h; |
473 |
|
474 |
if (!BitBlt(hDC, p.x, y1, pixelsWide, pixelsHigh, |
475 |
hDC2, 0, 0, SRCCOPY)) |
476 |
{ |
477 |
NSLog(@"Copy bitmap failed %d", GetLastError()); |
478 |
NSLog(@"DPSimage with %d %d %d %d to %d, %d", pixelsWide, pixelsHigh, |
479 |
bytesPerRow, bitsPerPixel, p.x, y1); |
480 |
} |
481 |
|
482 |
[self releaseHDC: hDC]; |
483 |
|
484 |
SelectObject(hDC2, old); |
485 |
DeleteDC(hDC2); |
486 |
DeleteObject(hbitmap); |
487 |
} |
488 |
|
489 |
@end |
490 |
|
491 |
@implementation WIN32GState (PathOps) |
492 |
|
493 |
- (void) _paintPath: (ctxt_object_t) drawType |
494 |
{ |
495 |
unsigned count; |
496 |
HDC hDC; |
497 |
|
498 |
hDC = [self getHDC]; |
499 |
if (!hDC) |
500 |
{ |
501 |
return; |
502 |
} |
503 |
|
504 |
count = [path elementCount]; |
505 |
if (count) |
506 |
{ |
507 |
NSBezierPathElement type; |
508 |
NSPoint points[3]; |
509 |
unsigned j, i = 0; |
510 |
POINT p; |
511 |
|
512 |
BeginPath(hDC); |
513 |
|
514 |
for(j = 0; j < count; j++) |
515 |
{ |
516 |
type = [path elementAtIndex: j associatedPoints: points]; |
517 |
switch(type) |
518 |
{ |
519 |
case NSMoveToBezierPathElement: |
520 |
p = GSWindowPointToMS(self, points[0]); |
521 |
MoveToEx(hDC, p.x, p.y, NULL); |
522 |
break; |
523 |
case NSLineToBezierPathElement: |
524 |
p = GSWindowPointToMS(self, points[0]); |
525 |
// FIXME This gives one pixel to few |
526 |
LineTo(hDC, p.x, p.y); |
527 |
break; |
528 |
case NSCurveToBezierPathElement: |
529 |
{ |
530 |
POINT bp[3]; |
531 |
|
532 |
for (i = 1; i < 3; i++) |
533 |
{ |
534 |
bp[i] = GSWindowPointToMS(self, points[i]); |
535 |
} |
536 |
PolyBezierTo(hDC, bp, 3); |
537 |
} |
538 |
break; |
539 |
case NSClosePathBezierPathElement: |
540 |
CloseFigure(hDC); |
541 |
break; |
542 |
default: |
543 |
break; |
544 |
} |
545 |
} |
546 |
EndPath(hDC); |
547 |
|
548 |
// Now operate on the path |
549 |
switch (drawType) |
550 |
{ |
551 |
case path_stroke: |
552 |
StrokePath(hDC); |
553 |
break; |
554 |
case path_eofill: |
555 |
SetPolyFillMode(hDC, ALTERNATE); |
556 |
FillPath(hDC); |
557 |
break; |
558 |
case path_fill: |
559 |
SetPolyFillMode(hDC, WINDING); |
560 |
FillPath(hDC); |
561 |
break; |
562 |
case path_eoclip: |
563 |
{ |
564 |
HRGN region; |
565 |
|
566 |
SetPolyFillMode(hDC, ALTERNATE); |
567 |
region = PathToRegion(hDC); |
568 |
if (clipRegion) |
569 |
{ |
570 |
CombineRgn(clipRegion, clipRegion, region, RGN_AND); |
571 |
DeleteObject(region); |
572 |
} |
573 |
else |
574 |
{ |
575 |
clipRegion = region; |
576 |
} |
577 |
break; |
578 |
} |
579 |
case path_clip: |
580 |
{ |
581 |
HRGN region; |
582 |
|
583 |
SetPolyFillMode(hDC, WINDING); |
584 |
region = PathToRegion(hDC); |
585 |
if (clipRegion) |
586 |
{ |
587 |
CombineRgn(clipRegion, clipRegion, region, RGN_AND); |
588 |
DeleteObject(region); |
589 |
} |
590 |
else |
591 |
{ |
592 |
clipRegion = region; |
593 |
} |
594 |
break; |
595 |
} |
596 |
default: |
597 |
break; |
598 |
} |
599 |
} |
600 |
[self releaseHDC: hDC]; |
601 |
|
602 |
/* |
603 |
* clip does not delete the current path, so we only clear the path if the |
604 |
* operation was not a clipping operation. |
605 |
*/ |
606 |
if ((drawType != path_clip) && (drawType != path_eoclip)) |
607 |
{ |
608 |
[path removeAllPoints]; |
609 |
} |
610 |
} |
611 |
|
612 |
- (void)DPSclip |
613 |
{ |
614 |
[self _paintPath: path_clip]; |
615 |
} |
616 |
|
617 |
- (void)DPSeoclip |
618 |
{ |
619 |
[self _paintPath: path_eoclip]; |
620 |
} |
621 |
|
622 |
- (void)DPSeofill |
623 |
{ |
624 |
[self _paintPath: path_eofill]; |
625 |
} |
626 |
|
627 |
- (void)DPSfill |
628 |
{ |
629 |
[self _paintPath: path_fill]; |
630 |
} |
631 |
|
632 |
- (void)DPSstroke |
633 |
{ |
634 |
[self _paintPath: path_stroke]; |
635 |
} |
636 |
|
637 |
|
638 |
- (void) DPSinitclip; |
639 |
{ |
640 |
if (clipRegion) |
641 |
{ |
642 |
DeleteObject(clipRegion); |
643 |
clipRegion = NULL; |
644 |
} |
645 |
} |
646 |
|
647 |
- (void)DPSrectfill: (float)x : (float)y : (float)w : (float)h |
648 |
{ |
649 |
HDC hDC; |
650 |
HBRUSH brush; |
651 |
RECT rect; |
652 |
|
653 |
hDC = [self getHDC]; |
654 |
if (!hDC) |
655 |
{ |
656 |
return; |
657 |
} |
658 |
|
659 |
brush = GetCurrentObject(hDC, OBJ_BRUSH); |
660 |
rect = GSViewRectToWin(self, NSMakeRect(x, y, w, h)); |
661 |
FillRect(hDC, &rect, brush); |
662 |
[self releaseHDC: hDC]; |
663 |
} |
664 |
|
665 |
- (void)DPSrectstroke: (float)x : (float)y : (float)w : (float)h |
666 |
{ |
667 |
NSRect rect = [ctm rectInMatrixSpace: NSMakeRect(x, y, w, h)]; |
668 |
NSBezierPath *oldPath = path; |
669 |
|
670 |
// Samll adjustment so that the line is visible |
671 |
if (rect.size.width > 0) |
672 |
rect.size.width--; |
673 |
if (rect.size.height > 0) |
674 |
rect.size.height--; |
675 |
rect.origin.y += 1; |
676 |
|
677 |
path = [NSBezierPath bezierPathWithRect: rect]; |
678 |
[self DPSstroke]; |
679 |
path = oldPath; |
680 |
} |
681 |
|
682 |
- (void)DPSrectclip: (float)x : (float)y : (float)w : (float)h |
683 |
{ |
684 |
RECT rect; |
685 |
HRGN region; |
686 |
|
687 |
rect = GSViewRectToWin(self, NSMakeRect(x, y, w, h)); |
688 |
region = CreateRectRgnIndirect(&rect); |
689 |
if (clipRegion) |
690 |
{ |
691 |
CombineRgn(clipRegion, clipRegion, region, RGN_AND); |
692 |
DeleteObject(region); |
693 |
} |
694 |
else |
695 |
{ |
696 |
clipRegion = region; |
697 |
} |
698 |
} |
699 |
|
700 |
- (void)DPSshow: (const char *)s |
701 |
{ |
702 |
NSPoint current = [path currentPoint]; |
703 |
POINT p; |
704 |
HDC hDC; |
705 |
|
706 |
hDC = [self getHDC]; |
707 |
if (!hDC) |
708 |
{ |
709 |
return; |
710 |
} |
711 |
|
712 |
p = GSWindowPointToMS(self, current); |
713 |
[(WIN32FontInfo*)font draw: s lenght: strlen(s) |
714 |
onDC: hDC at: p]; |
715 |
[self releaseHDC: hDC]; |
716 |
} |
717 |
|
718 |
- (void) GSShowGlyphs: (const NSGlyph *)glyphs : (size_t)length |
719 |
{ |
720 |
NSPoint current = [path currentPoint]; |
721 |
POINT p; |
722 |
HDC hDC; |
723 |
|
724 |
hDC = [self getHDC]; |
725 |
if (!hDC) |
726 |
{ |
727 |
return; |
728 |
} |
729 |
|
730 |
p = GSWindowPointToMS(self, current); |
731 |
[(WIN32FontInfo*)font drawGlyphs: glyphs |
732 |
length: length |
733 |
onDC: hDC |
734 |
at: p]; |
735 |
[self releaseHDC: hDC]; |
736 |
} |
737 |
@end |
738 |
|
739 |
@implementation WIN32GState (GStateOps) |
740 |
|
741 |
- (void)DPSinitgraphics |
742 |
{ |
743 |
[super DPSinitgraphics]; |
744 |
} |
745 |
|
746 |
- (void) DPSsetdash: (const float*)pattern : (int)count : (float)phase |
747 |
{ |
748 |
if (!path) |
749 |
{ |
750 |
path = [NSBezierPath new]; |
751 |
} |
752 |
|
753 |
[path setLineDash: pattern count: count phase: phase]; |
754 |
} |
755 |
|
756 |
- (void)DPScurrentmiterlimit: (float *)limit |
757 |
{ |
758 |
*limit = miterlimit; |
759 |
} |
760 |
|
761 |
- (void)DPSsetmiterlimit: (float)limit |
762 |
{ |
763 |
miterlimit = limit; |
764 |
} |
765 |
|
766 |
- (void)DPScurrentlinecap: (int *)linecap |
767 |
{ |
768 |
*linecap = lineCap; |
769 |
} |
770 |
|
771 |
- (void)DPSsetlinecap: (int)linecap |
772 |
{ |
773 |
lineCap = linecap; |
774 |
} |
775 |
|
776 |
- (void)DPScurrentlinejoin: (int *)linejoin |
777 |
{ |
778 |
*linejoin = joinStyle; |
779 |
} |
780 |
|
781 |
- (void)DPSsetlinejoin: (int)linejoin |
782 |
{ |
783 |
joinStyle = linejoin; |
784 |
} |
785 |
|
786 |
- (void)DPScurrentlinewidth: (float *)width |
787 |
{ |
788 |
*width = lineWidth; |
789 |
} |
790 |
|
791 |
- (void)DPSsetlinewidth: (float)width |
792 |
{ |
793 |
lineWidth = width; |
794 |
} |
795 |
|
796 |
- (void)DPScurrentstrokeadjust: (int *)b |
797 |
{ |
798 |
} |
799 |
|
800 |
- (void)DPSsetstrokeadjust: (int)b |
801 |
{ |
802 |
} |
803 |
|
804 |
@end |
805 |
|
806 |
@implementation WIN32GState (WinOps) |
807 |
|
808 |
- (void) setStyle: (HDC)hDC |
809 |
{ |
810 |
HPEN pen; |
811 |
HBRUSH brush; |
812 |
LOGBRUSH br; |
813 |
int join; |
814 |
int cap; |
815 |
DWORD penStyle; |
816 |
SetBkMode(hDC, TRANSPARENT); |
817 |
/* |
818 |
br.lbStyle = BS_SOLID; |
819 |
br.lbColor = color; |
820 |
brush = CreateBrushIndirect(&br); |
821 |
*/ |
822 |
brush = CreateSolidBrush(wfcolor); |
823 |
oldBrush = SelectObject(hDC, brush); |
824 |
|
825 |
switch (joinStyle) |
826 |
{ |
827 |
case NSBevelLineJoinStyle: |
828 |
join = PS_JOIN_BEVEL; |
829 |
break; |
830 |
case NSMiterLineJoinStyle: |
831 |
join = PS_JOIN_MITER; |
832 |
break; |
833 |
case NSRoundLineJoinStyle: |
834 |
join = PS_JOIN_ROUND; |
835 |
break; |
836 |
default: |
837 |
join = PS_JOIN_MITER; |
838 |
break; |
839 |
} |
840 |
|
841 |
switch (lineCap) |
842 |
{ |
843 |
case NSButtLineCapStyle: |
844 |
cap = PS_ENDCAP_FLAT; |
845 |
break; |
846 |
case NSSquareLineCapStyle: |
847 |
cap = PS_ENDCAP_SQUARE; |
848 |
break; |
849 |
case NSRoundLineCapStyle: |
850 |
cap = PS_ENDCAP_ROUND; |
851 |
break; |
852 |
default: |
853 |
cap = PS_ENDCAP_SQUARE; |
854 |
break; |
855 |
} |
856 |
|
857 |
penStyle = PS_GEOMETRIC | PS_SOLID; |
858 |
if (path) |
859 |
{ |
860 |
float pattern[10]; |
861 |
int count = 10; |
862 |
float phase; |
863 |
|
864 |
[path getLineDash: pattern count: &count phase: &phase]; |
865 |
|
866 |
if (count && (count < 10)) |
867 |
{ |
868 |
penStyle = PS_GEOMETRIC | PS_DASH; |
869 |
} |
870 |
} |
871 |
|
872 |
pen = ExtCreatePen(penStyle | join | cap, |
873 |
lineWidth, |
874 |
&br, |
875 |
0, NULL); |
876 |
|
877 |
oldPen = SelectObject(hDC, pen); |
878 |
|
879 |
SetMiterLimit(hDC, miterlimit, NULL); |
880 |
|
881 |
SetTextColor(hDC, wfcolor); |
882 |
|
883 |
oldClipRegion = CreateRectRgn(0, 0, 1, 1); |
884 |
if (1 != GetClipRgn(hDC, oldClipRegion)) |
885 |
{ |
886 |
DeleteObject(oldClipRegion); |
887 |
oldClipRegion = NULL; |
888 |
} |
889 |
|
890 |
SelectClipRgn(hDC, clipRegion); |
891 |
} |
892 |
|
893 |
- (void) restoreStyle: (HDC)hDC |
894 |
{ |
895 |
HGDIOBJ old; |
896 |
|
897 |
SelectClipRgn(hDC, oldClipRegion); |
898 |
DeleteObject(oldClipRegion); |
899 |
oldClipRegion = NULL; |
900 |
|
901 |
old = SelectObject(hDC, oldBrush); |
902 |
DeleteObject(old); |
903 |
|
904 |
old = SelectObject(hDC, oldPen); |
905 |
DeleteObject(old); |
906 |
} |
907 |
|
908 |
- (HDC) getHDC |
909 |
{ |
910 |
WIN_INTERN *win; |
911 |
HDC hDC; |
912 |
|
913 |
if (NULL == window) |
914 |
{ |
915 |
//Log(@"No window in getHDC"); |
916 |
return NULL; |
917 |
} |
918 |
|
919 |
win = (WIN_INTERN *)GetWindowLong((HWND)window, GWL_USERDATA); |
920 |
if (win && win->useHDC) |
921 |
{ |
922 |
hDC = win->hdc; |
923 |
//NSLog(@"getHDC found DC %d", hDC); |
924 |
} |
925 |
else |
926 |
{ |
927 |
hDC = GetDC((HWND)window); |
928 |
//NSLog(@"getHDC using window DC %d", hDC); |
929 |
} |
930 |
|
931 |
if (!hDC) |
932 |
{ |
933 |
//Log(@"No DC in getHDC"); |
934 |
return NULL; |
935 |
} |
936 |
|
937 |
[self setStyle: hDC]; |
938 |
return hDC; |
939 |
} |
940 |
|
941 |
- (void) releaseHDC: (HDC)hDC |
942 |
{ |
943 |
WIN_INTERN *win; |
944 |
|
945 |
if (NULL == window || |
946 |
NULL == hDC) |
947 |
{ |
948 |
return; |
949 |
} |
950 |
|
951 |
[self restoreStyle: hDC]; |
952 |
win = (WIN_INTERN *)GetWindowLong((HWND)window, GWL_USERDATA); |
953 |
if (win && !win->useHDC) |
954 |
ReleaseDC((HWND)window, hDC); |
955 |
} |
956 |
|
957 |
@end |