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 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
79 return SWELL_GDI_GetOSXVersion() >= 0x1050 && CTFontCreateWithName && CTLineDraw && CTFramesetterCreateWithAttributedString && CTFramesetterCreateFrame &&
80 CTFrameGetLines && CTLineGetTypographicBounds && CTLineCreateWithAttributedString && CTFontCopyPostScriptName
83 // 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 != sizeof(BITMAP)) 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);
1317 void *GetNSImageFromHICON(HICON ico)
1319 HGDIOBJ__ *i = (HGDIOBJ__ *)ico;
1320 if (!HGDIOBJ_VALID(i,TYPE_BITMAP)) return 0;
1321 return i->bitmapptr;
1325 static int ColorFromNSColor(NSColor *color, int valifnul)
1327 if (!color) return valifnul;
1329 NSColor *color2=[color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
1332 NSLog(@"error converting colorspace from: %@\n",[color colorSpaceName]);
1336 [color2 getRed:&r green:&g blue:&b alpha:NULL];
1337 return RGB((int)(r*255.0),(int)(g*255.0),(int)(b*255.0));
1340 #define ColorFromNSColor(a,b) (b)
1342 int GetSysColor(int idx)
1344 // NSColors that seem to be valid: textBackgroundColor, selectedTextBackgroundColor, textColor, selectedTextColor
1348 case COLOR_WINDOW: return ColorFromNSColor([NSColor controlColor],RGB(192,192,192));
1350 case COLOR_BTNFACE: return ColorFromNSColor([NSColor controlColor],RGB(192,192,192));
1351 case COLOR_SCROLLBAR: return ColorFromNSColor([NSColor controlColor],RGB(32,32,32));
1352 case COLOR_3DSHADOW: return ColorFromNSColor([NSColor selectedTextBackgroundColor],RGB(96,96,96));
1353 case COLOR_3DHILIGHT: return ColorFromNSColor([NSColor selectedTextBackgroundColor],RGB(224,224,224));
1354 case COLOR_BTNTEXT: return ColorFromNSColor([NSColor selectedTextBackgroundColor],RGB(0,0,0));
1355 case COLOR_3DDKSHADOW: return (ColorFromNSColor([NSColor selectedTextBackgroundColor],RGB(96,96,96))>>1)&0x7f7f7f;
1356 case COLOR_INFOBK: return RGB(255,240,200);
1357 case COLOR_INFOTEXT: return RGB(0,0,0);
1364 void BitBlt(HDC hdcOut, int x, int y, int w, int h, HDC hdcIn, int xin, int yin, int mode)
1366 StretchBlt(hdcOut,x,y,w,h,hdcIn,xin,yin,w,h,mode);
1369 void StretchBlt(HDC hdcOut, int x, int y, int destw, int desth, HDC hdcIn, int xin, int yin, int w, int h, int mode)
1371 if (!hdcOut || !hdcIn||w<1||h<1) return;
1372 HDC__ *src=(HDC__*)hdcIn;
1373 HDC__ *dest=(HDC__*)hdcOut;
1374 if (!HDC_VALID(src) || !HDC_VALID(dest) || !src->ownedData || !src->ctx || !dest->ctx) return;
1376 if (w<1||h<1) return;
1378 const int sw = (int)CGBitmapContextGetWidth(src->ctx);
1379 const int sh = (int)CGBitmapContextGetHeight(src->ctx);
1381 const int preclip_w=w;
1382 const int preclip_h=h;
1396 if (xin+w > sw) w=sw-xin;
1397 if (yin+h > sh) h=sh-yin;
1399 if (w<1||h<1) return;
1401 if (destw==preclip_w) destw=w; // no scaling, keep width the same
1402 else if (w != preclip_w) destw = (w*destw)/preclip_w;
1404 if (desth == preclip_h) desth=h;
1405 else if (h != preclip_h) desth = (h*desth)/preclip_h;
1407 const bool use_alphachannel = mode == SRCCOPY_USEALPHACHAN;
1409 CGContextRef output = (CGContextRef)dest->ctx;
1410 CGRect outputr = CGRectMake(x,-desth-y,destw,desth);
1412 unsigned char *p = (unsigned char *)ALIGN_FBUF(src->ownedData);
1413 p += (xin + sw*yin)*4;
1416 #ifdef SWELL_SUPPORT_OPENGL_BLIT
1419 NSOpenGLContext *glCtx = (NSOpenGLContext*) dest->GLgfxctx;
1420 NSOpenGLContext *cCtx = [NSOpenGLContext currentContext];
1423 [glCtx makeCurrentContext];
1426 glDisable(GL_TEXTURE_2D);
1427 glEnable(GL_TEXTURE_RECTANGLE_EXT);
1430 glGenTextures(1, &texid);
1431 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, texid);
1432 glPixelStorei(GL_UNPACK_ROW_LENGTH, sw);
1433 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1434 glTexImage2D(GL_TEXTURE_RECTANGLE_EXT,0,GL_RGBA8,w,h,0,GL_BGRA,GL_UNSIGNED_INT_8_8_8_8_REV, p);
1436 glViewport(x,[[glCtx view] bounds].size.height-desth-y,destw,desth);
1439 glTexCoord2f(0.0f, 0.0f);
1442 glTexCoord2f(0.0f, h);
1448 glTexCoord2f(w, 0.0f);
1452 glDeleteTextures(1,&texid);
1455 if (glCtx != cCtx) [cCtx makeCurrentContext];
1462 CGDataProviderRef provider = CGDataProviderCreateWithData(NULL,p,4*sw*h,NULL);
1463 CGImageRef img = CGImageCreate(w,h,8,32,4*sw,__GetDisplayColorSpace(),
1464 (use_alphachannel?kCGImageAlphaFirst:kCGImageAlphaNoneSkipFirst)|kCGBitmapByteOrder32Host,
1465 provider,NULL,NO,kCGRenderingIntentDefault);
1466 CGDataProviderRelease(provider);
1470 CGContextSaveGState(output);
1471 CGContextScaleCTM(output,1.0,-1.0);
1473 CGContextSetInterpolationQuality(output,kCGInterpolationNone);
1474 CGContextDrawImage(output,outputr,img);
1475 CGContextRestoreGState(output);
1477 CGImageRelease(img);
1481 void SWELL_PushClipRegion(HDC ctx)
1483 HDC__ *ct=(HDC__ *)ctx;
1484 if (HDC_VALID(ct) && ct->ctx) CGContextSaveGState(ct->ctx);
1487 void SWELL_SetClipRegion(HDC ctx, const RECT *r)
1489 HDC__ *ct=(HDC__ *)ctx;
1490 if (HDC_VALID(ct) && ct->ctx) CGContextClipToRect(ct->ctx,CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top));
1494 void SWELL_PopClipRegion(HDC ctx)
1496 HDC__ *ct=(HDC__ *)ctx;
1497 if (HDC_VALID(ct) && ct->ctx) CGContextRestoreGState(ct->ctx);
1500 void *SWELL_GetCtxFrameBuffer(HDC ctx)
1502 HDC__ *ct=(HDC__ *)ctx;
1503 if (HDC_VALID(ct)) return ALIGN_FBUF(ct->ownedData);
1510 if (h && [(id)h isKindOfClass:[NSWindow class]])
1512 if ([(id)h respondsToSelector:@selector(getSwellPaintInfo:)])
1514 PAINTSTRUCT ps={0,};
1515 [(id)h getSwellPaintInfo:(PAINTSTRUCT *)&ps];
1518 if ((ps.hdc)->ctx) CGContextSaveGState((ps.hdc)->ctx);
1522 h=(HWND)[(id)h contentView];
1525 if (h && [(id)h isKindOfClass:[NSView class]])
1527 if ([(id)h respondsToSelector:@selector(getSwellPaintInfo:)])
1529 PAINTSTRUCT ps={0,};
1530 [(id)h getSwellPaintInfo:(PAINTSTRUCT *)&ps];
1531 if (HDC_VALID((HDC__*)ps.hdc))
1533 if (((HDC__*)ps.hdc)->ctx) CGContextSaveGState((ps.hdc)->ctx);
1538 if ([(NSView*)h lockFocusIfCanDraw])
1540 HDC ret= SWELL_CreateGfxContext([NSGraphicsContext currentContext]);
1543 if (ret->ctx) CGContextSaveGState(ret->ctx);
1544 if (!ret->GLgfxctx && [(id)h respondsToSelector:@selector(swellGetGLContext)])
1546 NSOpenGLContext *glctx = (NSOpenGLContext*)[(id)h swellGetGLContext];
1547 ret->GLgfxctx = glctx;
1548 if (glctx) [glctx setView:(NSView *)h];
1557 HDC GetWindowDC(HWND h)
1563 if ([(id)h isKindOfClass:[NSWindow class]]) v=[(id)h contentView];
1564 else if ([(id)h isKindOfClass:[NSView class]]) v=(NSView *)h;
1568 NSRect b=[v bounds];
1569 float xsc=b.origin.x;
1570 float ysc=b.origin.y;
1571 if ((xsc || ysc) && (ret)->ctx) CGContextTranslateCTM((ret)->ctx,xsc,ysc);
1577 void ReleaseDC(HWND h, HDC hdc)
1581 if ((hdc)->ctx) CGContextRestoreGState((hdc)->ctx);
1583 if (h && [(id)h isKindOfClass:[NSWindow class]])
1585 if ([(id)h respondsToSelector:@selector(getSwellPaintInfo:)])
1587 PAINTSTRUCT ps={0,};
1588 [(id)h getSwellPaintInfo:(PAINTSTRUCT *)&ps];
1589 if (ps.hdc && ps.hdc==hdc) return;
1591 h=(HWND)[(id)h contentView];
1593 bool isView=h && [(id)h isKindOfClass:[NSView class]];
1596 if ([(id)h respondsToSelector:@selector(getSwellPaintInfo:)])
1598 PAINTSTRUCT ps={0,};
1599 [(id)h getSwellPaintInfo:(PAINTSTRUCT *)&ps];
1600 if (ps.hdc && ps.hdc==hdc) return;
1603 if (hdc && hdc->GLgfxctx)
1605 if ([NSOpenGLContext currentContext] == hdc->GLgfxctx) [NSOpenGLContext clearCurrentContext];
1606 hdc->GLgfxctx = NULL;
1609 if (hdc) SWELL_DeleteGfxContext(hdc);
1612 [(NSView *)h unlockFocus];
1613 // if ([(NSView *)h window]) [[(NSView *)h window] flushWindow];
1617 void SWELL_FillDialogBackground(HDC hdc, const RECT *r, int level)
1619 CGContextRef ctx=(CGContextRef)SWELL_GetCtxGC(hdc);
1622 // level 0 for now = this
1623 HIThemeSetFill(kThemeBrushDialogBackgroundActive,NULL,ctx,kHIThemeOrientationNormal);
1624 CGRect rect=CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top);
1625 CGContextFillRect(ctx,rect);
1629 HGDIOBJ SWELL_CloneGDIObject(HGDIOBJ a)
1631 if (HGDIOBJ_VALID(a))
1633 a->additional_refcnt++;
1640 HBITMAP CreateBitmap(int width, int height, int numplanes, int bitsperpixel, unsigned char* bits)
1642 int spp = bitsperpixel/8;
1643 Boolean hasa = (bitsperpixel == 32);
1644 Boolean hasp = (numplanes > 1); // won't actually work yet for planar data
1645 NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:0 pixelsWide:width pixelsHigh:height
1646 bitsPerSample:8 samplesPerPixel:spp
1647 hasAlpha:hasa isPlanar:hasp
1648 colorSpaceName:NSDeviceRGBColorSpace
1649 bitmapFormat:NSAlphaFirstBitmapFormat
1650 bytesPerRow:0 bitsPerPixel:0];
1652 unsigned char* p = [rep bitmapData];
1653 const int pspan = (int)[rep bytesPerRow]; // might not be the same as width
1655 for (int y=0;y<height;y ++)
1658 memcpy(p,bits,width*4);
1660 unsigned char *wr = p;
1661 const unsigned char *rd = bits;
1663 // convert BGRA to ARGB
1678 NSImage* img = [[NSImage alloc] init];
1679 [img addRepresentation:rep];
1682 HGDIOBJ__* obj = GDP_OBJECT_NEW();
1683 obj->type = TYPE_BITMAP;
1684 obj->wid = 1; // need free
1685 obj->bitmapptr = img;
1690 HIMAGELIST ImageList_CreateEx()
1692 return (HIMAGELIST)new WDL_PtrList<HGDIOBJ__>;
1695 BOOL ImageList_Remove(HIMAGELIST list, int idx)
1697 WDL_PtrList<HGDIOBJ__>* imglist=(WDL_PtrList<HGDIOBJ__>*)list;
1698 if (imglist && idx < imglist->GetSize())
1702 int x,n=imglist->GetSize();
1705 HGDIOBJ__ *a = imglist->Get(x);
1706 if (a) DeleteObject(a);
1712 HGDIOBJ__ *a = imglist->Get(idx);
1713 imglist->Set(idx, NULL);
1714 if (a) DeleteObject(a);
1722 void ImageList_Destroy(HIMAGELIST list)
1725 ImageList_Remove(list, -1);
1726 delete (WDL_PtrList<HGDIOBJ__>*)list;
1729 int ImageList_ReplaceIcon(HIMAGELIST list, int offset, HICON image)
1731 if (!image || !list) return -1;
1732 WDL_PtrList<HGDIOBJ__> *l=(WDL_PtrList<HGDIOBJ__> *)list;
1734 HGDIOBJ__ *imgsrc = (HGDIOBJ__*)image;
1735 if (!HGDIOBJ_VALID(imgsrc,TYPE_BITMAP)) return -1;
1737 HGDIOBJ__* icon=GDP_OBJECT_NEW();
1738 icon->type=TYPE_BITMAP;
1740 icon->bitmapptr = imgsrc->bitmapptr; // no need to duplicate it, can just retain a copy
1741 [icon->bitmapptr retain];
1742 image = (HICON) icon;
1744 if (offset<0||offset>=l->GetSize())
1747 offset=l->GetSize()-1;
1751 HICON old=l->Get(offset);
1752 l->Set(offset,image);
1753 if (old) DeleteObject(old);
1758 int ImageList_Add(HIMAGELIST list, HBITMAP image, HBITMAP mask)
1760 if (!image || !list) return -1;
1761 WDL_PtrList<HGDIOBJ__> *l=(WDL_PtrList<HGDIOBJ__> *)list;
1763 HGDIOBJ__ *imgsrc = (HGDIOBJ__*)image;
1764 if (!HGDIOBJ_VALID(imgsrc,TYPE_BITMAP)) return -1;
1766 HGDIOBJ__* icon=GDP_OBJECT_NEW();
1767 icon->type=TYPE_BITMAP;
1769 NSImage *nsimg = [imgsrc->bitmapptr copy]; // caller still owns the image
1770 [nsimg setFlipped:YES];
1771 icon->bitmapptr = nsimg;
1772 image = (HICON) icon;
1775 return l->GetSize();
1778 int AddFontResourceEx(LPCTSTR str, DWORD fl, void *pdv)
1780 if (SWELL_GDI_GetOSXVersion() < 0x1060) return 0;
1782 static bool (*_CTFontManagerRegisterFontsForURL)( CFURLRef fontURL, uint32_t scope, CFErrorRef *error );
1785 CFBundleRef b = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreText"));
1788 *(void **)&_CTFontManagerRegisterFontsForURL = CFBundleGetFunctionPointerForName(b,CFSTR("CTFontManagerRegisterFontsForURL"));
1794 if (!_CTFontManagerRegisterFontsForURL) return 0;
1796 CFStringRef s=(CFStringRef)CStringToNSString(str);
1798 CFURLRef r=CFURLCreateWithFileSystemPath(NULL,s,kCFURLPOSIXPathStyle,true);
1799 CFErrorRef err=NULL;
1800 const int v = _CTFontManagerRegisterFontsForURL(r,
1801 (fl & FR_PRIVATE) ? 1/*kCTFontManagerScopeProcess*/ : 2/*kCTFontManagerScopeUser*/,
1804 // release err? don't think so