//========================================================================
//
// AOutputDev.h
//
// adapted from XOutputDev.h - Copyright 1996 Derek B. Noonburg
//
// changes are copyright 1999 Emmanuel Lesueur
//
//========================================================================

#ifndef AOUTPUTDEV_H
#define AOUTPUTDEV_H

#ifdef __GNUC__
#pragma interface
#endif

#include <stddef.h>
#include <math.h>
#if defined(__SASC) && defined(_M68000)
#   include <m68881.h>
#endif

#include "config.h"
#include "OutputDev.h"
#include "AGfx.h"

class GString;
class GfxColor;
class GfxFont;
class GfxSubpath;
class TextPage;
struct RGBColor;

//------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------

static const int maxRGBCube=8;      // max size of RGB color cube

static const int numTmpPoints=256;  // number of XPoints in temporary array
static const int numTmpSubpaths=16; // number of elements in temporary arrays
				    //   for fill/clip
static const int penColor=0;
static const int paperColor=1;

static const int WindingRule=0;
static const int EvenOddRule=1;

//------------------------------------------------------------------------
// Misc types
//------------------------------------------------------------------------

enum CapStyle {
    CapButt, CapRound, CapProjecting
};

enum JoinStyle {
    JoinMiter, JoinRound, JoinBevel
};

struct BoundingRect {
  short xMin, xMax;             // min/max x values
  short yMin, yMax;             // min/max y values
};

struct RGBColor {
  double r, g, b;
};

//------------------------------------------------------------------------
// Parameters
//------------------------------------------------------------------------

// Install a private colormap.
//extern GBool installCmap;

// Size of RGB color cube.
//extern int rgbCubeSize;

//------------------------------------------------------------------------
// ColorTable
//------------------------------------------------------------------------

class ColorTable {
public:
  ColorTable() : num(0),entries(NULL), maxEntries(0) {}
  ~ColorTable() { gfree(entries); }
  Gulong find(Gulong) const;
  Gulong find_rgb(Gulong n) const;
  Gulong add(Gulong);
  void clear() { num = 0; }
private:
  ColorTable(const ColorTable&);
  ColorTable& operator = (const ColorTable&);
  Gulong num;
  struct entry {
      Gulong n;
      Gulong val;
  };
  entry* entries;
  Gulong maxEntries;
};

//------------------------------------------------------------------------
// AOutputFont
//------------------------------------------------------------------------

class AOutputFont {
public:

  // Constructor.
  AOutputFont(AGfx&, GfxFont *gfxFont, double m11, double m12,
	      double m21, double m22);

  // Destructor.
  ~AOutputFont();

  // Does this font match the ID, size, and angle?
  GBool matches(Ref id1, double m11, double m12, double m21, double m22)
    { return id.num == id1.num && id.gen == id1.gen &&
	fabs(mat11-m11) + fabs(mat12-m12) + fabs(mat21-m21) +
	fabs(mat22-m22) < 0.01; }

  // Get font.
  int getTextFont() { return xFont; }

  // Get character mapping.
  Gushort mapChar(Guchar c) { return map[c]; }

  // Reverse map a character.
  Guchar revMapChar(Gushort c) { return revMap[c]; }

  // Does this font use hex char codes?
  GBool isHex() { return hex; }

  static void reset() { xFontCount=0; }

private:
  AGfx& gfx;
  Ref id;
  double mat11, mat12, mat21, mat22;
  int xFont;
  static int xFontCount;
  GBool hex;                    // subsetted font with hex char codes
  Gushort map[256];
  Guchar revMap[256];
};

//------------------------------------------------------------------------
// AOutputFontCache
//------------------------------------------------------------------------

class AOutputFontCache {
public:

  // Constructor.
  AOutputFontCache(AGfx&);

  // Destructor.
  ~AOutputFontCache();

  // Get a font.  This creates a new font if necessary.
  AOutputFont *getFont(GfxFont *gfxFont, double m11, double m12,
		       double m21, double m22);

private:

  AOutputFont *                 // fonts in reverse-LRU order
    fonts[fontCacheSize];
  int numFonts;                 // number of valid entries
  AGfx& gfx;
};

//------------------------------------------------------------------------
// AOutputDev
//------------------------------------------------------------------------

class AOutputDev: public OutputDev {
public:

  // Constructor.
  AOutputDev(AGfx& g1, Guint depth1, ColorMap* colormap1);

  // Destructor.
  virtual ~AOutputDev();

  // Check if file was successfully created.
  virtual GBool isOk() { return gTrue; }

  //---- get info about output device

  // Does this device use upside-down coordinates?
  // (Upside-down means (0,0) is the top left corner of the page.)
  virtual GBool upsideDown() { return gTrue; }

  // Does this device use drawChar() or drawString()?
  virtual GBool useDrawChar() { return gTrue; }

  //----- initialization and control

  // Start a page.
  virtual void startPage(int pageNum, GfxState *state);

  // End a page.
  virtual void endPage();

  //----- link borders
  virtual void drawLinkBorder(double x1, double y1, double x2, double y2,
			      double w);

  //----- save/restore graphics state
  virtual void saveState(GfxState *state);
  virtual void restoreState(GfxState *state);

  //----- update graphics state
  virtual void updateAll(GfxState *state);
  virtual void updateCTM(GfxState *state, double m11, double m12,
			 double m21, double m22, double m31, double m32);
  virtual void updateLineDash(GfxState *state);
  virtual void updateFlatness(GfxState *state);
  virtual void updateLineJoin(GfxState *state);
  virtual void updateLineCap(GfxState *state);
  virtual void updateMiterLimit(GfxState *state);
  virtual void updateLineWidth(GfxState *state);
  virtual void updateFillColor(GfxState *state);
  virtual void updateStrokeColor(GfxState *state);

  //----- update text state
  virtual void updateFont(GfxState *state);

  //----- path painting
  virtual void stroke(GfxState *state);
  virtual void fill(GfxState *state);
  virtual void eoFill(GfxState *state);

  //----- path clipping
  virtual void clip(GfxState *state);
  virtual void eoClip(GfxState *state);

  //----- text drawing
  virtual void beginString(GfxState *state, GString *s);
  virtual void endString(GfxState *state);
  virtual void drawChar(GfxState *state, double x, double y,
			double dx, double dy, Guchar c);
  virtual void drawChar16(GfxState *state, double x, double y,
			  double dx, double dy, int c);

  //----- image drawing
  virtual void drawImageMask(GfxState *state, Stream *str,
			     int width, int height, GBool invert,
			     GBool inlineImg);
  virtual void drawImage(GfxState *state, Stream *str, int width,
			 int height, GfxImageColorMap *colorMap,
			 GBool inlineImg);

  //----- special access

  // Find a string.  If <top> is true, starts looking at <xMin>,<yMin>;
  // otherwise starts looking at top of page.  If <bottom> is true,
  // stops looking at <xMax>,<yMax>; otherwise stops looking at bottom
  // of page.  If found, sets the text bounding rectange and returns
  // true; otherwise returns false.
  GBool findText(char *s, GBool top, GBool bottom,
		 int *xMin, int *yMin, int *xMax, int *yMax);

  // Get the text which is inside the specified rectangle.
  GString *getText(int xMin, int yMin, int xMax, int yMax);

private:

  AGfx& gfx;
  ColorMap *colormap;
  Guint depth;                  // pixmap depth
  int flatness;                 // line flatness
  double lineWidth;
  CapStyle capStyle;
  JoinStyle joinStyle;
  Gulong strokeColor;
  Gulong fillColor;
  Gulong curColor;
  Gulong linkColor;
  ColorTable colorTable;
  Gulong colorMask;
  GBool trueColor;              // set if using a TrueColor visual
  int rMul, gMul, bMul;         // RGB multipliers (for TrueColor)
  int rShift, gShift, bShift;   // RGB shifts (for TrueColor)
  GfxFont *gfxFont;             // current PDF font
  AOutputFont *font;            // current font
  AOutputFontCache *fontCache;  // font cache
  TextPage *text;               // text from the current page
  PArea<double> clipRegion;
  array<PArea<double> > clipStack;

  void updateLineAttrs(GfxState *state, GBool updateDash);
  void doFill(GfxState *state, int rule);
  void doClip(GfxState *state, int rule);
  void installClip();
  PArea<double> convertPath(GfxState *state);
  Polygon<double> convertSubpath(GfxState *state, GfxSubpath *subpath);
  void doCurve(Polygon<double>&,
	       double x0, double y0, double x1, double y1,
	       double x2, double y2, double x3, double y3);
  Gulong findColor(GfxColor *color);
  Gulong findColor(RGBColor *x, RGBColor *err);
};

#endif
