Mercurial > emacs
comparison src/nsimage.m @ 96675:d45acf0c8d23
merging Emacs.app (NeXTstep port)
author | Adrian Robert <Adrian.B.Robert@gmail.com> |
---|---|
date | Tue, 15 Jul 2008 18:15:18 +0000 |
parents | |
children | e869d0172660 |
comparison
equal
deleted
inserted
replaced
96674:ff312a846b25 | 96675:d45acf0c8d23 |
---|---|
1 /* Image support for the NeXT/Open/GNUstep and MacOSX window system. | |
2 Copyright (C) 1989, 1992, 1993, 1994, 2005, 2006, 2008, | |
3 Free Software Foundation, Inc. | |
4 | |
5 This file is part of GNU Emacs. | |
6 | |
7 GNU Emacs is free software; you can redistribute it and/or modify | |
8 it under the terms of the GNU General Public License as published by | |
9 the Free Software Foundation; either version 3, or (at your option) | |
10 any later version. | |
11 | |
12 GNU Emacs is distributed in the hope that it will be useful, | |
13 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 GNU General Public License for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with GNU Emacs; see the file COPYING. If not, write to | |
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
20 Boston, MA 02110-1301, USA. | |
21 | |
22 Originally by Carl Edman | |
23 Updated by Christian Limpach (chris@nice.ch) | |
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com) | |
25 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net) | |
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) | |
27 | |
28 */ | |
29 | |
30 #include "config.h" | |
31 #include "lisp.h" | |
32 #include "dispextern.h" | |
33 #include "nsterm.h" | |
34 #include "frame.h" | |
35 | |
36 extern Lisp_Object QCfile, QCdata; | |
37 | |
38 /* call tracing */ | |
39 #if 0 | |
40 int image_trace_num = 0; | |
41 #define NSTRACE(x) fprintf (stderr, "%s:%d: [%d] " #x "\n", \ | |
42 __FILE__, __LINE__, ++image_trace_num) | |
43 #else | |
44 #define NSTRACE(x) | |
45 #endif | |
46 | |
47 | |
48 /* ========================================================================== | |
49 | |
50 C interface. This allows easy calling from C files. We could just | |
51 compile everything as Objective-C, but that might mean slower | |
52 compilation and possible difficulties on some platforms.. | |
53 | |
54 ========================================================================== */ | |
55 | |
56 void * | |
57 ns_image_from_XBM (unsigned char *bits, int width, int height) | |
58 { | |
59 NSTRACE (ns_image_from_XBM); | |
60 return [[EmacsImage alloc] initFromXBM: bits | |
61 width: width height: height | |
62 flip: YES]; | |
63 } | |
64 | |
65 void * | |
66 ns_image_for_XPM (int width, int height, int depth) | |
67 { | |
68 NSTRACE (ns_image_for_XPM); | |
69 return [[EmacsImage alloc] initForXPMWithDepth: depth | |
70 width: width height: height]; | |
71 } | |
72 | |
73 void * | |
74 ns_image_from_file (Lisp_Object file) | |
75 { | |
76 NSTRACE (ns_image_from_bitmap_file); | |
77 return [EmacsImage allocInitFromFile: file]; | |
78 } | |
79 | |
80 int | |
81 ns_load_image (struct frame *f, struct image *img, | |
82 Lisp_Object spec_file, Lisp_Object spec_data) | |
83 { | |
84 NSTRACE (ns_load_image); | |
85 | |
86 EmacsImage *eImg; | |
87 NSSize size; | |
88 | |
89 if (NILP (spec_data)) | |
90 { | |
91 eImg = [EmacsImage allocInitFromFile: spec_file]; | |
92 } | |
93 else | |
94 { | |
95 NSData *data = [NSData dataWithBytes: XSTRING (spec_data)->data | |
96 length: SBYTES (spec_data)]; | |
97 eImg = [[EmacsImage alloc] initWithData: data]; | |
98 [eImg setPixmapData]; | |
99 } | |
100 | |
101 if (eImg == nil) | |
102 { | |
103 add_to_log ("Unable to load image %s", img->spec, Qnil); | |
104 return 0; | |
105 } | |
106 | |
107 size = [eImg size]; | |
108 img->width = size.width; | |
109 img->height = size.height; | |
110 | |
111 /* 4) set img->pixmap = emacsimage */ | |
112 img->pixmap = eImg; | |
113 return 1; | |
114 } | |
115 | |
116 | |
117 int | |
118 ns_image_width (void *img) | |
119 { | |
120 return [(id)img size].width; | |
121 } | |
122 | |
123 int | |
124 ns_image_height (void *img) | |
125 { | |
126 return [(id)img size].height; | |
127 } | |
128 | |
129 unsigned long | |
130 ns_get_pixel (void *img, int x, int y) | |
131 { | |
132 return [(EmacsImage *)img getPixelAtX: x Y: y]; | |
133 } | |
134 | |
135 void | |
136 ns_put_pixel (void *img, int x, int y, unsigned long argb) | |
137 { | |
138 unsigned char alpha = (argb >> 24) & 0xFF; | |
139 if (alpha == 0) | |
140 alpha = 0xFF; | |
141 [(EmacsImage *)img setPixelAtX: x Y: y toRed: (argb >> 16) & 0xFF | |
142 green: (argb >> 8) & 0xFF blue: (argb & 0xFF) alpha: alpha]; | |
143 } | |
144 | |
145 void | |
146 ns_set_alpha (void *img, int x, int y, unsigned char a) | |
147 { | |
148 [(EmacsImage *)img setAlphaAtX: x Y: y to: a]; | |
149 } | |
150 | |
151 | |
152 /* ========================================================================== | |
153 | |
154 Class supporting bitmaps and images of various sorts. | |
155 | |
156 ========================================================================== */ | |
157 | |
158 @implementation EmacsImage | |
159 | |
160 static EmacsImage *ImageList = nil; | |
161 | |
162 + allocInitFromFile: (Lisp_Object)file | |
163 { | |
164 EmacsImage *image = ImageList; | |
165 Lisp_Object found; | |
166 | |
167 /* look for an existing image of the same name */ | |
168 while (image != nil && | |
169 [[image name] compare: [NSString stringWithUTF8String: SDATA (file)]] | |
170 != NSOrderedSame) | |
171 image = [image imageListNext]; | |
172 | |
173 if (image != nil) | |
174 { | |
175 [image reference]; | |
176 return image; | |
177 } | |
178 | |
179 /* Search bitmap-file-path for the file, if appropriate. */ | |
180 found = x_find_image_file (file); | |
181 if (!STRINGP (found)) | |
182 return nil; | |
183 | |
184 image = [[EmacsImage alloc] initByReferencingFile: | |
185 [NSString stringWithUTF8String: SDATA (found)]]; | |
186 | |
187 if ([image bestRepresentationForDevice: nil] == nil) | |
188 { | |
189 [image release]; | |
190 return nil; | |
191 } | |
192 | |
193 [image setName: [NSString stringWithUTF8String: SDATA (file)]]; | |
194 [image reference]; | |
195 ImageList = [image imageListSetNext: ImageList]; | |
196 | |
197 return image; | |
198 } | |
199 | |
200 | |
201 - reference | |
202 { | |
203 refCount++; | |
204 return self; | |
205 } | |
206 | |
207 | |
208 - imageListSetNext: (id)arg | |
209 { | |
210 imageListNext = arg; | |
211 return self; | |
212 } | |
213 | |
214 | |
215 - imageListNext | |
216 { | |
217 return imageListNext; | |
218 } | |
219 | |
220 | |
221 - (void)dealloc | |
222 { | |
223 id list = ImageList; | |
224 | |
225 if (refCount > 1) | |
226 { | |
227 refCount--; | |
228 return; | |
229 } | |
230 | |
231 [stippleMask release]; | |
232 | |
233 if (list == self) | |
234 ImageList = imageListNext; | |
235 else | |
236 { | |
237 while (list != nil && [list imageListNext] != self) | |
238 list = [list imageListNext]; | |
239 [list imageListSetNext: imageListNext]; | |
240 } | |
241 | |
242 [super dealloc]; | |
243 } | |
244 | |
245 | |
246 - initFromXBM: (unsigned char *)bits width: (int)w height: (int)h | |
247 flip: (BOOL)flip | |
248 { | |
249 return [self initFromSkipXBM: bits width: w height: h flip: flip length: 0]; | |
250 } | |
251 | |
252 | |
253 - initFromSkipXBM: (unsigned char *)bits width: (int)w height: (int)h | |
254 flip: (BOOL)flip length: (int)length; | |
255 { | |
256 int bpr = (w + 7) / 8; | |
257 unsigned char *planes[5]; | |
258 | |
259 [self initWithSize: NSMakeSize (w, h)]; | |
260 | |
261 bmRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL | |
262 pixelsWide: w pixelsHigh: h | |
263 bitsPerSample: 8 samplesPerPixel: 4 | |
264 hasAlpha: YES isPlanar: YES | |
265 colorSpaceName: NSCalibratedRGBColorSpace | |
266 bytesPerRow: w bitsPerPixel: 0]; | |
267 | |
268 [bmRep getBitmapDataPlanes: planes]; | |
269 { | |
270 /* pull bits out to set the (bytewise) alpha mask */ | |
271 int i, j, k; | |
272 unsigned char *s = bits; | |
273 unsigned char *alpha = planes[3]; | |
274 unsigned char swt[16] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, | |
275 3, 11, 7, 15}; | |
276 unsigned char c, bitPat; | |
277 | |
278 for (j = 0; j < h; j++) | |
279 for (i = 0; i < bpr; i++) | |
280 { | |
281 if (length) | |
282 { | |
283 unsigned char s1, s2; | |
284 while (*s++ != 'x' && s < bits + length); | |
285 if (s >= bits + length) | |
286 { | |
287 [bmRep release]; | |
288 return nil; | |
289 } | |
290 #define hexchar(x) (isdigit (x) ? x - '0' : x - 'a' + 10) | |
291 s1 = *s++; | |
292 s2 = *s++; | |
293 c = hexchar (s1) * 0x10 + hexchar (s2); | |
294 } | |
295 else | |
296 c = *s++; | |
297 | |
298 bitPat = flip ? swt[c >> 4] | (swt[c & 0xf] << 4) : c ^ 255; | |
299 for (k =0; k<8; k++) | |
300 { | |
301 *alpha++ = (bitPat & 0x80) ? 0xff : 0; | |
302 bitPat <<= 1; | |
303 } | |
304 } | |
305 } | |
306 | |
307 [self addRepresentation: bmRep]; | |
308 | |
309 bzero (planes[0], w*h); | |
310 bzero (planes[1], w*h); | |
311 bzero (planes[2], w*h); | |
312 [self setXBMColor: [NSColor blackColor]]; | |
313 return self; | |
314 } | |
315 | |
316 | |
317 /* Set color for a bitmap image (see initFromSkipXBM). Note that the alpha | |
318 is used as a mask, so we just memset the entire array. */ | |
319 - setXBMColor: (NSColor *)color | |
320 { | |
321 NSSize s = [self size]; | |
322 int len = (int) s.width * s.height; | |
323 unsigned char *planes[5]; | |
324 float r, g, b, a; | |
325 NSColor *rgbColor; | |
326 | |
327 if (bmRep == nil || color == nil) | |
328 return; | |
329 | |
330 if ([color colorSpaceName] != NSCalibratedRGBColorSpace) | |
331 rgbColor = [color colorUsingColorSpaceName: NSCalibratedRGBColorSpace]; | |
332 else | |
333 rgbColor = color; | |
334 | |
335 [rgbColor getRed: &r green: &g blue: &b alpha: &a]; | |
336 | |
337 [bmRep getBitmapDataPlanes: planes]; | |
338 | |
339 /* we used to just do this, but Cocoa seems to have a bug when rendering | |
340 an alpha-masked image onto a dark background where it bloats the mask */ | |
341 /* memset (planes[0..2], r, g, b*0xff, len); */ | |
342 { | |
343 int i, len = s.width*s.height; | |
344 int rr = r * 0xff, gg = g * 0xff, bb = b * 0xff; | |
345 for (i =0; i<len; i++) | |
346 if (planes[3][i] != 0) | |
347 { | |
348 planes[0][i] = rr; | |
349 planes[1][i] = gg; | |
350 planes[2][i] = bb; | |
351 } | |
352 } | |
353 } | |
354 | |
355 | |
356 - initForXPMWithDepth: (int)depth width: (int)width height: (int)height | |
357 { | |
358 NSSize s = {width, height}; | |
359 int i; | |
360 | |
361 [self initWithSize: s]; | |
362 | |
363 bmRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL | |
364 pixelsWide: width pixelsHigh: height | |
365 /* keep things simple for now */ | |
366 bitsPerSample: 8 samplesPerPixel: 4 /*RGB+A*/ | |
367 hasAlpha: YES isPlanar: YES | |
368 colorSpaceName: NSCalibratedRGBColorSpace | |
369 bytesPerRow: width bitsPerPixel: 0]; | |
370 | |
371 [bmRep getBitmapDataPlanes: pixmapData]; | |
372 for (i =0; i<4; i++) | |
373 bzero (pixmapData[i], width*height); | |
374 [self addRepresentation: bmRep]; | |
375 return self; | |
376 } | |
377 | |
378 | |
379 /* attempt to pull out pixmap data from a BitmapImageRep; returns NO if fails */ | |
380 - (void) setPixmapData | |
381 { | |
382 NSEnumerator *reps; | |
383 NSImageRep *rep; | |
384 | |
385 reps = [[self representations] objectEnumerator]; | |
386 while (rep = (NSImageRep *) [reps nextObject]) | |
387 { | |
388 if ([rep respondsToSelector: @selector (getBitmapDataPlanes:)]) | |
389 { | |
390 bmRep = (NSBitmapImageRep *) rep; | |
391 onTiger = [bmRep respondsToSelector: @selector (colorAtX:y:)]; | |
392 | |
393 if ([bmRep numberOfPlanes] >= 3) | |
394 [bmRep getBitmapDataPlanes: pixmapData]; | |
395 break; | |
396 } | |
397 } | |
398 } | |
399 | |
400 | |
401 /* note; this and next work only for image created with initForXPMWithDepth, | |
402 initFromSkipXBM, or where setPixmapData was called successfully */ | |
403 /* return ARGB */ | |
404 - (unsigned long) getPixelAtX: (int)x Y: (int)y | |
405 { | |
406 if (bmRep == nil) | |
407 return 0; | |
408 | |
409 /* this method is faster but won't work for bitmaps */ | |
410 if (pixmapData[0] != NULL) | |
411 { | |
412 int loc = x + y * [self size].width; | |
413 return (pixmapData[3][loc] << 24) /* alpha */ | |
414 | (pixmapData[0][loc] << 16) | (pixmapData[1][loc] << 8) | |
415 | (pixmapData[2][loc]); | |
416 } | |
417 else if (onTiger) | |
418 { | |
419 NSColor *color = [bmRep colorAtX: x y: y]; | |
420 float r, g, b, a; | |
421 [color getRed: &r green: &g blue: &b alpha: &a]; | |
422 return ((int)(a * 255.0) << 24) | |
423 | ((int)(r * 255.0) << 16) | ((int)(g * 255.0) << 8) | |
424 | ((int)(b * 255.0)); | |
425 | |
426 } | |
427 return 0; | |
428 } | |
429 | |
430 - (void) setPixelAtX: (int)x Y: (int)y toRed: (unsigned char)r | |
431 green: (unsigned char)g blue: (unsigned char)b | |
432 alpha:(unsigned char)a; | |
433 { | |
434 if (bmRep == nil) | |
435 return; | |
436 | |
437 if (pixmapData[0] != NULL) | |
438 { | |
439 int loc = x + y * [self size].width; | |
440 pixmapData[0][loc] = r; | |
441 pixmapData[1][loc] = g; | |
442 pixmapData[2][loc] = b; | |
443 pixmapData[3][loc] = a; | |
444 } | |
445 else if (onTiger) | |
446 { | |
447 [bmRep setColor: | |
448 [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a] | |
449 atX: x y: y]; | |
450 } | |
451 } | |
452 | |
453 - (void) setAlphaAtX: (int) x Y: (int) y to: (unsigned char) a | |
454 { | |
455 if (bmRep == nil) | |
456 return; | |
457 | |
458 if (pixmapData[0] != NULL) | |
459 { | |
460 int loc = x + y * [self size].width; | |
461 | |
462 pixmapData[3][loc] = a; | |
463 } | |
464 else if (onTiger) | |
465 { | |
466 NSColor *color = [bmRep colorAtX: x y: y]; | |
467 color = [color colorWithAlphaComponent: (a / 255.0)]; | |
468 [bmRep setColor: color atX: x y: y]; | |
469 } | |
470 } | |
471 | |
472 /* returns a pattern color, which is cached here */ | |
473 - (NSColor *)stippleMask | |
474 { | |
475 if (stippleMask == nil) | |
476 stippleMask = [[NSColor colorWithPatternImage: self] retain]; | |
477 return stippleMask; | |
478 } | |
479 | |
480 @end |