• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetXDisplay()15 XDisplay* GetXDisplay() {
16   static XDisplay* display = NULL;
17   if (!display)
18     display = OpenNewXDisplay();
19   return display;
20 }
21 
OpenNewXDisplay()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 
PutARGBImage(XDisplay * display,void * visual,int depth,XID pixmap,void * pixmap_gc,const uint8 * data,int width,int height)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 
BitsPerPixelForPixmapDepth(XDisplay * dpy,int depth)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 
PutARGBImage(XDisplay * display,void * visual,int depth,XID pixmap,void * pixmap_gc,const uint8 * 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)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