Home | History | Annotate | Download | only in x
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/gfx/x/x11_types.h"
      6 
      7 #include <X11/Xlib.h>
      8 
      9 #include "base/command_line.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "ui/gfx/x/x11_switches.h"
     12 
     13 namespace gfx {
     14 
     15 XDisplay* GetXDisplay() {
     16   static XDisplay* display = NULL;
     17   if (!display)
     18     display = OpenNewXDisplay();
     19   return display;
     20 }
     21 
     22 XDisplay* OpenNewXDisplay() {
     23 #if defined(OS_CHROMEOS)
     24   return XOpenDisplay(NULL);
     25 #else
     26   std::string display_str = base::CommandLine::ForCurrentProcess()->
     27                             GetSwitchValueASCII(switches::kX11Display);
     28   return XOpenDisplay(display_str.empty() ? NULL : display_str.c_str());
     29 #endif
     30 }
     31 
     32 void PutARGBImage(XDisplay* display,
     33                   void* visual, int depth,
     34                   XID pixmap, void* pixmap_gc,
     35                   const uint8* data,
     36                   int width, int height) {
     37   PutARGBImage(display,
     38                visual, depth,
     39                pixmap, pixmap_gc,
     40                data, width, height,
     41                0, 0, // src_x, src_y
     42                0, 0, // dst_x, dst_y
     43                width, height);
     44 }
     45 
     46 int BitsPerPixelForPixmapDepth(XDisplay* dpy, int depth) {
     47   int count;
     48   XPixmapFormatValues* formats = XListPixmapFormats(dpy, &count);
     49   if (!formats)
     50     return -1;
     51 
     52   int bits_per_pixel = -1;
     53   for (int i = 0; i < count; ++i) {
     54     if (formats[i].depth == depth) {
     55       bits_per_pixel = formats[i].bits_per_pixel;
     56       break;
     57     }
     58   }
     59 
     60   XFree(formats);
     61   return bits_per_pixel;
     62 }
     63 
     64 void PutARGBImage(XDisplay* display,
     65                   void* visual, int depth,
     66                   XID pixmap, void* pixmap_gc,
     67                   const uint8* data,
     68                   int data_width, int data_height,
     69                   int src_x, int src_y,
     70                   int dst_x, int dst_y,
     71                   int copy_width, int copy_height) {
     72   // TODO(scherkus): potential performance impact... consider passing in as a
     73   // parameter.
     74   int pixmap_bpp = BitsPerPixelForPixmapDepth(display, depth);
     75 
     76   XImage image;
     77   memset(&image, 0, sizeof(image));
     78 
     79   image.width = data_width;
     80   image.height = data_height;
     81   image.format = ZPixmap;
     82   image.byte_order = LSBFirst;
     83   image.bitmap_unit = 8;
     84   image.bitmap_bit_order = LSBFirst;
     85   image.depth = depth;
     86   image.bits_per_pixel = pixmap_bpp;
     87   image.bytes_per_line = data_width * pixmap_bpp / 8;
     88 
     89   if (pixmap_bpp == 32) {
     90     image.red_mask = 0xff0000;
     91     image.green_mask = 0xff00;
     92     image.blue_mask = 0xff;
     93 
     94     // If the X server depth is already 32-bits and the color masks match,
     95     // then our job is easy.
     96     Visual* vis = static_cast<Visual*>(visual);
     97     if (image.red_mask == vis->red_mask &&
     98         image.green_mask == vis->green_mask &&
     99         image.blue_mask == vis->blue_mask) {
    100       image.data = const_cast<char*>(reinterpret_cast<const char*>(data));
    101       XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
    102                 src_x, src_y, dst_x, dst_y,
    103                 copy_width, copy_height);
    104     } else {
    105       // Otherwise, we need to shuffle the colors around. Assume red and blue
    106       // need to be swapped.
    107       //
    108       // It's possible to use some fancy SSE tricks here, but since this is the
    109       // slow path anyway, we do it slowly.
    110 
    111       uint8_t* bitmap32 =
    112           static_cast<uint8_t*>(malloc(4 * data_width * data_height));
    113       if (!bitmap32)
    114         return;
    115       uint8_t* const orig_bitmap32 = bitmap32;
    116       const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data);
    117       for (int y = 0; y < data_height; ++y) {
    118         for (int x = 0; x < data_width; ++x) {
    119           const uint32_t pixel = *(bitmap_in++);
    120           bitmap32[0] = (pixel >> 16) & 0xff;  // Red
    121           bitmap32[1] = (pixel >> 8) & 0xff;   // Green
    122           bitmap32[2] = pixel & 0xff;          // Blue
    123           bitmap32[3] = (pixel >> 24) & 0xff;  // Alpha
    124           bitmap32 += 4;
    125         }
    126       }
    127       image.data = reinterpret_cast<char*>(orig_bitmap32);
    128       XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
    129                 src_x, src_y, dst_x, dst_y,
    130                 copy_width, copy_height);
    131       free(orig_bitmap32);
    132     }
    133   } else if (pixmap_bpp == 16) {
    134     // Some folks have VNC setups which still use 16-bit visuals and VNC
    135     // doesn't include Xrender.
    136 
    137     uint16_t* bitmap16 =
    138         static_cast<uint16_t*>(malloc(2 * data_width * data_height));
    139     if (!bitmap16)
    140       return;
    141     uint16_t* const orig_bitmap16 = bitmap16;
    142     const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data);
    143     for (int y = 0; y < data_height; ++y) {
    144       for (int x = 0; x < data_width; ++x) {
    145         const uint32_t pixel = *(bitmap_in++);
    146         uint16_t out_pixel = ((pixel >> 8) & 0xf800) |
    147                              ((pixel >> 5) & 0x07e0) |
    148                              ((pixel >> 3) & 0x001f);
    149         *(bitmap16++) = out_pixel;
    150       }
    151     }
    152 
    153     image.data = reinterpret_cast<char*>(orig_bitmap16);
    154     image.red_mask = 0xf800;
    155     image.green_mask = 0x07e0;
    156     image.blue_mask = 0x001f;
    157 
    158     XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
    159               src_x, src_y, dst_x, dst_y,
    160               copy_width, copy_height);
    161     free(orig_bitmap16);
    162   } else {
    163     LOG(FATAL) << "Sorry, we don't support your visual depth without "
    164                   "Xrender support (depth:" << depth
    165                << " bpp:" << pixmap_bpp << ")";
    166   }
    167 }
    168 
    169 }  // namespace gfx
    170 
    171