(linenum→info "unix/slp.c:2238")

emacs/22.1/src/image.c

    1: /* Functions for image support on window system.
    2:    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
    3:                  2001, 2002, 2003, 2004, 2005, 2006, 2007 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 2, 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: #include <config.h>
   23: #include <stdio.h>
   24: #include <math.h>
   25: #include <ctype.h>
   26: 
   27: #ifdef HAVE_UNISTD_H
   28: #include <unistd.h>
   29: #endif
   30: 
   31: /* This makes the fields of a Display accessible, in Xlib header files.  */
   32: 
   33: #define XLIB_ILLEGAL_ACCESS
   34: 
   35: #include "lisp.h"
   36: #include "frame.h"
   37: #include "window.h"
   38: #include "dispextern.h"
   39: #include "blockinput.h"
   40: #include "systime.h"
   41: #include <epaths.h>
   42: #include "charset.h"
   43: #include "coding.h"
   44: 
   45: 
   46: #ifdef HAVE_X_WINDOWS
   47: #include "xterm.h"
   48: #include <sys/types.h>
   49: #include <sys/stat.h>
   50: 
   51: #define COLOR_TABLE_SUPPORT 1
   52: 
   53: typedef struct x_bitmap_record Bitmap_Record;
   54: #define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
   55: #define NO_PIXMAP None
   56: 
   57: #define RGB_PIXEL_COLOR unsigned long
   58: 
   59: #define PIX_MASK_RETAIN 0
   60: #define PIX_MASK_DRAW   1
   61: #endif /* HAVE_X_WINDOWS */
   62: 
   63: 
   64: #ifdef HAVE_NTGUI
   65: #include "w32term.h"
   66: 
   67: /* W32_TODO : Color tables on W32.  */
   68: #undef COLOR_TABLE_SUPPORT
   69: 
   70: typedef struct w32_bitmap_record Bitmap_Record;
   71: #define GET_PIXEL(ximg, x, y) GetPixel(ximg, x, y)
   72: #define NO_PIXMAP 0
   73: 
   74: #define RGB_PIXEL_COLOR COLORREF
   75: 
   76: #define PIX_MASK_RETAIN 0
   77: #define PIX_MASK_DRAW   1
   78: 
   79: #define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
   80: #define x_defined_color w32_defined_color
   81: #define DefaultDepthOfScreen(screen) (one_w32_display_info.n_cbits)
   82: #endif /* HAVE_NTGUI */
   83: 
   84: 
   85: #ifdef MAC_OS
   86: #include "macterm.h"
   87: #include <sys/stat.h>
   88: #ifndef MAC_OSX
   89: #include <alloca.h>
   90: #include <sys/param.h>
   91: #endif
   92: #if TARGET_API_MAC_CARBON
   93: #ifdef MAC_OSX
   94: #include <QuickTime/QuickTime.h>
   95: #else  /* not MAC_OSX */
   96: #include <QuickTime.h>
   97: #endif  /* not MAC_OSX */
   98: #else  /* not TARGET_API_MAC_CARBON */
   99: #include <Windows.h>
  100: #include <Gestalt.h>
  101: #include <TextUtils.h>
  102: #include <ImageCompression.h>
  103: #include <QuickTimeComponents.h>
  104: #endif  /* not TARGET_API_MAC_CARBON */
  105: 
  106: /* MAC_TODO : Color tables on Mac.  */
  107: #undef COLOR_TABLE_SUPPORT
  108: 
  109: #define ZPixmap 0               /* arbitrary */
  110: typedef struct mac_bitmap_record Bitmap_Record;
  111: 
  112: #define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
  113: #define NO_PIXMAP 0
  114: 
  115: #define RGB_PIXEL_COLOR unsigned long
  116: 
  117: /* A black pixel in a mask bitmap/pixmap means ``draw a source
  118:    pixel''.  A white pixel means ``retain the current pixel''. */
  119: #define PIX_MASK_DRAW   RGB_TO_ULONG(0,0,0)
  120: #define PIX_MASK_RETAIN RGB_TO_ULONG(255,255,255)
  121: 
  122: #define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
  123: #define x_defined_color mac_defined_color
  124: #define DefaultDepthOfScreen(screen) (one_mac_display_info.n_planes)
  125: 
  126: #endif /* MAC_OS */
  127: 
  128: 
  129: /* Search path for bitmap files.  */
  130: 
  131: Lisp_Object Vx_bitmap_file_path;
  132: 
  133: 
  134: static void x_disable_image P_ ((struct frame *, struct image *));
  135: static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
  136:                                   Lisp_Object));
  137: 
  138: static void init_color_table P_ ((void));
  139: static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
  140: #ifdef COLOR_TABLE_SUPPORT
  141: static void free_color_table P_ ((void));
  142: static unsigned long *colors_in_color_table P_ ((int *n));
  143: static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
  144: #endif
  145: 
  146: /* Code to deal with bitmaps.  Bitmaps are referenced by their bitmap
  147:    id, which is just an int that this section returns.  Bitmaps are
  148:    reference counted so they can be shared among frames.
  149: 
  150:    Bitmap indices are guaranteed to be > 0, so a negative number can
  151:    be used to indicate no bitmap.
  152: 
  153:    If you use x_create_bitmap_from_data, then you must keep track of
  154:    the bitmaps yourself.  That is, creating a bitmap from the same
  155:    data more than once will not be caught.  */
  156: 
  157: #ifdef MAC_OS
  158: 
  159: static XImagePtr
  160: XGetImage (display, pixmap, x, y, width, height, plane_mask, format)
  161:      Display *display;          /* not used */
  162:      Pixmap pixmap;
  163:      int x, y;                  /* not used */
  164:      unsigned int width, height; /* not used */
  165:      unsigned long plane_mask;  /* not used */
  166:      int format;                /* not used */
  167: {
  168: #if GLYPH_DEBUG
  169:   xassert (x == 0 && y == 0);
  170:   {
  171:     Rect ri, rp;
  172:     SetRect (&ri, 0, 0, width, height);
  173:     xassert (EqualRect (&ri, GetPixBounds (GetGWorldPixMap (pixmap), &rp)));
  174:   }
  175:   xassert (! (pixelsLocked & GetPixelsState (GetGWorldPixMap (pixmap))));
  176: #endif
  177: 
  178:   LockPixels (GetGWorldPixMap (pixmap));
  179: 
  180:   return pixmap;
  181: }
  182: 
  183: static void
  184: XPutPixel (ximage, x, y, pixel)
  185:      XImagePtr ximage;
  186:      int x, y;
  187:      unsigned long pixel;
  188: {
  189:   PixMapHandle pixmap = GetGWorldPixMap (ximage);
  190:   short depth = GetPixDepth (pixmap);
  191: 
  192: #if defined (WORDS_BIG_ENDIAN) || !USE_CG_DRAWING
  193:   if (depth == 32)
  194:     {
  195:       char *base_addr = GetPixBaseAddr (pixmap);
  196:       short row_bytes = GetPixRowBytes (pixmap);
  197: 
  198:       ((unsigned long *) (base_addr + y * row_bytes))[x] = 0xff000000 | pixel;
  199:     }
  200:   else
  201: #endif
  202:   if (depth == 1)
  203:     {
  204:       char *base_addr = GetPixBaseAddr (pixmap);
  205:       short row_bytes = GetPixRowBytes (pixmap);
  206: 
  207:       if (pixel == PIX_MASK_DRAW)
  208:         base_addr[y * row_bytes + x / 8] |= (1 << 7) >> (x & 7);
  209:       else
  210:         base_addr[y * row_bytes + x / 8] &= ~((1 << 7) >> (x & 7));
  211:     }
  212:   else
  213:     {
  214:       CGrafPtr old_port;
  215:       GDHandle old_gdh;
  216:       RGBColor color;
  217: 
  218:       GetGWorld (&old_port, &old_gdh);
  219:       SetGWorld (ximage, NULL);
  220: 
  221:       color.red = RED16_FROM_ULONG (pixel);
  222:       color.green = GREEN16_FROM_ULONG (pixel);
  223:       color.blue = BLUE16_FROM_ULONG (pixel);
  224: 
  225:       SetCPixel (x, y, &color);
  226: 
  227:       SetGWorld (old_port, old_gdh);
  228:     }
  229: }
  230: 
  231: static unsigned long
  232: XGetPixel (ximage, x, y)
  233:      XImagePtr ximage;
  234:      int x, y;
  235: {
  236:   PixMapHandle pixmap = GetGWorldPixMap (ximage);
  237:   short depth = GetPixDepth (pixmap);
  238: 
  239: #if defined (WORDS_BIG_ENDIAN) || !USE_CG_DRAWING
  240:   if (depth == 32)
  241:     {
  242:       char *base_addr = GetPixBaseAddr (pixmap);
  243:       short row_bytes = GetPixRowBytes (pixmap);
  244: 
  245:       return ((unsigned long *) (base_addr + y * row_bytes))[x] & 0x00ffffff;
  246:     }
  247:   else
  248: #endif
  249:   if (depth == 1)
  250:     {
  251:       char *base_addr = GetPixBaseAddr (pixmap);
  252:       short row_bytes = GetPixRowBytes (pixmap);
  253: 
  254:       if (base_addr[y * row_bytes + x / 8] & (1 << (~x & 7)))
  255:         return PIX_MASK_DRAW;
  256:       else
  257:         return PIX_MASK_RETAIN;
  258:     }
  259:   else
  260:     {
  261:       CGrafPtr old_port;
  262:       GDHandle old_gdh;
  263:       RGBColor color;
  264: 
  265:       GetGWorld (&old_port, &old_gdh);
  266:       SetGWorld (ximage, NULL);
  267: 
  268:       GetCPixel (x, y, &color);
  269: 
  270:       SetGWorld (old_port, old_gdh);
  271:       return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
  272:     }
  273: }
  274: 
  275: static void
  276: XDestroyImage (ximg)
  277:      XImagePtr ximg;
  278: {
  279:   UnlockPixels (GetGWorldPixMap (ximg));
  280: }
  281: 
  282: #if USE_CG_DRAWING
  283: static CGImageRef
  284: mac_create_cg_image_from_image (f, img)
  285:      struct frame *f;
  286:      struct image *img;
  287: {
  288:   Pixmap mask;
  289:   CGImageRef result = NULL;
  290: 
  291:   BLOCK_INPUT;
  292:   if (img->mask)
  293:     mask = img->mask;
  294:   else
  295:     {
  296:       mask = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
  297:                             img->width, img->height, 1);
  298:       if (mask)
  299:         {
  300:           CGrafPtr old_port;
  301:           GDHandle old_gdh;
  302:           Rect r;
  303: 
  304:           GetGWorld (&old_port, &old_gdh);
  305:           SetGWorld (mask, NULL);
  306:           BackColor (blackColor); /* Don't mask.  */
  307:           SetRect (&r, 0, 0, img->width, img->height);
  308:           EraseRect (&r);
  309:           SetGWorld (old_port, old_gdh);
  310:         }
  311:     }
  312:   if (mask)
  313:     {
  314:       CreateCGImageFromPixMaps (GetGWorldPixMap (img->pixmap),
  315:                                 GetGWorldPixMap (mask), &result);
  316:       if (mask != img->mask)
  317:         XFreePixmap (FRAME_X_DISPLAY (f), mask);
  318:     }
  319:   UNBLOCK_INPUT;
  320: 
  321:   return result;
  322: }
  323: #endif /* USE_CG_DRAWING */
  324: #endif /* MAC_OS */
  325: 
  326: 
  327: /* Functions to access the contents of a bitmap, given an id.  */
  328: 
  329: int
  330: x_bitmap_height (f, id)
  331:      FRAME_PTR f;
  332:      int id;
  333: {
  334:   return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
  335: }
  336: 
  337: int
  338: x_bitmap_width (f, id)
  339:      FRAME_PTR f;
  340:      int id;
  341: {
  342:   return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
  343: }
  344: 
  345: #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
  346: int
  347: x_bitmap_pixmap (f, id)
  348:      FRAME_PTR f;
  349:      int id;
  350: {
  351:   return (int) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
  352: }
  353: #endif
  354: 
  355: #ifdef HAVE_X_WINDOWS
  356: int
  357: x_bitmap_mask (f, id)
  358:      FRAME_PTR f;
  359:      int id;
  360: {
  361:   return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
  362: }
  363: #endif
  364: 
  365: /* Allocate a new bitmap record.  Returns index of new record.  */
  366: 
  367: static int
  368: x_allocate_bitmap_record (f)
  369:      FRAME_PTR f;
  370: {
  371:   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
  372:   int i;
  373: 
  374:   if (dpyinfo->bitmaps == NULL)
  375:     {
  376:       dpyinfo->bitmaps_size = 10;
  377:       dpyinfo->bitmaps
  378:         = (Bitmap_Record *) xmalloc (dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
  379:       dpyinfo->bitmaps_last = 1;
  380:       return 1;
  381:     }
  382: 
  383:   if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
  384:     return ++dpyinfo->bitmaps_last;
  385: 
  386:   for (i = 0; i < dpyinfo->bitmaps_size; ++i)
  387:     if (dpyinfo->bitmaps[i].refcount == 0)
  388:       return i + 1;
  389: 
  390:   dpyinfo->bitmaps_size *= 2;
  391:   dpyinfo->bitmaps
  392:     = (Bitmap_Record *) xrealloc (dpyinfo->bitmaps,
  393:                                   dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
  394:   return ++dpyinfo->bitmaps_last;
  395: }
  396: 
  397: /* Add one reference to the reference count of the bitmap with id ID.  */
  398: 
  399: void
  400: x_reference_bitmap (f, id)
  401:      FRAME_PTR f;
  402:      int id;
  403: {
  404:   ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
  405: }
  406: 
  407: /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS.  */
  408: 
  409: int
  410: x_create_bitmap_from_data (f, bits, width, height)
  411:      struct frame *f;
  412:      char *bits;
  413:      unsigned int width, height;
  414: {
  415:   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
  416:   int id;
  417: 
  418: #ifdef HAVE_X_WINDOWS
  419:   Pixmap bitmap;
  420:   bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
  421:                                   bits, width, height);
  422:   if (! bitmap)
  423:     return -1;
  424: #endif /* HAVE_X_WINDOWS */
  425: 
  426: #ifdef HAVE_NTGUI
  427:   Pixmap bitmap;
  428:   bitmap = CreateBitmap (width, height,
  429:                          FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_planes,
  430:                          FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_cbits,
  431:                          bits);
  432:   if (! bitmap)
  433:     return -1;
  434: #endif /* HAVE_NTGUI */
  435: 
  436: #ifdef MAC_OS
  437:   /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */
  438:   if (width % 16 != 0)
  439:     return -1;
  440: #endif
  441: 
  442:   id = x_allocate_bitmap_record (f);
  443: #ifdef MAC_OS
  444:   dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width);
  445:   bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width);
  446: #endif  /* MAC_OS */
  447: 
  448:   dpyinfo->bitmaps[id - 1].file = NULL;
  449:   dpyinfo->bitmaps[id - 1].height = height;
  450:   dpyinfo->bitmaps[id - 1].width = width;
  451:   dpyinfo->bitmaps[id - 1].refcount = 1;
  452: 
  453: #ifdef HAVE_X_WINDOWS
  454:   dpyinfo->bitmaps[id - 1].pixmap = bitmap;
  455:   dpyinfo->bitmaps[id - 1].have_mask = 0;
  456:   dpyinfo->bitmaps[id - 1].depth = 1;
  457: #endif /* HAVE_X_WINDOWS */
  458: 
  459: #ifdef HAVE_NTGUI
  460:   dpyinfo->bitmaps[id - 1].pixmap = bitmap;
  461:   dpyinfo->bitmaps[id - 1].hinst = NULL;
  462:   dpyinfo->bitmaps[id - 1].depth = 1;
  463: #endif /* HAVE_NTGUI */
  464: 
  465:   return id;
  466: }
  467: 
  468: /* Create bitmap from file FILE for frame F.  */
  469: 
  470: int
  471: x_create_bitmap_from_file (f, file)
  472:      struct frame *f;
  473:      Lisp_Object file;
  474: {
  475: #ifdef MAC_OS
  476:   return -1;  /* MAC_TODO : bitmap support */
  477: #endif  /* MAC_OS */
  478: 
  479: #ifdef HAVE_NTGUI
  480:   return -1;  /* W32_TODO : bitmap support */
  481: #endif /* HAVE_NTGUI */
  482: 
  483: #ifdef HAVE_X_WINDOWS
  484:   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
  485:   unsigned int width, height;
  486:   Pixmap bitmap;
  487:   int xhot, yhot, result, id;
  488:   Lisp_Object found;
  489:   int fd;
  490:   char *filename;
  491: 
  492:   /* Look for an existing bitmap with the same name.  */
  493:   for (id = 0; id < dpyinfo->bitmaps_last; ++id)
  494:     {
  495:       if (dpyinfo->bitmaps[id].refcount
  496:           && dpyinfo->bitmaps[id].file
  497:           && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
  498:         {
  499:           ++dpyinfo->bitmaps[id].refcount;
  500:           return id + 1;
  501:         }
  502:     }
  503: 
  504:   /* Search bitmap-file-path for the file, if appropriate.  */
  505:   fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
  506:   if (fd < 0)
  507:     return -1;
  508:   emacs_close (fd);
  509: 
  510:   filename = (char *) SDATA (found);
  511: 
  512:   result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
  513:                             filename, &width, &height, &bitmap, &xhot, &yhot);
  514:   if (result != BitmapSuccess)
  515:     return -1;
  516: 
  517:   id = x_allocate_bitmap_record (f);
  518:   dpyinfo->bitmaps[id - 1].pixmap = bitmap;
  519:   dpyinfo->bitmaps[id - 1].have_mask = 0;
  520:   dpyinfo->bitmaps[id - 1].refcount = 1;
  521:   dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SBYTES (file) + 1);
  522:   dpyinfo->bitmaps[id - 1].depth = 1;
  523:   dpyinfo->bitmaps[id - 1].height = height;
  524:   dpyinfo->bitmaps[id - 1].width = width;
  525:   strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
  526: 
  527:   return id;
  528: #endif /* HAVE_X_WINDOWS */
  529: }
  530: 
  531: /* Free bitmap B.  */
  532: 
  533: static void
  534: Free_Bitmap_Record (dpyinfo, bm)
  535:      Display_Info *dpyinfo;
  536:      Bitmap_Record *bm;
  537: {
  538: #ifdef HAVE_X_WINDOWS
  539:   XFreePixmap (dpyinfo->display, bm->pixmap);
  540:   if (bm->have_mask)
  541:     XFreePixmap (dpyinfo->display, bm->mask);
  542: #endif /* HAVE_X_WINDOWS */
  543: 
  544: #ifdef HAVE_NTGUI
  545:   DeleteObject (bm->pixmap);
  546: #endif /* HAVE_NTGUI */
  547: 
  548: #ifdef MAC_OS
  549:   xfree (bm->bitmap_data);  /* Added ++kfs */
  550:   bm->bitmap_data = NULL;
  551: #endif  /* MAC_OS */
  552: 
  553:   if (bm->file)
  554:     {
  555:       xfree (bm->file);
  556:       bm->file = NULL;
  557:     }
  558: }
  559: 
  560: /* Remove reference to bitmap with id number ID.  */
  561: 
  562: void
  563: x_destroy_bitmap (f, id)
  564:      FRAME_PTR f;
  565: