168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// found in the LICENSE file. 468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/gfx/x/x11_types.h" 668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include <X11/Xlib.h> 868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/command_line.h" 1068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/message_loop/message_loop.h" 11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/x/x11_switches.h" 1268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 1368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)namespace gfx { 1468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 1568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)XDisplay* GetXDisplay() { 16a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch static XDisplay* display = NULL; 17a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!display) 18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) display = OpenNewXDisplay(); 19a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return display; 2068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 2168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)XDisplay* OpenNewXDisplay() { 23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if defined(OS_CHROMEOS) 24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return XOpenDisplay(NULL); 25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#else 26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string display_str = base::CommandLine::ForCurrentProcess()-> 27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GetSwitchValueASCII(switches::kX11Display); 28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return XOpenDisplay(display_str.empty() ? NULL : display_str.c_str()); 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif 30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 3268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void PutARGBImage(XDisplay* display, 3368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) void* visual, int depth, 3468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XID pixmap, void* pixmap_gc, 3568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const uint8* data, 3668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int width, int height) { 3768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) PutARGBImage(display, 3868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) visual, depth, 3968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) pixmap, pixmap_gc, 4068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) data, width, height, 4168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 0, 0, // src_x, src_y 4268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 0, 0, // dst_x, dst_y 4368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) width, height); 4468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 4568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 4668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)int BitsPerPixelForPixmapDepth(XDisplay* dpy, int depth) { 4768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int count; 4868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XPixmapFormatValues* formats = XListPixmapFormats(dpy, &count); 4968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (!formats) 5068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return -1; 5168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 5268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int bits_per_pixel = -1; 5368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (int i = 0; i < count; ++i) { 5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (formats[i].depth == depth) { 5568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) bits_per_pixel = formats[i].bits_per_pixel; 5668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) break; 5768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 5868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 5968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 6068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XFree(formats); 6168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return bits_per_pixel; 6268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 6368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 6468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void PutARGBImage(XDisplay* display, 6568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) void* visual, int depth, 6668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XID pixmap, void* pixmap_gc, 6768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const uint8* data, 6868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int data_width, int data_height, 6968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int src_x, int src_y, 7068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int dst_x, int dst_y, 7168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int copy_width, int copy_height) { 7268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // TODO(scherkus): potential performance impact... consider passing in as a 7368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // parameter. 7468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int pixmap_bpp = BitsPerPixelForPixmapDepth(display, depth); 7568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 7668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XImage image; 7768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) memset(&image, 0, sizeof(image)); 7868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 7968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.width = data_width; 8068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.height = data_height; 8168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.format = ZPixmap; 8268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.byte_order = LSBFirst; 8368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.bitmap_unit = 8; 8468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.bitmap_bit_order = LSBFirst; 8568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.depth = depth; 8668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.bits_per_pixel = pixmap_bpp; 8768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.bytes_per_line = data_width * pixmap_bpp / 8; 8868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 8968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (pixmap_bpp == 32) { 9068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.red_mask = 0xff0000; 9168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.green_mask = 0xff00; 9268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.blue_mask = 0xff; 9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 9468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // If the X server depth is already 32-bits and the color masks match, 9568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // then our job is easy. 9668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) Visual* vis = static_cast<Visual*>(visual); 9768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (image.red_mask == vis->red_mask && 9868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.green_mask == vis->green_mask && 9968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.blue_mask == vis->blue_mask) { 10068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.data = const_cast<char*>(reinterpret_cast<const char*>(data)); 10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image, 10268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) src_x, src_y, dst_x, dst_y, 10368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) copy_width, copy_height); 10468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } else { 10568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // Otherwise, we need to shuffle the colors around. Assume red and blue 10668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // need to be swapped. 10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // 10868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // It's possible to use some fancy SSE tricks here, but since this is the 10968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // slow path anyway, we do it slowly. 11068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 11168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) uint8_t* bitmap32 = 11268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) static_cast<uint8_t*>(malloc(4 * data_width * data_height)); 11368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (!bitmap32) 11468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return; 11568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) uint8_t* const orig_bitmap32 = bitmap32; 11668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data); 11768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (int y = 0; y < data_height; ++y) { 11868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (int x = 0; x < data_width; ++x) { 11968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const uint32_t pixel = *(bitmap_in++); 12068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) bitmap32[0] = (pixel >> 16) & 0xff; // Red 12168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) bitmap32[1] = (pixel >> 8) & 0xff; // Green 12268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) bitmap32[2] = pixel & 0xff; // Blue 12368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) bitmap32[3] = (pixel >> 24) & 0xff; // Alpha 12468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) bitmap32 += 4; 12568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 12668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 12768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.data = reinterpret_cast<char*>(orig_bitmap32); 12868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image, 12968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) src_x, src_y, dst_x, dst_y, 13068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) copy_width, copy_height); 13168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) free(orig_bitmap32); 13268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 13368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } else if (pixmap_bpp == 16) { 13468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // Some folks have VNC setups which still use 16-bit visuals and VNC 13568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // doesn't include Xrender. 13668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 13768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) uint16_t* bitmap16 = 13868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) static_cast<uint16_t*>(malloc(2 * data_width * data_height)); 13968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (!bitmap16) 14068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return; 14168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) uint16_t* const orig_bitmap16 = bitmap16; 14268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data); 14368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (int y = 0; y < data_height; ++y) { 14468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (int x = 0; x < data_width; ++x) { 14568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const uint32_t pixel = *(bitmap_in++); 14668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) uint16_t out_pixel = ((pixel >> 8) & 0xf800) | 14768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ((pixel >> 5) & 0x07e0) | 14868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ((pixel >> 3) & 0x001f); 14968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) *(bitmap16++) = out_pixel; 15068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 15168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 15268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 15368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.data = reinterpret_cast<char*>(orig_bitmap16); 15468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.red_mask = 0xf800; 15568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.green_mask = 0x07e0; 15668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) image.blue_mask = 0x001f; 15768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 15868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image, 15968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) src_x, src_y, dst_x, dst_y, 16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) copy_width, copy_height); 16168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) free(orig_bitmap16); 16268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } else { 16368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) LOG(FATAL) << "Sorry, we don't support your visual depth without " 16468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) "Xrender support (depth:" << depth 16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) << " bpp:" << pixmap_bpp << ")"; 16668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 16768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 16868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 16968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} // namespace gfx 17068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 171