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
|
// 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 "ui/gfx/x/x11_switches.h"
namespace gfx {
XDisplay* GetXDisplay() {
static XDisplay* display = NULL;
if (!display)
display = OpenNewXDisplay();
return display;
}
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* 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;
XPixmapFormatValues* formats = XListPixmapFormats(dpy, &count);
if (!formats)
return -1;
int bits_per_pixel = -1;
for (int i = 0; i < count; ++i) {
if (formats[i].depth == depth) {
bits_per_pixel = formats[i].bits_per_pixel;
break;
}
}
XFree(formats);
return bits_per_pixel;
}
void 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) {
// 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) & 0xf800) |
((pixel >> 5) & 0x07e0) |
((pixel >> 3) & 0x001f);
*(bitmap16++) = out_pixel;
}
}
image.data = reinterpret_cast<char*>(orig_bitmap16);
image.red_mask = 0xf800;
image.green_mask = 0x07e0;
image.blue_mask = 0x001f;
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
|