2 /* Cockos SWELL (Simple/Small Win32 Emulation Layer for Losers (who use OS X))
3 Copyright (C) 2006-2007, Cockos, Inc.
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
22 This file provides basic win32 GDI-->Quartz translation. It uses features that require OS X 10.4+
26 #ifndef SWELL_PROVIDED_BY_APP
28 #import <Carbon/Carbon.h>
29 #import <Cocoa/Cocoa.h>
30 #import <CoreFoundation/CFDictionary.h>
31 #import <objc/objc-runtime.h>
33 #include "swell-internal.h"
36 #include "../assocarray.h"
37 #include "../wdlcstring.h"
40 #include <xmmintrin.h>
43 #ifdef SWELL_SUPPORT_OPENGL_BLIT
44 #include <OpenGL/gl.h>
47 int SWELL_GetOSXVersion()
53 Gestalt(gestaltSystemVersion,&v);
59 #include <immintrin.h>
62 #ifndef SWELL_NO_CORETEXT
63 static bool IsCoreTextSupported()
65 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
66 return SWELL_GetOSXVersion() >= 0x1050 && CTFontCreateWithName && CTLineDraw && CTFramesetterCreateWithAttributedString && CTFramesetterCreateFrame &&
67 CTFrameGetLines && CTLineGetTypographicBounds && CTLineCreateWithAttributedString && CTFontCopyPostScriptName
70 // targetting 10.5+, CT is always valid
75 static CTFontRef GetCoreTextDefaultFont()
77 static CTFontRef deffr;
82 if (IsCoreTextSupported())
84 deffr=(CTFontRef) [[NSFont labelFontOfSize:10.0] retain];
89 #endif // !SWELL_NO_CORETEXT
92 static NSString *CStringToNSString(const char *str)
97 ret=(NSString *)CFStringCreateWithCString(NULL,str,kCFStringEncodingUTF8);
99 ret=(NSString *)CFStringCreateWithCString(NULL,str,kCFStringEncodingASCII);
103 CGColorSpaceRef __GetDisplayColorSpace()
105 static CGColorSpaceRef cs;
108 // use monitor profile for 10.7+
109 if (SWELL_GetOSXVersion() >= 0x1070)
111 CMProfileRef systemMonitorProfile = NULL;
112 CMError getProfileErr = CMGetSystemProfile(&systemMonitorProfile);
113 if(noErr == getProfileErr)
115 cs = CGColorSpaceCreateWithPlatformColorSpace(systemMonitorProfile);
116 CMCloseProfile(systemMonitorProfile);
121 cs = CGColorSpaceCreateDeviceRGB();
125 static CGColorRef CreateColor(int col, float alpha=1.0f)
127 CGFloat cols[4]={GetRValue(col)/255.0f,GetGValue(col)/255.0f,GetBValue(col)/255.0f,alpha};
128 CGColorRef color=CGColorCreate(__GetDisplayColorSpace(),cols);
133 #include "swell-gdi-internalpool.h"
135 int SWELL_IsRetinaHWND(HWND hwnd)
137 if (!hwnd || SWELL_GetOSXVersion() < 0x1070) return 0;
140 if ([(id)hwnd isKindOfClass:[NSView class]]) w = [(NSView *)hwnd window];
141 else if ([(id)hwnd isKindOfClass:[NSWindow class]]) w = (NSWindow *)hwnd;
145 NSRect r=NSMakeRect(0,0,1,1);
146 NSRect (*tmp)(id receiver, SEL operation, NSRect) = (NSRect (*)(id, SEL, NSRect))objc_msgSend_stret;
147 NSRect str = tmp(w,sel_getUid("convertRectToBacking:"),r);
149 if (str.size.width > 1.9) return 1;
154 int SWELL_IsRetinaDC(HDC hdc)
156 HDC__ *src=(HDC__*)hdc;
157 if (!src || !HDC_VALID(src) || !src->ctx) return 0;
158 return CGContextConvertSizeToDeviceSpace((CGContextRef)src->ctx, CGSizeMake(1,1)).width > 1.9 ? 1 : 0;
162 HDC SWELL_CreateGfxContext(void *c)
164 HDC__ *ctx=SWELL_GDP_CTX_NEW();
165 NSGraphicsContext *nsc = (NSGraphicsContext *)c;
166 // if (![nsc isFlipped])
167 // nsc = [NSGraphicsContext graphicsContextWithGraphicsPort:[nsc graphicsPort] flipped:YES];
169 ctx->ctx=(CGContextRef)[nsc graphicsPort];
170 // CGAffineTransform f={1,0,0,-1,0,0};
171 //CGContextSetTextMatrix(ctx->ctx,f);
172 //SetTextColor(ctx,0);
174 // CGContextSelectFont(ctx->ctx,"Arial",12.0,kCGEncodingMacRoman);
178 #define ALIGN_EXTRA 63
179 static void *ALIGN_FBUF(void *inbuf)
181 const UINT_PTR extra = ALIGN_EXTRA;
182 return (void *) (((UINT_PTR)inbuf+extra)&~extra);
185 HDC SWELL_CreateMemContext(HDC hdc, int w, int h)
187 void *buf=calloc(w*4*h+ALIGN_EXTRA,1);
189 CGContextRef c=CGBitmapContextCreate(ALIGN_FBUF(buf),w,h,8,w*4,__GetDisplayColorSpace(), kCGImageAlphaNoneSkipFirst);
197 CGContextTranslateCTM(c,0.0,h);
198 CGContextScaleCTM(c,1.0,-1.0);
201 HDC__ *ctx=SWELL_GDP_CTX_NEW();
202 ctx->ctx=(CGContextRef)c;
204 // CGContextSelectFont(ctx->ctx,"Arial",12.0,kCGEncodingMacRoman);
210 void SWELL_DeleteGfxContext(HDC ctx)
212 HDC__ *ct=(HDC__ *)ctx;
217 CGContextRelease(ct->ctx);
220 if (ct->curtextcol) CFRelease(ct->curtextcol);
221 SWELL_GDP_CTX_DELETE(ct);
224 HPEN CreatePen(int attr, int wid, int col)
226 return CreatePenAlpha(attr,wid,col,1.0f);
229 HBRUSH CreateSolidBrush(int col)
231 return CreateSolidBrushAlpha(col,1.0f);
236 HPEN CreatePenAlpha(int attr, int wid, int col, float alpha)
238 HGDIOBJ__ *pen=GDP_OBJECT_NEW();
240 pen->wid=wid<0?0:wid;
241 pen->color=CreateColor(col,alpha);
244 HBRUSH CreateSolidBrushAlpha(int col, float alpha)
246 HGDIOBJ__ *brush=GDP_OBJECT_NEW();
247 brush->type=TYPE_BRUSH;
248 brush->color=CreateColor(col,alpha);
254 HFONT CreateFontIndirect(LOGFONT *lf)
256 return CreateFont(lf->lfHeight, lf->lfWidth,lf->lfEscapement, lf->lfOrientation, lf->lfWeight, lf->lfItalic,
257 lf->lfUnderline, lf->lfStrikeOut, lf->lfCharSet, lf->lfOutPrecision,lf->lfClipPrecision,
258 lf->lfQuality, lf->lfPitchAndFamily, lf->lfFaceName);
261 static HGDIOBJ__ global_objs[2];
263 void DeleteObject(HGDIOBJ pen)
265 HGDIOBJ__ *p=(HGDIOBJ__ *)pen;
266 if (p >= global_objs && p < global_objs + sizeof(global_objs)/sizeof(global_objs[0])) return;
268 if (HGDIOBJ_VALID(p))
270 if (--p->additional_refcnt < 0)
272 if (p->type == TYPE_PEN || p->type == TYPE_BRUSH || p->type == TYPE_FONT || p->type == TYPE_BITMAP)
274 if (p->type == TYPE_PEN || p->type == TYPE_BRUSH)
275 if (p->wid<0) return;
276 if (p->color) CGColorRelease(p->color);
278 if (p->ct_FontRef) CFRelease(p->ct_FontRef);
280 #ifdef SWELL_ATSUI_TEXT_SUPPORT
281 if (p->atsui_font_style) ATSUDisposeStyle(p->atsui_font_style);
284 if (p->wid && p->bitmapptr) [p->bitmapptr release];
285 GDP_OBJECT_DELETE(p);
287 // JF> don't free unknown objects, this shouldn't ever happen anyway: else free(p);
293 HGDIOBJ SelectObject(HDC ctx, HGDIOBJ pen)
295 HDC__ *c=(HDC__ *)ctx;
296 HGDIOBJ__ *p=(HGDIOBJ__*) pen;
298 if (!HDC_VALID(c)) return 0;
300 if (p == (HGDIOBJ__*)TYPE_PEN) mod=&c->curpen;
301 else if (p == (HGDIOBJ__*)TYPE_BRUSH) mod=&c->curbrush;
302 else if (p == (HGDIOBJ__*)TYPE_FONT) mod=&c->curfont;
304 if (mod) // clearing a particular thing
308 return HGDIOBJ_VALID(np,(int)(INT_PTR)p)?np:p;
311 if (!HGDIOBJ_VALID(p)) return 0;
313 if (p->type == TYPE_PEN) mod=&c->curpen;
314 else if (p->type == TYPE_BRUSH) mod=&c->curbrush;
315 else if (p->type == TYPE_FONT) mod=&c->curfont;
320 if (!HGDIOBJ_VALID(op,p->type)) op=(HGDIOBJ__*)(INT_PTR)p->type;
327 void SWELL_FillRect(HDC ctx, const RECT *r, HBRUSH br)
329 HDC__ *c=(HDC__ *)ctx;
330 HGDIOBJ__ *b=(HGDIOBJ__*) br;
331 if (!HDC_VALID(c) || !HGDIOBJ_VALID(b,TYPE_BRUSH) || b == (HGDIOBJ__*)TYPE_BRUSH || b->type != TYPE_BRUSH) return;
333 if (b->wid<0) return;
335 CGRect rect=CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top);
336 CGContextSetFillColorWithColor(c->ctx,b->color);
337 CGContextFillRect(c->ctx,rect);
341 void RoundRect(HDC ctx, int x, int y, int x2, int y2, int xrnd, int yrnd)
345 POINT pts[10]={ // todo: curves between edges
358 WDL_GDP_Polygon(ctx,pts,sizeof(pts)/sizeof(pts[0]));
361 void Ellipse(HDC ctx, int l, int t, int r, int b)
363 HDC__ *c=(HDC__ *)ctx;
364 if (!HDC_VALID(c)) return;
366 CGRect rect=CGRectMake(l,t,r-l,b-t);
368 if (HGDIOBJ_VALID(c->curbrush,TYPE_BRUSH) && c->curbrush->wid >=0)
370 CGContextSetFillColorWithColor(c->ctx,c->curbrush->color);
371 CGContextFillEllipseInRect(c->ctx,rect);
373 if (HGDIOBJ_VALID(c->curpen,TYPE_PEN) && c->curpen->wid >= 0)
375 CGContextSetStrokeColorWithColor(c->ctx,c->curpen->color);
376 CGContextStrokeEllipseInRect(c->ctx, rect); //, (float)max(1,c->curpen->wid));
380 void Rectangle(HDC ctx, int l, int t, int r, int b)
382 HDC__ *c=(HDC__ *)ctx;
383 if (!HDC_VALID(c)) return;
385 CGRect rect=CGRectMake(l,t,r-l,b-t);
387 if (HGDIOBJ_VALID(c->curbrush,TYPE_BRUSH) && c->curbrush->wid >= 0)
389 CGContextSetFillColorWithColor(c->ctx,c->curbrush->color);
390 CGContextFillRect(c->ctx,rect);
392 if (HGDIOBJ_VALID(c->curpen,TYPE_PEN) && c->curpen->wid >= 0)
394 CGContextSetStrokeColorWithColor(c->ctx,c->curpen->color);
395 CGContextStrokeRectWithWidth(c->ctx, rect, (float)max(1,c->curpen->wid));
400 HGDIOBJ GetStockObject(int wh)
406 HGDIOBJ__ *p = &global_objs[0];
413 HGDIOBJ__ *p = &global_objs[1];
422 void Polygon(HDC ctx, POINT *pts, int npts)
424 HDC__ *c=(HDC__ *)ctx;
425 if (!HDC_VALID(c)) return;
426 if (((!HGDIOBJ_VALID(c->curbrush,TYPE_BRUSH)||c->curbrush->wid<0) && (!HGDIOBJ_VALID(c->curpen,TYPE_PEN)||c->curpen->wid<0)) || npts<2) return;
428 CGContextBeginPath(c->ctx);
429 CGContextMoveToPoint(c->ctx,(float)pts[0].x,(float)pts[0].y);
431 for (x = 1; x < npts; x ++)
433 CGContextAddLineToPoint(c->ctx,(float)pts[x].x,(float)pts[x].y);
435 if (HGDIOBJ_VALID(c->curbrush,TYPE_BRUSH) && c->curbrush->wid >= 0)
437 CGContextSetFillColorWithColor(c->ctx,c->curbrush->color);
439 if (HGDIOBJ_VALID(c->curpen,TYPE_PEN) && c->curpen->wid>=0)
441 CGContextSetLineWidth(c->ctx,(float)max(c->curpen->wid,1));
442 CGContextSetStrokeColorWithColor(c->ctx,c->curpen->color);
444 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);
447 void MoveToEx(HDC ctx, int x, int y, POINT *op)
449 HDC__ *c=(HDC__ *)ctx;
450 if (!HDC_VALID(c)) return;
453 op->x = (int) (c->lastpos_x);
454 op->y = (int) (c->lastpos_y);
456 c->lastpos_x=(float)x;
457 c->lastpos_y=(float)y;
460 void PolyBezierTo(HDC ctx, POINT *pts, int np)
462 HDC__ *c=(HDC__ *)ctx;
463 if (!HDC_VALID(c)||!HGDIOBJ_VALID(c->curpen,TYPE_PEN)||c->curpen->wid<0||np<3) return;
465 CGContextSetLineWidth(c->ctx,(float)max(c->curpen->wid,1));
466 CGContextSetStrokeColorWithColor(c->ctx,c->curpen->color);
468 CGContextBeginPath(c->ctx);
469 CGContextMoveToPoint(c->ctx,c->lastpos_x,c->lastpos_y);
472 for (x = 0; x < np-2; x += 3)
474 CGContextAddCurveToPoint(c->ctx,
475 (float)pts[x].x,(float)pts[x].y,
476 (float)pts[x+1].x,(float)pts[x+1].y,
477 xp=(float)pts[x+2].x,yp=(float)pts[x+2].y);
479 c->lastpos_x=(float)xp;
480 c->lastpos_y=(float)yp;
481 CGContextStrokePath(c->ctx);
485 void SWELL_LineTo(HDC ctx, int x, int y)
487 HDC__ *c=(HDC__ *)ctx;
488 if (!HDC_VALID(c)||!HGDIOBJ_VALID(c->curpen,TYPE_PEN)||c->curpen->wid<0) return;
490 float w = (float)max(c->curpen->wid,1);
491 CGContextSetLineWidth(c->ctx,w);
492 CGContextSetStrokeColorWithColor(c->ctx,c->curpen->color);
494 CGContextBeginPath(c->ctx);
495 CGContextMoveToPoint(c->ctx,c->lastpos_x + w * 0.5,c->lastpos_y + w*0.5);
496 float fx=(float)x,fy=(float)y;
498 CGContextAddLineToPoint(c->ctx,fx+w*0.5,fy+w*0.5);
501 CGContextStrokePath(c->ctx);
504 void PolyPolyline(HDC ctx, POINT *pts, DWORD *cnts, int nseg)
506 HDC__ *c=(HDC__ *)ctx;
507 if (!HDC_VALID(c)||!HGDIOBJ_VALID(c->curpen,TYPE_PEN)||c->curpen->wid<0||nseg<1) return;
509 float w = (float)max(c->curpen->wid,1);
510 CGContextSetLineWidth(c->ctx,w);
511 CGContextSetStrokeColorWithColor(c->ctx,c->curpen->color);
513 CGContextBeginPath(c->ctx);
519 if (!--cnt) { pts++; continue; }
521 CGContextMoveToPoint(c->ctx,(float)pts->x+w*0.5,(float)pts->y+w*0.5);
526 CGContextAddLineToPoint(c->ctx,(float)pts->x+w*0.5,(float)pts->y+w*0.5);
530 CGContextStrokePath(c->ctx);
532 void *SWELL_GetCtxGC(HDC ctx)
534 HDC__ *ct=(HDC__ *)ctx;
535 if (!HDC_VALID(ct)) return 0;
540 void SWELL_SetPixel(HDC ctx, int x, int y, int c)
542 HDC__ *ct=(HDC__ *)ctx;
543 if (!HDC_VALID(ct)) return;
544 CGContextBeginPath(ct->ctx);
545 CGContextMoveToPoint(ct->ctx,(float)x-0.5,(float)y-0.5);
546 CGContextAddLineToPoint(ct->ctx,(float)x+0.5,(float)y+0.5);
547 CGContextSetLineWidth(ct->ctx,(float)1.0);
548 CGContextSetRGBStrokeColor(ct->ctx,GetRValue(c)/255.0,GetGValue(c)/255.0,GetBValue(c)/255.0,1.0);
549 CGContextStrokePath(ct->ctx);
553 static WDL_Mutex s_fontnamecache_mutex;
555 #ifdef SWELL_CLEANUP_ON_UNLOAD
556 static void releaseString(NSString *s) { [s release]; }
558 static WDL_StringKeyedArray<NSString *> s_fontnamecache(true,
559 #ifdef SWELL_CLEANUP_ON_UNLOAD
566 static NSString *SWELL_GetCachedFontName(const char *nm)
568 NSString *ret = NULL;
571 s_fontnamecache_mutex.Enter();
572 ret = s_fontnamecache.Get(nm);
573 s_fontnamecache_mutex.Leave();
576 ret = CStringToNSString(nm);
579 #ifndef SWELL_NO_CORETEXT
580 // only do postscript name lookups on 10.9+
581 if (floor(NSFoundationVersionNumber) > 945.00) // NSFoundationVersionNumber10_8
583 NSFont *font = [NSFont fontWithName:ret size:10];
584 NSString *nr = font ? (NSString *)CTFontCopyPostScriptName((CTFontRef)font) : NULL;
593 s_fontnamecache_mutex.Enter();
594 s_fontnamecache.Insert(nm,ret);
595 s_fontnamecache_mutex.Leave();
599 return ret ? ret : @"";
602 HFONT CreateFont(int lfHeight, int lfWidth, int lfEscapement, int lfOrientation, int lfWeight, char lfItalic,
603 char lfUnderline, char lfStrikeOut, char lfCharSet, char lfOutPrecision, char lfClipPrecision,
604 char lfQuality, char lfPitchAndFamily, const char *lfFaceName)
606 HGDIOBJ__ *font=GDP_OBJECT_NEW();
607 font->type=TYPE_FONT;
608 float fontwid=lfHeight;
610 if (!fontwid) fontwid=lfWidth;
611 if (fontwid<0)fontwid=-fontwid;
613 if (fontwid < 2 || fontwid > 8192) fontwid=10;
615 font->font_rotation = lfOrientation/10.0;
617 #ifndef SWELL_NO_CORETEXT
618 if (IsCoreTextSupported())
621 lstrcpyn_safe(buf,lfFaceName,900);
622 if (lfWeight >= FW_BOLD) strcat(buf," Bold");
623 if (lfItalic) strcat(buf," Italic");
625 font->ct_FontRef = (void*)CTFontCreateWithName((CFStringRef)SWELL_GetCachedFontName(buf),fontwid,NULL);
626 if (!font->ct_FontRef) font->ct_FontRef = (void*)[[NSFont labelFontOfSize:fontwid] retain];
628 font->font_quality = (!lfQuality || lfQuality == ANTIALIASED_QUALITY || lfQuality == NONANTIALIASED_QUALITY ? lfQuality : 0);
630 // 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
635 #ifdef SWELL_ATSUI_TEXT_SUPPORT
636 ATSUFontID fontid=kATSUInvalidFontID;
637 if (lfFaceName && lfFaceName[0])
639 ATSUFindFontFromName(lfFaceName,strlen(lfFaceName),kFontFullName /* kFontFamilyName? */ ,(FontPlatformCode)kFontNoPlatform,kFontNoScriptCode,kFontNoLanguageCode,&fontid);
640 // if (fontid==kATSUInvalidFontID) printf("looked up %s and got %d\n",lfFaceName,fontid);
643 if (ATSUCreateStyle(&font->atsui_font_style) == noErr && font->atsui_font_style)
645 Fixed fsize=Long2Fix(fontwid);
647 Boolean isBold=lfWeight >= FW_BOLD;
648 Boolean isItal=!!lfItalic;
649 Boolean isUnder=!!lfUnderline;
651 ATSStyleRenderingOptions render;
653 render = kATSStyleNoOptions;
654 else if (lfQuality == ANTIALIASED_QUALITY)
655 render = kATSStyleApplyAntiAliasing;
656 else if (lfQuality == NONANTIALIASED_QUALITY)
657 render = kATSStyleNoAntiAliasing;
659 render = kATSStyleNoOptions;
661 ATSUAttributeTag theTags[] = { kATSUQDBoldfaceTag, kATSUQDItalicTag, kATSUQDUnderlineTag,kATSUSizeTag,kATSUFontTag, kATSUStyleRenderingOptionsTag };
662 ByteCount theSizes[] = { sizeof(Boolean),sizeof(Boolean),sizeof(Boolean), sizeof(Fixed),sizeof(ATSUFontID), sizeof(ATSStyleRenderingOptions) };
663 ATSUAttributeValuePtr theValues[] = {&isBold, &isItal, &isUnder, &fsize, &fontid, &render } ;
665 int attrcnt=sizeof(theTags)/sizeof(theTags[0]);
666 if (fontid == kATSUInvalidFontID) attrcnt--;
668 if (ATSUSetAttributes (font->atsui_font_style,
674 ATSUDisposeStyle(font->atsui_font_style);
675 font->atsui_font_style=0;
679 font->atsui_font_style=0;
687 int GetTextFace(HDC ctx, int nCount, LPTSTR lpFaceName)
689 HDC__ *ct=(HDC__*)ctx;
690 if (!HDC_VALID(ct) || !nCount || !lpFaceName) return 0;
692 #ifndef SWELL_NO_CORETEXT
694 if (HGDIOBJ_VALID(ct->curfont,TYPE_FONT)) fr=(CTFontRef)ct->curfont->ct_FontRef;
695 if (!fr) fr=GetCoreTextDefaultFont();
699 CFStringRef name=CTFontCopyDisplayName(fr);
700 const char* p=[(NSString*)name UTF8String];
703 lstrcpyn(lpFaceName, p, nCount);
704 return strlen(lpFaceName);
712 BOOL GetTextMetrics(HDC ctx, TEXTMETRIC *tm)
714 HDC__ *ct=(HDC__ *)ctx;
715 if (tm) // give some sane defaults
717 tm->tmInternalLeading=3;
721 tm->tmAveCharWidth = 10;
723 if (!HDC_VALID(ct)||!tm) return 0;
725 bool curfont_valid=HGDIOBJ_VALID(ct->curfont,TYPE_FONT);
727 #ifdef SWELL_ATSUI_TEXT_SUPPORT
728 if (curfont_valid && ct->curfont->atsui_font_style)
730 ATSUTextMeasurement ascent=Long2Fix(10);
731 ATSUTextMeasurement descent=Long2Fix(3);
732 ATSUTextMeasurement sz=Long2Fix(0);
733 ATSUTextMeasurement width =Long2Fix(12);
734 ATSUGetAttribute(ct->curfont->atsui_font_style, kATSUAscentTag, sizeof(ATSUTextMeasurement), &ascent,NULL);
735 ATSUGetAttribute(ct->curfont->atsui_font_style, kATSUDescentTag, sizeof(ATSUTextMeasurement), &descent,NULL);
736 ATSUGetAttribute(ct->curfont->atsui_font_style, kATSUSizeTag, sizeof(ATSUTextMeasurement), &sz,NULL);
737 ATSUGetAttribute(ct->curfont->atsui_font_style, kATSULineWidthTag, sizeof(ATSUTextMeasurement),&width,NULL);
739 float asc=Fix2X(ascent);
740 float desc=Fix2X(descent);
741 float size = Fix2X(sz);
743 if (size < (asc+desc)*0.2) size=asc+desc;
745 tm->tmAscent = (int)ceil(asc);
746 tm->tmDescent = (int)ceil(desc);
747 tm->tmInternalLeading=(int)ceil(asc+desc-size);
748 if (tm->tmInternalLeading<0)tm->tmInternalLeading=0;
749 tm->tmHeight=(int) ceil(asc+desc);
750 tm->tmAveCharWidth = (int) (ceil(asc+desc)*0.65); // (int)ceil(Fix2X(width));
756 #ifndef SWELL_NO_CORETEXT
757 CTFontRef fr = curfont_valid ? (CTFontRef)ct->curfont->ct_FontRef : NULL;
758 if (!fr) fr=GetCoreTextDefaultFont();
762 tm->tmInternalLeading = CTFontGetLeading(fr);
763 tm->tmAscent = CTFontGetAscent(fr);
764 tm->tmDescent = CTFontGetDescent(fr);
765 tm->tmHeight = (tm->tmInternalLeading + tm->tmAscent + tm->tmDescent);
766 tm->tmAveCharWidth = tm->tmHeight*2/3; // todo
768 if (tm->tmHeight) tm->tmHeight++;
780 #ifdef SWELL_ATSUI_TEXT_SUPPORT
782 static int DrawTextATSUI(HDC ctx, CFStringRef strin, RECT *r, int align, bool *err)
784 HDC__ *ct=(HDC__ *)ctx;
785 HGDIOBJ__ *font=ct->curfont; // caller must specify a valid font
787 UniChar strbuf[4096];
792 CFRange r = {0,CFStringGetLength(strin)};
793 if (r.length > 4095) r.length=4095;
794 strbuf_len=CFStringGetBytes(strin,r,kCFStringEncodingUTF16,' ',false,(UInt8*)strbuf,sizeof(strbuf)-2,NULL);
795 if (strbuf_len<0)strbuf_len=0;
796 else if (strbuf_len>4095) strbuf_len=4095;
797 strbuf[strbuf_len]=0;
801 ATSUAttributeTag theTags[] = { kATSUColorTag, };
802 ByteCount theSizes[] = { sizeof(RGBColor), };
805 ATSUAttributeValuePtr theValues[] = {&tcolor, } ;
807 tcolor.red = GetRValue(ct->cur_text_color_int)*256;
808 tcolor.green = GetGValue(ct->cur_text_color_int)*256;
809 tcolor.blue = GetBValue(ct->cur_text_color_int)*256;
811 // error check this? we can live with the wrong color maybe?
812 ATSUSetAttributes(font->atsui_font_style, sizeof(theTags)/sizeof(theTags[0]), theTags, theSizes, theValues);
815 UniCharCount runLengths[1]={kATSUToTextEnd};
816 ATSUTextLayout layout;
817 if (ATSUCreateTextLayoutWithTextPtr(strbuf, kATSUFromTextBeginning, kATSUToTextEnd, strbuf_len, 1, runLengths, &font->atsui_font_style, &layout)!=noErr)
824 Fixed frot = X2Fix(font->font_rotation);
826 ATSULineTruncation tv = (align & DT_END_ELLIPSIS) ? kATSUTruncateEnd : kATSUTruncateNone;
827 ATSUAttributeTag theTags[] = { kATSUCGContextTag, kATSULineTruncationTag, kATSULineRotationTag };
828 ByteCount theSizes[] = { sizeof (CGContextRef), sizeof(ATSULineTruncation), sizeof(Fixed)};
829 ATSUAttributeValuePtr theValues[] = { &ct->ctx, &tv, &frot } ;
832 if (ATSUSetLayoutControls (layout,
834 sizeof(theTags)/sizeof(theTags[0]),
843 ATSUDisposeTextLayout(layout);
849 ATSUTextMeasurement leftFixed, rightFixed, ascentFixed, descentFixed;
851 if (ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, kATSUToTextEnd, &leftFixed, &rightFixed, &ascentFixed, &descentFixed)!=noErr)
854 ATSUDisposeTextLayout(layout);
858 int w=Fix2Long(rightFixed);
859 int descent=Fix2Long(descentFixed);
860 int h=descent + Fix2Long(ascentFixed);
861 if (align&DT_CALCRECT)
863 ATSUDisposeTextLayout(layout);
868 CGContextSaveGState(ct->ctx);
870 if (!(align & DT_NOCLIP))
871 CGContextClipToRect(ct->ctx,CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top));
873 int l=r->left, t=r->top;
875 if (fabs(font->font_rotation)<45.0)
877 if (align & DT_RIGHT) l = r->right-w;
878 else if (align & DT_CENTER) l = (r->right+r->left)/2 - w/2;
880 else l+=Fix2Long(ascentFixed); // 90 degree special case (we should generalize this to be correct throughout the rotation range, but oh well)
882 if (align & DT_BOTTOM) t = r->bottom-h;
883 else if (align & DT_VCENTER) t = (r->bottom+r->top)/2 - h/2;
885 CGContextTranslateCTM(ct->ctx,0,t);
886 CGContextScaleCTM(ct->ctx,1,-1);
887 CGContextTranslateCTM(ct->ctx,0,-t-h);
889 if (ct->curbkmode == OPAQUE)
891 CGRect bgr = CGRectMake(l, t, w, h);
892 CGColorRef bgc = CreateColor(ct->curbkcol);
893 CGContextSetFillColorWithColor(ct->ctx, bgc);
894 CGContextFillRect(ct->ctx, bgr);
898 if (ATSUDrawText(layout,kATSUFromTextBeginning,kATSUToTextEnd,Long2Fix(l),Long2Fix(t+descent))!=noErr)
901 CGContextRestoreGState(ct->ctx);
903 ATSUDisposeTextLayout(layout);
910 int DrawText(HDC ctx, const char *buf, int buflen, RECT *r, int align)
912 HDC__ *ct=(HDC__ *)ctx;
913 if (!HDC_VALID(ct)) return 0;
919 while (*p && (op-tmp)<sizeof(tmp)-1 && (buflen<0 || (p-buf)<buflen))
921 if (*p == '&' && !(align&DT_NOPREFIX)) p++;
924 else if (*p == '\n' && (align&DT_SINGLELINE)) { *op++ = ' '; p++; }
927 if (*p == '\n') has_ml=true;
933 if (!tmp[0]) return 0; // dont draw empty strings
935 NSString *str=CStringToNSString(tmp);
939 bool curfont_valid = HGDIOBJ_VALID(ct->curfont,TYPE_FONT);
940 #ifdef SWELL_ATSUI_TEXT_SUPPORT
941 if (curfont_valid && ct->curfont->atsui_font_style)
944 int ret = DrawTextATSUI(ctx,(CFStringRef)str,r,align,&err);
947 if (!err) return ret;
952 #ifndef SWELL_NO_CORETEXT
953 CTFontRef fr = curfont_valid ? (CTFontRef)ct->curfont->ct_FontRef : NULL;
954 if (!fr) fr=GetCoreTextDefaultFont();
957 // Initialize string, font, and context
958 CFStringRef keys[] = { kCTFontAttributeName,kCTForegroundColorAttributeName };
959 CFTypeRef values[] = { fr,ct->curtextcol };
961 int nk= sizeof(keys) / sizeof(keys[0]);
962 if (!values[1]) nk--;
964 CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, (const void**)&values, nk,
965 &kCFTypeDictionaryKeyCallBacks,
966 &kCFTypeDictionaryValueCallBacks);
968 CFAttributedStringRef attrString =
969 CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)str, attributes);
970 CFRelease(attributes);
974 CTFrameRef frame = NULL;
975 CFArrayRef lines = NULL;
976 CTLineRef line = NULL;
978 int line_w=0,line_h=0;
981 CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);
984 CGMutablePathRef path=CGPathCreateMutable();
985 CGPathAddRect(path,NULL,CGRectMake(0,0,100000,100000));
986 frame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,0),path,NULL);
987 CFRelease(framesetter);
992 lines = CTFrameGetLines(frame);
993 int n=CFArrayGetCount(lines);
997 CTLineRef l = (CTLineRef)CFArrayGetValueAtIndex(lines,x);
1000 CGFloat asc=0,desc=0,lead=0;
1001 int w = (int) floor(CTLineGetTypographicBounds(l,&asc,&desc,&lead)+0.5);
1002 int h =(int) floor(asc+desc+lead+1.5);
1004 if (line_w < w) line_w=w;
1011 line = CTLineCreateWithAttributedString(attrString);
1015 CGFloat desc=0,lead=0;
1016 line_w = (int) floor(CTLineGetTypographicBounds(line,&asc,&desc,&lead)+0.5);
1017 line_h =(int) floor(asc+desc+lead+1.5);
1020 if (line_h) line_h++;
1022 CFRelease(attrString);
1024 if (align & DT_CALCRECT)
1026 r->right = r->left+line_w;
1027 r->bottom = r->top+line_h;
1028 if (line) CFRelease(line);
1029 if (frame) CFRelease(frame);
1033 float xo=r->left,yo=r->top;
1034 if (align & DT_RIGHT) xo += (r->right-r->left) - line_w;
1035 else if (align & DT_CENTER) xo += (r->right-r->left)/2 - line_w/2;
1037 if (align & DT_BOTTOM) yo += (r->bottom-r->top) - line_h;
1038 else if (align & DT_VCENTER) yo += (r->bottom-r->top)/2 - line_h/2;
1041 CGContextSaveGState(ct->ctx);
1043 CGAffineTransform f={1,0,0,-1,0,0};
1044 CGContextSetTextMatrix(ct->ctx, f);
1046 if (!(align & DT_NOCLIP))
1048 CGContextClipToRect(ct->ctx,CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top));
1051 CGColorRef bgc = NULL;
1052 if (ct->curbkmode == OPAQUE)
1054 bgc = CreateColor(ct->curbkcol);
1057 if (ct->curfont->font_quality)
1059 CGContextSetShouldAntialias(ct->ctx, ct->curfont->font_quality == ANTIALIASED_QUALITY);
1066 CGContextSetFillColorWithColor(ct->ctx, bgc);
1067 CGContextFillRect(ct->ctx, CGRectMake(xo,yo,line_w,line_h));
1069 CGContextSetTextPosition(ct->ctx, xo, yo + asc);
1070 CTLineDraw(line,ct->ctx);
1075 int n=CFArrayGetCount(lines);
1079 CTLineRef l = (CTLineRef)CFArrayGetValueAtIndex(lines,x);
1082 CGFloat asc=0,desc=0,lead=0;
1083 float lw=CTLineGetTypographicBounds(l,&asc,&desc,&lead);
1087 CGContextSetFillColorWithColor(ct->ctx, bgc);
1088 CGContextFillRect(ct->ctx, CGRectMake(xo,yo,lw,asc+desc+lead));
1090 CGContextSetTextPosition(ct->ctx, xo, yo + asc);
1091 CTLineDraw(l,ct->ctx);
1093 yo += floor(asc+desc+lead+0.5);
1099 CGContextRestoreGState(ct->ctx);
1100 if (bgc) CGColorRelease(bgc);
1101 if (line) CFRelease(line);
1102 if (frame) CFRelease(frame);
1118 void SetBkColor(HDC ctx, int col)
1120 HDC__ *ct=(HDC__ *)ctx;
1121 if (!HDC_VALID(ct)) return;
1125 void SetBkMode(HDC ctx, int col)
1127 HDC__ *ct=(HDC__ *)ctx;
1128 if (!HDC_VALID(ct)) return;
1132 int GetTextColor(HDC ctx)
1134 HDC__ *ct=(HDC__ *)ctx;
1135 if (!HDC_VALID(ct)) return -1;
1136 return ct->cur_text_color_int;
1139 void SetTextColor(HDC ctx, int col)
1141 HDC__ *ct=(HDC__ *)ctx;
1142 if (!HDC_VALID(ct)) return;
1143 ct->cur_text_color_int = col;
1145 if (ct->curtextcol) CFRelease(ct->curtextcol);
1147 ct->curtextcol = CreateColor(col);
1151 HICON CreateIconIndirect(ICONINFO* iconinfo)
1153 if (!iconinfo || !iconinfo->fIcon) return 0;
1154 HGDIOBJ__* i=iconinfo->hbmColor;
1155 if (!HGDIOBJ_VALID(i,TYPE_BITMAP) || !i->bitmapptr) return 0;
1156 NSImage* img=i->bitmapptr;
1159 HGDIOBJ__* icon=GDP_OBJECT_NEW();
1160 icon->type=TYPE_BITMAP;
1163 icon->bitmapptr=img;
1167 HICON LoadNamedImage(const char *name, bool alphaFromMask)
1170 NSString *str=CStringToNSString(name);
1171 if (strstr(name,"/"))
1173 img=[[NSImage alloc] initWithContentsOfFile:str];
1177 img=[NSImage imageNamed:str];
1178 if (img) [img retain];
1186 [img setFlipped:YES];
1189 const NSSize sz=[img size];
1190 const int w = (int)sz.width, h=(int)sz.height;
1192 if (w>0 && h>0 && NULL != (hdc=SWELL_CreateMemContext(NULL,w,h)))
1194 [NSGraphicsContext saveGraphicsState];
1195 NSGraphicsContext *gc=[NSGraphicsContext graphicsContextWithGraphicsPort:((struct HDC__*)hdc)->ctx flipped:NO];
1196 [NSGraphicsContext setCurrentContext:gc];
1197 [img drawInRect:NSMakeRect(0,0,w,h) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
1198 [NSGraphicsContext restoreGraphicsState];
1200 NSImage *newImage=[[NSImage alloc] initWithData:[img TIFFRepresentation]];
1201 [newImage setFlipped:YES];
1203 const int *fb = (const int *)SWELL_GetCtxFrameBuffer(hdc);
1205 [newImage lockFocus];
1206 CGContextRef myContext = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
1207 for (y=0; y < h; y ++)
1210 for (x = 0; x < w; x++)
1213 if ((*fb++ & 0xffffff) == 0xff00ff)
1215 if ((*fb++ & 0xffffff00) == 0xff00ff00)
1218 CGContextClearRect(myContext,CGRectMake(x,y,1,1));
1223 [newImage unlockFocus];
1225 SWELL_DeleteGfxContext(hdc);
1237 HGDIOBJ__ *i=GDP_OBJECT_NEW();
1238 i->type=TYPE_BITMAP;
1244 void DrawImageInRect(HDC ctx, HICON img, const RECT *r)
1246 HGDIOBJ__ *i = (HGDIOBJ__ *)img;
1247 HDC__ *ct=(HDC__*)ctx;
1248 if (!HDC_VALID(ct) || !HGDIOBJ_VALID(i,TYPE_BITMAP) || !i->bitmapptr) return;
1249 //CGContextDrawImage(ct->ctx,CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top),(CGImage*)i->bitmapptr);
1250 // probably a better way since this ignores the ctx
1251 [NSGraphicsContext saveGraphicsState];
1252 NSGraphicsContext *gc=[NSGraphicsContext graphicsContextWithGraphicsPort:ct->ctx flipped:NO];
1253 [NSGraphicsContext setCurrentContext:gc];
1254 NSImage *nsi=i->bitmapptr;
1255 NSRect rr=NSMakeRect(r->left,r->top,r->right-r->left,r->bottom-r->top);
1256 [nsi setFlipped:YES];
1257 [nsi drawInRect:rr fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
1258 [nsi setFlipped:NO]; // todo: restore old flippedness?
1259 [NSGraphicsContext restoreGraphicsState];
1264 BOOL GetObject(HICON icon, int bmsz, void *_bm)
1267 if (bmsz != sizeof(BITMAP)) return false;
1268 BITMAP *bm=(BITMAP *)_bm;
1269 HGDIOBJ__ *i = (HGDIOBJ__ *)icon;
1270 if (!HGDIOBJ_VALID(i,TYPE_BITMAP)) return false;
1271 NSImage *img = i->bitmapptr;
1272 if (!img) return false;
1273 bm->bmWidth = (int) ([img size].width+0.5);
1274 bm->bmHeight = (int) ([img size].height+0.5);
1279 void *GetNSImageFromHICON(HICON ico)
1281 HGDIOBJ__ *i = (HGDIOBJ__ *)ico;
1282 if (!HGDIOBJ_VALID(i,TYPE_BITMAP)) return 0;
1283 return i->bitmapptr;
1287 static int ColorFromNSColor(NSColor *color, int valifnul)
1289 if (!color) return valifnul;
1291 NSColor *color2=[color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
1294 NSLog(@"error converting colorspace from: %@\n",[color colorSpaceName]);
1298 [color2 getRed:&r green:&g blue:&b alpha:NULL];
1299 return RGB((int)(r*255.0),(int)(g*255.0),(int)(b*255.0));
1302 #define ColorFromNSColor(a,b) (b)
1304 int GetSysColor(int idx)
1306 // NSColors that seem to be valid: textBackgroundColor, selectedTextBackgroundColor, textColor, selectedTextColor
1310 case COLOR_WINDOW: return ColorFromNSColor([NSColor controlColor],RGB(192,192,192));
1312 case COLOR_BTNFACE: return ColorFromNSColor([NSColor controlColor],RGB(192,192,192));
1313 case COLOR_SCROLLBAR: return ColorFromNSColor([NSColor controlColor],RGB(32,32,32));
1314 case COLOR_3DSHADOW: return ColorFromNSColor([NSColor selectedTextBackgroundColor],RGB(96,96,96));
1315 case COLOR_3DHILIGHT: return ColorFromNSColor([NSColor selectedTextBackgroundColor],RGB(224,224,224));
1316 case COLOR_BTNTEXT: return ColorFromNSColor([NSColor selectedTextBackgroundColor],RGB(0,0,0));
1317 case COLOR_3DDKSHADOW: return (ColorFromNSColor([NSColor selectedTextBackgroundColor],RGB(96,96,96))>>1)&0x7f7f7f;
1318 case COLOR_INFOBK: return RGB(255,240,200);
1319 case COLOR_INFOTEXT: return RGB(0,0,0);
1326 void BitBlt(HDC hdcOut, int x, int y, int w, int h, HDC hdcIn, int xin, int yin, int mode)
1328 StretchBlt(hdcOut,x,y,w,h,hdcIn,xin,yin,w,h,mode);
1332 static void SWELL_fastDoubleUpImage(unsigned int *op, const unsigned int *ip, int w, int h, int sw, int newspan)
1337 const unsigned int *rd = ip;
1338 unsigned int *wr = op;
1341 #if 0 // def __AVX__
1342 // this isn't really any faster than SSE anyway
1345 if (!((INT_PTR)rd & 31))
1347 int x = remaining/8;
1350 const __m256 m = _mm256_load_ps((const float *)rd);
1353 const __m256 p1 = _mm256_permutevar_ps(_mm256_permute2f128_ps(m,m,0),_mm256_set_epi32(3,3,2,2,1,1,0,0));
1354 const __m256 p2 = _mm256_permutevar_ps(_mm256_permute2f128_ps(m,m,1|(1<<4)),_mm256_set_epi32(3,3,2,2,1,1,0,0));
1356 unsigned int *wr2 = wr+newspan;
1357 _mm256_store_ps((float*)wr,p1);
1358 _mm256_store_ps((float*)wr2,p1);
1360 _mm256_store_ps((float*)wr + 8,p2);
1361 _mm256_store_ps((float*)wr2 + 8,p2);
1374 // with SSE is about 2x faster than without
1375 if (((INT_PTR)rd & 7))
1377 // input isn't 8 byte aligned, must use unaligned reads
1378 int x = remaining/4;
1381 __m128 m = _mm_loadu_ps((const float *)rd);
1382 __m128 p1 = _mm_shuffle_ps(m,m,_MM_SHUFFLE(1,1,0,0));
1383 __m128 p2 = _mm_shuffle_ps(m,m,_MM_SHUFFLE(3,3,2,2));
1385 unsigned int *wr2 = wr+newspan;
1388 _mm_store_ps((float*)wr,p1);
1389 _mm_store_ps((float*)wr2,p1);
1391 _mm_store_ps((float*)wr + 4,p2);
1392 _mm_store_ps((float*)wr2 + 4,p2);
1399 // if rd is 8 byte aligned, we can do SSE without unaligned reads
1401 // but if it is not 16 byte aligned, we need to preprocess a pair of pixels
1402 // (advancing rd by 8 bytes, and wr by 16)
1404 if ((INT_PTR)rd & 15)
1406 unsigned int *nwr = wr+newspan;
1407 wr[0] = wr[1] = nwr[0] = nwr[1] = rd[0];
1408 wr[2] = wr[3] = nwr[2] = nwr[3] = rd[1];
1414 int x = remaining/4;
1417 __m128 m = _mm_load_ps((const float *)rd);
1418 __m128 p1 = _mm_shuffle_ps(m,m,_MM_SHUFFLE(1,1,0,0));
1419 __m128 p2 = _mm_shuffle_ps(m,m,_MM_SHUFFLE(3,3,2,2));
1421 unsigned int *wr2 = wr+newspan;
1424 _mm_store_ps((float*)wr,p1);
1425 _mm_store_ps((float*)wr2,p1);
1427 _mm_store_ps((float*)wr + 4,p2);
1428 _mm_store_ps((float*)wr2 + 4,p2);
1437 int x = remaining/2;
1440 unsigned int *nwr = wr+newspan;
1441 wr[0] = wr[1] = nwr[0] = nwr[1] = rd[0];
1442 wr[2] = wr[3] = nwr[2] = nwr[3] = rd[1];
1448 wr[0] = wr[1] = wr[newspan] = wr[newspan+1] = *rd;
1456 void StretchBlt(HDC hdcOut, int x, int y, int destw, int desth, HDC hdcIn, int xin, int yin, int w, int h, int mode)
1458 if (!hdcOut || !hdcIn||w<1||h<1) return;
1459 HDC__ *src=(HDC__*)hdcIn;
1460 HDC__ *dest=(HDC__*)hdcOut;
1461 if (!HDC_VALID(src) || !HDC_VALID(dest) || !src->ownedData || !src->ctx || !dest->ctx) return;
1463 if (w<1||h<1) return;
1465 int sw= CGBitmapContextGetWidth(src->ctx);
1466 int sh= CGBitmapContextGetHeight(src->ctx);
1483 if (xin+w > sw) w=sw-xin;
1484 if (yin+h > sh) h=sh-yin;
1486 if (w<1||h<1) return;
1488 if (destw==preclip_w) destw=w; // no scaling, keep width the same
1489 else if (w != preclip_w) destw = (w*destw)/preclip_w;
1491 if (desth == preclip_h) desth=h;
1492 else if (h != preclip_h) desth = (h*desth)/preclip_h;
1494 const bool use_alphachannel = mode == SRCCOPY_USEALPHACHAN;
1496 CGContextRef output = (CGContextRef)dest->ctx;
1497 CGRect outputr = CGRectMake(x,-desth-y,destw,desth);
1499 unsigned char *p = (unsigned char *)ALIGN_FBUF(src->ownedData);
1500 p += (xin + sw*yin)*4;
1503 #ifdef SWELL_SUPPORT_OPENGL_BLIT
1506 NSOpenGLContext *glCtx = (NSOpenGLContext*) dest->GLgfxctx;
1507 NSOpenGLContext *cCtx = [NSOpenGLContext currentContext];
1510 [glCtx makeCurrentContext];
1513 glDisable(GL_TEXTURE_2D);
1514 glEnable(GL_TEXTURE_RECTANGLE_EXT);
1517 glGenTextures(1, &texid);
1518 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, texid);
1519 glPixelStorei(GL_UNPACK_ROW_LENGTH, sw);
1520 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1521 glTexImage2D(GL_TEXTURE_RECTANGLE_EXT,0,GL_RGBA8,w,h,0,GL_BGRA,GL_UNSIGNED_INT_8_8_8_8, p);
1523 glClear(GL_COLOR_BUFFER_BIT);
1524 glViewport(x,[[glCtx view] bounds].size.height-h-y,w,h);
1527 glTexCoord2f(0.0f, 0.0f);
1530 glTexCoord2f(0.0f, h);
1536 glTexCoord2f(w, 0.0f);
1540 glDeleteTextures(1,&texid);
1543 if (glCtx != cCtx) [cCtx makeCurrentContext];
1549 // this is only faster when using the native color profile, it seems
1550 WDL_HeapBuf *retina_hb = NULL;
1551 unsigned char *retina_buf = NULL;
1553 if (destw == w && desth == h &&
1554 CGContextConvertSizeToDeviceSpace(output, CGSizeMake(1,1)).width > 1.9)
1556 const int newspan = (w*2+3)&~3;
1557 retina_hb = SWELL_GDP_GetTmpBuf();
1558 if (retina_hb && retina_hb->ResizeOK(sizeof(unsigned int) * newspan*h*2 + 32,false))
1560 retina_buf = (unsigned char *)retina_hb->Get();
1561 const UINT_PTR align = (UINT_PTR)retina_buf & 31;
1562 if (align) retina_buf += 32-align;
1564 SWELL_fastDoubleUpImage((unsigned int *)retina_buf,
1565 (const unsigned int *)p,w,h,sw,newspan);
1575 CGDataProviderRef provider = CGDataProviderCreateWithData(NULL,retina_buf ? retina_buf : p,4*sw*h,NULL);
1576 CGImageRef img = CGImageCreate(w,h,8,32,4*sw,__GetDisplayColorSpace(),
1577 use_alphachannel?kCGImageAlphaFirst:kCGImageAlphaNoneSkipFirst,
1578 provider,NULL,NO,kCGRenderingIntentDefault);
1579 CGDataProviderRelease(provider);
1583 CGContextSaveGState(output);
1584 CGContextScaleCTM(output,1.0,-1.0);
1586 CGContextSetInterpolationQuality(output,kCGInterpolationNone);
1587 CGContextDrawImage(output,outputr,img);
1588 CGContextRestoreGState(output);
1590 CGImageRelease(img);
1592 SWELL_GDP_DisposeTmpBuf(retina_hb);
1595 void SWELL_PushClipRegion(HDC ctx)
1597 HDC__ *ct=(HDC__ *)ctx;
1598 if (HDC_VALID(ct) && ct->ctx) CGContextSaveGState(ct->ctx);
1601 void SWELL_SetClipRegion(HDC ctx, const RECT *r)
1603 HDC__ *ct=(HDC__ *)ctx;
1604 if (HDC_VALID(ct) && ct->ctx) CGContextClipToRect(ct->ctx,CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top));
1608 void SWELL_PopClipRegion(HDC ctx)
1610 HDC__ *ct=(HDC__ *)ctx;
1611 if (HDC_VALID(ct) && ct->ctx) CGContextRestoreGState(ct->ctx);
1614 void *SWELL_GetCtxFrameBuffer(HDC ctx)
1616 HDC__ *ct=(HDC__ *)ctx;
1617 if (HDC_VALID(ct)) return ALIGN_FBUF(ct->ownedData);
1624 if (h && [(id)h isKindOfClass:[NSWindow class]])
1626 if ([(id)h respondsToSelector:@selector(getSwellPaintInfo:)])
1628 PAINTSTRUCT ps={0,};
1629 [(id)h getSwellPaintInfo:(PAINTSTRUCT *)&ps];
1632 if ((ps.hdc)->ctx) CGContextSaveGState((ps.hdc)->ctx);
1636 h=(HWND)[(id)h contentView];
1639 if (h && [(id)h isKindOfClass:[NSView class]])
1641 if ([(id)h respondsToSelector:@selector(getSwellPaintInfo:)])
1643 PAINTSTRUCT ps={0,};
1644 [(id)h getSwellPaintInfo:(PAINTSTRUCT *)&ps];
1645 if (HDC_VALID((HDC__*)ps.hdc))
1647 if (((HDC__*)ps.hdc)->ctx) CGContextSaveGState((ps.hdc)->ctx);
1652 if ([(NSView*)h lockFocusIfCanDraw])
1654 HDC ret= SWELL_CreateGfxContext([NSGraphicsContext currentContext]);
1657 if ((ret)->ctx) CGContextSaveGState((ret)->ctx);
1665 HDC GetWindowDC(HWND h)
1671 if ([(id)h isKindOfClass:[NSWindow class]]) v=[(id)h contentView];
1672 else if ([(id)h isKindOfClass:[NSView class]]) v=(NSView *)h;
1676 NSRect b=[v bounds];
1677 float xsc=b.origin.x;
1678 float ysc=b.origin.y;
1679 if ((xsc || ysc) && (ret)->ctx) CGContextTranslateCTM((ret)->ctx,xsc,ysc);
1685 void ReleaseDC(HWND h, HDC hdc)
1689 if ((hdc)->ctx) CGContextRestoreGState((hdc)->ctx);
1691 if (h && [(id)h isKindOfClass:[NSWindow class]])
1693 if ([(id)h respondsToSelector:@selector(getSwellPaintInfo:)])
1695 PAINTSTRUCT ps={0,};
1696 [(id)h getSwellPaintInfo:(PAINTSTRUCT *)&ps];
1697 if (ps.hdc && ps.hdc==hdc) return;
1699 h=(HWND)[(id)h contentView];
1701 bool isView=h && [(id)h isKindOfClass:[NSView class]];
1704 if ([(id)h respondsToSelector:@selector(getSwellPaintInfo:)])
1706 PAINTSTRUCT ps={0,};
1707 [(id)h getSwellPaintInfo:(PAINTSTRUCT *)&ps];
1708 if (ps.hdc && ps.hdc==hdc) return;
1712 if (hdc) SWELL_DeleteGfxContext(hdc);
1715 [(NSView *)h unlockFocus];
1716 // if ([(NSView *)h window]) [[(NSView *)h window] flushWindow];
1720 void SWELL_FillDialogBackground(HDC hdc, const RECT *r, int level)
1722 CGContextRef ctx=(CGContextRef)SWELL_GetCtxGC(hdc);
1725 // level 0 for now = this
1726 HIThemeSetFill(kThemeBrushDialogBackgroundActive,NULL,ctx,kHIThemeOrientationNormal);
1727 CGRect rect=CGRectMake(r->left,r->top,r->right-r->left,r->bottom-r->top);
1728 CGContextFillRect(ctx,rect);
1732 HGDIOBJ SWELL_CloneGDIObject(HGDIOBJ a)
1734 if (HGDIOBJ_VALID(a))
1736 a->additional_refcnt++;
1743 HBITMAP CreateBitmap(int width, int height, int numplanes, int bitsperpixel, unsigned char* bits)
1745 int spp = bitsperpixel/8;
1746 Boolean hasa = (bitsperpixel == 32);
1747 Boolean hasp = (numplanes > 1); // won't actually work yet for planar data
1748 NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:0 pixelsWide:width pixelsHigh:height
1749 bitsPerSample:8 samplesPerPixel:spp
1750 hasAlpha:hasa isPlanar:hasp
1751 colorSpaceName:NSDeviceRGBColorSpace
1752 bitmapFormat:NSAlphaFirstBitmapFormat
1753 bytesPerRow:0 bitsPerPixel:0];
1755 unsigned char* p = [rep bitmapData];
1756 int pspan = [rep bytesPerRow]; // might not be the same as width
1759 for (y=0;y<height;y ++)
1761 memcpy(p,bits,width*4);
1766 NSImage* img = [[NSImage alloc] init];
1767 [img addRepresentation:rep];
1770 HGDIOBJ__* obj = GDP_OBJECT_NEW();
1771 obj->type = TYPE_BITMAP;
1772 obj->wid = 1; // need free
1773 obj->bitmapptr = img;
1778 HIMAGELIST ImageList_CreateEx()
1780 return (HIMAGELIST)new WDL_PtrList<HGDIOBJ__>;
1783 BOOL ImageList_Remove(HIMAGELIST list, int idx)
1785 WDL_PtrList<HGDIOBJ__>* imglist=(WDL_PtrList<HGDIOBJ__>*)list;
1786 if (imglist && idx < imglist->GetSize())
1790 int x,n=imglist->GetSize();
1793 HGDIOBJ__ *a = imglist->Get(x);
1794 if (a) DeleteObject(a);
1800 HGDIOBJ__ *a = imglist->Get(idx);
1801 imglist->Set(idx, NULL);
1802 if (a) DeleteObject(a);
1810 void ImageList_Destroy(HIMAGELIST list)
1813 ImageList_Remove(list, -1);
1814 delete (WDL_PtrList<HGDIOBJ__>*)list;
1817 int ImageList_ReplaceIcon(HIMAGELIST list, int offset, HICON image)
1819 if (!image || !list) return -1;
1820 WDL_PtrList<HGDIOBJ__> *l=(WDL_PtrList<HGDIOBJ__> *)list;
1822 HGDIOBJ__ *imgsrc = (HGDIOBJ__*)image;
1823 if (!HGDIOBJ_VALID(imgsrc,TYPE_BITMAP)) return -1;
1825 HGDIOBJ__* icon=GDP_OBJECT_NEW();
1826 icon->type=TYPE_BITMAP;
1828 icon->bitmapptr = imgsrc->bitmapptr; // no need to duplicate it, can just retain a copy
1829 [icon->bitmapptr retain];
1830 image = (HICON) icon;
1832 if (offset<0||offset>=l->GetSize())
1835 offset=l->GetSize()-1;
1839 HICON old=l->Get(offset);
1840 l->Set(offset,image);
1841 if (old) DeleteObject(old);