#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <DeviceBitmap.h>
#include <Widget.h>
#include <Image.h>
#include <Icon.h>
#include <Application.h>
#include <Printer.h>
#ifdef PRIMA_PLATFORM_X11
#include <unix/guts.h>
#define Drawable XDrawable
#define Font XFont
#include <cairo.h>
#include <cairo-xlib.h>
#ifdef HAVE_X11_EXTENSIONS_XRENDER_H
#include <cairo-xlib-xrender.h>
#endif
#define sys (( PDrawableSysData) var-> sysData)
UnixGuts * pguts;
#else
#include <win32/win32guts.h>
#include <cairo.h>
#include <cairo-win32.h>
#define sys (( PDrawableData) var-> sysData)
#endif
#define REQ_TARGET_APPLICATION 0
#define REQ_TARGET_WINDOW 1
#define REQ_TARGET_BITMAP 2
#define REQ_TARGET_PIXMAP 3
#define REQ_TARGET_IMAGE 4
#define REQ_TARGET_PRINTER 5
#define var (( PDrawable) widget)
PWidget_vmt CWidget;
PDeviceBitmap_vmt CDeviceBitmap;
PImage_vmt CImage;
PIcon_vmt CIcon;
PApplication_vmt CApplication;
PPrinter_vmt CPrinter;
void
*
apc_cairo_surface_create( Handle widget,
int
request)
{
cairo_surface_t * result = NULL;
#ifdef PRIMA_PLATFORM_X11
Point p;
Visual *visual;
if
( pguts == NULL )
pguts = (UnixGuts*) apc_system_action(
"unix_guts"
);
XCHECKPOINT;
switch
( request) {
case
REQ_TARGET_BITMAP:
result = cairo_xlib_surface_create_for_bitmap(DISP, sys->gdrawable, ScreenOfDisplay(DISP,SCREEN), var->w, var->h);
break
;
case
REQ_TARGET_WINDOW:
p = apc_widget_get_size( widget );
#ifdef HAVE_X11_EXTENSIONS_XRENDER_H
if
( sys-> flags. layered )
result = cairo_xlib_surface_create_with_xrender_format(DISP, sys->gdrawable, ScreenOfDisplay(DISP,SCREEN), pguts->argb_pic_format, p.x, p.y);
else
#endif
result = cairo_xlib_surface_create(DISP, sys->gdrawable, VISUAL, p.x, p.y);
break
;
case
REQ_TARGET_PRINTER:
break
;
default
:
#ifdef HAVE_X11_EXTENSIONS_XRENDER_H
if
( sys-> flags. layered )
result = cairo_xlib_surface_create_with_xrender_format(DISP, sys->gdrawable, ScreenOfDisplay(DISP,SCREEN), pguts->argb_pic_format, var->w, var->h);
else
#endif
result = cairo_xlib_surface_create(DISP, sys->gdrawable, VISUAL, var->w, var->h);
}
XCHECKPOINT;
#else
result = ( request == REQ_TARGET_PRINTER ) ?
cairo_win32_printing_surface_create(sys-> ps) :
cairo_win32_surface_create(sys-> ps);
#endif
return
(
void
*) result;
}
static
Byte rev_bytes[256];
static
void
init_rev_bytes()
{
int
i = 0;
static
const
int
end = 1;
if
( *((
char
*) &end) == 0x01 ) {
for
( i = 0; i < 256; i++) {
unsigned
int
j,r = 0;
Byte x = i;
for
(j = 0; j < 8; j++) {
if
( x & 0x80 ) r |= 0x100;
x <<= 1;
r >>= 1;
}
rev_bytes[i] = r & 0xff;
}
}
else
{
for
( i = 0; i < 256; i++) rev_bytes[i] = i;
}
}
static
void
rev_memcpy(
register
Byte *dst,
register
Byte *src,
register
unsigned
int
stride)
{
while
(stride-- > 0) *dst++ = rev_bytes[*src++];
}
static
void
invert(
register
Byte *dst,
register
unsigned
int
stride)
{
while
(stride-- > 0) {
register
Byte x = ~*dst;
*dst++ = x;
}
}
#define T_FROM_CAIRO 0
#define T_TO_CAIRO 0x100
#define T_LE 0
#define T_BE 0x1000
#define T_PALETTE 0
#define T_RGB 0
#define T_ARGB 0x2000
#define T_A1 0
#define T_A8 0x4000
#define T_A0 0x8000
MODULE = Prima::Cairo PACKAGE = Prima::Cairo
BOOT:
{
PRIMA_VERSION_BOOTCHECK;
CWidget = (PWidget_vmt)gimme_the_vmt(
"Prima::Widget"
);
CDeviceBitmap = (PDeviceBitmap_vmt)gimme_the_vmt(
"Prima::DeviceBitmap"
);
CImage = (PImage_vmt)gimme_the_vmt(
"Prima::Image"
);
CIcon = (PIcon_vmt)gimme_the_vmt(
"Prima::Icon"
);
CApplication = (PApplication_vmt)gimme_the_vmt(
"Prima::Application"
);
CPrinter = (PPrinter_vmt)gimme_the_vmt(
"Prima::Printer"
);
init_rev_bytes();
}
PROTOTYPES: ENABLE
void
copy_image_data(im,s,direction)
SV * im;
UV s;
int
direction;
PREINIT:
Handle image;
int
i, w, h, dest_stride, src_stride, mask_stride, stride, selector, cformat;
Byte *dest_buf, *src_buf, *mask_buf, *mask_buf_byte;
Byte colorref_mono[2] = {255,0};
Byte colorref_byte[2] = {1,0};
cairo_surface_t * surface;
static
const
int
end = 1;
CODE:
surface = INT2PTR(cairo_surface_t*,s);
dest_stride = cairo_image_surface_get_stride(surface);
dest_buf = cairo_image_surface_get_data(surface);
cformat = cairo_image_surface_get_format(surface);
if
( !(image = gimme_the_mate(im)) || !kind_of( image, CImage))
croak(
"bad object: not an image"
);
switch
(PImage(image)->type) {
case
imBW:
if
( cformat != CAIRO_FORMAT_A1 ) croak(
"bad surface: not in a1 format"
);
break
;
case
imByte:
if
( cformat != CAIRO_FORMAT_A8 ) croak(
"bad surface: not in a8 format"
);
break
;
case
imRGB:
if
(kind_of( image, CIcon)) {
if
(cformat != CAIRO_FORMAT_ARGB32) croak(
"bad surface: not in argb32 format"
);
}
else
{
if
(cformat != CAIRO_FORMAT_RGB24 && cformat != CAIRO_FORMAT_ARGB32) croak(
"bad surface: not in rgb24/argb32 format"
);
}
break
;
}
w = PImage(image)->w;
h = PImage(image)->h;
src_stride = PImage(image)->lineSize;
src_buf = PImage(image)->data + src_stride * ( h - 1);
stride = ( src_stride > dest_stride ) ? dest_stride : src_stride;
selector = (PImage(image)->type & imBPP) + (direction ? T_TO_CAIRO : T_FROM_CAIRO);
if
(cformat == CAIRO_FORMAT_ARGB32 && kind_of( image, CIcon)) {
mask_stride = PIcon(image)->maskLine;
mask_buf = PIcon(image)->mask + mask_stride * (h - 1);
mask_buf_byte =
malloc
(w);
selector |= T_ARGB | T_A1;
if
( PIcon(image)->maskType == imbpp8) selector |= T_A8;
}
else
if
(direction && cformat == CAIRO_FORMAT_ARGB32) {
mask_buf = mask_buf_byte = NULL;
selector |= T_ARGB | T_A0;
}
else
{
mask_buf = mask_buf_byte = NULL;
mask_stride = 0;
}
if
( *((
char
*) &end) != 0x01 && (cformat == CAIRO_FORMAT_ARGB32 || cformat == CAIRO_FORMAT_RGB24) ) {
selector |= T_BE;
}
else
selector |= T_LE;
for
( i = 0; i < h; i++, src_buf -= src_stride, dest_buf += dest_stride, mask_buf -= mask_stride ) {
switch
(selector) {
case
T_FROM_CAIRO | T_LE | T_PALETTE | 1:
rev_memcpy(src_buf, dest_buf, stride);
invert(src_buf, stride);
break
;
case
T_FROM_CAIRO | T_LE | T_PALETTE | 8:
memcpy
(src_buf, dest_buf, w);
break
;
case
T_FROM_CAIRO | T_LE | T_RGB | 24:
bc_rgbi_rgb(dest_buf, src_buf, w);
break
;
case
T_FROM_CAIRO | T_LE | T_ARGB | 24 | T_A1 :
bc_rgbi_rgb(dest_buf, src_buf, w);
{
int
j;
Byte * alpha = dest_buf + 3;
for
(j = 0; j < w; j++, alpha += 4) mask_buf_byte[j] = (*alpha < 127) ? 0 : 1;
}
bc_byte_mono_cr( mask_buf_byte, mask_buf, w, colorref_byte);
break
;
case
T_FROM_CAIRO | T_LE | T_ARGB | 24 | T_A8 :
bc_rgbi_rgb(dest_buf, src_buf, w);
{
int
j;
Byte * alpha = dest_buf + 3;
for
(j = 0; j < w; j++, alpha += 4) mask_buf[j] = *alpha;
}
break
;
case
T_FROM_CAIRO | T_BE | T_RGB | 24:
bc_ibgr_rgb(dest_buf, src_buf, w);
break
;
case
T_FROM_CAIRO | T_BE | T_ARGB | 24 | T_A1:
bc_ibgr_rgb(dest_buf, src_buf, w);
{
int
j;
Byte * alpha = dest_buf;
for
(j = 0; j < w; j++, alpha += 4) mask_buf_byte[j] = (*alpha < 127) ? 0 : 1;
}
bc_byte_mono_cr( mask_buf_byte, mask_buf, w, colorref_byte);
break
;
case
T_FROM_CAIRO | T_BE | T_ARGB | 24 | T_A8:
bc_ibgr_rgb(dest_buf, src_buf, w);
{
int
j;
Byte * alpha = dest_buf;
for
(j = 0; j < w; j++, alpha += 4) mask_buf[j] = *alpha;
}
break
;
case
T_TO_CAIRO | T_LE | T_PALETTE | 1:
rev_memcpy(dest_buf, src_buf, stride);
invert(dest_buf, stride);
break
;
case
T_TO_CAIRO | T_LE | T_PALETTE | 8:
memcpy
(dest_buf, src_buf, w);
break
;
case
T_TO_CAIRO | T_LE | T_RGB | 24:
bc_rgb_rgbi(src_buf, dest_buf, w);
break
;
case
T_TO_CAIRO | T_LE | T_ARGB | 24 | T_A0:
bc_rgb_rgbi(src_buf, dest_buf, w);
{
int
j;
Byte * alpha = dest_buf + 3;
for
(j = 0; j < w; j++, alpha += 4) *alpha = 0xff;
}
break
;
case
T_TO_CAIRO | T_LE | T_ARGB | 24 | T_A1:
bc_rgb_rgbi(src_buf, dest_buf, w);
bc_mono_byte_cr( mask_buf, mask_buf_byte, w, colorref_mono);
{
int
j;
Byte * alpha = dest_buf + 3;
for
(j = 0; j < w; j++, alpha += 4) *alpha = mask_buf_byte[j];
}
break
;
case
T_TO_CAIRO | T_LE | T_ARGB | 24 | T_A8:
bc_rgb_rgbi(src_buf, dest_buf, w);
{
int
j;
Byte * alpha = dest_buf + 3;
for
(j = 0; j < w; j++, alpha += 4) *alpha = mask_buf[j];
}
break
;
case
T_TO_CAIRO | T_BE | T_RGB | 24:
bc_rgb_ibgr(src_buf, dest_buf, w);
break
;
case
T_TO_CAIRO | T_BE | T_ARGB | 24 | T_A0:
bc_rgb_ibgr(src_buf, dest_buf, w);
{
int
j;
Byte * alpha = dest_buf;
for
(j = 0; j < w; j++, alpha += 4) *alpha = 0xff;
}
break
;
case
T_TO_CAIRO | T_BE | T_ARGB | 24 | T_A1:
bc_rgb_ibgr(src_buf, dest_buf, w);
bc_mono_byte_cr( mask_buf, mask_buf_byte, w, colorref_mono);
{
int
j;
Byte * alpha = dest_buf;
for
(j = 0; j < w; j++, alpha += 4) *alpha = mask_buf_byte[j];
}
break
;
case
T_TO_CAIRO | T_BE | T_ARGB | 24 | T_A8:
bc_rgb_ibgr(src_buf, dest_buf, w);
{
int
j;
Byte * alpha = dest_buf;
for
(j = 0; j < w; j++, alpha += 4) *alpha = mask_buf[i];
}
break
;
default
:
croak(
"panic: unknown conversion %x"
, selector);
}
}
if
(mask_buf_byte)
free
( mask_buf_byte);
OUTPUT:
SV*
surface_create(sv)
SV *sv
PREINIT:
Handle object;
void
* context;
int
request;
Bool need_paint_state = 0;
CODE:
RETVAL = 0;
if
( !(object = gimme_the_mate(sv)))
croak(
"not a object"
);
if
( kind_of( object, CApplication)) {
request = REQ_TARGET_APPLICATION;
need_paint_state = 1;
}
else
if
( kind_of( object, CWidget))
request = REQ_TARGET_WINDOW;
else
if
( kind_of( object, CDeviceBitmap))
request = (((PDeviceBitmap)object)->type == dbtBitmap) ? REQ_TARGET_BITMAP : REQ_TARGET_PIXMAP;
else
if
( kind_of( object, CImage)) {
request = REQ_TARGET_IMAGE;
need_paint_state = 1;
}
else
if
( kind_of( object, CPrinter)) {
request = REQ_TARGET_PRINTER;
need_paint_state = 1;
}
else
croak(
"bad object"
);
if
( need_paint_state && !PObject(object)-> options. optInDraw )
croak(
"object not in paint state"
);
context = apc_cairo_surface_create(object, request);
RETVAL = newSV(0);
sv_setref_pv(RETVAL,
"Prima::Cairo::Surface"
, context);
OUTPUT:
RETVAL