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
13namespace gfx {
14
15XDisplay* GetXDisplay() {
16  static XDisplay* display = NULL;
17  if (!display)
18    display = OpenNewXDisplay();
19  return display;
20}
21
22XDisplay* 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
32void 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
46int 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
64void 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