-/* xscreensaver, Copyright (c) 1991-2006 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1991-2009 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
*/
#import <stdlib.h>
+#import <stdint.h>
#import <Cocoa/Cocoa.h>
#import "jwxyz.h"
#import "jwxyz-timers.h"
int i;
CGRect wr = d->frame;
+ push_fg_gc (d, gc, YES);
+
# ifdef XDRAWPOINTS_IMAGES
unsigned int argb = gc->gcv.foreground;
CGRect *rects = (CGRect *) malloc (count * sizeof(CGRect));
CGRect *r = rects;
- push_fg_gc (d, gc, YES);
for (i = 0; i < count; i++) {
r->size.width = r->size.height = 1;
if (i > 0 && mode == CoordModePrevious) {
# endif /* ! XDRAWPOINTS_IMAGES */
+ pop_gc (d, gc);
+
return 0;
}
XAllocColor (Display *dpy, Colormap cmap, XColor *color)
{
// store 32 bit ARGB in the pixel field.
- color->pixel = (( 0xFF << 24) |
+ // (The uint32_t is so that 0xFF000000 doesn't become 0xFFFFFFFFFF000000)
+ color->pixel = (uint32_t)
+ (( 0xFF << 24) |
(((color->red >> 8) & 0xFF) << 16) |
(((color->green >> 8) & 0xFF) << 8) |
(((color->blue >> 8) & 0xFF) ));
static unsigned long
ximage_getpixel_32 (XImage *ximage, int x, int y)
{
- return *((unsigned long *) ximage->data +
- (y * (ximage->bytes_per_line >> 2)) +
- x);
+ return ((unsigned long)
+ *((uint32_t *) ximage->data +
+ (y * (ximage->bytes_per_line >> 2)) +
+ x));
}
static int
ximage_putpixel_32 (XImage *ximage, int x, int y, unsigned long pixel)
{
- *((unsigned long *) ximage->data +
+ *((uint32_t *) ximage->data +
(y * (ximage->bytes_per_line >> 2)) +
- x) = pixel;
+ x) = (uint32_t) pixel;
return 0;
}
{
CGRect wr = d->frame;
+ Assert ((w < 65535), "improbably large width");
+ Assert ((h < 65535), "improbably large height");
+ Assert ((src_x < 65535 && src_x > -65535), "improbably large src_x");
+ Assert ((src_y < 65535 && src_y > -65535), "improbably large src_y");
+ Assert ((dest_x < 65535 && dest_x > -65535), "improbably large dest_x");
+ Assert ((dest_y < 65535 && dest_y > -65535), "improbably large dest_y");
+
// Clip width and height to the bounds of the Drawable
//
if (dest_x + w > wr.size.width) {
unsigned long plane_mask, int format)
{
const unsigned char *data = 0;
- int depth, ibpp, ibpl;
+ int depth, ibpp, ibpl, alpha_first_p;
NSBitmapImageRep *bm = 0;
+ Assert ((width < 65535), "improbably large width");
+ Assert ((height < 65535), "improbably large height");
+ Assert ((x < 65535 && x > -65535), "improbably large x");
+ Assert ((y < 65535 && y > -65535), "improbably large y");
+
if (d->type == PIXMAP) {
depth = d->pixmap.depth;
ibpp = CGBitmapContextGetBitsPerPixel (d->cgc);
nsfrom.size.height = height;
[bm initWithFocusedViewRect:nsfrom];
depth = 32;
+ alpha_first_p = ([bm bitmapFormat] & NSAlphaFirstBitmapFormat);
ibpp = [bm bitsPerPixel];
ibpl = [bm bytesPerRow];
data = [bm bitmapData];
Assert (data, "NSBitmapImageRep initWithFocusedViewRect failed");
-
- data += (y * ibpl) + (x * (ibpp/8));
}
+ // data points at (x,y) with ibpl rowstride. ignore x,y from now on.
+ data += (y * ibpl) + (x * (ibpp/8));
+
format = (depth == 1 ? XYPixmap : ZPixmap);
XImage *image = XCreateImage (dpy, 0, depth, format, 0, 0, width, height,
0, 0);
/* both PPC and Intel use word-ordered ARGB frame buffers, which
means that on Intel it is BGRA when viewed by bytes (And BGR
when using 24bpp packing).
+
+ BUT! Intel-64 stores alpha at the other end! 32bit=RGBA, 64bit=ARGB.
+ The NSAlphaFirstBitmapFormat bit in bitmapFormat seems to be the
+ indicator of this latest kink.
*/
int xx, yy;
if (depth == 1) {
const unsigned char *iline = data;
- for (yy = y; yy < y+height; yy++) {
+ for (yy = 0; yy < height; yy++) {
const unsigned char *iline2 = iline;
- for (xx = x; xx < x+width; xx++) {
+ for (xx = 0; xx < width; xx++) {
- iline2++; // ignore b or a
- iline2++; // ignore g or r
- unsigned char r = *iline2++; // r or g
- if (ibpp == 32) iline2++; // ignore a or b
+ iline2++; // ignore R or A or A or B
+ iline2++; // ignore G or B or R or G
+ unsigned char r = *iline2++; // use B or G or G or R
+ if (ibpp == 32) iline2++; // ignore A or R or B or A
XPutPixel (image, xx, yy, (r ? 1 : 0));
}
Assert (ibpp == 24 || ibpp == 32, "weird obpp");
const unsigned char *iline = data;
unsigned char *oline = (unsigned char *) image->data;
- oline += (y * obpl);
- for (yy = y; yy < y+height; yy++) {
+ for (yy = 0; yy < height; yy++) {
const unsigned char *iline2 = iline;
unsigned char *oline2 = oline;
- for (xx = x; xx < x+width; xx++) {
-
- unsigned char a = (ibpp == 32 ? (*iline2++) : 0xFF);
- unsigned char r = *iline2++;
- unsigned char g = *iline2++;
- unsigned char b = *iline2++;
- unsigned long pixel = ((a << 24) |
- (r << 16) |
- (g << 8) |
- (b << 0));
- *((unsigned int *) oline2) = pixel;
- oline2 += 4;
- }
+
+ if (alpha_first_p) // ARGB
+ for (xx = 0; xx < width; xx++) {
+ unsigned char a = (ibpp == 32 ? (*iline2++) : 0xFF);
+ unsigned char r = *iline2++;
+ unsigned char g = *iline2++;
+ unsigned char b = *iline2++;
+ uint32_t pixel = ((a << 24) |
+ (r << 16) |
+ (g << 8) |
+ (b << 0));
+ *((uint32_t *) oline2) = pixel;
+ oline2 += 4;
+ }
+ else // RGBA
+ for (xx = 0; xx < width; xx++) {
+ unsigned char r = *iline2++;
+ unsigned char g = *iline2++;
+ unsigned char b = *iline2++;
+ unsigned char a = (ibpp == 32 ? (*iline2++) : 0xFF);
+ uint32_t pixel = ((a << 24) |
+ (r << 16) |
+ (g << 8) |
+ (b << 0));
+ *((uint32_t *) oline2) = pixel;
+ oline2 += 4;
+ }
+
oline += obpl;
iline += ibpl;
}
return image;
}
+
+/* Returns a transformation matrix to do rotation as per the provided
+ EXIF "Orientation" value.
+ */
+static CGAffineTransform
+exif_rotate (int rot, CGSize rect)
+{
+ CGAffineTransform trans = CGAffineTransformIdentity;
+ switch (rot) {
+ case 2: // flip horizontal
+ trans = CGAffineTransformMakeTranslation (rect.width, 0);
+ trans = CGAffineTransformScale (trans, -1, 1);
+ break;
+
+ case 3: // rotate 180
+ trans = CGAffineTransformMakeTranslation (rect.width, rect.height);
+ trans = CGAffineTransformRotate (trans, M_PI);
+ break;
+
+ case 4: // flip vertical
+ trans = CGAffineTransformMakeTranslation (0, rect.height);
+ trans = CGAffineTransformScale (trans, 1, -1);
+ break;
+
+ case 5: // transpose (UL-to-LR axis)
+ trans = CGAffineTransformMakeTranslation (rect.height, rect.width);
+ trans = CGAffineTransformScale (trans, -1, 1);
+ trans = CGAffineTransformRotate (trans, 3 * M_PI / 2);
+ break;
+
+ case 6: // rotate 90
+ trans = CGAffineTransformMakeTranslation (0, rect.width);
+ trans = CGAffineTransformRotate (trans, 3 * M_PI / 2);
+ break;
+
+ case 7: // transverse (UR-to-LL axis)
+ trans = CGAffineTransformMakeScale (-1, 1);
+ trans = CGAffineTransformRotate (trans, M_PI / 2);
+ break;
+
+ case 8: // rotate 270
+ trans = CGAffineTransformMakeTranslation (rect.height, 0);
+ trans = CGAffineTransformRotate (trans, M_PI / 2);
+ break;
+
+ default:
+ break;
+ }
+
+ return trans;
+}
+
+
void
jwxyz_draw_NSImage (Display *dpy, Drawable d, void *nsimg_arg,
- XRectangle *geom_ret)
+ XRectangle *geom_ret, int exif_rotation)
{
NSImage *nsimg = (NSImage *) nsimg_arg;
CGImageRef cgi = CGImageSourceCreateImageAtIndex (cgsrc, 0, NULL);
NSSize imgr = [nsimg size];
+ Bool rot_p = (exif_rotation >= 5);
+
+ if (rot_p)
+ imgr = NSMakeSize (imgr.height, imgr.width);
+
CGRect winr = d->frame;
float rw = winr.size.width / imgr.width;
float rh = winr.size.height / imgr.height;
float r = (rw < rh ? rw : rh);
- CGRect dst;
+ CGRect dst, dst2;
dst.size.width = imgr.width * r;
dst.size.height = imgr.height * r;
dst.origin.x = (winr.size.width - dst.size.width) / 2;
dst.origin.y = (winr.size.height - dst.size.height) / 2;
+ dst2.origin.x = dst2.origin.y = 0;
+ if (rot_p) {
+ dst2.size.width = dst.size.height;
+ dst2.size.height = dst.size.width;
+ } else {
+ dst2.size = dst.size;
+ }
+
// Clear the part not covered by the image to background or black.
//
if (d->type == WINDOW)
draw_rect (dpy, d, 0, 0, 0, winr.size.width, winr.size.height, NO, YES);
}
+ CGAffineTransform trans =
+ exif_rotate (exif_rotation, rot_p ? dst2.size : dst.size);
+
+ CGContextSaveGState (d->cgc);
+ CGContextConcatCTM (d->cgc,
+ CGAffineTransformMakeTranslation (dst.origin.x,
+ dst.origin.y));
+ CGContextConcatCTM (d->cgc, trans);
//Assert (CGImageGetColorSpace (cgi) == dpy->colorspace, "bad colorspace");
- CGContextDrawImage (d->cgc, dst, cgi);
+ CGContextDrawImage (d->cgc, dst2, cgi);
+ CGContextRestoreGState (d->cgc);
CFRelease (cgsrc);
CGImageRelease (cgi);
static void
query_font (Font fid)
{
+ if (!fid || !fid->nsfont) {
+ NSLog(@"no NSFont in fid");
+ abort();
+ }
+ if (![fid->nsfont fontName]) {
+ NSLog(@"broken NSFont in fid");
+ abort();
+ }
+
int first = 32;
int last = 255;
// copy the other pointers
fid2->ps_name = strdup (fid->ps_name);
- [fid2->nsfont retain];
+// [fid2->nsfont retain];
fid2->metrics.fid = fid2;
return fid2;
try_font (BOOL fixed, BOOL bold, BOOL ital, BOOL serif, float size,
char **name_ret)
{
- const char *prefix = (fixed ? "Monaco" : (serif ? "Times" : "Helvetica"));
- const char *suffix = (bold && ital
- ? (serif ? "-BoldItalic" : "-BoldOblique")
- : (bold ? "-Bold" :
- ital ? (serif ? "-Italic" : "-Oblique") : ""));
- char *name = (char *) malloc (strlen(prefix) + strlen(suffix) + 1);
- strcpy (name, prefix);
- strcat (name, suffix);
+ Assert (size > 0, "zero font size");
+ const char *name;
+
+ if (fixed) {
+ //
+ // "Monaco" only exists in plain.
+ // "LucidaSansTypewriterStd" gets an AGL bad value error.
+ //
+ if (bold && ital) name = "Courier-BoldOblique";
+ else if (bold) name = "Courier-Bold";
+ else if (ital) name = "Courier-Oblique";
+ else name = "Courier";
+
+ } else if (serif) {
+ //
+ // "Georgia" looks better than "Times".
+ //
+ if (bold && ital) name = "Georgia-BoldItalic";
+ else if (bold) name = "Georgia-Bold";
+ else if (ital) name = "Georgia-Italic";
+ else name = "Georgia";
+
+ } else {
+ //
+ // "Geneva" only exists in plain.
+ // "LucidaSansStd-BoldItalic" gets an AGL bad value error.
+ // "Verdana" renders smoother than "Helvetica" for some reason.
+ //
+ if (bold && ital) name = "Verdana-BoldItalic";
+ else if (bold) name = "Verdana-Bold";
+ else if (ital) name = "Verdana-Italic";
+ else name = "Verdana";
+ }
NSString *nsname = [NSString stringWithCString:name
encoding:NSUTF8StringEncoding];
NSFont *f = [NSFont fontWithName:nsname size:size];
- if (f) {
- *name_ret = name;
- } else {
- free (name);
- }
+ if (f)
+ *name_ret = strdup(name);
return f;
}
static NSFont *
random_font (BOOL bold, BOOL ital, float size, char **name_ret)
{
- NSFontTraitMask mask = ((bold ? NSUnboldFontMask : NSBoldFontMask) |
- (ital ? NSUnitalicFontMask : NSItalicFontMask));
+ NSFontTraitMask mask = ((bold ? NSBoldFontMask : NSUnboldFontMask) |
+ (ital ? NSItalicFontMask : NSUnitalicFontMask));
NSArray *fonts = [[NSFontManager sharedFontManager]
availableFontNamesWithTraits:mask];
if (!fonts) return 0;
}
-/* This translates the NSFont into the numbers that aglUseFont() wants.
- */
-int
-jwxyz_font_info (Font f, int *size_ret, int *face_ret)
-{
- char *name = strdup (f->ps_name);
- char *dash = strchr (name, '-');
- int flags = 0;
- int size = f->size;
- if (dash) {
- // 0 = plain; 1=B; 2=I; 3=BI; 4=U; 5=UB; etc.
- if (strcasestr (dash, "bold")) flags |= 1;
- if (strcasestr (dash, "italic")) flags |= 2;
- if (strcasestr (dash, "oblique")) flags |= 2;
- *dash = 0;
- }
- NSString *nname = [NSString stringWithCString:name
- encoding:NSUTF8StringEncoding];
- ATSFontFamilyRef id =
- ATSFontFamilyFindFromName ((CFStringRef) nname, kATSOptionFlagsDefault);
-
-
- // WTF? aglUseFont gets a BadValue if size is small!!
- if (size < 9) size = 9;
-
- //NSLog (@"font %s %.1f => %d %d %d", f->ps_name, f->size, id, flags, size);
- Assert (id >= 0, "no ATS font family");
-
- *size_ret = size;
- *face_ret = flags;
- return id;
-}
-
-
XFontStruct *
XLoadQueryFont (Display *dpy, const char *name)
{
{
free (fid->ps_name);
free (fid->metrics.per_char);
- [fid->nsfont release];
+
+ // #### DAMMIT! I can't tell what's going wrong here, but I keep getting
+ // crashes in [NSFont ascender] <- query_font, and it seems to go away
+ // if I never release the nsfont. So, fuck it, we'll just leak fonts.
+ // They're probably not very big...
+ //
+ // [fid->nsfont release];
+
free (fid);
return 0;
}
if (gc->gcv.font)
XUnloadFont (dpy, gc->gcv.font);
gc->gcv.font = copy_font (fid);
+ [gc->gcv.font->nsfont retain];
return 0;
}
-Font // really GContext
-XGContextFromGC (GC gc) // WTF is this actually supposed to do?
-{
- return gc->gcv.font;
-}
-
int
XTextExtents (XFontStruct *f, const char *s, int length,
int *dir_ret, int *ascent_ret, int *descent_ret,
set_font (CGContextRef cgc, GC gc)
{
Font font = gc->gcv.font;
- if (! font)
- font = gc->gcv.font = XLoadFont (0, 0);
+ if (! font) {
+ font = XLoadFont (0, 0);
+ gc->gcv.font = font;
+ [gc->gcv.font->nsfont retain];
+ }
CGContextSelectFont (cgc, font->ps_name, font->size, kCGEncodingMacRoman);
CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
}
set_font (d->cgc, gc);
CGContextSetTextDrawingMode (d->cgc, kCGTextFill);
- if (! gc->gcv.antialias_p)
- CGContextSetShouldAntialias (d->cgc, YES); // always antialias text
+ if (gc->gcv.antialias_p)
+ CGContextSetShouldAntialias (d->cgc, YES);
CGContextShowTextAtPoint (d->cgc,
wr.origin.x + x,
wr.origin.y + wr.size.height - y,