//
// FXDCNativePrinter.cpp
//
// cf FXDCPrint but this version can use a native WIN32 printer
//    and also provides richer scaling capabilities. It also
//    uses FXPostscriptFont when printing Postscript so that it gets
//    metrics right (at least for the standard 35 fonts).
//
// Contributed to FOX project by Manuel (address@te...) who
// made a deliberate choice not to add a copyright notice, so that
// the code could be added to FOX (and hence released under the FOX
// relaxed version of the LGPL).
//

// This version worked on by Arthur Norman mainly to make the
// behaviour under Linux more robust, but also to clean up some
// oddities etc. and add bits of functionality.

/* Signature: 636f80a6 27-Jun-2005 */


#ifdef HAVE_CONFIG_H
#include "config.h"
#else
#define HAVE_LIBFOX 1
#endif

#ifdef HAVE_LIBFOX

#include <string.h>
#include <ctype.h>
#include <fx.h>
#include <FXDC.h>
#include <FXDCPrint.h>
#include <FXDCWindow.h>

#include "FXPostscriptFont.h"

//////////////////////////////////////////////////////////////////////////////
// The following implements two minorish patches to the FXDCPrint class
// that make it handle Postscript better for me. I mark the changes
// with "@@@"
//

// define a version of FOX where these patches become unnecessary needed
#define PRINT_MAJOR 99
#define PRINT_MINOR 99
#define PRINT_LEVEL 99

#if (FOX_MAJOR<PRINT_MAJOR || (FOX_MAJOR==PRINT_MAJOR && \
    (FOX_MINOR<PRINT_MINOR || (FOX_MINOR==PRINT_MINOR && \
    (FOX_LEVEL<PRINT_LEVEL)))))

class FXAPI FXDCPatchedPrint : public FXDCPrint {
public:
  FXDCPatchedPrint(FXApp* a);
  ~FXDCPatchedPrint();
  FXbool beginPage(FXuint page);   // NB not virtual in FXDCPrint
  virtual void drawText(FXint x,FXint y,const FXchar* string,FXuint len);
  };


// Construct
FXDCPatchedPrint::FXDCPatchedPrint(FXApp* a) : FXDCPrint(a){
  }


// Destruct
FXDCPatchedPrint::~FXDCPatchedPrint(){
  }


// Generate begin of page
FXbool FXDCPatchedPrint::beginPage(FXuint page){

  // Output page number
  outf("%%%%Page: %d %d\n",page,page);   // @@@ 2 values after "%%Page:"

  // Reset page bounding box
  if(flags&PRINT_NOBOUNDS){
    pagebb.xmin= 1000000;
    pagebb.xmax=-1000000;
    pagebb.ymin= 1000000;
    pagebb.ymax=-1000000;
    outf("%%%%PageBoundingBox: (atend)\n");
    }

  // Use the doc bounding box
  else{
    pagebb.xmin=docbb.xmin;
    pagebb.xmax=docbb.xmax;
    pagebb.ymin=docbb.ymin;
    pagebb.ymax=docbb.ymax;
    outf("%%%%PageBoundingBox: %d %d %d %d\n",(int)pagebb.xmin,(int)pagebb.ymin,(int)pagebb.xmax,(int)pagebb.ymax);
    }

  // Page setup
  outf("%%%%BeginPageSetup\n");
  outf("%%%%EndPageSetup\n");
  outf("gsave\n");

  // Maybe in landscape?
  if(flags&PRINT_LANDSCAPE){
    outf("%g %g translate\n",mediawidth,0.0);
    outf("90 rotate\n");
    }

  return TRUE;
  }


// Draw string (only foreground bits)
// Contributed by S. Ancelot <sancelot@online.fr>
void FXDCPatchedPrint::drawText(FXint x,FXint y,const FXchar* string,FXuint len){
  FXfloat xx,yy;
  tfm(xx,yy,(FXfloat)x,(FXfloat)y);
  bbox(xx,yy);
  FXFontDesc fontdesc;
  font->getFontDesc(fontdesc);
  outf("gsave /%s findfont\n",font->getName().text());
// @@@ Support fractions of a point in font sizes by using float not int here
  outf("%g scalefont\n",(double)font->getSize()/10.0);
  outf("setfont\n");
  outf("newpath\n%g %g moveto\n(",xx,yy);
  for(FXuint i=0; i<len; i++){
    if(string[i]=='(') outf("\\050");
    else if(string[i]==')') outf("\\051");
    else outf("%c",string[i]);
    }
  outf(") show\n");
  outf("grestore\n");
  }

// The macro here subverts all FXPrintDC instances that follow into
// being the patched variety.

#define FXDCPrint FXDCPatchedPrint

// end of patches to FXDCPrint.

#endif // version check in PRINT_MAJOR, PRINT_MINOR and PRINT_LEVEL

//////////////////////////////////////////////////////////////////////////////




#include "FXDCNativePrinter.h"
#include "FXPostscriptFont.h"


//
// When generating Postscript I need font metrics. These can be extracted
// from "afm" files that Adobe supply. I have a program "get-adobe-metrics.c"
// that can be run on a typical Linux system to extract the (minimal) metric
// information that I need here and build a file "font-info.c". By including
// that file here I collect info about all the standard Postscript Fonts.
// I will not permit a user to use any other fonts than these!
//


#ifdef WIN32
//
// The WIN32 version here works by mapping the printer much as if it
// was a window. A Postscript version will generate Postscript directly
// from the print requests that the user makes.
//
class FXAPI FXPrinterVisual : public FXVisual 
{
public:
    FXPrinterVisual();
    void create() { xid=(void *)1; }
    void detach() { xid=(void *)0; }
    void destroy() { xid=(void *)0; }
    FXPixel getPixel(FXColor clr)
    { return RGB( FXREDVAL(clr), FXGREENVAL(clr), FXBLUEVAL(clr) ); }
    FXColor getColor(FXPixel pix)
    { return FXRGB( GetRValue(pix), GetGValue(pix), GetBValue(pix) ); }
};

FXPrinterVisual::FXPrinterVisual():FXVisual() 
{
    depth=24;
    numred=numgreen=numblue=256;
    numcolors=256*256*256;
    type=(FXVisualType)VISUALTYPE_TRUE;
    xid=(void *)0;
//  hPalette = NULL;  // not available in FOX 1.1.49 and unclear whether needed here anyway!
};

class FXAPI FXPrinterDrawable : public FXDrawable 
{
protected:
    FXID dc;
public:
    FXPrinterDrawable(FXID gc);
    FXPrinterDrawable();
    ~FXPrinterDrawable();
    void SetDC(FXID gc);
    virtual FXID GetDC() const { return (FXID)dc; }
    virtual int ReleaseDC(FXID) const { return 0; }
};

FXPrinterDrawable::~FXPrinterDrawable()
{
    delete visual;
}

FXPrinterDrawable::FXPrinterDrawable()
{
    FXPrinterDrawable(0);
}

FXPrinterDrawable::FXPrinterDrawable(FXID gc) : FXDrawable()
{
    dc = gc;
    visual=new FXPrinterVisual();
    xid=(FXID)1;
}

void FXPrinterDrawable::SetDC(FXID gc)
{
    dc = (HDC)gc;
}

#endif // end of WIN32-specific stuff

// Construct

FXDCNativePrinter::FXDCNativePrinter(FXApp *a):FXDC(a)
{
#ifdef WIN32
    opaque = (FXObject *)NULL;
    dctype=TYPE_WIN32;
#else
    dctype=TYPE_PS;
#endif
#ifdef FONT_NOT_VIRTUAL
    postscriptFont = NULL;
#endif
    pageheight = 0.0;   // report this until the print job starts
    pagewidth = 0.0;
    fontoffset = 0;     // Baseline of font
    fontScaleBack = 1.0;
    fontScale = 1.0;
    PSscale = 1.0;
    logpixelsx = 72;
    logpixelsy = 72;
    scalex = 1.0;
    scaley = 1.0;
    unitsx = 72.0;
    unitsy = 72.0;
    pdc = (FXDC *)NULL;
    pagecount=0;
}


// Destruct

FXDCNativePrinter::~FXDCNativePrinter()
{
}

// Generate print job prolog, return TRUE if all is OK

FXbool FXDCNativePrinter::beginPrint(FXPrinter &job)
{
    pagecount=0;

#ifdef WIN32
// on Windows printing to file uses Postscript but anything direct to
// a printer goes via the Windows drivers.
    if (job.flags&PRINT_DEST_FILE) dctype = TYPE_PS;
    else dctype=TYPE_WIN32;
#else
// On other than WIN32 the only print mode supported is Postscript
    dctype=TYPE_PS;
#endif

    switch (dctype)
    {
#ifdef WIN32
case TYPE_WIN32:
        devmode_handle=0;
        FXPrinterDrawable *prn;
// TODO: Paper size
        memset(&devmode, 0, sizeof(devmode));
        devmode.dmFields = DM_ORIENTATION | DM_COLOR;
        devmode.dmSize = sizeof(devmode);
        devmode.dmOrientation = (job.flags&PRINT_LANDSCAPE) ?
                                DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
        devmode.dmColor = (job.flags&PRINT_COLOR) ?
                          DMCOLOR_COLOR : DMCOLOR_MONOCHROME;
        char devicename[256];
// Note: Under Win 9x/ME   "WINSPOOL" should be replaced by NULL,
//       but this seems to work anyway!
        strcpy(devicename, job.name.text());
        dc = CreateDC("WINSPOOL", devicename, NULL, &devmode);
        if (dc==(HANDLE)NULL) return FALSE;

// Initialize the members of a DOCINFO structure.
        memset((void *)&di, 0, sizeof(di));
        di.cbSize = sizeof(DOCINFO);
        di.lpszDocName = "Document";  // FIXME: API to support document name?
        di.lpszOutput = (LPTSTR) NULL;
        di.fwType = 0;

// Start document
        if (::StartDoc(dc, &di)==SP_ERROR)
        {   ::DeleteDC(dc);
            dc=0;
            return FALSE;
        }

        SetMapMode(dc, MM_TEXT);

// get pixels per inch, usually 600x600 or 300x300
        logpixelsy = ::GetDeviceCaps(dc, LOGPIXELSY);
        logpixelsx = ::GetDeviceCaps(dc, LOGPIXELSX);
#ifdef OLD
        fontScale = logpixelsy / 96.0;
        fontScaleBack = 96.0 / logpixelsy;
#else
// The font size I need to create under Windows will be related to the
// pixel-pitch on my output device. My reading of the Windows documentation
// is that the scaling shown here is what is wanted, but the alternative
// scaling by 96 not 72 was present in the original code so I leave it as
// a comment for now in case there is something I do not understand.
        fontScale = logpixelsy / 72.0;
        fontScaleBack = 72.0 / logpixelsy;
#endif
        setHorzUnitsInch(72.0);
        setVertUnitsInch(72.0);

// Create drawable
        prn = new FXPrinterDrawable((FXID)dc);
        opaque= (FXObject *)prn;
        FXdouble dx, dy;
        dx = (FXdouble)job.mediawidth;
        dy = (FXdouble)job.mediaheight;
        if (job.flags&PRINT_LANDSCAPE)
        {   FXdouble kk=dx;
            dx=dy;
            dy=kk;
        }
        pageheight = dy * scaley;   /* Store size in pixels */
        pagewidth = dx * scalex;
        prn->resize( (FXint)(scalex * dx) , (FXint)(scaley * dy) );
// Create a WIN32 FXDC from our drawable
        pdc = (FXDC *)new FXDCWindow(prn);
        SetTextAlign(dc, TA_TOP|TA_LEFT); // TA_BASLINE fails in some printers
        pdc->setForeground(FXRGB(0,0,0));
        pdc->setBackground(FXRGB(255,255,255));
        return TRUE;
#endif

default:      // case TYPE_PS:
// Postscript printing delegates to the existing FXDCPrint class.
//  But note that until metric-returning things in FXFont are virtual
//  I have a HACK whenever I extract measurements here.
        pdc = (FXDC *)new FXDCPrint(getApp());
        if (((FXDCPrint *)pdc)->beginPrint(job) == 0) return FALSE;
        logpixelsx = 72;
        logpixelsy = 72;
        scalex = 1.0;
        scaley = 1.0;
        PSscale = 0.001;  // see usage later on for explanation
// There is an uncertainty here about who is supposed to be
// responsible for margins. The FXPrinter that I was passed has
// given me some suggestions but I ignore them here! What is done here
// is at least compatible with what is done in the WIN32 case.
        pagewidth = (FXfloat)job.mediawidth;
        pageheight = (FXfloat)job.mediaheight;
        if (job.flags&PRINT_LANDSCAPE)
        {   FXdouble kk=pagewidth;
            pagewidth=pageheight;
            pageheight=kk;
        }
// The following 2 lines may not be needed for Postscript printing but
// are harmless anyway.
        pdc->setForeground(FXRGB(0,0,0));
        pdc->setBackground(FXRGB(255,255,255));
        return TRUE;
    }
}

// Generate print job epilog

FXbool FXDCNativePrinter::endPrint()
{
    switch (dctype)
    {
#ifdef WIN32
case TYPE_WIN32:      // End of Document
        if (dc!=0)
        {   ::EndDoc(dc);
            FXDCWindow *pd=(FXDCWindow *)pdc;
            delete pd;
            FXPrinterDrawable *prn=(FXPrinterDrawable *)opaque;
            delete prn;
            ::DeleteDC(dc);
            dc=0;
            opaque=(FXObject *)NULL;
            pdc=(FXDC*)NULL;
        }
        return 1;
#endif
default:              // case TYPE_PS:
        FXDCPrint *pd=(FXDCPrint *)pdc;
        FXbool v=pd->endPrint();
        delete pd;
        pdc=(FXDC *)NULL;
        return v;
    }
}

// Generate begin of page

FXbool FXDCNativePrinter::beginPage(FXuint page)
{
    switch (dctype)
    {
#ifdef WIN32
case TYPE_WIN32:
        if (::StartPage(dc)<=0)
        {   endPrint();
            return 0;
        }
        return 1;
#endif
default:                  // case TYPE_PS:
// Note that if I had to apply my patch then it gets activated here.
        FXDCPrint *pd=(FXDCPrint *)pdc;
        return pd->beginPage(page);
    }
}

// Generate end of page

FXbool FXDCNativePrinter::endPage()
{
    switch (dctype)
    {
#ifdef WIN32
case TYPE_WIN32:
        ::EndPage(dc);
        pagecount++;
        return TRUE;
#endif
default:                  // case TYPE_PS:
        FXDCPrint *pd=(FXDCPrint *)pdc;
        return pd->endPage();
    }
}

// Draw a point in the current pen color

void FXDCNativePrinter::drawPoint(FXint x, FXint y)
{
    pdc->drawPoint(ScaleX(x), ScaleY(y));
}

// I need an array of points, arcs, rectangles into which I can scale things.
// By keeping a single array here I can extend it by need in a reasonably
// tidy way.

static void *dst = NULL;
static int dst_buffer_size = 0;
#define DST_BUFFER_INCREMENT 128

static void check_dst_buffer(int n, int sz)
{
    int len = n*sz;
    if (dst_buffer_size >= len) return;
    if (dst_buffer_size!=0) free((void *)dst);
// I keep the buffer size a multiple of 128 bytes, and any time I have to
// extend it I round up the needed size to a multiple of that.
    dst_buffer_size = len + (DST_BUFFER_INCREMENT - len%DST_BUFFER_INCREMENT);
    void *p = (void *)malloc(len);
// my treatment of failure here is somewhat abrupt, and perhaps I should
// just do less drawing. But for now I intend to be fierce on this count.
    if (p == NULL)
    {   fprintf(stderr, "Fatal error: ran out of memory\n");
        exit(1);
    }
    dst = p;
}

// Draw points in the current pen color.
// Each point's position is relative to the drawable's origin (as usual).

void FXDCNativePrinter::drawPoints(const FXPoint* points,FXuint npoints)
{
    check_dst_buffer(npoints, sizeof(FXPoint));
    scalePoints((FXPoint *)dst, (FXPoint *)points, npoints);
    pdc->drawPoints((FXPoint *)dst, npoints);
}

// Draw points in the current pen color. The first point's position is
// relative to the drawable's origin, but each subsequent point's position
// is relative to the previous point's position; each FXPoint defines
// the relative coordinates. Think LOGO.

void FXDCNativePrinter::drawPointsRel(const FXPoint*points,FXuint npoints)
{
    check_dst_buffer(npoints, sizeof(FXPoint));
    scalePoints((FXPoint *)dst, (FXPoint *)points, npoints);
    pdc->drawPointsRel((FXPoint *)dst, npoints);
}

// Draw a line

void FXDCNativePrinter::drawLine(FXint x1, FXint y1, FXint x2, FXint y2)
{
    pdc->drawLine(ScaleX(x1), ScaleY(y1), ScaleX(x2), ScaleY(y2));
}

// Draw multiple lines. All points are drawn connected.
// Each point is specified relative to Drawable's origin.

void FXDCNativePrinter::drawLines(const FXPoint* points, FXuint npoints)
{
    check_dst_buffer(npoints, sizeof(FXPoint));
    scalePoints((FXPoint *)dst, (FXPoint *)points, npoints);
    pdc->drawLines((FXPoint *)dst, npoints);
}

// Draw multiple lines. All points are drawn connected.
// First point's coordinate is relative to drawable's origin, but
// subsequent points' coordinates are relative to previous point.

void FXDCNativePrinter::drawLinesRel(const FXPoint* points, FXuint npoints)
{
    check_dst_buffer(npoints, sizeof(FXPoint));
    scalePoints((FXPoint *)dst, (FXPoint *)points, npoints);
    pdc->drawLinesRel((FXPoint *)dst, npoints);
}

// Draw unconnected line segments

void FXDCNativePrinter::drawLineSegments(const FXSegment* segments, FXuint nsegments)
{
    check_dst_buffer(nsegments, sizeof(FXSegment));
    scaleSegments((FXSegment *)dst, (FXSegment *)segments, nsegments);
    pdc->drawLineSegments((FXSegment *)dst, nsegments);
}

// Draw unfilled rectangle

void FXDCNativePrinter::drawRectangle(FXint x, FXint y, FXint w, FXint h)
{
    pdc->drawRectangle(ScaleX(x), ScaleY(y), ScaleX(w), ScaleY(h));
}

// Draw unfilled rectangles

void FXDCNativePrinter::drawRectangles(const FXRectangle* rectangles,FXuint nrectangles)
{
    check_dst_buffer(nrectangles, sizeof(FXRectangle));
    scaleRectangles((FXRectangle *)dst, (FXRectangle *)rectangles, nrectangles);
    pdc->drawRectangles((FXRectangle *)dst, nrectangles);
}

// Draw arc

void FXDCNativePrinter::drawArc(FXint x, FXint y, FXint w,
                                FXint h, FXint ang1, FXint ang2)
{
    pdc->drawArc(ScaleX(x), ScaleY(y), ScaleX(w), ScaleY(h), ang1, ang2);
}

// Draw arcs

void FXDCNativePrinter::drawArcs(const FXArc* arcs,FXuint narcs)
{
    check_dst_buffer(narcs, sizeof(FXArc));
    scaleArcs((FXArc *)dst, (FXArc *)arcs, narcs);
    pdc->drawArcs((FXArc *)dst, narcs);
}

// Filled rectangle

void FXDCNativePrinter::fillRectangle(FXint x, FXint y, FXint w, FXint h)
{
    pdc->fillRectangle(ScaleX(x), ScaleY(y), ScaleX(w), ScaleY(h));
}

// Filled rectangles

void FXDCNativePrinter::fillRectangles(const FXRectangle* rectangles,
                                       FXuint nrectangles)
{
    check_dst_buffer(nrectangles, sizeof(FXRectangle));
    scaleRectangles((FXRectangle *)dst, (FXRectangle *)rectangles, nrectangles);
    pdc->fillRectangles((FXRectangle *)dst, nrectangles);
}

// Fill arc

void FXDCNativePrinter::fillArc(FXint x, FXint y, FXint w,
                                FXint h, FXint ang1, FXint ang2)
{
    pdc->fillArc(ScaleX(x), ScaleY(y), ScaleX(w), ScaleY(h), ang1, ang2);
}


// Fill arcs

void FXDCNativePrinter::fillArcs(const FXArc *arcs, FXuint narcs)
{
    check_dst_buffer(narcs, sizeof(FXArc));
    scaleArcs((FXArc *)dst, (FXArc *)arcs, narcs);
    pdc->fillArcs((FXArc *)dst, narcs);
}

// Filled simple polygon

void FXDCNativePrinter::fillPolygon(const FXPoint* points, FXuint npoints)
{
    check_dst_buffer(npoints, sizeof(FXPoint));
    scalePoints((FXPoint *)dst, (FXPoint *)points, npoints);
    pdc->fillPolygon((FXPoint *)dst, npoints);
}

// Fill concave polygon

void FXDCNativePrinter::fillConcavePolygon(const FXPoint *points, FXuint npoints)
{
    check_dst_buffer(npoints, sizeof(FXPoint));
    scalePoints((FXPoint *)dst, (FXPoint *)points, npoints);
    pdc->fillConcavePolygon((FXPoint *)dst, npoints);
}

// Fill complex (self-intersecting) polygon

void FXDCNativePrinter::fillComplexPolygon(const FXPoint *points, FXuint npoints)
{
    check_dst_buffer(npoints, sizeof(FXPoint));
    scalePoints((FXPoint *)dst, (FXPoint *)points, npoints);
    pdc->fillComplexPolygon((FXPoint *)dst, npoints);
}


// Filled simple polygon with relative points

void FXDCNativePrinter::fillPolygonRel(const FXPoint *points, FXuint npoints)
{
    check_dst_buffer(npoints, sizeof(FXPoint));
    scalePoints((FXPoint *)dst, (FXPoint *)points, npoints);
    pdc->fillPolygonRel((FXPoint *)dst, npoints);
}

// Fill concave polygon

void FXDCNativePrinter::fillConcavePolygonRel(const FXPoint *points, FXuint npoints)
{
    check_dst_buffer(npoints, sizeof(FXPoint));
    scalePoints((FXPoint *)dst, (FXPoint *)points, npoints);
    pdc->fillConcavePolygonRel((FXPoint *)dst, npoints);
}

// Fill complex (self-intersecting) polygon

void FXDCNativePrinter::fillComplexPolygonRel(const FXPoint *points, FXuint npoints)
{
    check_dst_buffer(npoints, sizeof(FXPoint));
    scalePoints((FXPoint *)dst, (FXPoint *)points, npoints);
    pdc->fillComplexPolygonRel((FXPoint *)dst, npoints);
}

// Draw string (only foreground bits)

void FXDCNativePrinter::drawText(FXint x, FXint y,
                                 const FXchar *string, FXuint len)
{
/* TA_BASELINE does not work reliably with printers, so we need to adjust by hand */
    pdc->drawText(ScaleX(x), ScaleY(y)-fontoffset, string, len);
}

// Draw string (both foreground and background bits)

void FXDCNativePrinter::drawImageText(FXint x, FXint y,
                                      const FXchar*string,FXuint len)
{
    pdc->drawImageText(ScaleX(x), ScaleY(y)-fontoffset, string, len);
}

// Draw area from source

void FXDCNativePrinter::drawArea(const FXDrawable *source,
                                 FXint sx, FXint sy, FXint sw, FXint sh,
                                 FXint dx, FXint dy)
{
    pdc->drawArea(source, sx, sy, sw, sh, ScaleX(dx), ScaleY(dy));
}

// Draw image

void FXDCNativePrinter::drawImage(const FXImage *img, FXint dx, FXint dy)
{
    pdc->drawImage(img, ScaleX(dx), ScaleY(dy));
}

// Draw bitmap

void FXDCNativePrinter::drawBitmap(const FXBitmap *bitmap, FXint dx, FXint dy)
{
    pdc->drawBitmap(bitmap, ScaleX(dx), ScaleY(dy));
}


// Draw icon

void FXDCNativePrinter::drawIcon(const FXIcon *icon, FXint dx, FXint dy)
{
    pdc->drawIcon(icon, ScaleX(dx), ScaleY(dy));
}

// Draw icon shaded

void FXDCNativePrinter::drawIconShaded(const FXIcon *icon, FXint dx, FXint dy)
{
    pdc->drawIconShaded(icon, ScaleX(dx), ScaleY(dy));
}

// Draw icon sunken

void FXDCNativePrinter::drawIconSunken(const FXIcon *icon, FXint dx, FXint dy)
{
    pdc->drawIconSunken(icon, ScaleX(dx), ScaleY(dy));
}

// Draw hashed box

void FXDCNativePrinter::drawHashBox(FXint x, FXint y, FXint w, FXint h,
                                    FXint b)
{
  // FIXME: Scaling border by horizontal resolution,
  // what when logpixelsx != logpixelsy ??
    pdc->drawHashBox(ScaleX(x), ScaleY(y), ScaleX(w), ScaleY(h), ScaleX(b));
}

// Set foreground drawing color (brush)

void FXDCNativePrinter::setForeground(FXColor clr)
{
    pdc->setForeground(clr);
}

// Set background drawing color (brush)

void FXDCNativePrinter::setBackground(FXColor clr)
{
    pdc->setBackground(clr);
}

// Set dash pattern

void FXDCNativePrinter::setDashes(FXuint dashoffset, const FXchar *dashpattern, FXuint dashlength)
{
    pdc->setDashes(dashoffset, dashpattern, dashlength);
}

// Set line width

void FXDCNativePrinter::setLineWidth(FXuint linewidth)
{
    // FIXME: Scaling by X resolution, what if Xdpi != Ydpi ????
    pdc->setLineWidth(ScaleX(linewidth));
}

// Set line cap style

void FXDCNativePrinter::setLineCap(FXCapStyle capstyle)
{
    pdc->setLineCap(capstyle);
}

// Set line join style

void FXDCNativePrinter::setLineJoin(FXJoinStyle joinstyle)
{
    pdc->setLineJoin(joinstyle);
}

// Set line style

void FXDCNativePrinter::setLineStyle(FXLineStyle linestyle)
{
    pdc->setLineStyle(linestyle);
}

// Set fill style

void FXDCNativePrinter::setFillStyle(FXFillStyle fillstyle)
{
    pdc->setFillStyle(fillstyle);
}

// Set fill rule

void FXDCNativePrinter::setFillRule(FXFillRule fillrule)
{
    pdc->setFillRule(fillrule);
}

// Set blit function

void FXDCNativePrinter::setFunction(FXFunction func)
{
    pdc->setFunction(func);
}

// Set tile image

void FXDCNativePrinter::setTile(FXImage *image, FXint dx, FXint dy)
{
    pdc->setTile(image, dx, dy);  // TODO: Check if dx,dy should be scaled
}

// Set stipple pattern

void FXDCNativePrinter::setStipple(FXBitmap *bitmap, FXint dx, FXint dy)
{
    pdc->setStipple(bitmap, dx, dy); // TODO: Check if dx,dy should be scaled
}

// Set stipple pattern

void FXDCNativePrinter::setStipple(FXStipplePattern pat, FXint dx, FXint dy)
{
    pdc->setStipple(pat, dx, dy); // TODO: Check if dx,dy should be scaled
}

// Set clip rectangle

void FXDCNativePrinter::setClipRectangle(FXint x, FXint y, FXint w, FXint h)
{
    pdc->setClipRectangle(ScaleX(x), ScaleY(y), ScaleX(w), ScaleY(h));
}

// Set clip rectangle

void FXDCNativePrinter::setClipRectangle(const FXRectangle &rectangle)
{
    pdc->setClipRectangle(ScaleX(rectangle.x), ScaleY(rectangle.y),
                          ScaleX(rectangle.w), ScaleY(rectangle.h));
}

// Clear clipping

void FXDCNativePrinter::clearClipRectangle()
{
    pdc->clearClipRectangle();
}

// Set clip mask

void FXDCNativePrinter::setClipMask(FXBitmap *bitmap, FXint dx, FXint dy)
{
    pdc->setClipMask(bitmap, dx, dy);  // TODO: Check if dx,dy should be scaled
}

// Clear clip mask

void FXDCNativePrinter::clearClipMask()
{
    pdc->clearClipMask();
}

// Set font to draw text with

void FXDCNativePrinter::setFont(FXFont *fnt)
{
    font=fnt;
#if FOX_MAJOR==1 && FOX_MINOR==0
    pdc->setTextFont(fnt);
#else
    pdc->setFont(fnt);
#endif
    fontoffset=0;
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) postscriptFont = (FX::FXPostscriptFont *)font;
#endif
    if (dctype==TYPE_WIN32) fontoffset = font->getFontAscent();
}

// Change clip-against-child windows mode

void FXDCNativePrinter::clipChildren(FXbool yes)
{
   // Do nothing
}

//
// Now the helper code that scales vectors of stuff for me.
//

void FXDCNativePrinter::scalePoints(FXPoint *dst, FXPoint *src, FXuint npoints)
{
    for (;npoints>0;npoints--,dst++,src++)
    {   dst->x = ScaleX(src->x);
        dst->y = ScaleY(src->y);
    }
}

void FXDCNativePrinter::scaleRectangles(FXRectangle *dst, FXRectangle *src, FXuint nrectangles)
{
    for (;nrectangles>0;nrectangles--,dst++,src++)
    {   dst->x = ScaleX(src->x);
        dst->y = ScaleY(src->y);
        dst->w = ScaleX(src->w);
        dst->h = ScaleY(src->h);
    }
}

void FXDCNativePrinter::scaleSegments(FXSegment *dst, FXSegment *src, FXuint nsegments)
{
    for (;nsegments>0;nsegments--,dst++,src++)
    {   dst->x1 = ScaleX(src->x1);
        dst->y1 = ScaleY(src->y1);
        dst->x2 = ScaleX(src->x2);
        dst->y2 = ScaleY(src->y2);
    }
}

void FXDCNativePrinter::scaleArcs(FXArc *dst, FXArc *src, FXuint narcs)
{
    for (;narcs>0;narcs--,dst++,src++)
    {   dst->x = ScaleX(src->x);
        dst->y = ScaleY(src->y);
        dst->w = ScaleX(src->w);
        dst->h = ScaleY(src->h);
        dst->a = src->a;
        dst->b = src->b;
    }
}


void FXDCNativePrinter::setHorzUnitsInch(FXfloat sx)
{
    scalex = logpixelsx / sx;
    unitsx = sx;
}

void FXDCNativePrinter::setVertUnitsInch(FXfloat sy)
{
    scaley = logpixelsy / sy;
    unitsx = sy;
}

// Create a font, paying attention to the scaling currently in force.

FXFont *FXDCNativePrinter::fntGenerateFont(const FXString &face,
    FXuint sz, FXuint wt, FXuint sl, FXuint enc, FXuint setw, FXuint h)
{
    return fntDoubleGenerateFont(face, (double)sz, wt, sl, enc, setw, h);
}

// The next version takes the desired point size as a double not an
// int. Because windows printer fonts actually exist at pixel-size based on
// printer resolution they can exist in visible sizes that vary much
// more finely than integer point sizes would allow one to express. And
// both with Postscript and Truetype fonts utterly arbitrary scaling
// can be applied. With Postscript my font's size will be specified
// internally in decipoints so at least we can have sizes 5.1, 5.2, 5.3 etc.

FXFont *FXDCNativePrinter::fntDoubleGenerateFont(const FXString &face,
    double sz, FXuint wt, FXuint sl, FXuint enc, FXuint setw, FXuint h)
{
    if (dctype == TYPE_WIN32)
        return new FXFont(getApp(), face, (int)(sz * fontScale), wt,
                          sl, enc, setw, h);
    else  // otherwise I am to generate Postscript
    {   FXFontDesc fdd;
        memset((void *)&fdd, 0, sizeof(fdd));
        strcpy(fdd.face, face.text());
// The whole purpose of constructing via FXFontDesc is to give size in
// decipoints not points. I can not use the fontScale trick here without
// re-working how FXDCPrint prints things...
        fdd.size = (int)(10.0*sz + 0.5);
        fdd.weight = wt;
        fdd.slant = sl;
        fdd.encoding = enc;
        fdd.setwidth = setw;
        fdd.flags = h;
// the explicit FX:: on the next line is needed to allow this code to
// compile using both FOX 1.0 and FOX 1.1!!!
        return new FX::FXPostscriptFont(getApp(), fdd);
    }
}

//
// Most of the stuff that follows is just delegating actions to an
// underlying DC, possibly applying scaling. The scaling is so that the
// user can select the (integer-based) unit of measurement... in some cases
// the default unit of 1pt (= 1/72in here) would be too coarse. It is
// STRONGLY suggested that anybody changing units should use the same
// ones for both X and Y, since otherwise indicating sizes for values
// not keyed to axis direction (eg line width) gets very questionable indeed.
// I think maybe the API would be safer with just a single scaling option
// not two.  Note also that font sizes are always specified in points
// regardless of other options being set.

FXString FXDCNativePrinter::fntGetName()
{
// the font-name returned will be the full Postscript font name. Handing it
// back to try to create a new font will NOT be a good idea, since it has
// Bold and Italic/Oblique info muddled up in it.
    return font->getName();
}

FXuint FXDCNativePrinter::fntGetSize()
{
// NOTE that this returns the size in decipoints not points.
    return (FXuint)(fontScaleBack * (FXfloat)font->getSize());
}

// return font size (in points) as a double not an integer, so that
// fractional point sizes can be handled better.

double FXDCNativePrinter::fntDoubleSize()
{
// NOTE that this returns the size in decipoints not points.
    return (double)(fontScaleBack * (FXfloat)font->getSize());
}

FXuint FXDCNativePrinter::fntGetWeight()
{
    return font->getWeight();
}

FXuint FXDCNativePrinter::fntGetSlant()
{
    return font->getSlant();
}

FXuint FXDCNativePrinter::fntGetEncoding()
{
    return font->getEncoding();
}

FXuint FXDCNativePrinter::fntGetSetWidth()
{
    return font->getSetWidth();
}

FXuint FXDCNativePrinter::fntGetHints()
{
    return font->getHints();
}

void FXDCNativePrinter::fntGetFontDesc(FXFontDesc &fontdesc) const
{
    font->getFontDesc(fontdesc);
}

void FXDCNativePrinter::fntSetFontDesc(const FXFontDesc &fontdesc)
{
    font->setFontDesc(fontdesc);
}

FXbool FXDCNativePrinter::fntIsFontMono() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return postscriptFont->isFontMono();
#endif
    return font->isFontMono();
}

FXbool FXDCNativePrinter::fntHasChar(FXint ch) const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return postscriptFont->hasChar(ch);
#endif
    return font->hasChar(ch);
}

FXint FXDCNativePrinter::fntGetMinChar() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return postscriptFont->getMinChar();
#endif
    return (FXint)font->getMinChar();
}

FXint FXDCNativePrinter::fntGetMaxChar() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return postscriptFont->getMaxChar();
#endif
    return (FXint)font->getMaxChar();
}

//
// There is a big ugly issue about fonts and measurements here. For Windows
// fonts will have been created internally at some huge point size based
// on the actual resolution of the printer. The factor scalex includes
// allowance for that and so enough precision is kept.
// For Postscript generation the font thinks (at an internal level) that
// it is the point size you actually want it to appear at. The effect is
// that character heights and widths are often quite small values (eg
// for a 10pt pont they are comparable with 10. Returning measurements as
// integers in such a case would give severe truncation effects.
// To work around this I arrange that the FXPostScriptFont class returns
// font measurements scaled by 1000. I have to undo this here. The
// multiplication by PSscale is to do that.
//

// For Postscript generation (and on X) the bearings that I return will be
// the maximum values across the font.

FXint FXDCNativePrinter::fntLeftBearing(FXchar ch) const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (FXint)(PSscale * postscriptFont->leftBearing(ch) / scalex);
#endif
    return (FXint)(PSscale * font->leftBearing(ch) / scalex);
}

double FXDCNativePrinter::fntDoubleLeftBearing(FXchar ch) const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (double)(PSscale * postscriptFont->leftBearing(ch) / scalex);
#endif
    return (double)(PSscale * font->leftBearing(ch) / scalex);
}

FXint FXDCNativePrinter::fntRightBearing(FXchar ch) const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (FXint)(PSscale * postscriptFont->rightBearing(ch) / scalex);
#endif
    return (FXint)(PSscale * font->rightBearing(ch) / scalex);
}

double FXDCNativePrinter::fntDoubleRightBearing(FXchar ch) const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (double)(PSscale * postscriptFont->rightBearing(ch) / scalex);
#endif
    return (double)(PSscale * font->rightBearing(ch) / scalex);
}

//
// If one has left the UnitsInch at its default of 72 then
// measurements are only precise to 1pt. This is generally not good
// enough when laying out a line. To get better accuracy you can either
// reset your units to say 1/3600in or use floating point values here.
//

FXint FXDCNativePrinter::fntGetFontWidth() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (FXint)(PSscale * postscriptFont->getFontWidth() / scalex);
#endif
    return (FXint)(PSscale * font->getFontWidth() / scalex);
}

double FXDCNativePrinter::fntDoubleFontWidth() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (double)(PSscale * postscriptFont->getFontWidth() / scalex);
#endif
    return (double)(PSscale * font->getFontWidth() / scalex);
}

FXint FXDCNativePrinter::fntGetFontHeight() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (FXint)(PSscale * postscriptFont->getFontHeight() / scaley);
#endif
    return (FXint)(PSscale * font->getFontHeight() / scaley);
}

double FXDCNativePrinter::fntDoubleFontHeight() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (double)(PSscale * postscriptFont->getFontHeight() / scaley);
#endif
    return (double)(PSscale * font->getFontHeight() / scaley);
}

FXint FXDCNativePrinter::fntGetFontAscent() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (FXint)(PSscale * postscriptFont->getFontAscent() / scaley);
#endif
    return (FXint)(PSscale * font->getFontAscent() / scaley);
}

double FXDCNativePrinter::fntDoubleFontAscent() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (double)(PSscale * postscriptFont->getFontAscent() / scaley);
#endif
    return (double)(PSscale * font->getFontAscent() / scaley);
}

FXint FXDCNativePrinter::fntGetFontDescent() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (FXint)(PSscale * postscriptFont->getFontDescent() / scaley);
#endif
    return (FXint)(PSscale * font->getFontDescent() / scaley);
}

double FXDCNativePrinter::fntDoubleFontDescent() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (double)(PSscale * postscriptFont->getFontDescent() / scaley);
#endif
    return (double)(PSscale * font->getFontDescent() / scaley);
}

FXint FXDCNativePrinter::fntGetFontLeading() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (FXint)(PSscale * postscriptFont->getFontLeading() / scaley);
#endif
    return (FXint)(PSscale * font->getFontLeading() / scaley);
}

double FXDCNativePrinter::fntDoubleFontLeading() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (double)(PSscale * postscriptFont->getFontLeading() / scaley);
#endif
    return (FXint)(PSscale * font->getFontLeading() / scaley);
}

FXint FXDCNativePrinter::fntGetFontSpacing() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (FXint)(PSscale * postscriptFont->getFontSpacing() / scaley);
#endif
    return (FXint)(PSscale * font->getFontSpacing() / scaley);
}

double FXDCNativePrinter::fntDoubleFontSpacing() const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (double)(PSscale * postscriptFont->getFontSpacing() / scaley);
#endif
    return (double)(PSscale * font->getFontSpacing() / scaley);
}

FXint FXDCNativePrinter::fntGetTextWidth(const FXchar *text, FXuint n) const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (FXint)(PSscale * postscriptFont->getTextWidth(text, n) / scalex);
#endif
    return (FXint)(PSscale * font->getTextWidth(text, n) / scalex);
}

double FXDCNativePrinter::fntDoubleTextWidth(const FXchar *text, FXuint n) const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (double)(PSscale * postscriptFont->getTextWidth(text, n) / scalex);
#endif
    return (double)(PSscale * font->getTextWidth(text, n) / scalex);
}

FXint FXDCNativePrinter::fntGetTextHeight(const FXchar *text, FXuint n) const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (FXint)(PSscale * postscriptFont->getTextHeight(text, n) / scaley);
#endif
    return (FXint)(PSscale * font->getTextHeight(text, n) / scaley);
}

double FXDCNativePrinter::fntDoubleTextHeight(const FXchar *text, FXuint n) const
{
#ifdef FONT_NOT_VIRTUAL
    if (dctype==TYPE_PS) return (double)(PSscale * postscriptFont->getTextHeight(text, n) / scaley);
#endif
    return (double)(PSscale * font->getTextHeight(text, n) / scaley);
}

FXint FXDCNativePrinter::getPageWidth(void)
{
    return (FXint)(pagewidth / scalex);
}

double FXDCNativePrinter::doublePageWidth(void)
{
    return (double)(pagewidth / scalex);
}

FXint FXDCNativePrinter::getPageHeight(void)
{
    return (FXint)(pageheight / scaley);
}

double FXDCNativePrinter::doublePageHeight(void)
{
    return (double)(pageheight / scaley);
}

#endif /* HAVE_LIBFOX */

// end of FXDCNativePrinter.cpp
