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 15 XDisplay* GetXDisplay() { 16 static XDisplay* display = NULL; 17 if (!display) 18 display = OpenNewXDisplay(); 19 return display; 20 } 21 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 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 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 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