spice/client/windows/red_pixmap_cairo.cpp
Alexander Larsson 774e5bd36f Client: Support pixmap format conversion in copy_pixels
In order to be able to support 16bit canvases on 32bit screens and 32bit
canvases on 16bit screens we need to handle format conversion when drawing
RedPixmaps.

The way this works now for X11 is that we only have one PIXELS_SOURCE_TYPE
for pixmaps, which always has a pixman_image_t for the data, but additionally
it has an XImage (shared mem or not) if the screen the pixmap was created
for (i.e. an explicit one or the default screen) has the same format as
the pixmap.

When we draw a pixmap on a drawable we have two variants. If the pixmap
has a XImage and it matches the format of the target drawable then we
just X(Shm)PutImage it to the drawable. If the formats differ, then we
create a temporary XImage and convert into that before drawing it to
the screen.

Right now this is a bit inefficient, because we always allocate a new
temporary image when converting. We want to add some caching here, but
at least this lets things work again.
2010-04-23 16:39:13 +02:00

99 lines
3.6 KiB
C++

/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "common.h"
#include "red_pixmap_cairo.h"
#include "red_pixmap.h"
#include "debug.h"
#include "utils.h"
#include "pixels_source_p.h"
#include "platform_utils.h"
struct RedPixmap_p {
PixelsSource_p pixels_source_p;
HBITMAP prev_bitmap;
};
RedPixmapCairo::RedPixmapCairo(int width, int height, RedDrawable::Format format,
bool top_bottom, RedWindow *win)
: RedPixmap(width, height, format, top_bottom)
{
ASSERT(format == RedDrawable::ARGB32 || format == RedDrawable::RGB32 || format == RedDrawable::A1);
ASSERT(sizeof(RedPixmap_p) <= PIXELES_SOURCE_OPAQUE_SIZE);
struct {
BITMAPINFO inf;
RGBQUAD palette[255];
} bitmap_info;
memset(&bitmap_info, 0, sizeof(bitmap_info));
bitmap_info.inf.bmiHeader.biSize = sizeof(bitmap_info.inf.bmiHeader);
bitmap_info.inf.bmiHeader.biWidth = _width;
bitmap_info.inf.bmiHeader.biHeight = top_bottom ? -_height : _height;
/*#ifdef USE_OGL
// -----------------------------------------------------------------------------
// ensure valid access to additional stride.
// apparently glReadPixels validate ((ptr of last line) + GL_PACK_ROW_LENGTH + 1).
// seen on "ATI Radeon HD 2400 PRO" "2.0.6479 Release"
if (top_bottom) {
bitmap_info.inf.bmiHeader.biHeight--;
} else {
bitmap_info.inf.bmiHeader.biHeight++;
}
//------------------------------------------------------------------------------
#endif*/
bitmap_info.inf.bmiHeader.biPlanes = 1;
bitmap_info.inf.bmiHeader.biBitCount = RedDrawable::format_to_bpp(format);
bitmap_info.inf.bmiHeader.biCompression = BI_RGB;
switch (format) {
case RedDrawable::A1:
bitmap_info.inf.bmiColors[0].rgbRed = 0;
bitmap_info.inf.bmiColors[0].rgbGreen = 0;
bitmap_info.inf.bmiColors[0].rgbBlue = 0;
bitmap_info.inf.bmiColors[1].rgbRed = 0xff;
bitmap_info.inf.bmiColors[1].rgbGreen = 0xff;
bitmap_info.inf.bmiColors[1].rgbBlue = 0xff;
break;
}
AutoDC dc(create_compatible_dc());
AutoGDIObject bitmap(CreateDIBSection(dc.get(), &bitmap_info.inf, 0,
(VOID **)&_data, NULL, 0));
if (!bitmap.valid()) {
THROW("create compatible bitmap failed");
}
/*#ifdef USE_OGL
SetWindowOrgEx(dc.get(), 0, -1, NULL); // compensate for one pad line
#endif*/
((RedPixmap_p*)get_opaque())->prev_bitmap = (HBITMAP)SelectObject(dc.get(), bitmap.release());
((RedPixmap_p*)get_opaque())->pixels_source_p.dc = dc.release();
}
RedPixmapCairo::~RedPixmapCairo()
{
HDC dc = ((RedPixmap_p*)get_opaque())->pixels_source_p.dc;
if (dc) {
HBITMAP prev_bitmap = ((RedPixmap_p*)get_opaque())->prev_bitmap;
HBITMAP bitmap = (HBITMAP)SelectObject(dc, prev_bitmap);
DeleteObject(bitmap);
DeleteDC(dc);
}
}