summaryrefslogtreecommitdiffstats
path: root/chromium/ui/gfx/x/x11_types.cc
blob: 3858212aa36f5b98697246ac9c4a52d2cfd1f530 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gfx/x/x11_types.h"

#include <X11/Xlib.h>

#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "build/build_config.h"
#include "ui/gfx/x/x11_switches.h"

#ifdef TOOLKIT_QT
extern XDisplay* GetQtXDisplay();
#endif

namespace gfx {

XDisplay* GetXDisplay() {
#ifdef TOOLKIT_QT
  return GetQtXDisplay();
#else
  static XDisplay* display = NULL;
  if (!display)
    display = OpenNewXDisplay();
  return display;
#endif
}

XDisplay* OpenNewXDisplay() {
#if defined(OS_CHROMEOS)
  return XOpenDisplay(NULL);
#else
  std::string display_str = base::CommandLine::ForCurrentProcess()->
                            GetSwitchValueASCII(switches::kX11Display);
  return XOpenDisplay(display_str.empty() ? NULL : display_str.c_str());
#endif
}

void PutARGBImage(XDisplay* display,
                  void* visual,
                  int depth,
                  XID pixmap,
                  void* pixmap_gc,
                  const uint8_t* data,
                  int width,
                  int height) {
  PutARGBImage(display,
               visual, depth,
               pixmap, pixmap_gc,
               data, width, height,
               0, 0, // src_x, src_y
               0, 0, // dst_x, dst_y
               width, height);
}

int BitsPerPixelForPixmapDepth(XDisplay* dpy, int depth) {
  int count;
  XScopedPtr<XPixmapFormatValues[]> formats(XListPixmapFormats(dpy, &count));
  if (!formats)
    return -1;

  for (int i = 0; i < count; ++i) {
    if (formats[i].depth == depth)
      return formats[i].bits_per_pixel;
  }

  return -1;
}

void PutARGBImage(XDisplay* display,
                  void* visual,
                  int depth,
                  XID pixmap,
                  void* pixmap_gc,
                  const uint8_t* data,
                  int data_width,
                  int data_height,
                  int src_x,
                  int src_y,
                  int dst_x,
                  int dst_y,
                  int copy_width,
                  int copy_height) {
  // TODO(scherkus): potential performance impact... consider passing in as a
  // parameter.
  int pixmap_bpp = BitsPerPixelForPixmapDepth(display, depth);

  XImage image;
  memset(&image, 0, sizeof(image));

  image.width = data_width;
  image.height = data_height;
  image.format = ZPixmap;
  image.byte_order = LSBFirst;
  image.bitmap_unit = 8;
  image.bitmap_bit_order = LSBFirst;
  image.depth = depth;
  image.bits_per_pixel = pixmap_bpp;
  image.bytes_per_line = data_width * pixmap_bpp / 8;

  if (pixmap_bpp == 32) {
    image.red_mask = 0xff0000;
    image.green_mask = 0xff00;
    image.blue_mask = 0xff;

    // If the X server depth is already 32-bits and the color masks match,
    // then our job is easy.
    Visual* vis = static_cast<Visual*>(visual);
    if (image.red_mask == vis->red_mask &&
        image.green_mask == vis->green_mask &&
        image.blue_mask == vis->blue_mask) {
      image.data = const_cast<char*>(reinterpret_cast<const char*>(data));
      XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
                src_x, src_y, dst_x, dst_y,
                copy_width, copy_height);
    } else {
      // Otherwise, we need to shuffle the colors around. Assume red and blue
      // need to be swapped.
      //
      // It's possible to use some fancy SSE tricks here, but since this is the
      // slow path anyway, we do it slowly.

      uint8_t* bitmap32 =
          static_cast<uint8_t*>(malloc(4 * data_width * data_height));
      if (!bitmap32)
        return;
      uint8_t* const orig_bitmap32 = bitmap32;
      const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data);
      for (int y = 0; y < data_height; ++y) {
        for (int x = 0; x < data_width; ++x) {
          const uint32_t pixel = *(bitmap_in++);
          bitmap32[0] = (pixel >> 16) & 0xff;  // Red
          bitmap32[1] = (pixel >> 8) & 0xff;   // Green
          bitmap32[2] = pixel & 0xff;          // Blue
          bitmap32[3] = (pixel >> 24) & 0xff;  // Alpha
          bitmap32 += 4;
        }
      }
      image.data = reinterpret_cast<char*>(orig_bitmap32);
      XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
                src_x, src_y, dst_x, dst_y,
                copy_width, copy_height);
      free(orig_bitmap32);
    }
  } else if (pixmap_bpp == 16) {
    // Some folks have VNC setups which still use 16-bit visuals and VNC
    // doesn't include Xrender.

    uint16_t* bitmap16 =
        static_cast<uint16_t*>(malloc(2 * data_width * data_height));
    if (!bitmap16)
      return;
    uint16_t* const orig_bitmap16 = bitmap16;
    const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data);
    for (int y = 0; y < data_height; ++y) {
      for (int x = 0; x < data_width; ++x) {
        const uint32_t pixel = *(bitmap_in++);
        uint16_t out_pixel = ((pixel >> 8) & 0b1111100000000000) |
                             ((pixel >> 5) & 0b0000011111100000) |
                             ((pixel >> 3) & 0b0000000000011111);
        *(bitmap16++) = out_pixel;
      }
    }

    image.data = reinterpret_cast<char*>(orig_bitmap16);
    image.red_mask = 0b1111100000000000;
    image.green_mask = 0b0000011111100000;
    image.blue_mask = 0b0000000000011111;

    XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
              src_x, src_y, dst_x, dst_y,
              copy_width, copy_height);
    free(orig_bitmap16);
  } else {
    LOG(FATAL) << "Sorry, we don't support your visual depth without "
                  "Xrender support (depth:" << depth
               << " bpp:" << pixmap_bpp << ")";
  }
}

}  // namespace gfx