X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=OSX%2Fjwxyz.m;h=78a9bc56043bbf7bf8eac7d2601e37aa4eff1831;hp=330d0632adfab3a5d34fe4f39daf074629c5d0e0;hb=d5186197bc394e10a4402f7f6d23fbb14103bc50;hpb=6afd6db0ae9396cd7ff897ade597cd5483f49b0e diff --git a/OSX/jwxyz.m b/OSX/jwxyz.m index 330d0632..78a9bc56 100644 --- a/OSX/jwxyz.m +++ b/OSX/jwxyz.m @@ -47,6 +47,7 @@ #import "jwxyz.h" #import "jwxyz-timers.h" #import "yarandom.h" +#import "utf8wc.h" # define USE_BACKBUFFER /* must be in sync with XScreenSaverView.h */ @@ -116,6 +117,10 @@ struct jwxyz_Font { XFontStruct metrics; }; +struct jwxyz_XFontSet { + Font font; +}; + /* Instead of calling abort(), throw a real exception, so that XScreenSaverView can catch it and display a dialog. @@ -2477,7 +2482,8 @@ copy_pixmap (Display *dpy, Pixmap p) "rbearing" is the distance from the logical origin to the rightmost pixel. "descent" is the distance from the logical origin to the bottommost pixel. - For characters with descenders, it is negative. + For characters with descenders, it is positive. For superscripts, it + is negative. "ascent" is the distance from the logical origin to the topmost pixel. It is the number of pixels above the baseline. @@ -2490,6 +2496,46 @@ copy_pixmap (Display *dpy, Pixmap p) */ +static void +glyph_metrics (CTFontRef ctfont, CGGlyph cgglyph, XCharStruct *cs) +{ + CGRect bbox = CTFontGetBoundingRectsForGlyphs (ctfont, + kCTFontDefaultOrientation, + &cgglyph, NULL, 1); + CGSize advancement; + CTFontGetAdvancesForGlyphs (ctfont, kCTFontDefaultOrientation, + &cgglyph, &advancement, 1); + +# ifndef USE_IPHONE + // Only necessary for when LCD smoothing is enabled, which iOS doesn't do. + bbox.origin.x -= 2.0/3.0; + bbox.size.width += 4.0/3.0; + bbox.size.height += 1.0/2.0; +# endif + +//#define CEIL(F) ((F) < 0 ? floor(F) : ceil(F)) +//#define FLOOR(F) ((F) < 0 ? ceil(F) : floor(F)) +#define CEIL(F) ceil(F) +#define FLOOR(F) floor(F) + + /* Now that we know the advancement and bounding box, we can compute + the lbearing and rbearing. + */ +//cs->ascent = CEIL (bbox.origin.y) + CEIL (bbox.size.height); + cs->ascent = CEIL (bbox.origin.y + bbox.size.height); + cs->descent = CEIL(-bbox.origin.y); + cs->lbearing = FLOOR (bbox.origin.x); +//cs->rbearing = CEIL (bbox.origin.x) + CEIL (bbox.size.width); + cs->rbearing = CEIL (bbox.origin.x + bbox.size.width); + cs->width = FLOOR (advancement.width + 0.5); + + // Assert (cs->rbearing - cs->lbearing == CEIL(bbox.size.width), + // "bbox w wrong"); + // Assert (cs->ascent + cs->descent == CEIL(bbox.size.height), + // "bbox h wrong"); +} + + // This is XQueryFont, but for the XFontStruct embedded in 'Font' // static void @@ -2511,11 +2557,6 @@ query_font (Font fid) XCharStruct *min = &f->min_bounds; XCharStruct *max = &f->max_bounds; -//#define CEIL(F) ((F) < 0 ? floor(F) : ceil(F)) -//#define FLOOR(F) ((F) < 0 ? ceil(F) : floor(F)) -#define CEIL(F) ceil(F) -#define FLOOR(F) floor(F) - f->fid = fid; f->min_char_or_byte2 = first; f->max_char_or_byte2 = last; @@ -2539,8 +2580,7 @@ query_font (Font fid) Assert (ctfont, @"no CTFontRef for UIFont"); for (i = first; i <= last; i++) { - CGSize advancement = CGSizeMake (0, 0); - CGRect bbox = CGRectMake (0, 0, 0, 0); + XCharStruct *cs = &f->per_char[i-first]; /* There is no way to get "lbearing", "rbearing" or "descent" out of NSFont. 'sizeWithFont' gives us "width" and "height" only. @@ -2554,18 +2594,10 @@ query_font (Font fid) CGGlyph cgglyph = 0; if (CTFontGetGlyphsForCharacters (ctfont, &i, &cgglyph, 1)) - { - bbox = CTFontGetBoundingRectsForGlyphs (ctfont, - kCTFontDefaultOrientation, - &cgglyph, NULL, 1); - CTFontGetAdvancesForGlyphs (ctfont, kCTFontDefaultOrientation, - &cgglyph, &advancement, 1); - } + glyph_metrics (ctfont, cgglyph, cs); else - { - // This is normal, since Latin1 does not encode 0-31 or 127-159. - // NSLog (@"no glyph for character %d\n", i); - } + // This is normal, since Latin1 does not encode 0-31 or 127-159. + memset (cs, 0, sizeof(*cs)); # if 0 if (i == 224) { // Latin1 == "agrave", MacRoman == "daggerdouble". @@ -2580,32 +2612,7 @@ query_font (Font fid) cgglyph); Assert ([glyph_name isEqualToString:@"uacute"], @"wrong encoding"); } -# endif // 9 - -# ifndef USE_IPHONE - // Only necessary for when LCD smoothing is enabled, which iOS doesn't do. - bbox.origin.x -= 2.0/3.0; - bbox.size.width += 4.0/3.0; - bbox.size.height += 1.0/2.0; -# endif - - /* Now that we know the advancement and bounding box, we can compute - the lbearing and rbearing. - */ - XCharStruct *cs = &f->per_char[i-first]; - -// cs->ascent = CEIL (bbox.origin.y) + CEIL (bbox.size.height); - cs->ascent = CEIL (bbox.origin.y + bbox.size.height); - cs->descent = CEIL(-bbox.origin.y); - cs->lbearing = FLOOR (bbox.origin.x); -// cs->rbearing = CEIL (bbox.origin.x) + CEIL (bbox.size.width); - cs->rbearing = CEIL (bbox.origin.x + bbox.size.width); - cs->width = FLOOR (advancement.width + 0.5); - -// Assert (cs->rbearing - cs->lbearing == CEIL(bbox.size.width), -// "bbox w wrong"); -// Assert (cs->ascent + cs->descent == CEIL(bbox.size.height), -// "bbox h wrong"); +# endif // 0 max->width = MAX (max->width, cs->width); max->ascent = MAX (max->ascent, cs->ascent); @@ -3061,14 +3068,57 @@ XSetFont (Display *dpy, GC gc, Font fid) return 0; } + +XFontSet +XCreateFontSet (Display *dpy, char *name, + char ***missing_charset_list_return, + int *missing_charset_count_return, + char **def_string_return) +{ + char *name2 = strdup (name); + char *s = strchr (name, ","); + if (s) *s = 0; + XFontSet set = 0; + Font f = XLoadFont (dpy, name2); + if (f) + { + set = (XFontSet) calloc (1, sizeof(*set)); + set->font = f; + } + free (name2); + if (missing_charset_list_return) *missing_charset_list_return = 0; + if (missing_charset_count_return) *missing_charset_count_return = 0; + if (def_string_return) *def_string_return = 0; + return set; +} + + +void +XFreeFontSet (Display *dpy, XFontSet set) +{ + XUnloadFont (dpy, set->font); + free (set); +} + + +void +XFreeStringList (char **list) +{ + int i; + if (!list) return; + for (i = 0; list[i]; i++) + XFree (list[i]); + XFree (list); +} + + int XTextExtents (XFontStruct *f, const char *s, int length, int *dir_ret, int *ascent_ret, int *descent_ret, XCharStruct *cs) { memset (cs, 0, sizeof(*cs)); - int i; - for (i = 0; i < length; i++) { + for (int i = 0; i < length; i++) { unsigned char c = (unsigned char) s[i]; if (c < f->min_char_or_byte2 || c > f->max_char_or_byte2) c = f->default_char; @@ -3099,24 +3149,118 @@ XTextWidth (XFontStruct *f, const char *s, int length) } -static int -draw_string (Display *dpy, Drawable d, GC gc, int x, int y, - const char *str, int len, BOOL clear_background_p) +int +XTextExtents16 (XFontStruct *f, const XChar2b *s, int length, + int *dir_ret, int *ascent_ret, int *descent_ret, + XCharStruct *cs) { - if (clear_background_p) { - int ascent, descent, dir; + Font fid = f->fid; + CTFontRef ctfont = + CTFontCreateWithName ((CFStringRef) [fid->nsfont fontName], + [fid->nsfont pointSize], + NULL); + Assert (ctfont, @"no CTFontRef for UIFont"); + + int utf8_len = 0; + char *utf8 = XChar2b_to_utf8 (s, &utf8_len); + NSString *nsstr = [NSString stringWithCString:utf8 + encoding:NSUTF8StringEncoding]; + NSUInteger L = [nsstr length]; + + for (int i = 0; i < L; i++) { + unichar c = [nsstr characterAtIndex:i]; + XCharStruct cc; + CGGlyph cgglyph = 0; + + if (CTFontGetGlyphsForCharacters (ctfont, &c, &cgglyph, 1)) + glyph_metrics (ctfont, cgglyph, &cc); + else + // This is normal, since Latin1 does not encode 0-31 or 127-159. + memset (&cc, 0, sizeof(cc)); + + if (i == 0) { + *cs = cc; + } else { + cs->ascent = MAX (cs->ascent, cc.ascent); + cs->descent = MAX (cs->descent, cc.descent); + cs->lbearing = MIN (cs->lbearing, cs->width + cc.lbearing); + cs->rbearing = MAX (cs->rbearing, cs->width + cc.rbearing); + cs->width += cc.width; + } + } + *dir_ret = 0; + *ascent_ret = f->ascent; + *descent_ret = f->descent; + + free (utf8); + CFRelease (ctfont); + + return 0; +} + + +int +Xutf8TextExtents (XFontSet set, const char *str, int num_bytes, + XRectangle *overall_ink_return, + XRectangle *overall_logical_return) +{ + Font fid = set->font; + CTFontRef ctfont = + CTFontCreateWithName ((CFStringRef) [fid->nsfont fontName], + [fid->nsfont pointSize], + NULL); + Assert (ctfont, @"no CTFontRef for UIFont"); + + NSString *nsstr = [NSString stringWithCString:str + encoding:NSUTF8StringEncoding]; + NSUInteger L = [nsstr length]; + + XRectangle ink = { 0, }; + XRectangle logical = { 0, }; + + logical.height = fid->metrics.ascent; + + for (int i = 0; i < L; i++) { + unichar c = [nsstr characterAtIndex:i]; XCharStruct cs; - XTextExtents (&gc->gcv.font->metrics, str, len, - &dir, &ascent, &descent, &cs); - draw_rect (dpy, d, gc, - x + MIN (0, cs.lbearing), - y - MAX (0, ascent), - MAX (MAX (0, cs.rbearing) - - MIN (0, cs.lbearing), - cs.width), - MAX (0, ascent) + MAX (0, descent), - NO, YES); + CGGlyph cgglyph = 0; + + if (CTFontGetGlyphsForCharacters (ctfont, &c, &cgglyph, 1)) + glyph_metrics (ctfont, cgglyph, &cs); + else + // This is normal, since Latin1 does not encode 0-31 or 127-159. + memset (&cs, 0, sizeof(cs)); + + logical.width += cs.width; + + ink.height = MAX(ink.height, cs.ascent); + ink.y = MIN(ink.y, cs.descent); + + if (i == 0) + ink.x = cs.lbearing; + + if (i == L-1) { + ink.width += cs.rbearing; + } else { + ink.width += cs.width; + } } + + CFRelease (ctfont); + + if (overall_ink_return) + *overall_ink_return = ink; + if (overall_logical_return) + *overall_logical_return = logical; + return 0; +} + + +static int +draw_string (Display *dpy, Drawable d, GC gc, int x, int y, + NSString *nsstr) +{ + if (! nsstr) return 1; CGRect wr = d->frame; CGContextRef cgc = d->cgc; @@ -3145,11 +3289,6 @@ draw_string (Display *dpy, Drawable d, GC gc, int x, int y, // set_color (cgc, argb, 32, NO, YES); - char *s2 = (char *) malloc (len + 1); - strncpy (s2, str, len); - s2[len] = 0; - NSString *nsstr = [NSString stringWithCString:s2 - encoding:NSISOLatin1StringEncoding]; NSAttributedString *astr = [[NSAttributedString alloc] initWithString:nsstr attributes:attr]; @@ -3171,14 +3310,69 @@ int XDrawString (Display *dpy, Drawable d, GC gc, int x, int y, const char *str, int len) { - return draw_string (dpy, d, gc, x, y, str, len, NO); + char *s2 = (char *) malloc (len + 1); + strncpy (s2, str, len); + s2[len] = 0; + NSString *nsstr = [NSString stringWithCString:s2 + encoding:NSISOLatin1StringEncoding]; + int ret = draw_string (dpy, d, gc, x, y, nsstr); + free (s2); + return ret; +} + + +int +XDrawString16 (Display *dpy, Drawable d, GC gc, int x, int y, + const XChar2b *str, int len) +{ + char *s2 = XChar2b_to_utf8 (str, 0); + NSString *nsstr = [NSString stringWithCString:s2 + encoding:NSUTF8StringEncoding]; + if (! nsstr) + /* If the C string has invalid UTF8 bytes in it, the result is + "undefined", which turns out to mean "return a null string" + instead of just omitting the bogus characters. Greaaat. + So try it again as Latin1, I guess. */ + nsstr = [NSString stringWithCString:s2 encoding:NSISOLatin1StringEncoding]; + int ret = draw_string (dpy, d, gc, x, y, nsstr); + free (s2); + return ret; +} + + +void +Xutf8DrawString (Display *dpy, Drawable d, XFontSet set, GC gc, + int x, int y, const char *str, int len) +{ + char *s2 = (char *) malloc (len + 1); + strncpy (s2, str, len); + s2[len] = 0; + NSString *nsstr = [NSString stringWithCString:s2 + encoding:NSUTF8StringEncoding]; + if (! nsstr) + nsstr = [NSString stringWithCString:s2 encoding:NSISOLatin1StringEncoding]; + draw_string (dpy, d, gc, x, y, nsstr); + free (s2); } + int XDrawImageString (Display *dpy, Drawable d, GC gc, int x, int y, const char *str, int len) { - return draw_string (dpy, d, gc, x, y, str, len, YES); + int ascent, descent, dir; + XCharStruct cs; + XTextExtents (&gc->gcv.font->metrics, str, len, + &dir, &ascent, &descent, &cs); + draw_rect (dpy, d, gc, + x + MIN (0, cs.lbearing), + y - MAX (0, ascent), + MAX (MAX (0, cs.rbearing) - + MIN (0, cs.lbearing), + cs.width), + MAX (0, ascent) + MAX (0, descent), + NO, YES); + return XDrawString (dpy, d, gc, x, y, str, len); } @@ -3490,6 +3684,18 @@ get_bits_per_pixel (Display *dpy, int depth) return depth; } +int +screen_number (Screen *screen) +{ + Display *dpy = DisplayOfScreen (screen); + int i; + for (i = 0; i < ScreenCount (dpy); i++) + if (ScreenOfDisplay (dpy, i) == screen) + return i; + abort (); + return 0; +} + // declared in utils/grabclient.h Bool use_subwindow_mode_p (Screen *screen, Window window)