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