2009-07-08 21:43:14 -07:00
# include <u.h>
# define Point OSXPoint
# define Rect OSXRect
# define Cursor OSXCursor
# include <Carbon/Carbon.h>
# undef Rect
# undef Point
# undef Cursor
# undef offsetof
# undef nil
# include <libc.h>
# include <draw.h>
# include <memdraw.h>
# include "a.h"
extern void CGFontGetGlyphsForUnichars ( CGFontRef , const UniChar [ ] , const CGGlyph [ ] , size_t ) ;
2012-12-03 15:55:13 -05:00
int
mapUnicode ( int i )
{
switch ( i ) {
case ' \' ' :
return 0x2019 ;
case ' ` ' :
return 0x2018 ;
}
return i ;
}
2009-07-08 21:43:14 -07:00
char *
mac2c ( CFStringRef s )
{
char * p ;
int n ;
n = CFStringGetLength ( s ) * 8 ;
p = malloc ( n ) ;
CFStringGetCString ( s , p , n , kCFStringEncodingUTF8 ) ;
return p ;
}
CFStringRef
c2mac ( char * p )
{
return CFStringCreateWithBytes ( nil , ( uchar * ) p , strlen ( p ) , kCFStringEncodingUTF8 , false ) ;
}
Rectangle
mac2r ( CGRect r , int size , int unit )
{
Rectangle rr ;
rr . min . x = r . origin . x * size / unit ;
rr . min . y = r . origin . y * size / unit ;
rr . max . x = ( r . origin . x + r . size . width ) * size / unit + 0.99999999 ;
rr . max . y = ( r . origin . x + r . size . width ) * size / unit + 0.99999999 ;
return rr ;
}
void
loadfonts ( void )
{
int i , n ;
CTFontCollectionRef allc ;
CFArrayRef array ;
CFStringRef s ;
CTFontDescriptorRef f ;
allc = CTFontCollectionCreateFromAvailableFonts ( 0 ) ;
array = CTFontCollectionCreateMatchingFontDescriptors ( allc ) ;
n = CFArrayGetCount ( array ) ;
xfont = emalloc9p ( n * sizeof xfont [ 0 ] ) ;
for ( i = 0 ; i < n ; i + + ) {
f = ( void * ) CFArrayGetValueAtIndex ( array , i ) ;
if ( f = = nil )
continue ;
s = CTFontDescriptorCopyAttribute ( f , kCTFontNameAttribute ) ;
xfont [ nxfont ] . name = mac2c ( s ) ;
CFRelease ( s ) ;
nxfont + + ;
}
}
2015-02-16 23:58:22 -05:00
// Some representative text to try to discern line heights.
static char * lines [ ] = {
" ABCDEFGHIJKLMNOPQRSTUVWXYZ " ,
" abcdefghijklmnopqrstuvwxyz " ,
" g " ,
" ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει. " ,
" 私はガラスを食べられます。それは私を傷つけません。 " ,
" Aš galiu valgyti stiklą ir jis manęs nežeidžia " ,
" Môžem jesť sklo. Nezraní ma. " ,
} ;
static void
fontheight ( XFont * f , int size , int * height , int * ascent )
2009-07-08 21:43:14 -07:00
{
2015-02-16 23:58:22 -05:00
int i ;
CFStringRef s ;
2009-07-08 21:43:14 -07:00
CGRect bbox ;
2015-02-16 23:58:22 -05:00
CTFontRef font ;
CTFontDescriptorRef desc ;
CGContextRef ctxt ;
CGColorSpaceRef color ;
s = c2mac ( f - > name ) ;
desc = CTFontDescriptorCreateWithNameAndSize ( s , size ) ;
CFRelease ( s ) ;
if ( desc = = nil )
return ;
font = CTFontCreateWithFontDescriptor ( desc , 0 , nil ) ;
CFRelease ( desc ) ;
if ( font = = nil )
return ;
2009-07-08 21:43:14 -07:00
2015-02-16 23:58:22 -05:00
color = CGColorSpaceCreateWithName ( kCGColorSpaceGenericGray ) ;
ctxt = CGBitmapContextCreate ( nil , 1 , 1 , 8 , 1 , color , kCGImageAlphaNone ) ;
CGColorSpaceRelease ( color ) ;
CGContextSetTextPosition ( ctxt , 0 , 0 ) ;
2009-07-08 21:43:14 -07:00
2015-02-16 23:58:22 -05:00
for ( i = 0 ; i < nelem ( lines ) ; i + + ) {
CFStringRef keys [ ] = { kCTFontAttributeName } ;
CFTypeRef values [ ] = { font } ;
CFStringRef str ;
CFDictionaryRef attrs ;
CFAttributedStringRef attrString ;
2009-07-08 21:43:14 -07:00
CGRect r ;
2015-02-16 23:58:22 -05:00
CTLineRef line ;
2009-07-08 21:43:14 -07:00
2015-02-16 23:58:22 -05:00
str = c2mac ( lines [ i ] ) ;
// See https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW2
attrs = CFDictionaryCreate ( kCFAllocatorDefault , ( const void * * ) & keys ,
( const void * * ) & values , sizeof ( keys ) / sizeof ( keys [ 0 ] ) ,
& kCFTypeDictionaryKeyCallBacks ,
& kCFTypeDictionaryValueCallBacks ) ;
attrString = CFAttributedStringCreate ( kCFAllocatorDefault , str , attrs ) ;
CFRelease ( str ) ;
CFRelease ( attrs ) ;
2009-07-08 21:43:14 -07:00
2015-02-16 23:58:22 -05:00
line = CTLineCreateWithAttributedString ( attrString ) ;
r = CTLineGetImageBounds ( line , ctxt ) ;
2009-07-08 21:43:14 -07:00
r . size . width + = r . origin . x ;
r . size . height + = r . origin . y ;
2015-02-16 23:58:22 -05:00
CFRelease ( line ) ;
// fprint(2, "%s: %g %g %g %g\n", lines[i], r.origin.x, r.origin.y, r.size.width, r.size.height);
if ( i = = 0 )
2009-07-08 21:43:14 -07:00
bbox = r ;
if ( bbox . origin . x > r . origin . x )
bbox . origin . x = r . origin . x ;
if ( bbox . origin . y > r . origin . y )
bbox . origin . y = r . origin . y ;
if ( bbox . size . width < r . size . width )
bbox . size . width = r . size . width ;
if ( bbox . size . height < r . size . height )
bbox . size . height = r . size . height ;
}
2015-02-16 23:58:22 -05:00
2009-07-08 21:43:14 -07:00
bbox . size . width - = bbox . origin . x ;
bbox . size . height - = bbox . origin . y ;
2015-02-16 23:58:22 -05:00
* height = bbox . size . height + 0.999999 ;
* ascent = * height - ( - bbox . origin . y + 0.999999 ) ;
CGContextRelease ( ctxt ) ;
CFRelease ( font ) ;
2009-07-08 21:43:14 -07:00
}
void
load ( XFont * f )
{
2015-02-16 23:58:22 -05:00
int i ;
2009-07-08 21:43:14 -07:00
if ( f - > loaded )
return ;
f - > loaded = 1 ;
2015-02-16 23:58:22 -05:00
// compute height and ascent for each size on demand
f - > loadheight = fontheight ;
// enable all Unicode ranges
for ( i = 0 ; i < nelem ( f - > range ) ; i + + ) {
f - > range [ i ] = 1 ;
f - > nrange + + ;
2009-07-08 21:43:14 -07:00
}
}
Memsubfont *
2015-02-16 23:58:22 -05:00
mksubfont ( XFont * f , char * name , int lo , int hi , int size , int antialias )
2009-07-08 21:43:14 -07:00
{
CFStringRef s ;
CGColorSpaceRef color ;
CGContextRef ctxt ;
2015-02-16 23:58:22 -05:00
CTFontRef font ;
CTFontDescriptorRef desc ;
2009-07-08 21:43:14 -07:00
CGRect bbox ;
Memimage * m , * mc , * m1 ;
int x , y , y0 ;
2015-02-16 23:58:22 -05:00
int i , height , ascent ;
2009-07-08 21:43:14 -07:00
Fontchar * fc , * fc0 ;
Memsubfont * sf ;
2015-02-16 23:58:22 -05:00
CGFloat whitef [ ] = { 1.0 , 1.0 } ;
CGColorRef white ;
2009-07-08 21:43:14 -07:00
s = c2mac ( name ) ;
2015-02-16 23:58:22 -05:00
desc = CTFontDescriptorCreateWithNameAndSize ( s , size ) ;
2009-07-08 21:43:14 -07:00
CFRelease ( s ) ;
2015-02-16 23:58:22 -05:00
if ( desc = = nil )
return nil ;
font = CTFontCreateWithFontDescriptor ( desc , 0 , nil ) ;
CFRelease ( desc ) ;
2009-07-08 21:43:14 -07:00
if ( font = = nil )
return nil ;
2015-02-16 23:58:22 -05:00
bbox = CTFontGetBoundingBox ( font ) ;
x = ( int ) ( bbox . size . width + 0.99999999 ) ;
fontheight ( f , size , & height , & ascent ) ;
y = height ;
y0 = height - ascent ;
2012-11-25 22:45:32 -05:00
m = allocmemimage ( Rect ( 0 , 0 , x * ( hi + 1 - lo ) + 1 , y + 1 ) , GREY8 ) ;
2009-07-08 21:43:14 -07:00
if ( m = = nil )
return nil ;
2012-11-25 22:45:32 -05:00
mc = allocmemimage ( Rect ( 0 , 0 , x + 1 , y + 1 ) , GREY8 ) ;
2009-07-08 21:43:14 -07:00
if ( mc = = nil )
return nil ;
memfillcolor ( m , DBlack ) ;
memfillcolor ( mc , DBlack ) ;
fc = malloc ( ( hi + 2 - lo ) * sizeof fc [ 0 ] ) ;
sf = malloc ( sizeof * sf ) ;
if ( fc = = nil | | sf = = nil ) {
freememimage ( m ) ;
freememimage ( mc ) ;
free ( fc ) ;
free ( sf ) ;
return nil ;
}
fc0 = fc ;
color = CGColorSpaceCreateWithName ( kCGColorSpaceGenericGray ) ;
ctxt = CGBitmapContextCreate ( byteaddr ( mc , mc - > r . min ) , Dx ( mc - > r ) , Dy ( mc - > r ) , 8 ,
mc - > width * sizeof ( u32int ) , color , kCGImageAlphaNone ) ;
2015-02-16 23:58:22 -05:00
white = CGColorCreate ( color , whitef ) ;
2009-07-08 21:43:14 -07:00
CGColorSpaceRelease ( color ) ;
if ( ctxt = = nil ) {
freememimage ( m ) ;
freememimage ( mc ) ;
free ( fc ) ;
free ( sf ) ;
return nil ;
}
CGContextSetAllowsAntialiasing ( ctxt , antialias ) ;
CGContextSetTextPosition ( ctxt , 0 , 0 ) ; // XXX
x = 0 ;
for ( i = lo ; i < = hi ; i + + , fc + + ) {
2015-02-16 23:58:22 -05:00
char buf [ 20 ] ;
CFStringRef str ;
CFDictionaryRef attrs ;
CFAttributedStringRef attrString ;
CTLineRef line ;
CGRect r ;
2009-07-08 21:43:14 -07:00
CGPoint p1 ;
2015-02-16 23:58:22 -05:00
CFStringRef keys [ ] = { kCTFontAttributeName , kCTForegroundColorAttributeName } ;
CFTypeRef values [ ] = { font , white } ;
sprint ( buf , " %C " , ( Rune ) mapUnicode ( i ) ) ;
str = c2mac ( buf ) ;
// See https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/CoreText_Programming/LayoutOperations/LayoutOperations.html#//apple_ref/doc/uid/TP40005533-CH12-SW2
attrs = CFDictionaryCreate ( kCFAllocatorDefault , ( const void * * ) & keys ,
( const void * * ) & values , sizeof ( keys ) / sizeof ( keys [ 0 ] ) ,
& kCFTypeDictionaryKeyCallBacks ,
& kCFTypeDictionaryValueCallBacks ) ;
attrString = CFAttributedStringCreate ( kCFAllocatorDefault , str , attrs ) ;
CFRelease ( str ) ;
CFRelease ( attrs ) ;
line = CTLineCreateWithAttributedString ( attrString ) ;
CGContextSetTextPosition ( ctxt , 0 , y0 ) ;
r = CTLineGetImageBounds ( line , ctxt ) ;
memfillcolor ( mc , DBlack ) ;
CTLineDraw ( line , ctxt ) ;
CFRelease ( line ) ;
2009-07-08 21:43:14 -07:00
fc - > x = x ;
fc - > top = 0 ;
fc - > bottom = Dy ( m - > r ) ;
2015-02-16 23:58:22 -05:00
// fprint(2, "printed %#x: %g %g\n", mapUnicode(i), p1.x, p1.y);
p1 = CGContextGetTextPosition ( ctxt ) ;
if ( p1 . x < = 0 | | mapUnicode ( i ) = = 0xfffd ) {
2009-07-08 21:43:14 -07:00
fc - > width = 0 ;
2012-12-01 00:35:06 -05:00
fc - > left = 0 ;
2009-07-08 21:43:14 -07:00
if ( i = = 0 ) {
2015-02-16 23:58:22 -05:00
drawpjw ( m , fc , x , ( int ) ( bbox . size . width + 0.99999999 ) , y , y - y0 ) ;
2012-12-01 00:35:06 -05:00
x + = fc - > width ;
2009-07-08 21:43:14 -07:00
}
continue ;
}
2015-02-16 23:58:22 -05:00
2009-07-08 21:43:14 -07:00
memimagedraw ( m , Rect ( x , 0 , x + p1 . x , y ) , mc , ZP , memopaque , ZP , S ) ;
fc - > width = p1 . x ;
fc - > left = 0 ;
x + = p1 . x ;
}
fc - > x = x ;
// round up to 32-bit boundary
// so that in-memory data is same
// layout as in-file data.
2012-11-25 22:45:32 -05:00
if ( x = = 0 )
x = 1 ;
if ( y = = 0 )
y = 1 ;
2009-07-08 21:43:14 -07:00
if ( antialias )
x + = - x & 3 ;
else
x + = - x & 31 ;
m1 = allocmemimage ( Rect ( 0 , 0 , x , y ) , antialias ? GREY8 : GREY1 ) ;
memimagedraw ( m1 , m1 - > r , m , m - > r . min , memopaque , ZP , S ) ;
freememimage ( m ) ;
sf - > name = nil ;
sf - > n = hi + 1 - lo ;
sf - > height = Dy ( m1 - > r ) ;
sf - > ascent = Dy ( m1 - > r ) - y0 ;
sf - > info = fc0 ;
sf - > bits = m1 ;
return sf ;
}