168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// found in the LICENSE file.
468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/gfx/x/x11_types.h"
668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include <X11/Xlib.h>
868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/command_line.h"
1068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/message_loop/message_loop.h"
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/x/x11_switches.h"
1268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)namespace gfx {
1468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)XDisplay* GetXDisplay() {
16a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  static XDisplay* display = NULL;
17a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!display)
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    display = OpenNewXDisplay();
19a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return display;
2068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
2168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)XDisplay* OpenNewXDisplay() {
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if defined(OS_CHROMEOS)
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return XOpenDisplay(NULL);
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#else
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string display_str = base::CommandLine::ForCurrentProcess()->
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            GetSwitchValueASCII(switches::kX11Display);
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return XOpenDisplay(display_str.empty() ? NULL : display_str.c_str());
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
3268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void PutARGBImage(XDisplay* display,
3368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  void* visual, int depth,
3468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  XID pixmap, void* pixmap_gc,
3568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  const uint8* data,
3668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  int width, int height) {
3768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  PutARGBImage(display,
3868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)               visual, depth,
3968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)               pixmap, pixmap_gc,
4068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)               data, width, height,
4168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)               0, 0, // src_x, src_y
4268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)               0, 0, // dst_x, dst_y
4368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)               width, height);
4468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
4568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
4668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)int BitsPerPixelForPixmapDepth(XDisplay* dpy, int depth) {
4768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int count;
4868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XPixmapFormatValues* formats = XListPixmapFormats(dpy, &count);
4968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!formats)
5068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return -1;
5168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int bits_per_pixel = -1;
5368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (int i = 0; i < count; ++i) {
5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (formats[i].depth == depth) {
5568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      bits_per_pixel = formats[i].bits_per_pixel;
5668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      break;
5768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
5868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
5968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
6068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XFree(formats);
6168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return bits_per_pixel;
6268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
6368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
6468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void PutARGBImage(XDisplay* display,
6568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  void* visual, int depth,
6668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  XID pixmap, void* pixmap_gc,
6768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  const uint8* data,
6868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  int data_width, int data_height,
6968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  int src_x, int src_y,
7068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  int dst_x, int dst_y,
7168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  int copy_width, int copy_height) {
7268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // TODO(scherkus): potential performance impact... consider passing in as a
7368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // parameter.
7468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int pixmap_bpp = BitsPerPixelForPixmapDepth(display, depth);
7568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
7668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  XImage image;
7768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  memset(&image, 0, sizeof(image));
7868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
7968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  image.width = data_width;
8068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  image.height = data_height;
8168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  image.format = ZPixmap;
8268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  image.byte_order = LSBFirst;
8368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  image.bitmap_unit = 8;
8468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  image.bitmap_bit_order = LSBFirst;
8568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  image.depth = depth;
8668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  image.bits_per_pixel = pixmap_bpp;
8768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  image.bytes_per_line = data_width * pixmap_bpp / 8;
8868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
8968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (pixmap_bpp == 32) {
9068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    image.red_mask = 0xff0000;
9168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    image.green_mask = 0xff00;
9268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    image.blue_mask = 0xff;
9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
9468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // If the X server depth is already 32-bits and the color masks match,
9568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // then our job is easy.
9668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    Visual* vis = static_cast<Visual*>(visual);
9768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (image.red_mask == vis->red_mask &&
9868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        image.green_mask == vis->green_mask &&
9968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        image.blue_mask == vis->blue_mask) {
10068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      image.data = const_cast<char*>(reinterpret_cast<const char*>(data));
10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
10268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                src_x, src_y, dst_x, dst_y,
10368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                copy_width, copy_height);
10468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    } else {
10568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      // Otherwise, we need to shuffle the colors around. Assume red and blue
10668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      // need to be swapped.
10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      //
10868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      // It's possible to use some fancy SSE tricks here, but since this is the
10968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      // slow path anyway, we do it slowly.
11068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
11168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      uint8_t* bitmap32 =
11268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          static_cast<uint8_t*>(malloc(4 * data_width * data_height));
11368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      if (!bitmap32)
11468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        return;
11568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      uint8_t* const orig_bitmap32 = bitmap32;
11668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data);
11768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      for (int y = 0; y < data_height; ++y) {
11868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        for (int x = 0; x < data_width; ++x) {
11968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          const uint32_t pixel = *(bitmap_in++);
12068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          bitmap32[0] = (pixel >> 16) & 0xff;  // Red
12168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          bitmap32[1] = (pixel >> 8) & 0xff;   // Green
12268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          bitmap32[2] = pixel & 0xff;          // Blue
12368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          bitmap32[3] = (pixel >> 24) & 0xff;  // Alpha
12468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          bitmap32 += 4;
12568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        }
12668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      }
12768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      image.data = reinterpret_cast<char*>(orig_bitmap32);
12868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
12968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                src_x, src_y, dst_x, dst_y,
13068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                copy_width, copy_height);
13168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      free(orig_bitmap32);
13268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
13368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else if (pixmap_bpp == 16) {
13468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Some folks have VNC setups which still use 16-bit visuals and VNC
13568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // doesn't include Xrender.
13668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
13768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    uint16_t* bitmap16 =
13868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        static_cast<uint16_t*>(malloc(2 * data_width * data_height));
13968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (!bitmap16)
14068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      return;
14168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    uint16_t* const orig_bitmap16 = bitmap16;
14268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data);
14368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    for (int y = 0; y < data_height; ++y) {
14468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      for (int x = 0; x < data_width; ++x) {
14568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        const uint32_t pixel = *(bitmap_in++);
14668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        uint16_t out_pixel = ((pixel >> 8) & 0xf800) |
14768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                             ((pixel >> 5) & 0x07e0) |
14868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                             ((pixel >> 3) & 0x001f);
14968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        *(bitmap16++) = out_pixel;
15068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      }
15168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
15268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
15368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    image.data = reinterpret_cast<char*>(orig_bitmap16);
15468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    image.red_mask = 0xf800;
15568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    image.green_mask = 0x07e0;
15668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    image.blue_mask = 0x001f;
15768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
15868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
15968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              src_x, src_y, dst_x, dst_y,
16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              copy_width, copy_height);
16168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    free(orig_bitmap16);
16268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else {
16368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    LOG(FATAL) << "Sorry, we don't support your visual depth without "
16468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  "Xrender support (depth:" << depth
16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)               << " bpp:" << pixmap_bpp << ")";
16668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
16768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
16868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
16968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}  // namespace gfx
17068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
171