racket/src/wxcommon/PSDC.cxx
Matthew Flatt 24d6604cd5 299.404
svn: r1073
2005-10-13 19:58:38 +00:00

2414 lines
60 KiB
C++

/*
* File: wb_ps.cc
* Purpose: Device context implementation (PostScript)
* Author: Julian Smart
* Created: 1993
* Updated: August 1994
* Copyright: (c) 2004-2005 PLT Scheme, Inc.
* Copyright: (c) 1993, AIAI, University of Edinburgh
*/
/* This file is the same for all three version of wxWindows from
PLT. */
#if defined(_MSC_VER)
# include "wx.h"
#else
#ifdef wx_xt
# define Uses_XLib
# define Uses_wxList
# define Uses_wxWindowDC
# define Uses_wxMemoryDC
# define Uses_wxPostScriptDC
# define Uses_wxPrintSetup
# define Uses_wxFontNameDirectory
# define Uses_wxDialogBox
# define Uses_wxButton
# define Uses_wxRadioBox
# define Uses_wxText
# define Uses_wxChoice
# define Uses_wxCheckBox
# include "wx.h"
# include <math.h>
# include <string.h>
#else
# ifdef __GNUG__
# pragma implementation "wx_dcps.h"
# pragma implementation
# pragma interface
#endif
# include "common.h"
# include "wx_frame.h"
# include "wx_dcps.h"
# include "wx_dcmem.h"
# include "wx_utils.h"
# include "wx_dialg.h"
# include "wx_cmdlg.h"
# include "wx_main.h"
# include "wx_lbox.h"
# include "wx_rbox.h"
# include "wx_buttn.h"
# include "wx_choic.h"
# include "wx_check.h"
# include "wx_messg.h"
#ifdef wx_mac
# include "wx_print.h"
#endif
#endif
#endif
#include "wx_rgn.h"
#include "../mzscheme/include/scheme.h"
extern void wxPostScriptDrawText(Scheme_Object *f, const char *fontname,
const char *text, int dt, Bool combine, int use16,
double font_size, int symbol_map);
extern void wxPostScriptGetTextExtent(const char *fontname,
const char *text, int dt, Bool combine, int use16,
double font_size,
double *x, double *y, double *descent, double *topSpace,
int symbol_map);
extern char *wxPostScriptFixupFontName(const char *fontname);
extern Bool wxPostScriptGlyphExists(const char *fontname, int c, int symbol_map);
# define YSCALE(y) ((paper_h) - ((y) * user_scale_y + device_origin_y))
# define XSCALE(x) ((x) * user_scale_x + device_origin_x)
# define YOFFSET(y) ((paper_h) - ((y) + device_origin_y))
# define XOFFSET(x) ((x) + device_origin_x)
# define YSCALEREL(dy) ((dy) * user_scale_y)
# define XSCALEREL(dx) ((dx) * user_scale_x)
# define XSCALEBND(dx) (XSCALEREL(dx) + device_origin_x)
# define YSCALEBND(dy) (YSCALEREL(dy) + device_origin_y)
# define ASCALEREL(a) ((a) * ascale)
# define PIE pie
#define RESET_FONT 0x1
#define RESET_COLOR 0x2
static double pie = 0.0;
#ifndef WXUNUSED
# define WXUNUSED(x) x
#endif
#ifdef wx_xt
# define WXXTUNUSED(c) /* empty */
#else
# define WXXTUNUSED(x) x
#endif
#define DEFAULT_PAPER "Letter 8 1/2 x 11 in"
class wxCanvas;
#ifdef wx_msw
# include "wx_privt.h"
#endif
#include <math.h>
#include <stdlib.h>
#include <limits.h>
static char *default_afm_path = NULL;
Bool XPrinterDialog(wxWindow *parent);
#ifdef wx_mac
wxPrintPaperDatabase *wxThePrintPaperDatabase;
#endif
#ifndef wx_xt
# define current_font font
#else
# define current_bk_mode current_text_bgmode
# define current_text_foreground current_text_fg
# define current_text_background current_text_bg
#endif
/**************************************************/
wxPSStream::wxPSStream(char *file) {
f = scheme_open_output_file(file, "post-script-dc%");
int_width = 0;
}
wxPSStream::~wxPSStream(void) {
if (f) scheme_close_output_port((Scheme_Object *)f);
}
int wxPSStream::good(void) {
return !!f;
}
void wxPSStream::Out(char s) {
char s2[2];
s2[0] = s;
s2[1] = 0;
Out(s2);
}
void wxPSStream::Out(const char *s) {
scheme_put_byte_string("post-script-dc%", (Scheme_Object *)f, s, 0, strlen(s), 0);
}
void wxPSStream::Out(int i) {
Out((long)i);
}
void wxPSStream::Out(double n)
{
char buf[64];
if ((double)(long)n == n) {
Out((long)n);
return;
}
sprintf(buf, "%f", n);
Out(buf);
}
void wxPSStream::Out(long l)
{
char buf[64];
if (int_width > 0) {
char buffer[50];
sprintf(buffer, "%% %d.%dld", int_width, int_width);
sprintf(buf, buffer, l);
int_width = 0;
} else
sprintf(buf, "%ld", l);
Out(buf);
}
long wxPSStream::tellp(void) {
return scheme_set_file_position((Scheme_Object *)f, -1);
}
void wxPSStream::seekp(long pos) {
scheme_set_file_position((Scheme_Object *)f, pos);
}
void wxPSStream::width(int w) {
int_width = w;
}
/**************************************************/
wxPostScriptDC::wxPostScriptDC (Bool interactive, wxWindow *parent, Bool usePaperBBox, Bool asEPS)
{
Create(interactive, parent, usePaperBBox, asEPS);
}
Bool wxPostScriptDC::Create(Bool interactive, wxWindow *parent, Bool usePaperBBox, Bool asEPS)
{
wxPrintSetupData *wxThePrintSetupData;
char *paperType;
wxPrintPaperType *paper;
if (!pie)
pie = 2 * asin((double)1.0);
__type = wxTYPE_DC_POSTSCRIPT;
#ifndef wx_xt
wx_interactive = interactive;
#endif
current_font = wxNORMAL_FONT;
device = wxDEVICE_EPS;
clipping = NULL;
#ifndef wx_xt
# ifdef wx_mac
logical_origin_x = 0;
logical_origin_y = 0;
logical_scale_x = 1.0;
logical_scale_y = 1.0;
# endif
device_origin_x = 0;
device_origin_y = 0;
user_scale_x = 1.0;
user_scale_y = 1.0;
current_pen = NULL;
current_brush = NULL;
current_background_color = new wxColour(wxWHITE);
current_text_foreground = new wxColour(wxBLACK);
mapping_mode = MM_TEXT;
#else
current_pen = wxBLACK_PEN;
current_pen->Lock(1);
current_brush = wxWHITE_BRUSH;
current_brush->Lock(1);
current_background_color->CopyFrom(wxWHITE);
#endif
title = NULL;
filename = NULL;
pstream = NULL;
min_x = 10000.0;
min_y = 10000.0;
max_x = -10000.0;
max_y = -10000.0;
clipx = -100000.0;
clipy = -100000.0;
clipw = 200000.0;
cliph = 200000.0;
as_eps = asEPS;
ok = PrinterDialog(interactive, parent, usePaperBBox);
/* We set these even if !ok, for use with text sizing: */
wxThePrintSetupData = wxGetThePrintSetupData();
level2ok = wxThePrintSetupData->GetLevel2();
afm_path = wxThePrintSetupData->GetAFMPath();
if (!ok)
return FALSE;
currentRed = 0;
currentGreen = 0;
currentBlue = 0;
Colour = TRUE;
paperType = wxThePrintSetupData->GetPaperName();
if (!paperType)
paperType = DEFAULT_PAPER;
paper = wxThePrintPaperDatabase->FindPaperType(paperType);
if (!paper)
paper = wxThePrintPaperDatabase->FindPaperType(DEFAULT_PAPER);
if (paper) {
paper_w = (double)paper->widthPixels;
paper_h = (double)paper->heightPixels;
} else {
paper_w = 1000;
paper_h = 1000;
}
if (wxThePrintSetupData) {
wxThePrintSetupData->GetPrinterTranslation(&paper_x, &paper_y);
wxThePrintSetupData->GetPrinterScaling(&paper_x_scale, &paper_y_scale);
if (wxThePrintSetupData->GetPrinterOrientation() == PS_LANDSCAPE)
landscape = 1;
else
landscape = 0;
wxThePrintSetupData->GetMargin(&paper_margin_x, &paper_margin_y);
} else {
paper_x = paper_y = 0;
paper_x_scale = paper_y_scale = 1;
paper_margin_x = paper_margin_y = 0;
landscape = 0;
}
if (landscape) {
double tmp;
tmp = paper_w;
paper_w = paper_h;
paper_h = tmp;
}
paper_w -= (paper_margin_x * 2);
paper_h -= (paper_margin_y * 2);
paper_w /= paper_x_scale;
if (paper_w <= 0)
paper_w = 1;
paper_h /= paper_y_scale;
if (paper_h <= 0)
paper_h = 1;
anti_alias = 1;
return ok;
}
wxPostScriptDC::~wxPostScriptDC (void)
{
if (current_brush) current_brush->Lock(-1);
if (current_pen) current_pen->Lock(-1);
if (pstream)
DELETE_OBJ pstream;
}
Bool wxPostScriptDC::PrinterDialog(Bool interactive, wxWindow *parent, Bool usePaperBBox)
{
wxPrintSetupData *wxThePrintSetupData;
char *s;
if (interactive) {
ok = XPrinterDialog(parent);
if (!ok)
return FALSE;
} else
ok = TRUE;
wxThePrintSetupData = wxGetThePrintSetupData();
mode = wxThePrintSetupData->GetPrinterMode();
s = wxThePrintSetupData->GetPrintPreviewCommand();
preview_cmd = copystring(s);
s = wxThePrintSetupData->GetPrinterCommand();
print_cmd = copystring(s);
s = wxThePrintSetupData->GetPrinterOptions();
print_opts = copystring(s);
use_paper_bbox = usePaperBBox;
if ((mode == PS_PREVIEW) || (mode == PS_PRINTER)) {
// For PS_PRINTER action this depends on a Unix-style print spooler
// since the wx_printer_file can be destroyed during a session
char userId[256];
char tmp[256];
wxGetUserId (userId, sizeof (userId) / sizeof (char));
strcpy(tmp, "/tmp/preview_");
strcat(tmp, userId);
strcat(tmp, ".ps");
filename = copystring(tmp);
} else if (mode == PS_FILE) {
char *file;
file = interactive ? (char *)NULL : wxThePrintSetupData->GetPrinterFile();
if (!file) {
char *dir = NULL;
file = wxThePrintSetupData->GetPrinterFile();
if (file) {
dir = wxPathOnly(file);
file = wxFileNameFromPath(file);
}
file = wxFileSelector("Save PostScript As", dir, file, "ps", NULL, wxSAVE, parent, -1, -1);
}
if (!file) {
ok = FALSE;
return FALSE;
}
filename = copystring(file);
ok = TRUE;
}
return ok;
}
void wxPostScriptDC::SetClippingRect(double cx, double cy, double cw, double ch)
{
wxRegion *r;
if (!pstream)
return;
r = new wxRegion(this);
r->SetRectangle(cx, cy, cw, ch);
SetClippingRegion(r);
}
wxRegion *wxPostScriptDC::GetClippingRegion()
{
return clipping;
}
void wxPostScriptDC::SetClippingRegion(wxRegion *r)
{
if (!pstream)
return;
if (r && (r->GetDC() != this))
return;
if (r) {
double x, y, w, h;
r->BoundingBox(&x, &y, &w, &h);
clipx = XSCALEBND(x);
clipy = YSCALEBND(y);
clipw = XSCALEREL(w);
cliph = YSCALEREL(h);
} else {
clipx = -100000.0;
clipy = -100000.0;
clipw = 200000.0;
cliph = 200000.0;
}
if (clipping) {
--clipping->locked;
clipping = NULL;
pstream->Out("initclip\n");
}
if (r) {
r->InstallPS(this, pstream);
clipping = r;
clipping->locked++;
}
}
void wxPostScriptDC::CalcBoundingBoxClip(double x, double y)
{
if (x < clipx)
x = clipx;
else if (x >= (clipx + clipw))
x = clipx + clipw;
if (y < clipy)
y = clipy;
else if (y >= (clipy + cliph))
y = clipy + cliph;
if (x < min_x) min_x = x;
if (y < min_y) min_y = y;
if (x > max_x) max_x = x;
if (y > max_y) max_y = y;
}
void wxPostScriptDC::SetAntiAlias(int mode)
{
/* Don't change */
}
void wxPostScriptDC::Clear(void)
{
unsigned char red, blue, green;
if (!pstream)
return;
red = current_background_color->Red();
blue = current_background_color->Blue();
green = current_background_color->Green();
{
double redPS = (double) (((int) red) / 255.0);
double bluePS = (double) (((int) blue) / 255.0);
double greenPS = (double) (((int) green) / 255.0);
/* Fill with current background */
pstream->Out("gsave newpath\n");
pstream->Out(redPS); pstream->Out(" "); pstream->Out(greenPS); pstream->Out(" "); pstream->Out(bluePS); pstream->Out(" setrgbcolor\n");
pstream->Out(0); pstream->Out(" "); pstream->Out(0); pstream->Out(" moveto\n");
pstream->Out(0); pstream->Out(" "); pstream->Out(paper_h); pstream->Out(" lineto\n");
pstream->Out(paper_w); pstream->Out(" "); pstream->Out(paper_h); pstream->Out(" lineto\n");
pstream->Out(paper_w); pstream->Out(" "); pstream->Out(0); pstream->Out(" lineto\n");
pstream->Out("closepath\n");
pstream->Out("fill grestore\n");
}
}
Bool wxPostScriptDC::GetPixel(double WXUNUSED(x), double WXUNUSED(y), wxColour * WXUNUSED(col))
{
return FALSE;
}
void wxPostScriptDC::DrawLine (double x1, double y1, double x2, double y2)
{
if (!pstream)
return;
if (current_pen)
SetPen (current_pen);
pstream->Out("newpath\n");
pstream->Out(XSCALE(x1)); pstream->Out(" "); pstream->Out(YSCALE (y1)); pstream->Out(" moveto\n");
pstream->Out(XSCALE(x2)); pstream->Out(" "); pstream->Out(YSCALE (y2)); pstream->Out(" lineto\n");
pstream->Out("stroke\n");
{
/* Need to make bounding box wide enough to show the pen.
(Part of the reason for this is to avoid zero-sized boounding boxes.) */
double width;
if (current_pen) {
width = current_pen->GetWidthF();
width /= 2;
} else
width = 0;
if (!width) width = 0.01;
if (x1 == x2) {
CalcBoundingBoxClip(XSCALEBND(x1 - width), YSCALEBND(y1));
CalcBoundingBoxClip(XSCALEBND(x2 + width), YSCALEBND(y2));
} else if (y1 == y2) {
CalcBoundingBoxClip(XSCALEBND(x1), YSCALEBND(y1 - width));
CalcBoundingBoxClip(XSCALEBND(x2), YSCALEBND(y2 + width));
} else {
CalcBoundingBoxClip(XSCALEBND(x1 - width), YSCALEBND(y1 - width));
CalcBoundingBoxClip(XSCALEBND(x2 + width), YSCALEBND(y2 + width));
}
}
}
void wxPostScriptDC::DrawArc (double x, double y, double w, double h, double start, double end)
{
if (!pstream)
return;
if (start != end) {
double a1, a2, radius, xscale;
/* Before we scale: */
CalcBoundingBoxClip(XSCALEBND(x), YSCALEBND(y));
CalcBoundingBoxClip(XSCALEBND(x + w), YSCALEBND(y + h));
x = XSCALE(x);
y = YSCALE(y);
w = XSCALEREL(w);
h = YSCALEREL(h);
radius = (h / 2);
xscale = (w / h);
a1 = start * (180 / pie);
a2 = end * (180 / pie);
pstream->Out("gsave\n");
pstream->Out((x + w/2)); pstream->Out(" ");
pstream->Out((y - h/2)); pstream->Out(" translate\n");
pstream->Out(xscale); pstream->Out(" "); pstream->Out(1); pstream->Out(" scale\n");
if (current_brush && current_brush->GetStyle () != wxTRANSPARENT) {
SetBrush(current_brush);
pstream->Out("newpath\n");
pstream->Out(0); pstream->Out(" ");
pstream->Out(0); pstream->Out(" moveto\n");
pstream->Out("0 0 "); pstream->Out(radius); pstream->Out(" "); pstream->Out(a1);
pstream->Out(" "); pstream->Out(a2); pstream->Out(" arc\n");
pstream->Out("closepath\n");
pstream->Out("fill\n");
}
if (current_pen && current_pen->GetStyle () != wxTRANSPARENT) {
SetPen(current_pen);
pstream->Out("newpath\n");
pstream->Out("0 0 "); pstream->Out(radius); pstream->Out(" ");
pstream->Out(a1); pstream->Out(" "); pstream->Out(a2); pstream->Out(" arc\n");
pstream->Out("stroke\n");
}
pstream->Out("grestore\n");
resetFont |= RESET_COLOR;
}
}
void wxPostScriptDC::DrawPoint (double x, double y)
{
if (!pstream)
return;
if (current_pen)
SetPen (current_pen);
pstream->Out("newpath\n");
pstream->Out(XSCALE(x)); pstream->Out(" "); pstream->Out(YSCALE (y)); pstream->Out(" moveto\n");
pstream->Out(XSCALE(x+1)); pstream->Out(" "); pstream->Out(YSCALE (y)); pstream->Out(" lineto\n");
pstream->Out("stroke\n");
CalcBoundingBoxClip(XSCALEBND(x), YSCALEBND(y));
}
void wxPostScriptDC::DrawSpline(double x1, double y1, double x2, double y2, double x3, double y3)
{
double x21, y21, x22, y22;
double xm1, ym1, xm2, ym2;
if (!pstream)
return;
if (current_pen)
SetPen (current_pen);
pstream->Out("newpath\n");
pstream->Out(XSCALE(x1)); pstream->Out(" "); pstream->Out(YSCALE(y1)); pstream->Out(" moveto ");
x21 = (x1 + x2) / 2;
y21 = (y1 + y2) / 2;
pstream->Out(XSCALE(x21)); pstream->Out(" "); pstream->Out(YSCALE(y21)); pstream->Out(" lineto\n");
x22 = (x2 + x3) / 2;
y22 = (y2 + y3) / 2;
xm1 = (x21 + x2) / 2;
ym1 = (y21 + y2) / 2;
xm2 = (x2 + x22) / 2;
ym2 = (y2 + y22) / 2;
pstream->Out(XSCALE(xm1)); pstream->Out(" "); pstream->Out(YSCALE(ym1)); pstream->Out(" ");
pstream->Out(XSCALE(xm2)); pstream->Out(" "); pstream->Out(YSCALE(ym2)); pstream->Out(" ");
pstream->Out(XSCALE(x22)); pstream->Out(" "); pstream->Out(YSCALE(y22)); pstream->Out(" curveto\n");
pstream->Out(XSCALE(x3)); pstream->Out(" "); pstream->Out(YSCALE(y3)); pstream->Out(" lineto\n");
pstream->Out("stroke\n");
CalcBoundingBoxClip(XSCALEBND(x1), YSCALEBND(y1));
CalcBoundingBoxClip(XSCALEBND(x2), YSCALEBND(y2));
CalcBoundingBoxClip(XSCALEBND(x3), YSCALEBND(y3));
}
void wxPostScriptDC::DrawPolygon (int n, wxPoint points[], double xoffset, double yoffset, int fillStyle)
{
if (!pstream)
return;
if (n > 0)
{
if (current_brush && current_brush->GetStyle () != wxTRANSPARENT)
{
int i;
double xx, yy;
SetBrush (current_brush);
pstream->Out("newpath\n");
xx = points[0].x + xoffset;
yy = (points[0].y + yoffset);
pstream->Out(XSCALE(xx)); pstream->Out(" "); pstream->Out(YSCALE(yy)); pstream->Out(" moveto\n");
CalcBoundingBoxClip(XSCALEBND(xx), YSCALEBND(yy));
for (i = 1; i < n; i++)
{
xx = points[i].x + xoffset;
yy = (points[i].y + yoffset);
pstream->Out(XSCALE(xx)); pstream->Out(" "); pstream->Out(YSCALE(yy)); pstream->Out(" lineto\n");
CalcBoundingBoxClip(XSCALEBND(xx), YSCALEBND(yy));
}
pstream->Out(((fillStyle == wxODDEVEN_RULE) ? "eofill\n" : "fill\n"));
}
if (current_pen && current_pen->GetStyle () != wxTRANSPARENT)
{
int i;
double xx, yy;
SetPen (current_pen);
pstream->Out("newpath\n");
xx = points[0].x + xoffset;
yy = (points[0].y + yoffset);
pstream->Out(XSCALE(xx)); pstream->Out(" "); pstream->Out(YSCALE(yy)); pstream->Out(" moveto\n");
CalcBoundingBoxClip(XSCALEBND(xx), YSCALEBND(yy));
for (i = 1; i < n; i++)
{
xx = points[i].x + xoffset;
yy = (points[i].y + yoffset);
pstream->Out(XSCALE(xx)); pstream->Out(" "); pstream->Out(YSCALE(yy)); pstream->Out(" lineto\n");
CalcBoundingBoxClip(XSCALEBND(xx), YSCALEBND(yy));
}
// Close the polygon
pstream->Out(" closepath\n");
// Output the line
pstream->Out("stroke\n");
}
}
}
void wxPostScriptDC::DrawPath(wxPath *p, double xoff, double yoff, int fillStyle)
{
int did = 0;
if (!pstream)
return;
if (current_brush && current_brush->GetStyle () != wxTRANSPARENT) {
SetBrush (current_brush);
pstream->Out("newpath\n");
p->InstallPS(this, pstream, xoff, yoff);
pstream->Out(((fillStyle == wxODDEVEN_RULE) ? "eofill\n" : "fill\n"));
did = 1;
}
if (current_pen && current_pen->GetStyle () != wxTRANSPARENT) {
SetPen (current_pen);
pstream->Out("newpath\n");
p->InstallPS(this, pstream, xoff, yoff);
pstream->Out("stroke\n");
did = 1;
}
if (did) {
double x1, x2, y1, y2;
p->BoundingBox(&x1, &y1, &x2, &y2);
x1 += xoff;
x2 += xoff;
y1 += yoff;
y2 += yoff;
CalcBoundingBoxClip(XSCALEBND(x1), YSCALEBND(y1));
CalcBoundingBoxClip(XSCALEBND(x2), YSCALEBND(y2));
}
}
void wxPostScriptDC::DrawLines (int n, wxPoint points[], double xoffset, double yoffset)
{
if (!pstream)
return;
if (n > 0 && current_pen && (current_pen->GetStyle () != wxTRANSPARENT)) {
int i;
double xx, yy;
SetPen(current_pen);
pstream->Out("newpath\n");
xx = points[0].x + xoffset;
yy = (points[0].y + yoffset);
pstream->Out(XSCALE(xx)); pstream->Out(" "); pstream->Out(YSCALE(yy)); pstream->Out(" moveto\n");
CalcBoundingBoxClip(XSCALEBND(xx), YSCALEBND(yy));
for (i = 1; i < n; i++)
{
xx = points[i].x + xoffset;
yy = (points[i].y + yoffset);
pstream->Out(XSCALE(xx)); pstream->Out(" "); pstream->Out(YSCALE(yy)); pstream->Out(" lineto\n");
CalcBoundingBoxClip(XSCALEBND(xx), YSCALEBND(yy));
}
pstream->Out("stroke\n");
}
}
void wxPostScriptDC::DrawRectangle (double x, double y, double width, double height)
{
if (!pstream)
return;
if (current_brush && current_brush->GetStyle () != wxTRANSPARENT)
{
SetBrush (current_brush);
pstream->Out("newpath\n");
pstream->Out(XSCALE(x)); pstream->Out(" "); pstream->Out(YSCALE (y)); pstream->Out(" moveto\n");
pstream->Out(XSCALE(x + width)); pstream->Out(" "); pstream->Out(YSCALE (y)); pstream->Out(" lineto\n");
pstream->Out(XSCALE(x + width)); pstream->Out(" "); pstream->Out(YSCALE (y + height)); pstream->Out(" lineto\n");
pstream->Out(XSCALE(x)); pstream->Out(" "); pstream->Out(YSCALE (y + height)); pstream->Out(" lineto\n");
pstream->Out("closepath\n");
pstream->Out("fill\n");
CalcBoundingBoxClip(XSCALEBND(x), YSCALEBND(y));
CalcBoundingBoxClip(XSCALEBND(x + width), YSCALEBND(y + height));
}
if (current_pen && current_pen->GetStyle () != wxTRANSPARENT)
{
SetPen (current_pen);
pstream->Out("newpath\n");
pstream->Out(XSCALE(x)); pstream->Out(" "); pstream->Out(YSCALE (y)); pstream->Out(" moveto\n");
pstream->Out(XSCALE(x + width)); pstream->Out(" "); pstream->Out(YSCALE (y)); pstream->Out(" lineto\n");
pstream->Out(XSCALE(x + width)); pstream->Out(" "); pstream->Out(YSCALE (y + height)); pstream->Out(" lineto\n");
pstream->Out(XSCALE(x)); pstream->Out(" "); pstream->Out(YSCALE (y + height)); pstream->Out(" lineto\n");
pstream->Out("closepath\n");
pstream->Out("stroke\n");
CalcBoundingBoxClip(XSCALEBND(x), YSCALEBND(y));
CalcBoundingBoxClip(XSCALEBND(x + width), YSCALEBND(y + height));
}
}
void wxPostScriptDC::DrawRoundedRectangle (double x, double y, double width, double height, double radius)
{
double ascale;
if (!pstream)
return;
if (radius < 0.0)
{
// Now, a negative radius is interpreted to mean
// 'the proportion of the smallest X or Y dimension'
double smallest = 0.0;
if (width < height)
smallest = width;
else
smallest = height;
radius = (double) (-radius * smallest);
}
ascale = (user_scale_x < user_scale_y) ? user_scale_x : user_scale_y;
if (current_brush && current_brush->GetStyle () != wxTRANSPARENT)
{
SetBrush (current_brush);
// Draw rectangle anticlockwise
pstream->Out("newpath\n");
pstream->Out(XSCALE(x) + ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(YSCALE(y)); pstream->Out(" moveto\n");
pstream->Out(XSCALE(x) + ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(YSCALE(y) - ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(ASCALEREL(radius)); pstream->Out(" 90 180 arc\n");
pstream->Out(XSCALE(x) + ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(YSCALE(y + height) + ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(ASCALEREL(radius)); pstream->Out(" 180 270 arc\n");
pstream->Out(XSCALE(x + width) - ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(YSCALE(y + height) + ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(ASCALEREL(radius)); pstream->Out(" 270 0 arc\n");
pstream->Out(XSCALE(x + width) - ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(YSCALE(y) - ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(ASCALEREL(radius)); pstream->Out(" 0 90 arc\n");
pstream->Out("closepath\n");
pstream->Out("fill\n");
CalcBoundingBoxClip(XSCALEBND(x), YSCALEBND(y));
CalcBoundingBoxClip(XSCALEBND(x + width), YSCALEBND(y + height));
}
if (current_pen && current_pen->GetStyle () != wxTRANSPARENT)
{
SetPen (current_pen);
// Draw rectangle anticlockwise
pstream->Out("newpath\n");
pstream->Out(XSCALE(x) + ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(YSCALE(y)); pstream->Out(" moveto\n");
pstream->Out(XSCALE(x) + ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(YSCALE(y) - ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(ASCALEREL(radius)); pstream->Out(" 90 180 arc\n");
pstream->Out(XSCALE(x) + ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(YSCALE(y + height) + ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(ASCALEREL(radius)); pstream->Out(" 180 270 arc\n");
pstream->Out(XSCALE(x + width) - ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(YSCALE(y + height) + ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(ASCALEREL(radius)); pstream->Out(" 270 0 arc\n");
pstream->Out(XSCALE(x + width) - ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(YSCALE(y) - ASCALEREL(radius)); pstream->Out(" ");
pstream->Out(ASCALEREL(radius)); pstream->Out(" 0 90 arc\n");
pstream->Out("closepath\n");
pstream->Out("stroke\n");
CalcBoundingBoxClip(XSCALEBND(x), YSCALEBND(y));
CalcBoundingBoxClip(XSCALEBND(x + width), YSCALEBND(y + height));
}
}
void wxPostScriptDC::DrawEllipse (double x, double y, double width, double height)
{
if (!pstream)
return;
if (current_brush && current_brush->GetStyle () != wxTRANSPARENT)
{
SetBrush (current_brush);
pstream->Out("newpath\n");
pstream->Out(XSCALE(x + width / 2)); pstream->Out(" "); pstream->Out(YSCALE(y + height / 2)); pstream->Out(" ");
pstream->Out(XSCALEREL(width / 2)); pstream->Out(" "); pstream->Out(YSCALEREL(height / 2)); pstream->Out(" 0 360 ellipse\n");
pstream->Out("fill\n");
CalcBoundingBoxClip(XSCALEBND(x), YSCALEBND(y));
CalcBoundingBoxClip(XSCALEBND(x + width), YSCALEBND(y + height));
}
if (current_pen && current_pen->GetStyle () != wxTRANSPARENT)
{
SetPen (current_pen);
pstream->Out("newpath\n");
pstream->Out(XSCALE(x + width / 2)); pstream->Out(" "); pstream->Out(YSCALE(y + height / 2)); pstream->Out(" ");
pstream->Out(XSCALEREL(width / 2)); pstream->Out(" "); pstream->Out(YSCALEREL(height / 2)); pstream->Out(" 0 360 ellipse\n");
pstream->Out("stroke\n");
CalcBoundingBoxClip (XSCALEBND(x), YSCALEBND(y));
CalcBoundingBoxClip (XSCALEBND(x + width), YSCALEBND(y + height));
}
}
void wxPostScriptDC::SetFont (wxFont * the_font)
{
char *name;
int family, style, weight, size;
if (!pstream)
return;
if ((current_font == the_font) && !(resetFont & RESET_FONT))
return;
resetFont -= (resetFont & RESET_FONT);
current_font = the_font;
family = current_font->GetFontId();
style = current_font->GetStyle();
weight = current_font->GetWeight();
name = wxTheFontNameDirectory->GetPostScriptName(family, weight, style);
if (!name)
name = "Times-Roman";
size = current_font->GetPointSize();
next_font_name = name;
next_font_size = size;
}
static void set_pattern(wxPostScriptDC *dc, wxPSStream *pstream, wxBitmap *bm, int rop, wxColour *col)
{
int width, height;
width = bm->GetWidth();
height = bm->GetHeight();
pstream->Out("8 dict\n");
pstream->Out("dup\n");
pstream->Out("begin\n");
pstream->Out(" /PatternType 1 def\n");
pstream->Out(" /PaintType 1 def\n");
pstream->Out(" /TilingType 1 def\n");
pstream->Out(" /BBox [ 0 0 "); pstream->Out(width); pstream->Out(" "); pstream->Out(height); pstream->Out(" ] def\n");
pstream->Out(" /XStep "); pstream->Out(width); pstream->Out(" def\n");
pstream->Out(" /YStep "); pstream->Out(height); pstream->Out(" def\n");
dc->Blit(0, 0, width, height, bm, 0, 0, -rop - 1, col);
pstream->Out("end\n");
pstream->Out(" matrix makepattern setpattern\n");
}
static char *dotted = "[2 5] 2";
static char *short_dashed = "[4 4] 2";
static char *long_dashed = "[4 8] 2";
static char *dotted_dashed = "[6 6 2 6] 4";
void wxPostScriptDC::SetPen (wxPen * pen)
{
wxPen *oldPen = current_pen;
char *psdash = NULL;
unsigned char red, blue, green;
int val;
double width;
if (!pstream)
return;
if (current_pen) current_pen->Lock(-1);
if (pen) pen->Lock(1);
if ((current_pen = pen) == NULL)
return; /* NIL */
// Line width
width = pen->GetWidthF();
pstream->Out(XSCALEREL(width));
pstream->Out(" setlinewidth\n");
if (level2ok) {
wxBitmap *stipple;
stipple = pen->GetStipple();
if (stipple && stipple->Ok()) {
int ps;
wxColour *pc;
ps = pen->GetStyle();
pc = pen->GetColour();
set_pattern(this, pstream, stipple, ps, pc);
resetFont |= RESET_COLOR;
return;
}
}
switch (pen->GetStyle ())
{
case wxDOT:
psdash = dotted;
break;
case wxSHORT_DASH:
psdash = short_dashed;
break;
case wxLONG_DASH:
psdash = long_dashed;
break;
case wxDOT_DASH:
psdash = dotted_dashed;
break;
case wxSOLID:
case wxTRANSPARENT:
default:
psdash = "[] 0";
break;
}
if (oldPen != pen) {
pstream->Out(psdash); pstream->Out(" setdash\n");
}
switch (pen->GetCap()) {
case wxCAP_ROUND:
val = 1;
break;
case wxCAP_PROJECTING:
val = 2;
break;
default:
case wxCAP_BUTT:
val = 0;
break;
}
pstream->Out(val);
pstream->Out(" setlinecap\n");
switch (pen->GetJoin()) {
case wxJOIN_ROUND:
val = 1;
break;
case wxJOIN_BEVEL:
val = 2;
break;
default:
case wxJOIN_MITER:
val = 0;
break;
}
pstream->Out(val);
pstream->Out(" setlinejoin\n");
// Line colour
{
wxColour *pc;
pc = pen->GetColour();
red = pc->Red();
blue = pc->Blue();
green = pc->Green();
}
if (!Colour)
{
// Anything not white is black
if (!(red == (unsigned char) 255 && blue == (unsigned char) 255
&& green == (unsigned char) 255))
{
red = (unsigned char) 0;
green = (unsigned char) 0;
blue = (unsigned char) 0;
}
}
if (!(red == currentRed && green == currentGreen && blue == currentBlue)
|| (resetFont & RESET_COLOR)) {
double redPS = (double) (((int) red) / 255.0);
double bluePS = (double) (((int) blue) / 255.0);
double greenPS = (double) (((int) green) / 255.0);
pstream->Out(redPS); pstream->Out(" "); pstream->Out(greenPS);
pstream->Out(" "); pstream->Out(bluePS); pstream->Out(" setrgbcolor\n");
currentRed = red;
currentBlue = blue;
currentGreen = green;
resetFont -= (resetFont & RESET_COLOR);
}
}
static char *ps_brush_hatch[] = { " 0 0 moveto 8 8",
" 0 0 moveto 8 8 lineto closepath stroke 8 0 moveto 0 8",
" 8 0 moveto 0 8",
" 0 4 moveto 8 4 lineto closepath stroke 4 0 moveto 4 8",
" 0 4 moveto 8 4",
" 4 0 moveto 4 8",
" 0 0 moveto 0.1 0.1" };
void wxPostScriptDC::SetBrush(wxBrush * brush)
{
unsigned char red, blue, green;
int hatch_id;
char *hatch_size;
double redPS, bluePS, greenPS;
if (!pstream)
return;
if (current_brush) current_brush->Lock(-1);
if (brush) brush->Lock(1);
if ((current_brush = brush) == NULL)
return;
if (level2ok) {
wxBitmap *stipple;
stipple = brush->GetStipple();
if (stipple && stipple->Ok()) {
int bs;
wxColour *bc;
bs = brush->GetStyle();
bc = brush->GetColour();
set_pattern(this, pstream, stipple, bs, bc);
resetFont |= RESET_COLOR;
return;
}
}
// Brush colour
{
wxColour *bc;
bc = brush->GetColour();
red = bc->Red();
blue = bc->Blue();
green = bc->Green();
}
if (!Colour) {
// Anything not black is white
if (!(red == (unsigned char) 0 && blue == (unsigned char) 0
&& green == (unsigned char) 0)) {
red = (unsigned char) 255;
green = (unsigned char) 255;
blue = (unsigned char) 255;
}
}
hatch_id = -1;
hatch_size = "8";
switch (brush->GetStyle()) {
case wxBDIAGONAL_HATCH:
hatch_id = 0;
break;
case wxCROSSDIAG_HATCH:
hatch_id = 1;
break;
case wxFDIAGONAL_HATCH:
hatch_id = 2;
break;
case wxCROSS_HATCH:
hatch_id = 3;
break;
case wxHORIZONTAL_HATCH:
hatch_id = 4;
break;
case wxVERTICAL_HATCH:
hatch_id = 5;
break;
case wxCOLOR:
hatch_id = 6;
hatch_size = "0.3";
break;
}
redPS = (double) (((int) red) / 255.0);
bluePS = (double) (((int) blue) / 255.0);
greenPS = (double) (((int) green) / 255.0);
if (hatch_id > -1) {
pstream->Out("7 dict\n");
pstream->Out("dup\n");
pstream->Out("begin\n");
pstream->Out(" /PatternType 1 def\n");
pstream->Out(" /PaintType 1 def\n");
pstream->Out(" /TilingType 1 def\n");
pstream->Out(" /BBox [ 0 0 ");
pstream->Out(hatch_size);
pstream->Out(" ");
pstream->Out(hatch_size);
pstream->Out(" ] def\n");
pstream->Out(" /XStep ");
pstream->Out(hatch_size);
pstream->Out(" def\n");
pstream->Out(" /YStep ");
pstream->Out(hatch_size);
pstream->Out(" def\n");
pstream->Out(" /PaintProc { begin gsave \n");
pstream->Out(" 0.05 setlinewidth\n");
pstream->Out(" [] 0 setdash\n");
pstream->Out(" "); pstream->Out(redPS); pstream->Out(" "); pstream->Out(greenPS);
pstream->Out(" "); pstream->Out(bluePS); pstream->Out(" setrgbcolor\n");
pstream->Out(" "); pstream->Out(ps_brush_hatch[hatch_id]); pstream->Out(" lineto closepath stroke \n");
pstream->Out("grestore\n } def \n");
pstream->Out("end\n"); pstream->Out(" matrix makepattern setpattern\n");
resetFont |= RESET_COLOR;
return;
}
if (!(red == currentRed && green == currentGreen && blue == currentBlue)
|| (resetFont & RESET_COLOR)) {
pstream->Out(redPS); pstream->Out(" "); pstream->Out(greenPS); pstream->Out(" ");
pstream->Out(bluePS); pstream->Out(" setrgbcolor\n");
currentRed = red;
currentBlue = blue;
currentGreen = green;
resetFont -= (resetFont & RESET_COLOR);
}
}
void wxPostScriptDC::DrawText(DRAW_TEXT_CONST char *text, double x, double y,
Bool combine, Bool use16, int dt, double angle)
{
double tw, th;
const char *name;
int sym_map;
if (!pstream)
return;
if (current_font)
SetFont (current_font);
GetTextExtent(text, &tw, &th, NULL, NULL, NULL, combine, use16, dt);
if (current_bk_mode == wxSOLID) {
unsigned char red, blue, green;
red = current_text_background->Red();
blue = current_text_background->Blue();
green = current_text_background->Green();
{
double redPS = (double) (((int) red) / 255.0);
double bluePS = (double) (((int) blue) / 255.0);
double greenPS = (double) (((int) green) / 255.0);
pstream->Out("gsave newpath\n");
pstream->Out(redPS); pstream->Out(" "); pstream->Out(greenPS); pstream->Out(" ");
pstream->Out(bluePS); pstream->Out(" setrgbcolor\n");
pstream->Out(XSCALE(x)); pstream->Out(" "); pstream->Out(YSCALE (y)); pstream->Out(" moveto\n");
pstream->Out(XSCALE(x + tw)); pstream->Out(" "); pstream->Out(YSCALE (y)); pstream->Out(" lineto\n");
pstream->Out(XSCALE(x + tw)); pstream->Out(" "); pstream->Out(YSCALE (y + th)); pstream->Out(" lineto\n");
pstream->Out(XSCALE(x)); pstream->Out(" "); pstream->Out(YSCALE (y + th)); pstream->Out(" lineto\n");
pstream->Out("closepath\n");
pstream->Out("fill grestore\n");
}
}
if (current_text_foreground->Ok()) {
unsigned char red, blue, green;
red = current_text_foreground->Red();
blue = current_text_foreground->Blue();
green = current_text_foreground->Green();
if (!Colour) {
// Anything not white is black
if (!(red == (unsigned char) 255 && blue == (unsigned char) 255
&& green == (unsigned char) 255))
{
red = (unsigned char) 0;
green = (unsigned char) 0;
blue = (unsigned char) 0;
}
}
if (!(red == currentRed && green == currentGreen && blue == currentBlue)
|| (resetFont & RESET_COLOR)) {
double redPS = (double) (((int) red) / 255.0);
double bluePS = (double) (((int) blue) / 255.0);
double greenPS = (double) (((int) green) / 255.0);
pstream->Out(redPS); pstream->Out(" "); pstream->Out(greenPS); pstream->Out(" ");
pstream->Out(bluePS); pstream->Out(" setrgbcolor\n");
currentRed = red;
currentBlue = blue;
currentGreen = green;
resetFont -= (resetFont & RESET_COLOR);
}
}
if (next_font_name) {
if (!current_font_name
|| (next_font_size != current_font_size)
|| strcmp(next_font_name, current_font_name)) {
pstream->Out("/"); pstream->Out(wxPostScriptFixupFontName(next_font_name)); pstream->Out(" findfont\n");
pstream->Out(next_font_size); pstream->Out(" scalefont setfont\n");
current_font_size = next_font_size;
current_font_name = next_font_name;
}
name = next_font_name;
next_font_name = NULL;
} else {
int family, style, weight;
if (current_font) {
family = current_font->GetFontId();
style = current_font->GetStyle();
weight = current_font->GetWeight();
} else {
family = wxDEFAULT;
style = wxNORMAL;
weight = wxNORMAL;
}
name = wxTheFontNameDirectory->GetPostScriptName(family, weight, style);
if (!name)
name = "Times-Roman";
}
if (angle != 0.0) {
pstream->Out("gsave\n");
}
if (angle != 0.0) {
pstream->Out(XSCALE(x)); pstream->Out(" "); pstream->Out(YSCALE(y));
pstream->Out(" translate\n");
if ((user_scale_x != 1) || (user_scale_y != 1)) {
pstream->Out(user_scale_x); pstream->Out(" "); pstream->Out(user_scale_y); pstream->Out(" scale\n");
}
pstream->Out(angle * 180 / pie);
pstream->Out(" rotate 0 0 moveto\n");
} else {
pstream->Out(XSCALE(x)); pstream->Out(" "); pstream->Out(YSCALE(y));
pstream->Out(" moveto\n");
if ((user_scale_x != 1) || (user_scale_y != 1)) {
pstream->Out("gsave\n");
pstream->Out(user_scale_x); pstream->Out(" "); pstream->Out(user_scale_y); pstream->Out(" scale\n");
}
}
sym_map = current_font->GetFamily() == wxSYMBOL;
wxPostScriptDrawText((Scheme_Object *)pstream->f, name, text, dt, combine, use16, current_font_size,
sym_map);
if ((angle != 0.0) || (user_scale_x != 1) || (user_scale_y != 1)) {
pstream->Out("grestore\n");
}
CalcBoundingBoxClip(XSCALEBND(x), YSCALEBND(y));
if (angle != 0.0) {
double xe, ye;
xe = x + (tw * cos(angle)) + (th * sin(angle));
ye = y - (th * cos(angle)) - (tw * sin(angle));
CalcBoundingBoxClip(XSCALEBND(xe), YSCALEBND(ye));
} else {
CalcBoundingBoxClip(XSCALEBND(x + tw), YSCALEBND(y + th));
}
}
Bool wxPostScriptDC::GlyphAvailable(int c, wxFont *f)
{
const char *name;
int family, style, weight, sym_map;
if (!f)
f = current_font;
family = f->GetFontId();
style = f->GetStyle();
weight = f->GetWeight();
name = wxTheFontNameDirectory->GetPostScriptName(family, weight, style);
if (!name)
name = "Times-Roman";
sym_map = current_font->GetFamily() == wxSYMBOL;
return wxPostScriptGlyphExists(name, c, sym_map);
}
void wxPostScriptDC::SetBackground (wxColour * c)
{
current_background_color->CopyFrom(c);
}
void wxPostScriptDC::SetBackgroundMode(int mode)
{
current_bk_mode = mode;
}
void wxPostScriptDC::SetTextBackground(wxColour *col)
{
current_text_background->CopyFrom(col);
}
void wxPostScriptDC::SetTextForeground(wxColour *col)
{
current_text_foreground->CopyFrom(col);
}
void wxPostScriptDC::TryColour(wxColour *src, wxColour *dest)
{
if (!Colour) {
if ((src->Red() == 255)
&& (src->Green() == 255)
&& (src->Blue() == 255))
dest->Set(255, 255, 255);
else
dest->Set(0, 0, 0);
} else
dest->CopyFrom(src);
}
static const char *wxPostScriptHeaderEllipse = "\
/ellipsedict 8 dict def\n\
ellipsedict /mtrx matrix put\n\
/ellipse\n\
{ ellipsedict begin\n\
/endangle exch def\n\
/startangle exch def\n\
/yrad exch def\n\
/xrad exch def\n\
/y exch def\n\
/x exch def\n\
/savematrix mtrx currentmatrix def\n\
x y translate\n\
xrad yrad scale\n\
0 0 1 endangle startangle arcn\n\
savematrix setmatrix\n\
end\n\
} def\n\
";
Bool wxPostScriptDC::StartDoc (char *message)
{
char userID[256];
if (device == wxDEVICE_EPS) {
wxPSStream *pss;
pss = new wxPSStream(filename);
pstream = pss;
if (!pstream || !pstream->good()) {
ok = FALSE;
pstream = NULL;
return FALSE;
}
ok = TRUE;
}
pstream->Out("%!PS-Adobe-2.0"); /* PostScript magic strings */
if (as_eps) {
pstream->Out(" EPSF-2.0"); /* EPS magic strings */
}
pstream->Out("\n");
if (title) {
pstream->Out("%%Title: "); pstream->Out(title); pstream->Out("\n");
}
pstream->Out("%%Creator: "); pstream->Out("MrEd"); pstream->Out("\n");
pstream->Out("%%CreationDate: "); pstream->Out(wxNow()); pstream->Out("\n");
// User Id information
if (wxGetEmailAddress(userID, sizeof(userID))) {
char userName[245];
pstream->Out("%%For: "); pstream->Out((char *)userID);
if (wxGetUserName(userName, sizeof(userName))) {
pstream->Out(" ("); pstream->Out((char *)userName); pstream->Out(")");
}
pstream->Out("\n");
} else if ( wxGetUserName(userID, sizeof(userID))) {
pstream->Out("%%For: "); pstream->Out((char *)userID); pstream->Out("\n");
}
boundingboxpos = pstream->tellp();
pstream->Out("%%BoundingBox: -00000 -00000 -00000 -00000\n");
pstream->Out("%%Pages: -00000\n");
if (landscape)
pstream->Out("%%Orientation: Landscape\n");
pstream->Out("%%EndComments\n\n");
pstream->Out(wxPostScriptHeaderEllipse);
SetBrush(wxWHITE_BRUSH);
SetPen(wxBLACK_PEN);
page_number = 1;
if (message) {
title = copystring (message);
}
return TRUE;
}
#ifdef wx_x
extern void wxsExecute(char **);
#endif
void wxPostScriptDC::EndDoc (void)
{
double llx, lly, urx, ury;
double minx, miny, maxx, maxy;
if (!pstream)
return;
if (clipping) {
clipping = FALSE;
pstream->Out("grestore\n");
}
// Compute the bounding box. Note that it is in the default user
// coordinate system, thus we have to convert the values.
// If we're landscape, our sense of "x" and "y" is reversed.
if (use_paper_bbox) {
minx = 0;
miny = 0;
maxx = paper_w;
maxy = paper_h;
} else {
minx = min_x;
miny = min_y;
maxx = max_x;
maxy = max_y;
}
if (landscape) {
llx = miny * paper_y_scale + paper_y + paper_margin_y;
lly = minx * paper_x_scale + paper_x + paper_margin_x;
urx = maxy * paper_y_scale + paper_y + paper_margin_y;
ury = maxx * paper_x_scale + paper_x + paper_margin_x;
} else {
llx = minx * paper_x_scale + paper_x + paper_margin_x;
lly = paper_h * paper_y_scale - (maxy * paper_y_scale) + paper_y + paper_margin_y;
urx = maxx * paper_x_scale + paper_x + paper_margin_x;
ury = paper_h * paper_y_scale - (miny * paper_y_scale) + paper_y + paper_margin_y;
}
/* Don't allow a negative-sized bounding box! */
if (urx <= llx)
urx = llx + 1;
if (ury <= lly)
ury = lly + 1;
// The Adobe specifications call for integers; we round as to make
// the bounding larger.
pstream->seekp(boundingboxpos);
pstream->Out("%%BoundingBox: ");
pstream->width(5);
pstream->Out(floor(llx)); pstream->Out(" ");
pstream->width(5);
pstream->Out(floor(lly)); pstream->Out(" ");
pstream->width(5);
pstream->Out(ceil(urx) ); pstream->Out(" ");
pstream->width(5);
pstream->Out(ceil(ury)); pstream->Out("\n");
pstream->Out("%%Pages: ");
pstream->width(5);
pstream->Out((page_number - 1)); pstream->Out("\n");
DELETE_OBJ pstream;
pstream = NULL;
#ifdef wx_x
if (ok /* && wx_interactive */)
{
switch (mode) {
case PS_PREVIEW:
{
char *argv[3];
argv[0] = preview_cmd;
argv[1] = filename;
argv[2] = NULL;
wxsExecute (argv);
}
break;
case PS_PRINTER:
{
char *argv[4];
char *opts;
int i;
argv[0] = print_cmd;
i = 1;
opts = print_opts;
if (opts && *opts)
argv[i++] = opts;
argv[i++] = filename;
argv[i] = NULL;
wxsExecute(argv);
}
break;
case PS_FILE:
break;
}
}
#endif
}
void wxPostScriptDC::StartPage (void)
{
if (!pstream)
return;
pstream->Out("%%Page: "); pstream->Out(page_number++); pstream->Out("\n");
pstream->Out("%%BeginPageSetup\n");
/* pstream->Out("userdict /pgsave save put\n"); */
pstream->Out((paper_x + paper_margin_x + (landscape ? (paper_h * paper_y_scale) : 0)));
pstream->Out(" "); pstream->Out(paper_y + paper_margin_y); pstream->Out(" translate\n");
if (landscape) {
pstream->Out(paper_y_scale); pstream->Out(" "); pstream->Out(paper_x_scale); pstream->Out(" scale\n");
pstream->Out("90 rotate\n");
} else {
pstream->Out(paper_x_scale); pstream->Out(" "); pstream->Out(paper_y_scale); pstream->Out(" scale\n");
}
pstream->Out("2 setlinecap\n");
pstream->Out("%%EndPageSetup\n");
resetFont = RESET_FONT | RESET_COLOR;
if (clipping)
SetClippingRegion(clipping);
}
void wxPostScriptDC::EndPage (void)
{
if (!pstream)
return;
/* pstream->Out("userdict /pgsave get restore\n"); */
pstream->Out("showpage\n");
}
static void printhex(wxPSStream *pstream, int v)
{
int h, l;
char s[3];
s[2] = 0;
h = (v >> 4) & 0xF;
l = v & 0xF;
if (h <= 9)
s[0] = '0' + h;
else
s[0] = 'a' + (h - 10);
if (l <= 9)
s[1] = '0' + l;
else
s[1] = 'a' + (l - 10);
pstream->Out(s);
}
Bool wxPostScriptDC::
Blit (double xdest, double ydest, double fwidth, double fheight,
wxMemoryDC *src, double xsrc, double ysrc, int rop, wxColour *dcolor,
wxMemoryDC *mask)
{
int mono;
long j, i;
wxColour *c;
int pixel;
int pr, pg, pb;
wxCanvasDC *source = (wxCanvasDC *)src;
long width, height, x, y;
Bool asColour = level2ok;
if (!pstream)
return FALSE;
width = (long)floor(fwidth);
height = (long)floor(fheight);
if (rop >= 0) {
fwidth = XSCALEREL(fwidth);
fheight = YSCALEREL(fheight);
}
x = (long)floor(xsrc);
y = (long)floor(ysrc);
c = new wxColour;
/* Since we want a definition, may need to start a dictionary: */
if (rop >= 0) {
pstream->Out("1 dict begin\n");
}
/* Allocate space. */
pstream->Out("/DataString ");
pstream->Out((width * (asColour ? 3 : 1) * ((rop < 0) ? height : 1)));
pstream->Out(" string def\n");
if (rop < 0) {
pstream->Out(" /PaintProc { begin \n");
}
/* PostScript setup: */
pstream->Out("gsave\n");
if (rop >= 0) {
pstream->Out(XSCALE(xdest)); pstream->Out(" "); pstream->Out(YSCALE(ydest) - fheight); pstream->Out(" translate\n");
}
/* Mask => clip */
if (mask) {
int red, green, blue;
int skip_start, skip;
pstream->Out("newpath\n");
for (i = 0; i < width; i++) {
skip = 0;
skip_start = 0;
for (j = 0; j < height + 1; j++) {
mask->GetPixel(i, j, c);
if (j == height) {
red = green = blue = 255;
} else {
red = c->Red();
green = c->Green();
blue = c->Blue();
}
if ((red < 255) || (green < 255) || (blue < 255)) {
skip++;
} else {
if (skip) {
double si, sip, ss, ssk;
si = XSCALEREL(i);
sip = XSCALEREL(i+1);
ss = fheight - YSCALEREL(skip_start);
ssk = fheight - YSCALEREL(skip_start + skip);
pstream->Out(si); pstream->Out(" "); pstream->Out(ss); pstream->Out(" moveto\n");
pstream->Out(sip); pstream->Out(" "); pstream->Out(ss); pstream->Out(" lineto\n");
pstream->Out(sip); pstream->Out(" "); pstream->Out(ssk); pstream->Out(" lineto\n");
pstream->Out(si); pstream->Out(" "); pstream->Out(ssk); pstream->Out(" lineto\n");
}
skip = 0;
skip_start = j + 1;
}
}
}
pstream->Out("clip\n");
}
/* Image scale */
pstream->Out(fwidth); pstream->Out(" "); pstream->Out(fheight); pstream->Out(" scale\n");
/* Image matrix */
pstream->Out(width); pstream->Out(" "); pstream->Out(height); pstream->Out(" 8 [ ");
pstream->Out(width); pstream->Out(" 0 0 "); pstream->Out((-height)); pstream->Out(" 0 "); pstream->Out(height);
pstream->Out(" ]\n");
if (rop >= 0) {
pstream->Out("{\n");
pstream->Out(" currentfile DataString readhexstring pop\n");
pstream->Out("} bind");
} else {
pstream->Out(" { DataString } ");
}
if (asColour) {
pstream->Out(" false 3 colorimage\n");
} else {
pstream->Out(" image\n");
}
if (rop < 0) {
pstream->Out("grestore\n } def \n");
pstream->Out(" { currentfile DataString readhexstring pop pop } exec\n");
}
/* Output data as hex digits: */
{
wxBitmap *sbm;
sbm = src->GetObject();
mono = (sbm->GetDepth() == 1);
}
if (mono && dcolor) {
pr = dcolor->Red();
pg = dcolor->Green();
pb = dcolor->Blue();
} else
pr = pg = pb = 0;
for (j = 0; j < height; j++) {
for (i = 0; i < width; i++) {
int red, green, blue;
source->GetPixel(i, j, c);
red = c->Red();
green = c->Green();
blue = c->Blue();
if (mono && !red && !green && !blue) {
red = pr;
green = pg;
blue = pb;
} else if (mono) {
if ((rop != wxSOLID) && (rop != (-wxSOLID - 1))) {
red = current_background_color->Red();
green = current_background_color->Green();
blue = current_background_color->Blue();
}
}
if (asColour) {
printhex(pstream, red);
printhex(pstream, green);
printhex(pstream, blue);
/* Avoid making lines longer than 255 chars: */
if (i && !(i & 0x1F))
pstream->Out("\n");
} else {
double r, gr, b;
r = ((double)(red) / 255);
gr = ((double)(green) / 255);
b = ((double)(blue) / 255);
pixel = (int)(255 * sqrt(((r * r) + (gr * gr) + (b * b)) / 3));
printhex(pstream, pixel);
/* Avoid making lines longer than 255 chars: */
if (i && !(i & 0x3F))
pstream->Out("\n");
}
}
pstream->Out("\n");
}
if (rop >= 0) {
pstream->Out("grestore\n");
/* End dictionary: */
pstream->Out("end\n");
}
if (rop >= 0) {
CalcBoundingBoxClip(XSCALEBND(xdest), YSCALEBND(ydest));
/* Bitmap isn't scaled: */
CalcBoundingBoxClip(XSCALEBND(xdest) + fwidth, YSCALEBND(ydest) + fheight);
}
return TRUE;
}
static wxMemoryDC *temp_mdc, *temp_mask_mdc;
Bool wxPostScriptDC::Blit (double xdest, double ydest, double fwidth, double fheight,
wxBitmap *bm, double xsrc, double ysrc, int rop, wxColour *c, wxBitmap *mask)
{
Bool v;
wxMemoryDC *mask_dc = NULL, *main_dc = NULL;
#ifdef wx_msw
main_dc = (wxMemoryDC *)bm->selectedInto;
#endif
if (!main_dc) {
if (!temp_mdc) {
wxREGGLOB(temp_mdc);
temp_mdc = new wxMemoryDC(1);
}
temp_mdc->SelectObject(bm);
/* Might fail, so we double-check: */
if (temp_mdc->GetObject())
main_dc = temp_mdc;
}
if (mask) {
#ifdef wx_msw
mask_dc = (wxMemoryDC *)mask->selectedInto;
#endif
if (!mask_dc) {
if (!temp_mask_mdc) {
wxREGGLOB(temp_mask_mdc);
temp_mask_mdc = new wxMemoryDC(1);
}
temp_mask_mdc->SelectObject(mask);
if (temp_mask_mdc->GetObject()) {
mask_dc = temp_mask_mdc;
}
}
}
if (main_dc) {
v = Blit(xdest, ydest, fwidth, fheight,
main_dc, xsrc, ysrc, rop, c, mask_dc);
if (main_dc == temp_mdc)
temp_mdc->SelectObject(NULL);
} else
v = FALSE;
if (mask_dc && (mask_dc == temp_mask_mdc)) {
mask_dc->SelectObject(NULL);
}
return v;
}
double wxPostScriptDC::GetCharHeight (void)
{
if (current_font)
return (double) current_font->GetPointSize ();
else
return 12.0;
}
double wxPostScriptDC::GetCharWidth (void)
{
return 0;
}
void wxPostScriptDC::GetTextExtent (const char *string, double *x, double *y,
double *descent, double *topSpace, wxFont *theFont,
Bool combine, Bool use16, int dt)
{
wxFont *fontToUse = theFont;
int family;
int size;
int style;
int weight;
int sym_map;
const char *name;
if (!fontToUse)
fontToUse = current_font;
family = fontToUse->GetFontId();
size = fontToUse->GetPointSize();
style = fontToUse->GetStyle();
weight = fontToUse->GetWeight();
name = wxTheFontNameDirectory->GetPostScriptName(family, weight, style);
if (!name)
name = "Times-Roman";
sym_map = fontToUse->GetFamily() == wxSYMBOL;
wxPostScriptGetTextExtent(name, string, dt, combine, use16, size,
x, y, descent, topSpace, sym_map);
}
void wxPostScriptDC::SetMapMode (int WXXTUNUSED(mode))
{
#ifndef wx_xt
mapping_mode = mode;
#endif
return;
}
void wxPostScriptDC::SetUserScale (double x, double y)
{
user_scale_x = x;
user_scale_y = y;
resetFont |= RESET_FONT;
}
double wxPostScriptDC::DeviceToLogicalX(int x)
{
return (x - device_origin_x) / user_scale_x;
}
double wxPostScriptDC::DeviceToLogicalXRel(int x)
{
return x / user_scale_x;
}
double wxPostScriptDC::DeviceToLogicalY(int y)
{
double y2 = -(y - paper_h);
return (y2 - device_origin_y) / user_scale_y;
}
double wxPostScriptDC::DeviceToLogicalYRel(int y)
{
return y / user_scale_y;
}
int wxPostScriptDC::LogicalToDeviceX(double x)
{
return (int)floor(XSCALE(x));
}
int wxPostScriptDC::LogicalToDeviceXRel(double x)
{
return (int)floor(XSCALEREL(x));
}
int wxPostScriptDC::LogicalToDeviceY(double y)
{
return (int)floor(YSCALE(y));
}
int wxPostScriptDC::LogicalToDeviceYRel(double y)
{
return (int)floor(YSCALEREL(y));
}
double wxPostScriptDC::FLogicalToDeviceX(double x)
{
return XSCALE(x);
}
double wxPostScriptDC::FLogicalToDeviceXRel(double x)
{
return XSCALEREL(x);
}
double wxPostScriptDC::FLogicalToDeviceY(double y)
{
return YSCALE(y);
}
double wxPostScriptDC::FLogicalToDeviceYRel(double y)
{
return YSCALEREL(y);
}
double wxPostScriptDC::FsLogicalToDeviceX(double x, double device_origin_x, double user_scale_x)
{
/* Intentional capture of arguments by macro! */
return XSCALE(x);
}
double wxPostScriptDC::FsLogicalToDeviceXRel(double x, double device_origin_x, double user_scale_x)
{
/* Intentional capture of arguments by macro! */
return XSCALEREL(x);
}
double wxPostScriptDC::FsLogicalToDeviceY(double y, double device_origin_y, double user_scale_y)
{
/* Intentional capture of arguments by macro! */
return YSCALE(y);
}
double wxPostScriptDC::FsLogicalToDeviceYRel(double y, double device_origin_y, double user_scale_y)
{
/* Intentional capture of arguments by macro! */
return YSCALEREL(y);
}
void wxPostScriptDC::GetSize(double *width, double *height)
{
if (width)
*width = paper_w;
if (height)
*height = paper_h;
}
void wxPostScriptDC::GetSizeMM(double *WXUNUSED(width), double *WXUNUSED(height))
{
}
extern Bool wxsPrinterDialog(wxWindow *parent);
Bool XPrinterDialog(wxWindow *parent)
{
return wxsPrinterDialog(parent);
}
//-----------------------------------------------------------------------------
// wxPrintSetup implementation
//-----------------------------------------------------------------------------
#define PS_DEFAULT_PAPER "Letter 8 1/2 x 11 in"
#define PS_PREVIEW_COMMAND "gv"
#define PS_PRINTER_COMMAND "lpr"
#define PS_PRINTER_OPTIONS ""
#define PS_AFM_PATH NULL
wxPrintSetupData::wxPrintSetupData(void)
{
printer_command = PS_PRINTER_COMMAND;
preview_command = PS_PREVIEW_COMMAND;
printer_flags = PS_PRINTER_OPTIONS;
printer_orient = PS_PORTRAIT;
printer_scale_x = 0.8;
printer_scale_y = 0.8;
printer_translate_x = 0.0;
printer_translate_y = 0.0;
#ifdef wx_x
printer_mode = PS_PREVIEW;
#else
printer_mode = PS_FILE;
#endif
afm_path = default_afm_path;
paper_name = DEFAULT_PAPER;
print_colour = TRUE;
print_level_2 = TRUE;
printer_file = NULL;
emargin_v = emargin_h = 20;
ps_margin_v = ps_margin_h = 16;
}
wxPrintSetupData::~wxPrintSetupData(void)
{
}
void wxPrintSetupData::SetPrinterCommand(char *cmd)
{
if (cmd == printer_command)
return;
if (cmd) {
printer_command = copystring(cmd);
} else
printer_command = NULL;
}
void wxPrintSetupData::SetPrintPreviewCommand(char *cmd)
{
if (cmd == preview_command)
return;
if (cmd) {
preview_command = copystring(cmd);
} else
preview_command = NULL;
}
void wxPrintSetupData::SetPaperName(char *name)
{
if (name == paper_name)
return;
if (name) {
paper_name = copystring(name);
} else
paper_name = NULL;
}
void wxPrintSetupData::SetPrinterOptions(char *flags)
{
if (printer_flags == flags)
return;
if (flags) {
printer_flags = copystring(flags);
} else
printer_flags = NULL;
}
void wxPrintSetupData::SetPrinterFile(char *f)
{
if (f == printer_file)
return;
if (f) {
printer_file = copystring(f);
} else
printer_file = NULL;
}
void wxPrintSetupData::SetPrinterMode(int mode)
{
printer_mode = PS_FILE;
if (mode == PS_PREVIEW && preview_command
|| mode == PS_PRINTER && printer_command)
printer_mode = mode;
}
void wxPrintSetupData::SetPrinterOrientation(int orient)
{
printer_orient = orient;
#ifdef wx_mac
if (native) {
native->SetLandscape(printer_orient == PS_LANDSCAPE);
}
#endif
}
void wxPrintSetupData::SetAFMPath(char *f)
{
if (f && !default_afm_path) {
wxREGGLOB(default_afm_path);
default_afm_path = f;
}
if (f == afm_path)
return;
if (f) {
afm_path = copystring(f);
} else
afm_path = NULL;
}
void wxPrintSetupData::copy(wxPrintSetupData* data)
{
double x, y;
long lx, ly;
char *s;
int i;
s = data->GetPrinterCommand();
SetPrinterCommand(s);
s = data->GetPrintPreviewCommand();
SetPrintPreviewCommand(s);
s = data->GetPrinterOptions();
SetPrinterOptions(s);
i = data->GetPrinterOrientation();
SetPrinterOrientation(i);
i = data->GetPrinterMode();
SetPrinterMode(i);
s = data->GetAFMPath();
SetAFMPath(s);
s = data->GetPaperName();
SetPaperName(s);
i = data->GetColour();
SetColour(i);
data->GetPrinterTranslation(&x, &y);
SetPrinterTranslation(x, y);
data->GetPrinterScaling(&x, &y);
SetPrinterScaling(x, y);
data->GetMargin(&x, &y);
SetMargin(x, y);
data->GetEditorMargin(&lx, &ly);
SetEditorMargin(lx, ly);
#ifdef wx_mac
if (data->native) {
wxPrintData *n;
n = data->native->copy();
native = n;
}
#endif
}
Bool wxPrintSetupData::CanShowNative()
{
#ifdef wx_mac
return TRUE;
#else
return FALSE;
#endif
}
Bool wxPrintSetupData::ShowNative(wxWindow *parent)
{
#ifdef wx_mac
wxPrintDialog *d;
int ls;
Bool ok;
if (!native) {
native = new wxPrintData();
native->SetLandscape(printer_orient == PS_LANDSCAPE);
}
d = new wxPrintDialog(parent, native);
ok = d->UseIt();
DELETE_OBJ d;
if (ok) {
ls = native->GetLandscape();
printer_orient = (ls ? PS_LANDSCAPE : PS_PORTRAIT);
}
return ok;
#else
return TRUE;
#endif
}
//-----------------------------------------------------------------------------
// wxInitializePrintSetupData
//-----------------------------------------------------------------------------
void wxInitializePrintSetupData(Bool /* init */)
{
wxPrintSetupData *wxThePrintSetupData;
#ifdef wx_mac
wxThePrintPaperDatabase = new wxPrintPaperDatabase;
wxThePrintPaperDatabase->CreateDatabase();
#endif
wxThePrintSetupData = new wxPrintSetupData;
wxThePrintSetupData->SetPrintPreviewCommand(PS_PREVIEW_COMMAND);
wxThePrintSetupData->SetPrinterOrientation(PS_PORTRAIT);
#ifdef wx_x
wxThePrintSetupData->SetPrinterMode(PS_PREVIEW);
#else
wxThePrintSetupData->SetPrinterMode(PS_FILE);
#endif
wxThePrintSetupData->SetPaperName(PS_DEFAULT_PAPER);
wxThePrintSetupData->SetPrinterCommand(PS_PRINTER_COMMAND);
wxThePrintSetupData->SetPrinterOptions(PS_PRINTER_OPTIONS);
wxThePrintSetupData->SetAFMPath(PS_AFM_PATH);
wxSetThePrintSetupData(wxThePrintSetupData);
}
//-----------------------------------------------------------------------------
// wxPrintPaperType implementation
//-----------------------------------------------------------------------------
wxPrintPaperType::wxPrintPaperType(char *name, int wmm, int hmm, int wp, int hp)
{
widthMM = wmm;
heightMM = hmm;
widthPixels = wp;
heightPixels = hp;
pageName = copystring(name);
}
wxPrintPaperType::~wxPrintPaperType(void)
{
}
//-----------------------------------------------------------------------------
// wxPrintPaperDatabase implementation
//-----------------------------------------------------------------------------
wxPrintPaperDatabase::wxPrintPaperDatabase(void) : wxList(wxKEY_STRING)
{
DeleteContents(TRUE);
}
wxPrintPaperDatabase::~wxPrintPaperDatabase(void)
{
}
void wxPrintPaperDatabase::CreateDatabase(void)
{
// Need correct values for page size in pixels.
// Each unit is one 'point' = 1/72 of an inch.
// NOTE: WE NEED ALSO TO MAKE ADJUSTMENTS WHEN TRANSLATING
// in wxPostScriptDC code, so we can start from top left.
// So access this database and translate by appropriate number
// of points for this paper size. OR IS IT OK ALREADY?
// Can't remember where the PostScript origin is by default.
// Heck, someone will know how to make it hunky-dory...
// JACS 25/5/95
AddPaperType("A4 210 x 297 mm", 210, 297, 595, 842);
AddPaperType("A3 297 x 420 mm", 297, 420, 842, 1191);
AddPaperType("Letter 8 1/2 x 11 in", 216, 279, 612, 791);
AddPaperType("Legal 8 1/2 x 14 in", 216, 356, 612, 1009);
}
void wxPrintPaperDatabase::ClearDatabase(void)
{
Clear();
}
void wxPrintPaperDatabase::AddPaperType(char *name, int wmm, int hmm,
int wp, int hp)
{
wxPrintPaperType *ppt;
ppt = new wxPrintPaperType(name, wmm, hmm, wp, hp);
Append(name, ppt);
}
wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(char *name)
{
wxNode *node;
if ((node = Find(name)))
return (wxPrintPaperType*)node->Data();
else
return NULL;
}