1 /* Cockos SWELL (Simple/Small Win32 Emulation Layer for Linux/OSX)
2 Copyright (C) 2006 and later, Cockos, Inc.
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
21 This file provides basic win32 GDI-->Quartz translation. It uses features that require OS X 10.4+
25 #ifndef SWELL_PROVIDED_BY_APP
27 #import <Carbon/Carbon.h>
28 #import <Cocoa/Cocoa.h>
29 #import <CoreFoundation/CFDictionary.h>
30 #import <objc/objc-runtime.h>
32 #include "swell-internal.h"
35 #include "../assocarray.h"
36 #include "../wdlcstring.h"
39 #include <xmmintrin.h>
42 #ifdef SWELL_SUPPORT_OPENGL_BLIT
43 #include <OpenGL/gl.h>
46 // reimplement here so that swell-gdi isn't dependent on swell-misc, and vice-versa
47 static int SWELL_GDI_GetOSXVersion()
52 if (NSAppKitVersionNumber >= 1266.0)
54 v=0x10a0; // 10.10+ Gestalt(gsv) return 0x109x, so we bump this to 0x10a0
59 Gestalt(gestaltSystemVersion,&a);
67 #include <immintrin.h>
70 #ifndef MAC_OS_X_VERSION_10_6
71 // 10.5 SDK doesn't include CGContextSetAllowsFontSmoothing() in header (but apparently does in libs)
72 CG_EXTERN void CGContextSetAllowsFontSmoothing(CGContextRef c, bool) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER;
75 #ifndef SWELL_NO_CORETEXT
76 static bool IsCoreTextSupported()
78 #ifdef SWELL_ATSUI_TEXT_SUPPORT
79 return SWELL_GDI_GetOSXVersion() >= 0x1050 && CTFontCreateWithName && CTLineDraw && CTFramesetterCreateWithAttributedString && CTFramesetterCreateFrame &&
80 CTFrameGetLines && CTLineGetTypographicBounds && CTLineCreateWithAttributedString && CTFontCopyPostScriptName
83 // no ATSUI, targetting 10.5+, CT is always valid
88 static CTFontRef GetCoreTextDefaultFont()
90 static CTFontRef deffr;
95 if (IsCoreTextSupported())
97 deffr=(CTFontRef) [[NSFont labelFontOfSize:10.0] retain];
102 #endif // !SWELL_NO_CORETEXT
105 static NSString *CStringToNSString(const char *str)
110 ret=(NSString *)CFStringCreateWithCString(NULL,str,kCFStringEncodingUTF8);
112 ret=(NSString *)CFStringCreateWithCString(NULL,str,kCFStringEncodingASCII);
115 CGColorSpaceRef __GetBitmapColorSpace()
117 static CGColorSpaceRef cs;
118 if (!cs) cs = CGColorSpaceCreateDeviceRGB();
122 CGColorSpaceRef __GetDisplayColorSpace()
124 static CGColorSpaceRef cs;
127 // use monitor profile for 10.7+
128 if (SWELL_GDI_GetOSXVersion() >= 0x1070)
131 #ifdef MAC_OS_X_VERSION_10_11
132 // OSX 10.11 SDK removes CMGetSystemProfile
133 // this may be preferable on older SDKs as well, need to test (though CGDisplayCopyColorSpace is only available on 10.5+)
134 cs = CGDisplayCopyColorSpace(CGMainDisplayID());
136 CMProfileRef systemMonitorProfile = NULL;
137 CMError getProfileErr = CMGetSystemProfile(&systemMonitorProfile);
138 if(noErr == getProfileErr)
140 cs = CGColorSpaceCreateWithPlatformColorSpace(systemMonitorProfile);
141 CMCloseProfile(systemMonitorProfile);
147 cs = CGColorSpaceCreateDeviceRGB();
151 static CGColorRef CreateColor(int col, float alpha=1.0f)
153 CGFloat cols[4]={GetRValue(col)/255.0f,GetGValue(col)/255.0f,GetBValue(col)/255.0f,alpha};
154 CGColorRef color=CGColorCreate(__GetBitmapColorSpace(),cols);
159 #include "swell-gdi-internalpool.h"
161 int SWELL_IsRetinaHWND(HWND hwnd)
163 if (!hwnd || SWELL_GDI_GetOSXVersion() < 0x1070) return 0;
166 if ([(id)hwnd isKindOfClass:[NSView class]]) w = [(NSView *)hwnd window];
167 else if ([(id)hwnd isKindOfClass:[NSWindow class]]) w = (NSWindow *)hwnd;
171 NSRect r=NSMakeRect(0,0,1,1);
172 NSRect (*tmp)(id receiver, SEL operation, NSRect) = (NSRect (*)(id, SEL, NSRect))objc_msgSend_stret;
173 NSRect str = tmp(w,sel_getUid("convertRectToBacking:"),r);
175 if (str.size.width > 1.9) return 1;
180 int SWELL_IsRetinaDC(HDC hdc)
182 HDC__ *src=(HDC__*)hdc;
183 if (!src || !HDC_VALID(src) || !src->ctx) return 0;
184 return CGContextConvertSizeToDeviceSpace((CGContextRef)src->ctx, CGSizeMake(1,1)).width > 1.9 ? 1 : 0;
188 HDC SWELL_CreateGfxContext(void *c)
190 HDC__ *ctx=SWELL_GDP_CTX_NEW();
191 NSGraphicsContext *nsc = (NSGraphicsContext *)c;
192 // if (![nsc isFlipped])
193 // nsc = [NSGraphicsContext graphicsContextWithGraphicsPort:[nsc graphicsPort] flipped:YES];
195 ctx->ctx=(CGContextRef)[nsc graphicsPort];
196 // CGAffineTransform f={1,0,0,-1,0,0};
197 //CGContextSetTextMatrix(ctx->ctx,f);
198 //SetTextColor(ctx,0);
200 // CGContextSelectFont(ctx->ctx,"Arial",12.0,kCGEncodingMacRoman);
204 #define ALIGN_EXTRA 63
205 static void *ALIGN_FBUF(void *inbuf)
207 const UINT_PTR extra = ALIGN_EXTRA;
208 return (void *) (((UINT_PTR)inbuf+extra)&~extra);
211 HDC SWELL_CreateMemContext(HDC hdc, int w, int h)
213 void *buf=calloc(w*4*h+ALIGN_EXTRA,1);
215 CGContextRef c=CGBitmapContextCreate(ALIGN_FBUF(buf),w,h,8,w*4, __GetBitmapColorSpace(), kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host);
223 CGContextTranslateCTM(c,0.0,h);
224 CGContextScaleCTM(c,1.0,-1.0);
225 CGContextSetAllowsFontSmoothing(c,0); // we may wish to enable this for some contexts eventually, but this is to match previous behavior
227 HDC__ *ctx=SWELL_GDP_CTX_NEW();
228 ctx->ctx=(CGContextRef)c;
230 // CGContextSelectFont(ctx->ctx,"Arial",12.0,kCGEncodingMacRoman);
236 void SWELL_DeleteGfxContext(HDC ctx)
238 HDC__ *ct=(HDC__ *)ctx;
243 CGContextRelease(ct->ctx);
246 if (ct->curtextcol) CFRelease(ct->curtextcol);
247 SWELL_GDP_CTX_DELETE(ct);
250 HPEN CreatePen(int attr, int wid, int col)
252 return CreatePenAlpha(attr,wid,col,1.0f);
255 HBRUSH CreateSolidBrush(int col)
257 return CreateSolidBrushAlpha(col,1.0f);
262 HPEN CreatePenAlpha(int attr, int wid, int col, float alpha)
264 HGDIOBJ__ *pen=GDP_OBJECT_NEW();
266 pen->wid=wid<0?0:wid;
267 pen->color=CreateColor(col,alpha);
270 HBRUSH CreateSolidBrushAlpha(int col, float alpha)
272 HGDIOBJ__ *brush=GDP_OBJECT_NEW();
273 brush->type=TYPE_BRUSH;
274 brush->color=CreateColor(col,alpha);
280 HFONT CreateFontIndirect(LOGFONT *lf)
282 return CreateFont(lf->lfHeight, lf->lfWidth,lf->lfEscapement, lf->lfOrientation, lf->lfWeight, lf->lfItalic,
283 lf->lfUnderline, lf->lfStrikeOut, lf->lfCharSet, lf->lfOutPrecision,lf->lfClipPrecision,
284 lf->lfQuality, lf->lfPitchAndFamily, lf->lfFaceName);
287 static HGDIOBJ__ global_objs[2];
289 void DeleteObject(HGDIOBJ pen)
291 HGDIOBJ__ *p=(HGDIOBJ__ *)pen;
292 if (p >= global_objs && p < global_objs + sizeof(global_objs)/sizeof(global_objs[0])) return;
294 if (HGDIOBJ_VALID(p))
296 if (--p->additional_refcnt < 0)
298 if (p->type == TYPE_PEN || p->type == TYPE_BRUSH || p->type == TYPE_FONT || p->type == TYPE_BITMAP)
300 if (p->type == TYPE_PEN || p->type == TYPE_BRUSH)
301 if (p->wid<0) return;
302 if (p->color) CGColorRelease(p->color);
304 if (p->ct_FontRef) CFRelease(p->ct_FontRef);
306 #ifdef SWELL_ATSUI_TEXT_SUPPORT
307 if (p->atsui_font_style) ATSUDisposeStyle(p->atsui_font_style);
310 if (p->wid && p->bitmapptr) [p->bitmapptr release];
311 GDP_OBJECT_DELETE(p);
313 // JF> don't free unknown objects, this shouldn't ever happen anyway: else free(p);
319 HGDIOBJ SelectObject(HDC ctx, HGDIOBJ pen)
321 HDC__ *c=(HDC__ *)ctx;
322 HGDIOBJ__ *p=(HGDIOBJ__*) pen;
324 if (!HDC_VALID(c)) return 0;
326 if (p == (HGDIOBJ__*)TYPE_PEN) mod=&c->curpen;
327 else if (p == (HGDIOBJ__*)TYPE_BRUSH) mod=&c->curbrush;
328 else if (p == (HGDIOBJ__*)TYPE_FONT) mod=&c->curfont;
330 if (mod) // clearing a particular thing
334 return HGDIOBJ_VALID(np,(int)(INT_PTR)p)?np:p;
337 if (!HGDIOBJ_VALID(p)) return 0;
339 if (p->type == TYPE_PEN) mod=&c->curpen;
340 else if (p->type == TYPE_BRUSH) mod=&c->curbrush;
341 else if (p->type == TYPE_FONT) mod=&c->curfont;
346 if (!HGDIOBJ_VALID(op,p->type)) op=(HGDIOBJ__*)(INT_PTR)p->type;
353 void SWELL_FillRect(HDC ctx, const RECT *r, HBRUSH br)
355 HDC__ *c=(HDC__ *)ctx;
356 HGDIOBJ__ *b=(HGDIOBJ__*) br;
357 if (!HDC_VALID(c) || !HGDIOBJ_VALID(b,TYPE_BRUSH) || b == (HGDIOBJ__*)TYPE_BRUSH || b->type != TYPE_BRUSH) return;
359 if (b->wid<0) return;
361 CGRect rect=CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top);
362 CGContextSetFillColorWithColor(c->ctx,b->color);
363 CGContextFillRect(c->ctx,rect);
367 void RoundRect(HDC ctx, int x, int y, int x2, int y2, int xrnd, int yrnd)
371 POINT pts[10]={ // todo: curves between edges
384 WDL_GDP_Polygon(ctx,pts,sizeof(pts)/sizeof(pts[0]));
387 void Ellipse(HDC ctx, int l, int t, int r, int b)
389 HDC__ *c=(HDC__ *)ctx;
390 if (!HDC_VALID(c)) return;
392 CGRect rect=CGRectMake(l,t,r-l,b-t);
394 if (HGDIOBJ_VALID(c->curbrush,TYPE_BRUSH) && c->curbrush->wid >=0)
396 CGContextSetFillColorWithColor(c->ctx,c->curbrush->color);
397 CGContextFillEllipseInRect(c->ctx,rect);
399 if (HGDIOBJ_VALID(c->curpen,TYPE_PEN) && c->curpen->wid >= 0)
401 CGContextSetStrokeColorWithColor(c->ctx,c->curpen->color);
402 CGContextStrokeEllipseInRect(c->ctx, rect); //, (float)wdl_max(1,c->curpen->wid));
406 void Rectangle(HDC ctx, int l, int t, int r, int b)
408 HDC__ *c=(HDC__ *)ctx;
409 if (!HDC_VALID(c)) return;
411 CGRect rect=CGRectMake(l,t,r-l,b-t);
413 if (HGDIOBJ_VALID(c->curbrush,TYPE_BRUSH) && c->curbrush->wid >= 0)
415 CGContextSetFillColorWithColor(c->ctx,c->curbrush->color);
416 CGContextFillRect(c->ctx,rect);
418 if (HGDIOBJ_VALID(c->curpen,TYPE_PEN) && c->curpen->wid >= 0)
420 CGContextSetStrokeColorWithColor(c->ctx,c->curpen->color);
421 CGContextStrokeRectWithWidth(c->ctx, rect, (float)wdl_max(1,c->curpen->wid));
426 HGDIOBJ GetStockObject(int wh)
432 HGDIOBJ__ *p = &global_objs[0];
439 HGDIOBJ__ *p = &global_objs[1];
448 void Polygon(HDC ctx, POINT *pts, int npts)
450 HDC__ *c=(HDC__ *)ctx;
451 if (!HDC_VALID(c)) return;
452 if (((!HGDIOBJ_VALID(c->curbrush,TYPE_BRUSH)||c->curbrush->wid<0) && (!HGDIOBJ_VALID(c->curpen,TYPE_PEN)||c->curpen->wid<0)) || npts<2) return;
454 CGContextBeginPath(c->ctx);
455 CGContextMoveToPoint(c->ctx,(float)pts[0].x,(float)pts[0].y);
457 for (x = 1; x < npts; x ++)
459 CGContextAddLineToPoint(c->ctx,(float)pts[x].x,(float)pts[x].y);
461 if (HGDIOBJ_VALID(c->curbrush,TYPE_BRUSH) && c->curbrush->wid >= 0)
463 CGContextSetFillColorWithColor(c->ctx,c->curbrush->color);
465 if (HGDIOBJ_VALID(c->curpen,TYPE_PEN) && c->curpen->wid>=0)
467 CGContextSetLineWidth(c->ctx,(float)wdl_max(c->curpen->wid,1));
468 CGContextSetStrokeColorWithColor(c->ctx,c->curpen->color);
470 CGContextDrawPath(c->ctx,HGDIOBJ_VALID(c->curpen,TYPE_PEN) && c->curpen->wid>=0 && HGDIOBJ_VALID(c->curbrush,TYPE_BRUSH) && c->curbrush->wid>=0 ? kCGPathFillStroke : HGDIOBJ_VALID(c->curpen,TYPE_PEN) && c->curpen->wid>=0 ? kCGPathStroke : kCGPathFill);
473 void MoveToEx(HDC ctx, int x, int y, POINT *op)
475 HDC__ *c=(HDC__ *)ctx;
476 if (!HDC_VALID(c)) return;
479 op->x = (int) (c->lastpos_x);
480 op->y = (int) (c->lastpos_y);
482 c->lastpos_x=(float)x;
483 c->lastpos_y=(float)y;
486 void PolyBezierTo(HDC ctx, POINT *pts, int np)
488 HDC__ *c=(HDC__ *)ctx;
489 if (!HDC_VALID(c)||!HGDIOBJ_VALID(c->curpen,TYPE_PEN)||c->curpen->wid<0||np<3) return;
491 CGContextSetLineWidth(c->ctx,(float)wdl_max(c->curpen->wid,1));
492 CGContextSetStrokeColorWithColor(c->ctx,c->curpen->color);
494 CGContextBeginPath(c->ctx);
495 CGContextMoveToPoint(c->ctx,c->lastpos_x,c->lastpos_y);
498 for (x = 0; x < np-2; x += 3)
500 CGContextAddCurveToPoint(c->ctx,
501 (float)pts[x].x,(float)pts[x].y,
502 (float)pts[x+1].x,(float)pts[x+1].y,
503 xp=(float)pts[x+2].x,yp=(float)pts[x+2].y);
505 c->lastpos_x=(float)xp;
506 c->lastpos_y=(float)yp;
507 CGContextStrokePath(c->ctx);
511 void SWELL_LineTo(HDC ctx, int x, int y)
513 HDC__ *c=(HDC__ *)ctx;
514 if (!HDC_VALID(c)||!HGDIOBJ_VALID(c->curpen,TYPE_PEN)||c->curpen->wid<0) return;
516 float w = (float)wdl_max(c->curpen->wid,1);
517 CGContextSetLineWidth(c->ctx,w);
518 CGContextSetStrokeColorWithColor(c->ctx,c->curpen->color);
520 CGContextBeginPath(c->ctx);
521 CGContextMoveToPoint(c->ctx,c->lastpos_x + w * 0.5,c->lastpos_y + w*0.5);
522 float fx=(float)x,fy=(float)y;
524 CGContextAddLineToPoint(c->ctx,fx+w*0.5,fy+w*0.5);
527 CGContextStrokePath(c->ctx);
530 void PolyPolyline(HDC ctx, POINT *pts, DWORD *cnts, int nseg)
532 HDC__ *c=(HDC__ *)ctx;
533 if (!HDC_VALID(c)||!HGDIOBJ_VALID(c->curpen,TYPE_PEN)||c->curpen->wid<0||nseg<1) return;
535 float w = (float)wdl_max(c->curpen->wid,1);
536 CGContextSetLineWidth(c->ctx,w);
537 CGContextSetStrokeColorWithColor(c->ctx,c->curpen->color);
539 CGContextBeginPath(c->ctx);
545 if (!--cnt) { pts++; continue; }
547 CGContextMoveToPoint(c->ctx,(float)pts->x+w*0.5,(float)pts->y+w*0.5);
552 CGContextAddLineToPoint(c->ctx,(float)pts->x+w*0.5,(float)pts->y+w*0.5);
556 CGContextStrokePath(c->ctx);
558 void *SWELL_GetCtxGC(HDC ctx)
560 HDC__ *ct=(HDC__ *)ctx;
561 if (!HDC_VALID(ct)) return 0;
566 void SWELL_SetPixel(HDC ctx, int x, int y, int c)
568 HDC__ *ct=(HDC__ *)ctx;
569 if (!HDC_VALID(ct)) return;
570 CGContextBeginPath(ct->ctx);
571 CGContextMoveToPoint(ct->ctx,(float)x-0.5,(float)y-0.5);
572 CGContextAddLineToPoint(ct->ctx,(float)x+0.5,(float)y+0.5);
573 CGContextSetLineWidth(ct->ctx,(float)1.0);
574 CGContextSetRGBStrokeColor(ct->ctx,GetRValue(c)/255.0,GetGValue(c)/255.0,GetBValue(c)/255.0,1.0);
575 CGContextStrokePath(ct->ctx);
579 static WDL_Mutex s_fontnamecache_mutex;
581 #ifdef SWELL_CLEANUP_ON_UNLOAD
582 static void releaseString(NSString *s) { [s release]; }
584 static WDL_StringKeyedArray<NSString *> s_fontnamecache(true,
585 #ifdef SWELL_CLEANUP_ON_UNLOAD
592 static NSString *SWELL_GetCachedFontName(const char *nm)
594 NSString *ret = NULL;
597 s_fontnamecache_mutex.Enter();
598 ret = s_fontnamecache.Get(nm);
599 s_fontnamecache_mutex.Leave();
602 ret = CStringToNSString(nm);
605 #ifndef SWELL_NO_CORETEXT
606 // only do postscript name lookups on 10.9+
607 if (floor(NSFoundationVersionNumber) > 945.00) // NSFoundationVersionNumber10_8
609 NSFont *font = [NSFont fontWithName:ret size:10];
610 NSString *nr = font ? (NSString *)CTFontCopyPostScriptName((CTFontRef)font) : NULL;
619 s_fontnamecache_mutex.Enter();
620 s_fontnamecache.Insert(nm,ret);
621 s_fontnamecache_mutex.Leave();
625 return ret ? ret : @"";
628 HFONT CreateFont(int lfHeight, int lfWidth, int lfEscapement, int lfOrientation, int lfWeight, char lfItalic,
629 char lfUnderline, char lfStrikeOut, char lfCharSet, char lfOutPrecision, char lfClipPrecision,
630 char lfQuality, char lfPitchAndFamily, const char *lfFaceName)
632 HGDIOBJ__ *font=GDP_OBJECT_NEW();
633 font->type=TYPE_FONT;
634 float fontwid=lfHeight;
636 if (!fontwid) fontwid=lfWidth;
637 if (fontwid<0)fontwid=-fontwid;
639 if (fontwid < 2 || fontwid > 8192) fontwid=10;
641 font->font_rotation = lfOrientation/10.0;
643 #ifndef SWELL_NO_CORETEXT
644 if (IsCoreTextSupported())
647 lstrcpyn_safe(buf,lfFaceName,900);
648 if (lfWeight >= FW_BOLD) strcat(buf," Bold");
649 if (lfItalic) strcat(buf," Italic");
651 font->ct_FontRef = (void*)CTFontCreateWithName((CFStringRef)SWELL_GetCachedFontName(buf),fontwid,NULL);
652 if (!font->ct_FontRef) font->ct_FontRef = (void*)[[NSFont labelFontOfSize:fontwid] retain];
654 font->font_quality = (!lfQuality || lfQuality == ANTIALIASED_QUALITY || lfQuality == NONANTIALIASED_QUALITY ? lfQuality : 0);
656 // might want to make this conditional (i.e. only return font if created successfully), but I think we'd rather fallback to a system font than use ATSUI
661 #ifdef SWELL_ATSUI_TEXT_SUPPORT
662 ATSUFontID fontid=kATSUInvalidFontID;
663 if (lfFaceName && lfFaceName[0])
665 ATSUFindFontFromName(lfFaceName,strlen(lfFaceName),kFontFullName /* kFontFamilyName? */ ,(FontPlatformCode)kFontNoPlatform,kFontNoScriptCode,kFontNoLanguageCode,&fontid);
666 // if (fontid==kATSUInvalidFontID) printf("looked up %s and got %d\n",lfFaceName,fontid);
669 if (ATSUCreateStyle(&font->atsui_font_style) == noErr && font->atsui_font_style)
671 Fixed fsize=Long2Fix(fontwid);
673 Boolean isBold=lfWeight >= FW_BOLD;
674 Boolean isItal=!!lfItalic;
675 Boolean isUnder=!!lfUnderline;
677 ATSStyleRenderingOptions render;
679 render = kATSStyleNoOptions;
680 else if (lfQuality == ANTIALIASED_QUALITY)
681 render = kATSStyleApplyAntiAliasing;
682 else if (lfQuality == NONANTIALIASED_QUALITY)
683 render = kATSStyleNoAntiAliasing;
685 render = kATSStyleNoOptions;
687 ATSUAttributeTag theTags[] = { kATSUQDBoldfaceTag, kATSUQDItalicTag, kATSUQDUnderlineTag,kATSUSizeTag,kATSUFontTag, kATSUStyleRenderingOptionsTag };
688 ByteCount theSizes[] = { sizeof(Boolean),sizeof(Boolean),sizeof(Boolean), sizeof(Fixed),sizeof(ATSUFontID), sizeof(ATSStyleRenderingOptions) };
689 ATSUAttributeValuePtr theValues[] = {&isBold, &isItal, &isUnder, &fsize, &fontid, &render } ;
691 int attrcnt=sizeof(theTags)/sizeof(theTags[0]);
692 if (fontid == kATSUInvalidFontID) attrcnt--;
694 if (ATSUSetAttributes (font->atsui_font_style,
700 ATSUDisposeStyle(font->atsui_font_style);
701 font->atsui_font_style=0;
705 font->atsui_font_style=0;
713 int GetTextFace(HDC ctx, int nCount, LPTSTR lpFaceName)
715 HDC__ *ct=(HDC__*)ctx;
716 if (!HDC_VALID(ct) || !nCount || !lpFaceName) return 0;
718 #ifndef SWELL_NO_CORETEXT
720 if (HGDIOBJ_VALID(ct->curfont,TYPE_FONT)) fr=(CTFontRef)ct->curfont->ct_FontRef;
721 if (!fr) fr=GetCoreTextDefaultFont();
725 CFStringRef name=CTFontCopyDisplayName(fr);
726 const char* p=[(NSString*)name UTF8String];
729 lstrcpyn_safe(lpFaceName, p, nCount);
730 return (int)strlen(lpFaceName);
738 BOOL GetTextMetrics(HDC ctx, TEXTMETRIC *tm)
740 HDC__ *ct=(HDC__ *)ctx;
741 if (tm) // give some sane defaults
743 tm->tmInternalLeading=3;
747 tm->tmAveCharWidth = 10;
749 if (!HDC_VALID(ct)||!tm) return 0;
751 bool curfont_valid=HGDIOBJ_VALID(ct->curfont,TYPE_FONT);
753 #ifdef SWELL_ATSUI_TEXT_SUPPORT
754 if (curfont_valid && ct->curfont->atsui_font_style)
756 ATSUTextMeasurement ascent=Long2Fix(10);
757 ATSUTextMeasurement descent=Long2Fix(3);
758 ATSUTextMeasurement sz=Long2Fix(0);
759 ATSUTextMeasurement width =Long2Fix(12);
760 ATSUGetAttribute(ct->curfont->atsui_font_style, kATSUAscentTag, sizeof(ATSUTextMeasurement), &ascent,NULL);
761 ATSUGetAttribute(ct->curfont->atsui_font_style, kATSUDescentTag, sizeof(ATSUTextMeasurement), &descent,NULL);
762 ATSUGetAttribute(ct->curfont->atsui_font_style, kATSUSizeTag, sizeof(ATSUTextMeasurement), &sz,NULL);
763 ATSUGetAttribute(ct->curfont->atsui_font_style, kATSULineWidthTag, sizeof(ATSUTextMeasurement),&width,NULL);
765 float asc=Fix2X(ascent);
766 float desc=Fix2X(descent);
767 float size = Fix2X(sz);
769 if (size < (asc+desc)*0.2) size=asc+desc;
771 tm->tmAscent = (int)ceil(asc);
772 tm->tmDescent = (int)ceil(desc);
773 tm->tmInternalLeading=(int)ceil(asc+desc-size);
774 if (tm->tmInternalLeading<0)tm->tmInternalLeading=0;
775 tm->tmHeight=(int) ceil(asc+desc);
776 tm->tmAveCharWidth = (int) (ceil(asc+desc)*0.65); // (int)ceil(Fix2X(width));
782 #ifndef SWELL_NO_CORETEXT
783 CTFontRef fr = curfont_valid ? (CTFontRef)ct->curfont->ct_FontRef : NULL;
784 if (!fr) fr=GetCoreTextDefaultFont();
788 tm->tmInternalLeading = CTFontGetLeading(fr);
789 tm->tmAscent = CTFontGetAscent(fr);
790 tm->tmDescent = CTFontGetDescent(fr);
791 tm->tmHeight = (tm->tmInternalLeading + tm->tmAscent + tm->tmDescent);
792 tm->tmAveCharWidth = tm->tmHeight*2/3; // todo
794 if (tm->tmHeight) tm->tmHeight++;
806 #ifdef SWELL_ATSUI_TEXT_SUPPORT
808 static int DrawTextATSUI(HDC ctx, CFStringRef strin, RECT *r, int align, bool *err)
810 HDC__ *ct=(HDC__ *)ctx;
811 HGDIOBJ__ *font=ct->curfont; // caller must specify a valid font
813 UniChar strbuf[4096];
818 CFRange r = {0,CFStringGetLength(strin)};
819 if (r.length > 4095) r.length=4095;
820 strbuf_len=CFStringGetBytes(strin,r,kCFStringEncodingUTF16,' ',false,(UInt8*)strbuf,sizeof(strbuf)-2,NULL);
821 if (strbuf_len<0)strbuf_len=0;
822 else if (strbuf_len>4095) strbuf_len=4095;
823 strbuf[strbuf_len]=0;
827 ATSUAttributeTag theTags[] = { kATSUColorTag, };
828 ByteCount theSizes[] = { sizeof(RGBColor), };
831 ATSUAttributeValuePtr theValues[] = {&tcolor, } ;
833 tcolor.red = GetRValue(ct->cur_text_color_int)*256;
834 tcolor.green = GetGValue(ct->cur_text_color_int)*256;
835 tcolor.blue = GetBValue(ct->cur_text_color_int)*256;
837 // error check this? we can live with the wrong color maybe?
838 ATSUSetAttributes(font->atsui_font_style, sizeof(theTags)/sizeof(theTags[0]), theTags, theSizes, theValues);
841 UniCharCount runLengths[1]={kATSUToTextEnd};
842 ATSUTextLayout layout;
843 if (ATSUCreateTextLayoutWithTextPtr(strbuf, kATSUFromTextBeginning, kATSUToTextEnd, strbuf_len, 1, runLengths, &font->atsui_font_style, &layout)!=noErr)
850 Fixed frot = X2Fix(font->font_rotation);
852 ATSULineTruncation tv = (align & DT_END_ELLIPSIS) ? kATSUTruncateEnd : kATSUTruncateNone;
853 ATSUAttributeTag theTags[] = { kATSUCGContextTag, kATSULineTruncationTag, kATSULineRotationTag };
854 ByteCount theSizes[] = { sizeof (CGContextRef), sizeof(ATSULineTruncation), sizeof(Fixed)};
855 ATSUAttributeValuePtr theValues[] = { &ct->ctx, &tv, &frot } ;
858 if (ATSUSetLayoutControls (layout,
860 sizeof(theTags)/sizeof(theTags[0]),
869 ATSUDisposeTextLayout(layout);
875 ATSUTextMeasurement leftFixed, rightFixed, ascentFixed, descentFixed;
877 if (ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, kATSUToTextEnd, &leftFixed, &rightFixed, &ascentFixed, &descentFixed)!=noErr)
880 ATSUDisposeTextLayout(layout);
884 int w=Fix2Long(rightFixed);
885 int descent=Fix2Long(descentFixed);
886 int h=descent + Fix2Long(ascentFixed);
887 if (align&DT_CALCRECT)
889 ATSUDisposeTextLayout(layout);
894 CGContextSaveGState(ct->ctx);
896 if (!(align & DT_NOCLIP))
897 CGContextClipToRect(ct->ctx,CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top));
899 int l=r->left, t=r->top;
901 if (fabs(font->font_rotation)<45.0)
903 if (align & DT_RIGHT) l = r->right-w;
904 else if (align & DT_CENTER) l = (r->right+r->left)/2 - w/2;
906 else l+=Fix2Long(ascentFixed); // 90 degree special case (we should generalize this to be correct throughout the rotation range, but oh well)
908 if (align & DT_BOTTOM) t = r->bottom-h;
909 else if (align & DT_VCENTER) t = (r->bottom+r->top)/2 - h/2;
911 CGContextTranslateCTM(ct->ctx,0,t);
912 CGContextScaleCTM(ct->ctx,1,-1);
913 CGContextTranslateCTM(ct->ctx,0,-t-h);
915 if (ct->curbkmode == OPAQUE)
917 CGRect bgr = CGRectMake(l, t, w, h);
918 CGColorRef bgc = CreateColor(ct->curbkcol);
919 CGContextSetFillColorWithColor(ct->ctx, bgc);
920 CGContextFillRect(ct->ctx, bgr);
924 if (ATSUDrawText(layout,kATSUFromTextBeginning,kATSUToTextEnd,Long2Fix(l),Long2Fix(t+descent))!=noErr)
927 CGContextRestoreGState(ct->ctx);
929 ATSUDisposeTextLayout(layout);
936 int DrawText(HDC ctx, const char *buf, int buflen, RECT *r, int align)
938 HDC__ *ct=(HDC__ *)ctx;
939 if (!HDC_VALID(ct)) return 0;
945 while (*p && (op-tmp)<sizeof(tmp)-1 && (buflen<0 || (p-buf)<buflen))
947 if (*p == '&' && !(align&DT_NOPREFIX)) p++;
950 else if (*p == '\n' && (align&DT_SINGLELINE)) { *op++ = ' '; p++; }
953 if (*p == '\n') has_ml=true;
959 if (!tmp[0]) return 0; // dont draw empty strings
961 NSString *str=CStringToNSString(tmp);
965 bool curfont_valid = HGDIOBJ_VALID(ct->curfont,TYPE_FONT);
966 #ifdef SWELL_ATSUI_TEXT_SUPPORT
967 if (curfont_valid && ct->curfont->atsui_font_style)
970 int ret = DrawTextATSUI(ctx,(CFStringRef)str,r,align,&err);
973 if (!err) return ret;
978 #ifndef SWELL_NO_CORETEXT
979 CTFontRef fr = curfont_valid ? (CTFontRef)ct->curfont->ct_FontRef : NULL;
980 if (!fr) fr=GetCoreTextDefaultFont();
983 // Initialize string, font, and context
984 CFStringRef keys[] = { kCTFontAttributeName,kCTForegroundColorAttributeName };
985 CFTypeRef values[] = { fr,ct->curtextcol };
987 int nk= sizeof(keys) / sizeof(keys[0]);
988 if (!values[1]) nk--;
990 CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, (const void**)&values, nk,
991 &kCFTypeDictionaryKeyCallBacks,
992 &kCFTypeDictionaryValueCallBacks);
994 CFAttributedStringRef attrString =
995 CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)str, attributes);
996 CFRelease(attributes);
1000 CTFrameRef frame = NULL;
1001 CFArrayRef lines = NULL;
1002 CTLineRef line = NULL;
1004 int line_w=0,line_h=0;
1007 CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);
1010 CGMutablePathRef path=CGPathCreateMutable();
1011 CGPathAddRect(path,NULL,CGRectMake(0,0,100000,100000));
1012 frame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,0),path,NULL);
1013 CFRelease(framesetter);
1018 lines = CTFrameGetLines(frame);
1019 const int n = (int)CFArrayGetCount(lines);
1020 for (int x=0;x<n;x++)
1022 CTLineRef l = (CTLineRef)CFArrayGetValueAtIndex(lines,x);
1025 CGFloat desc=0,lead=0;
1026 int w = (int) floor(CTLineGetTypographicBounds(l,&asc,&desc,&lead)+0.5);
1027 int h =(int) floor(asc+desc+lead+1.5);
1029 if (line_w < w) line_w=w;
1036 line = CTLineCreateWithAttributedString(attrString);
1040 CGFloat desc=0,lead=0;
1041 line_w = (int) floor(CTLineGetTypographicBounds(line,&asc,&desc,&lead)+0.5);
1042 line_h =(int) floor(asc+desc+lead+1.5);
1045 if (line_h) line_h++;
1047 CFRelease(attrString);
1049 if (align & DT_CALCRECT)
1051 r->right = r->left+line_w;
1052 r->bottom = r->top+line_h;
1053 if (line) CFRelease(line);
1054 if (frame) CFRelease(frame);
1058 float xo=r->left,yo=r->top;
1059 if (align & DT_RIGHT) xo += (r->right-r->left) - line_w;
1060 else if (align & DT_CENTER) xo += (r->right-r->left)/2 - line_w/2;
1062 if (align & DT_BOTTOM) yo += (r->bottom-r->top) - line_h;
1063 else if (align & DT_VCENTER) yo += (r->bottom-r->top)/2 - line_h/2;
1066 CGContextSaveGState(ct->ctx);
1068 CGAffineTransform f={1,0,0,-1,0,0};
1069 CGContextSetTextMatrix(ct->ctx, f);
1071 if (!(align & DT_NOCLIP))
1073 CGContextClipToRect(ct->ctx,CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top));
1076 CGColorRef bgc = NULL;
1077 if (ct->curbkmode == OPAQUE)
1079 bgc = CreateColor(ct->curbkcol);
1082 if (ct->curfont->font_quality)
1084 CGContextSetShouldAntialias(ct->ctx, ct->curfont->font_quality == ANTIALIASED_QUALITY);
1091 CGContextSetFillColorWithColor(ct->ctx, bgc);
1092 CGContextFillRect(ct->ctx, CGRectMake(xo,yo,line_w,line_h));
1094 CGContextSetTextPosition(ct->ctx, xo, yo + asc);
1095 CTLineDraw(line,ct->ctx);
1100 const int n = (int)CFArrayGetCount(lines);
1101 for (int x=0;x<n;x++)
1103 CTLineRef l = (CTLineRef)CFArrayGetValueAtIndex(lines,x);
1106 CGFloat desc=0.0,lead=0.0;
1108 float lw=CTLineGetTypographicBounds(l,&asc,&desc,&lead);
1112 CGContextSetFillColorWithColor(ct->ctx, bgc);
1113 CGContextFillRect(ct->ctx, CGRectMake(xo,yo,lw,asc+desc+lead));
1115 CGContextSetTextPosition(ct->ctx, xo, yo + asc);
1116 CTLineDraw(l,ct->ctx);
1118 yo += floor(asc+desc+lead+0.5);
1123 CGContextRestoreGState(ct->ctx);
1124 if (bgc) CGColorRelease(bgc);
1125 if (line) CFRelease(line);
1126 if (frame) CFRelease(frame);
1138 int GetGlyphIndicesW(HDC ctx, wchar_t *buf, int len, unsigned short *indices, int flags)
1140 HDC__ *ct=(HDC__*)ctx;
1141 if (HDC_VALID(ct) && HGDIOBJ_VALID(ct->curfont, TYPE_FONT))
1143 #ifndef SWELL_NO_CORETEXT
1144 CTFontRef f=(CTFontRef)ct->curfont->ct_FontRef;
1145 if (f && CTFontGetGlyphsForCharacters(f, (const UniChar*)buf, (CGGlyph*)indices, (CFIndex)len)) return len;
1150 for (i=0; i < len; ++i) indices[i]=(flags == GGI_MARK_NONEXISTING_GLYPHS ? 0xFFFF : 0);
1157 void SetBkColor(HDC ctx, int col)
1159 HDC__ *ct=(HDC__ *)ctx;
1160 if (!HDC_VALID(ct)) return;
1164 void SetBkMode(HDC ctx, int col)
1166 HDC__ *ct=(HDC__ *)ctx;
1167 if (!HDC_VALID(ct)) return;
1171 int GetTextColor(HDC ctx)
1173 HDC__ *ct=(HDC__ *)ctx;
1174 if (!HDC_VALID(ct)) return -1;
1175 return ct->cur_text_color_int;
1178 void SetTextColor(HDC ctx, int col)
1180 HDC__ *ct=(HDC__ *)ctx;
1181 if (!HDC_VALID(ct)) return;
1182 ct->cur_text_color_int = col;
1184 if (ct->curtextcol) CFRelease(ct->curtextcol);
1186 ct->curtextcol = CreateColor(col);
1190 HICON CreateIconIndirect(ICONINFO* iconinfo)
1192 if (!iconinfo || !iconinfo->fIcon) return 0;
1193 HGDIOBJ__* i=iconinfo->hbmColor;
1194 if (!HGDIOBJ_VALID(i,TYPE_BITMAP) || !i->bitmapptr) return 0;
1195 NSImage* img=i->bitmapptr;
1198 HGDIOBJ__* icon=GDP_OBJECT_NEW();
1199 icon->type=TYPE_BITMAP;
1202 icon->bitmapptr=img;
1206 HICON LoadNamedImage(const char *name, bool alphaFromMask)
1209 NSString *str=CStringToNSString(name);
1210 if (strstr(name,"/"))
1212 img=[[NSImage alloc] initWithContentsOfFile:str];
1216 img=[NSImage imageNamed:str];
1217 if (img) [img retain];
1225 [img setFlipped:YES];
1228 const NSSize sz=[img size];
1229 const int w = (int)sz.width, h=(int)sz.height;
1231 if (w>0 && h>0 && NULL != (hdc=SWELL_CreateMemContext(NULL,w,h)))
1233 [NSGraphicsContext saveGraphicsState];
1234 NSGraphicsContext *gc=[NSGraphicsContext graphicsContextWithGraphicsPort:((struct HDC__*)hdc)->ctx flipped:NO];
1235 [NSGraphicsContext setCurrentContext:gc];
1236 [img drawInRect:NSMakeRect(0,0,w,h) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
1237 [NSGraphicsContext restoreGraphicsState];
1239 // on yosemite, calling [img TIFFRepresentation] seems to change img somehow for some images, ouch.
1240 // in this case, we should always replace img with newImage (set rcnt=1), but in general
1241 // maybe we shoulnt use alphaFromMask anyhow
1242 NSImage *newImage=[[NSImage alloc] initWithData:[img TIFFRepresentation]];
1243 [newImage setFlipped:YES];
1245 const int *fb = (const int *)SWELL_GetCtxFrameBuffer(hdc);
1247 [newImage lockFocus];
1248 CGContextRef myContext = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
1249 for (y=0; y < h; y ++)
1252 for (x = 0; x < w; x++)
1254 if ((*fb++ & 0xffffff) == 0xff00ff)
1256 CGContextClearRect(myContext,CGRectMake(x,y,1,1));
1261 [newImage unlockFocus];
1263 SWELL_DeleteGfxContext(hdc);
1275 HGDIOBJ__ *i=GDP_OBJECT_NEW();
1276 i->type=TYPE_BITMAP;
1282 void DrawImageInRect(HDC ctx, HICON img, const RECT *r)
1284 HGDIOBJ__ *i = (HGDIOBJ__ *)img;
1285 HDC__ *ct=(HDC__*)ctx;
1286 if (!HDC_VALID(ct) || !HGDIOBJ_VALID(i,TYPE_BITMAP) || !i->bitmapptr) return;
1287 //CGContextDrawImage(ct->ctx,CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top),(CGImage*)i->bitmapptr);
1288 // probably a better way since this ignores the ctx
1289 [NSGraphicsContext saveGraphicsState];
1290 NSGraphicsContext *gc=[NSGraphicsContext graphicsContextWithGraphicsPort:ct->ctx flipped:NO];
1291 [NSGraphicsContext setCurrentContext:gc];
1292 NSImage *nsi=i->bitmapptr;
1293 NSRect rr=NSMakeRect(r->left,r->top,r->right-r->left,r->bottom-r->top);
1294 [nsi setFlipped:YES];
1295 [nsi drawInRect:rr fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
1296 [nsi setFlipped:NO]; // todo: restore old flippedness?
1297 [NSGraphicsContext restoreGraphicsState];
1302 BOOL GetObject(HICON icon, int bmsz, void *_bm)
1305 if (bmsz < 2*(int)sizeof(LONG)) return false;
1306 BITMAP *bm=(BITMAP *)_bm;
1307 HGDIOBJ__ *i = (HGDIOBJ__ *)icon;
1308 if (!HGDIOBJ_VALID(i,TYPE_BITMAP)) return false;
1309 NSImage *img = i->bitmapptr;
1310 if (!img) return false;
1311 bm->bmWidth = (int) ([img size].width+0.5);
1312 bm->bmHeight = (int) ([img size].height+0.5);
1313 if (bmsz >= (int)sizeof(BITMAP))
1315 bm->bmWidthBytes = bm->bmWidth * 4;
1317 bm->bmBitsPixel = 32;
1325 void *GetNSImageFromHICON(HICON ico)
1327 HGDIOBJ__ *i = (HGDIOBJ__ *)ico;
1328 if (!HGDIOBJ_VALID(i,TYPE_BITMAP)) return 0;
1329 return i->bitmapptr;
1333 static int ColorFromNSColor(NSColor *color, int valifnul)
1335 if (!color) return valifnul;
1337 NSColor *color2=[color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
1340 NSLog(@"error converting colorspace from: %@\n",[color colorSpaceName]);
1344 [color2 getRed:&r green:&g blue:&b alpha:NULL];
1345 return RGB((int)(r*255.0),(int)(g*255.0),(int)(b*255.0));
1348 #define ColorFromNSColor(a,b) (b)
1350 int GetSysColor(int idx)
1352 // NSColors that seem to be valid: textBackgroundColor, selectedTextBackgroundColor, textColor, selectedTextColor
1356 case COLOR_WINDOW: return ColorFromNSColor([NSColor controlColor],RGB(192,192,192));
1358 case COLOR_BTNFACE: return ColorFromNSColor([NSColor controlColor],RGB(192,192,192));
1359 case COLOR_SCROLLBAR: return ColorFromNSColor([NSColor controlColor],RGB(32,32,32));
1360 case COLOR_3DSHADOW: return ColorFromNSColor([NSColor selectedTextBackgroundColor],RGB(96,96,96));
1361 case COLOR_3DHILIGHT: return ColorFromNSColor([NSColor selectedTextBackgroundColor],RGB(224,224,224));
1362 case COLOR_BTNTEXT: return ColorFromNSColor([NSColor selectedTextBackgroundColor],RGB(0,0,0));
1363 case COLOR_3DDKSHADOW: return (ColorFromNSColor([NSColor selectedTextBackgroundColor],RGB(96,96,96))>>1)&0x7f7f7f;
1364 case COLOR_INFOBK: return RGB(255,240,200);
1365 case COLOR_INFOTEXT: return RGB(0,0,0);
1372 void BitBlt(HDC hdcOut, int x, int y, int w, int h, HDC hdcIn, int xin, int yin, int mode)
1374 StretchBlt(hdcOut,x,y,w,h,hdcIn,xin,yin,w,h,mode);
1377 void StretchBlt(HDC hdcOut, int x, int y, int destw, int desth, HDC hdcIn, int xin, int yin, int w, int h, int mode)
1379 if (!hdcOut || !hdcIn||w<1||h<1) return;
1380 HDC__ *src=(HDC__*)hdcIn;
1381 HDC__ *dest=(HDC__*)hdcOut;
1382 if (!HDC_VALID(src) || !HDC_VALID(dest) || !src->ownedData || !src->ctx || !dest->ctx) return;
1384 if (w<1||h<1) return;
1386 const int sw = (int)CGBitmapContextGetWidth(src->ctx);
1387 const int sh = (int)CGBitmapContextGetHeight(src->ctx);
1389 const int preclip_w=w;
1390 const int preclip_h=h;
1404 if (xin+w > sw) w=sw-xin;
1405 if (yin+h > sh) h=sh-yin;
1407 if (w<1||h<1) return;
1409 if (destw==preclip_w) destw=w; // no scaling, keep width the same
1410 else if (w != preclip_w) destw = (w*destw)/preclip_w;
1412 if (desth == preclip_h) desth=h;
1413 else if (h != preclip_h) desth = (h*desth)/preclip_h;
1415 const bool use_alphachannel = mode == SRCCOPY_USEALPHACHAN;
1417 CGContextRef output = (CGContextRef)dest->ctx;
1418 CGRect outputr = CGRectMake(x,-desth-y,destw,desth);
1420 unsigned char *p = (unsigned char *)ALIGN_FBUF(src->ownedData);
1421 p += (xin + sw*yin)*4;
1424 #ifdef SWELL_SUPPORT_OPENGL_BLIT
1427 NSOpenGLContext *glCtx = (NSOpenGLContext*) dest->GLgfxctx;
1428 NSOpenGLContext *cCtx = [NSOpenGLContext currentContext];
1431 [glCtx makeCurrentContext];
1434 glDisable(GL_TEXTURE_2D);
1435 glEnable(GL_TEXTURE_RECTANGLE_EXT);
1438 glGenTextures(1, &texid);
1439 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, texid);
1440 glPixelStorei(GL_UNPACK_ROW_LENGTH, sw);
1441 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1442 glTexImage2D(GL_TEXTURE_RECTANGLE_EXT,0,GL_RGBA8,w,h,0,GL_BGRA,GL_UNSIGNED_INT_8_8_8_8_REV, p);
1444 glViewport(x,[[glCtx view] bounds].size.height-desth-y,destw,desth);
1447 glTexCoord2f(0.0f, 0.0f);
1450 glTexCoord2f(0.0f, h);
1456 glTexCoord2f(w, 0.0f);
1460 glDeleteTextures(1,&texid);
1463 if (glCtx != cCtx) [cCtx makeCurrentContext];
1470 CGDataProviderRef provider = CGDataProviderCreateWithData(NULL,p,4*sw*h,NULL);
1471 CGImageRef img = CGImageCreate(w,h,8,32,4*sw,__GetDisplayColorSpace(),
1472 (use_alphachannel?kCGImageAlphaFirst:kCGImageAlphaNoneSkipFirst)|kCGBitmapByteOrder32Host,
1473 provider,NULL,NO,kCGRenderingIntentDefault);
1474 CGDataProviderRelease(provider);
1478 CGContextSaveGState(output);
1479 CGContextScaleCTM(output,1.0,-1.0);
1481 CGContextSetInterpolationQuality(output,kCGInterpolationNone);
1482 CGContextDrawImage(output,outputr,img);
1483 CGContextRestoreGState(output);
1485 CGImageRelease(img);
1489 void SWELL_PushClipRegion(HDC ctx)
1491 HDC__ *ct=(HDC__ *)ctx;
1492 if (HDC_VALID(ct) && ct->ctx) CGContextSaveGState(ct->ctx);
1495 void SWELL_SetClipRegion(HDC ctx, const RECT *r)
1497 HDC__ *ct=(HDC__ *)ctx;
1498 if (HDC_VALID(ct) && ct->ctx) CGContextClipToRect(ct->ctx,CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top));
1502 void SWELL_PopClipRegion(HDC ctx)
1504 HDC__ *ct=(HDC__ *)ctx;
1505 if (HDC_VALID(ct) && ct->ctx) CGContextRestoreGState(ct->ctx);
1508 void *SWELL_GetCtxFrameBuffer(HDC ctx)
1510 HDC__ *ct=(HDC__ *)ctx;
1511 if (HDC_VALID(ct)) return ALIGN_FBUF(ct->ownedData);
1518 if (h && [(id)h isKindOfClass:[NSWindow class]])
1520 if ([(id)h respondsToSelector:@selector(getSwellPaintInfo:)])
1522 PAINTSTRUCT ps={0,};
1523 [(id)h getSwellPaintInfo:(PAINTSTRUCT *)&ps];
1526 if ((ps.hdc)->ctx) CGContextSaveGState((ps.hdc)->ctx);
1530 h=(HWND)[(id)h contentView];
1533 if (h && [(id)h isKindOfClass:[NSView class]])
1535 if ([(id)h respondsToSelector:@selector(getSwellPaintInfo:)])
1537 PAINTSTRUCT ps={0,};
1538 [(id)h getSwellPaintInfo:(PAINTSTRUCT *)&ps];
1539 if (HDC_VALID((HDC__*)ps.hdc))
1541 if (((HDC__*)ps.hdc)->ctx) CGContextSaveGState((ps.hdc)->ctx);
1546 if ([(NSView*)h lockFocusIfCanDraw])
1548 HDC ret= SWELL_CreateGfxContext([NSGraphicsContext currentContext]);
1551 if (ret->ctx) CGContextSaveGState(ret->ctx);
1552 if (!ret->GLgfxctx && [(id)h respondsToSelector:@selector(swellGetGLContext)])
1554 NSOpenGLContext *glctx = (NSOpenGLContext*)[(id)h swellGetGLContext];
1555 ret->GLgfxctx = glctx;
1556 if (glctx) [glctx setView:(NSView *)h];
1565 HDC GetWindowDC(HWND h)
1571 if ([(id)h isKindOfClass:[NSWindow class]]) v=[(id)h contentView];
1572 else if ([(id)h isKindOfClass:[NSView class]]) v=(NSView *)h;
1576 NSRect b=[v bounds];
1577 float xsc=b.origin.x;
1578 float ysc=b.origin.y;
1579 if ((xsc || ysc) && (ret)->ctx) CGContextTranslateCTM((ret)->ctx,xsc,ysc);
1585 void ReleaseDC(HWND h, HDC hdc)
1589 if ((hdc)->ctx) CGContextRestoreGState((hdc)->ctx);
1591 if (h && [(id)h isKindOfClass:[NSWindow class]])
1593 if ([(id)h respondsToSelector:@selector(getSwellPaintInfo:)])
1595 PAINTSTRUCT ps={0,};
1596 [(id)h getSwellPaintInfo:(PAINTSTRUCT *)&ps];
1597 if (ps.hdc && ps.hdc==hdc) return;
1599 h=(HWND)[(id)h contentView];
1601 bool isView=h && [(id)h isKindOfClass:[NSView class]];
1604 if ([(id)h respondsToSelector:@selector(getSwellPaintInfo:)])
1606 PAINTSTRUCT ps={0,};
1607 [(id)h getSwellPaintInfo:(PAINTSTRUCT *)&ps];
1608 if (ps.hdc && ps.hdc==hdc) return;
1611 if (hdc && hdc->GLgfxctx)
1613 if ([NSOpenGLContext currentContext] == hdc->GLgfxctx) [NSOpenGLContext clearCurrentContext];
1614 hdc->GLgfxctx = NULL;
1617 if (hdc) SWELL_DeleteGfxContext(hdc);
1620 [(NSView *)h unlockFocus];
1621 // if ([(NSView *)h window]) [[(NSView *)h window] flushWindow];
1625 void SWELL_FillDialogBackground(HDC hdc, const RECT *r, int level)
1627 CGContextRef ctx=(CGContextRef)SWELL_GetCtxGC(hdc);
1630 // level 0 for now = this
1631 HIThemeSetFill(kThemeBrushDialogBackgroundActive,NULL,ctx,kHIThemeOrientationNormal);
1632 CGRect rect=CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top);
1633 CGContextFillRect(ctx,rect);
1637 HGDIOBJ SWELL_CloneGDIObject(HGDIOBJ a)
1639 if (HGDIOBJ_VALID(a))
1641 a->additional_refcnt++;
1648 HBITMAP CreateBitmap(int width, int height, int numplanes, int bitsperpixel, unsigned char* bits)
1650 int spp = bitsperpixel/8;
1651 Boolean hasa = (bitsperpixel == 32);
1652 Boolean hasp = (numplanes > 1); // won't actually work yet for planar data
1653 NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:0 pixelsWide:width pixelsHigh:height
1654 bitsPerSample:8 samplesPerPixel:spp
1655 hasAlpha:hasa isPlanar:hasp
1656 colorSpaceName:NSDeviceRGBColorSpace
1657 bitmapFormat:NSAlphaFirstBitmapFormat
1658 bytesPerRow:0 bitsPerPixel:0];
1660 unsigned char* p = [rep bitmapData];
1661 const int pspan = (int)[rep bytesPerRow]; // might not be the same as width
1663 for (int y=0;y<height;y ++)
1666 memcpy(p,bits,width*4);
1668 unsigned char *wr = p;
1669 const unsigned char *rd = bits;
1671 // convert BGRA to ARGB
1686 NSImage* img = [[NSImage alloc] init];
1687 [img addRepresentation:rep];
1690 HGDIOBJ__* obj = GDP_OBJECT_NEW();
1691 obj->type = TYPE_BITMAP;
1692 obj->wid = 1; // need free
1693 obj->bitmapptr = img;
1698 HIMAGELIST ImageList_CreateEx()
1700 return (HIMAGELIST)new WDL_PtrList<HGDIOBJ__>;
1703 BOOL ImageList_Remove(HIMAGELIST list, int idx)
1705 WDL_PtrList<HGDIOBJ__>* imglist=(WDL_PtrList<HGDIOBJ__>*)list;
1706 if (imglist && idx < imglist->GetSize())
1710 int x,n=imglist->GetSize();
1713 HGDIOBJ__ *a = imglist->Get(x);
1714 if (a) DeleteObject(a);
1720 HGDIOBJ__ *a = imglist->Get(idx);
1721 imglist->Set(idx, NULL);
1722 if (a) DeleteObject(a);
1730 void ImageList_Destroy(HIMAGELIST list)
1733 ImageList_Remove(list, -1);
1734 delete (WDL_PtrList<HGDIOBJ__>*)list;
1737 int ImageList_ReplaceIcon(HIMAGELIST list, int offset, HICON image)
1739 if (!image || !list) return -1;
1740 WDL_PtrList<HGDIOBJ__> *l=(WDL_PtrList<HGDIOBJ__> *)list;
1742 HGDIOBJ__ *imgsrc = (HGDIOBJ__*)image;
1743 if (!HGDIOBJ_VALID(imgsrc,TYPE_BITMAP)) return -1;
1745 HGDIOBJ__* icon=GDP_OBJECT_NEW();
1746 icon->type=TYPE_BITMAP;
1748 icon->bitmapptr = imgsrc->bitmapptr; // no need to duplicate it, can just retain a copy
1749 [icon->bitmapptr retain];
1750 image = (HICON) icon;
1752 if (offset<0||offset>=l->GetSize())
1755 offset=l->GetSize()-1;
1759 HICON old=l->Get(offset);
1760 l->Set(offset,image);
1761 if (old) DeleteObject(old);
1766 int ImageList_Add(HIMAGELIST list, HBITMAP image, HBITMAP mask)
1768 if (!image || !list) return -1;
1769 WDL_PtrList<HGDIOBJ__> *l=(WDL_PtrList<HGDIOBJ__> *)list;
1771 HGDIOBJ__ *imgsrc = (HGDIOBJ__*)image;
1772 if (!HGDIOBJ_VALID(imgsrc,TYPE_BITMAP)) return -1;
1774 HGDIOBJ__* icon=GDP_OBJECT_NEW();
1775 icon->type=TYPE_BITMAP;
1777 NSImage *nsimg = [imgsrc->bitmapptr copy]; // caller still owns the image
1778 [nsimg setFlipped:YES];
1779 icon->bitmapptr = nsimg;
1780 image = (HICON) icon;
1783 return l->GetSize();
1786 int AddFontResourceEx(LPCTSTR str, DWORD fl, void *pdv)
1788 if (SWELL_GDI_GetOSXVersion() < 0x1060) return 0;
1790 static bool (*_CTFontManagerRegisterFontsForURL)( CFURLRef fontURL, uint32_t scope, CFErrorRef *error );
1793 CFBundleRef b = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreText"));
1796 *(void **)&_CTFontManagerRegisterFontsForURL = CFBundleGetFunctionPointerForName(b,CFSTR("CTFontManagerRegisterFontsForURL"));
1802 if (!_CTFontManagerRegisterFontsForURL) return 0;
1804 CFStringRef s=(CFStringRef)CStringToNSString(str);
1806 CFURLRef r=CFURLCreateWithFileSystemPath(NULL,s,kCFURLPOSIXPathStyle,true);
1807 CFErrorRef err=NULL;
1808 const int v = _CTFontManagerRegisterFontsForURL(r,
1809 (fl & FR_PRIVATE) ? 1/*kCTFontManagerScopeProcess*/ : 2/*kCTFontManagerScopeUser*/,
1812 // release err? don't think so