//========================================================================
//
// Splash.h
//
//========================================================================

//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
// Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com>
// Copyright (C) 2007, 2011, 2018, 2019 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2010-2013, 2015 Thomas Freitag <Thomas.Freitag@alfa.de>
// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
// Copyright (C) 2012, 2017 Adrian Johnson <ajohnson@redneon.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================

#ifndef SPLASH_H
#define SPLASH_H

#include <cstddef>
#include "SplashTypes.h"
#include "SplashClip.h"
#include "SplashPattern.h"

class SplashBitmap;
struct SplashGlyphBitmap;
class SplashState;
class SplashScreen;
class SplashPath;
class SplashXPath;
class SplashFont;
struct SplashPipe;

//------------------------------------------------------------------------

// Retrieves the next line of pixels in an image mask.  Normally,
// fills in *<line> and returns true.  If the image stream is
// exhausted, returns false.
typedef bool (*SplashImageMaskSource)(void *data, SplashColorPtr pixel);

// Retrieves the next line of pixels in an image.  Normally, fills in
// *<line> and returns true.  If the image stream is exhausted,
// returns false.
typedef bool (*SplashImageSource)(void *data, SplashColorPtr colorLine,
				   unsigned char *alphaLine);

// Use ICCColorSpace to transform a bitmap
typedef void (*SplashICCTransform)(void *data, SplashBitmap *bitmap);

//------------------------------------------------------------------------

enum SplashPipeResultColorCtrl {
  splashPipeResultColorNoAlphaBlendCMYK,
  splashPipeResultColorNoAlphaBlendDeviceN,
  splashPipeResultColorNoAlphaBlendRGB,
  splashPipeResultColorNoAlphaBlendMono,
  splashPipeResultColorAlphaNoBlendMono,
  splashPipeResultColorAlphaNoBlendRGB,
  splashPipeResultColorAlphaNoBlendCMYK,
  splashPipeResultColorAlphaNoBlendDeviceN,
  splashPipeResultColorAlphaBlendMono,
  splashPipeResultColorAlphaBlendRGB,
  splashPipeResultColorAlphaBlendCMYK,
  splashPipeResultColorAlphaBlendDeviceN
};

//------------------------------------------------------------------------
// Splash
//------------------------------------------------------------------------

class Splash {
public:

  // Create a new rasterizer object.
  Splash(SplashBitmap *bitmapA, bool vectorAntialiasA,
	 SplashScreenParams *screenParams = nullptr);
  Splash(SplashBitmap *bitmapA, bool vectorAntialiasA,
	 SplashScreen *screenA);

  ~Splash();

  Splash(const Splash &) = delete;
  Splash& operator=(const Splash &) = delete;

  //----- state read

  SplashCoord *getMatrix();
  SplashPattern *getStrokePattern();
  SplashPattern *getFillPattern();
  SplashScreen *getScreen();
  SplashBlendFunc getBlendFunc();
  SplashCoord getStrokeAlpha();
  SplashCoord getFillAlpha();
  SplashCoord getLineWidth();
  int getLineCap();
  int getLineJoin();
  SplashCoord getMiterLimit();
  SplashCoord getFlatness();
  SplashCoord *getLineDash();
  int getLineDashLength();
  SplashCoord getLineDashPhase();
  bool getStrokeAdjust();
  SplashClip *getClip();
  SplashBitmap *getSoftMask();
  bool getInNonIsolatedGroup();

  //----- state write

  void setMatrix(SplashCoord *matrix);
  void setStrokePattern(SplashPattern *strokePattern);
  void setFillPattern(SplashPattern *fillPattern);
  void setScreen(SplashScreen *screen);
  void setBlendFunc(SplashBlendFunc func);
  void setStrokeAlpha(SplashCoord alpha);
  void setFillAlpha(SplashCoord alpha);
  void setPatternAlpha(SplashCoord strokeAlpha, SplashCoord fillAlpha);
  void clearPatternAlpha();
  void setFillOverprint(bool fop);
  void setStrokeOverprint(bool sop);
  void setOverprintMode(int opm);
  void setLineWidth(SplashCoord lineWidth);
  void setLineCap(int lineCap);
  void setLineJoin(int lineJoin);
  void setMiterLimit(SplashCoord miterLimit);
  void setFlatness(SplashCoord flatness);
  // the <lineDash> array will be copied
  void setLineDash(SplashCoord *lineDash, int lineDashLength,
		   SplashCoord lineDashPhase);
  void setStrokeAdjust(bool strokeAdjust);
  // NB: uses transformed coordinates.
  void clipResetToRect(SplashCoord x0, SplashCoord y0,
		       SplashCoord x1, SplashCoord y1);
  // NB: uses transformed coordinates.
  SplashError clipToRect(SplashCoord x0, SplashCoord y0,
			 SplashCoord x1, SplashCoord y1);
  // NB: uses untransformed coordinates.
  SplashError clipToPath(SplashPath *path, bool eo);
  void setSoftMask(SplashBitmap *softMask);
  void setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
			     int alpha0XA, int alpha0YA);
  void setTransfer(unsigned char *red, unsigned char *green, unsigned char *blue, unsigned char *gray);
  void setOverprintMask(unsigned int overprintMask, bool additive);

  //----- state save/restore

  void saveState();
  SplashError restoreState();

  //----- drawing operations

  // Fill the bitmap with <color>.  This is not subject to clipping.
  void clear(SplashColorPtr color, unsigned char alpha = 0x00);

  // Stroke a path using the current stroke pattern.
  SplashError stroke(SplashPath *path);

  // Fill a path using the current fill pattern.
  SplashError fill(SplashPath *path, bool eo);

  // Fill a path, XORing with the current fill pattern.
  SplashError xorFill(SplashPath *path, bool eo);

  // Draw a character, using the current fill pattern.
  SplashError fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font);

  // Draw a glyph, using the current fill pattern.  This function does
  // not free any data, i.e., it ignores glyph->freeData.
  void fillGlyph(SplashCoord x, SplashCoord y,
			SplashGlyphBitmap *glyph);

  // Draws an image mask using the fill color.  This will read <h>
  // lines of <w> pixels from <src>, starting with the top line.  "1"
  // pixels will be drawn with the current fill color; "0" pixels are
  // transparent.  The matrix:
  //    [ mat[0] mat[1] 0 ]
  //    [ mat[2] mat[3] 0 ]
  //    [ mat[4] mat[5] 1 ]
  // maps a unit square to the desired destination for the image, in
  // PostScript style:
  //    [x' y' 1] = [x y 1] * mat
  // Note that the Splash y axis points downward, and the image source
  // is assumed to produce pixels in raster order, starting from the
  // top line.
  SplashError fillImageMask(SplashImageMaskSource src, void *srcData,
			    int w, int h, SplashCoord *mat,
			    bool glyphMode);

  // Draw an image.  This will read <h> lines of <w> pixels from
  // <src>, starting with the top line.  These pixels are assumed to
  // be in the source mode, <srcMode>.  If <srcAlpha> is true, the
  // alpha values returned by <src> are used; otherwise they are
  // ignored.  The following combinations of source and target modes
  // are supported:
  //    source       target
  //    ------       ------
  //    Mono1        Mono1
  //    Mono8        Mono1   -- with dithering
  //    Mono8        Mono8
  //    RGB8         RGB8
  //    BGR8         BGR8
  //    CMYK8        CMYK8
  // The matrix behaves as for fillImageMask.
  SplashError drawImage(SplashImageSource src, SplashICCTransform tf, void *srcData,
			SplashColorMode srcMode, bool srcAlpha,
			int w, int h, SplashCoord *mat, bool interpolate,
			bool tilingPattern = false);

  // Composite a rectangular region from <src> onto this Splash
  // object.
  SplashError composite(SplashBitmap *src, int xSrc, int ySrc,
			int xDest, int yDest, int w, int h,
			bool noClip, bool nonIsolated,
			bool knockout = false, SplashCoord knockoutOpacity = 1.0);

  // Composite this Splash object onto a background color.  The
  // background alpha is assumed to be 1.
  void compositeBackground(SplashColorConstPtr color);

  // Copy a rectangular region from <src> onto the bitmap belonging to
  // this Splash object.  The destination alpha values are all set to
  // zero.
  SplashError blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
			      int xDest, int yDest, int w, int h);
  void blitImage(SplashBitmap *src, bool srcAlpha, int xDest, int yDest);

  //----- misc

  // Construct a path for a stroke, given the path to be stroked and
  // the line width <w>.  All other stroke parameters are taken from
  // the current state.  If <flatten> is true, this function will
  // first flatten the path and handle the linedash.
  SplashPath *makeStrokePath(SplashPath *path, SplashCoord w,
			     bool flatten = true);

  // Return the associated bitmap.
  SplashBitmap *getBitmap() { return bitmap; }

  // Set the minimum line width.
  void setMinLineWidth(SplashCoord w) { minLineWidth = w; }

  // Setter/Getter for thin line mode
  void setThinLineMode(SplashThinLineMode thinLineModeA) { thinLineMode = thinLineModeA; }
  SplashThinLineMode getThinLineMode() { return thinLineMode; }

  // Get clipping status for the last drawing operation subject to
  // clipping.
  SplashClipResult getClipRes() { return opClipRes; }

  // Toggle debug mode on or off.
  void setDebugMode(bool debugModeA) { debugMode = debugModeA; }

#if 1 //~tmp: turn off anti-aliasing temporarily
  void setInShading(bool sh) { inShading = sh; }
  bool getVectorAntialias() { return vectorAntialias; }
  void setVectorAntialias(bool vaa) { vectorAntialias = vaa; }
#endif

  // Do shaded fills with dynamic patterns
  SplashError shadedFill(SplashPath *path, bool hasBBox,
                         SplashPattern *pattern);
  // Draw a gouraud triangle shading.
  bool gouraudTriangleShadedFill(SplashGouraudColor *shading);

private:

  void pipeInit(SplashPipe *pipe, int x, int y,
		SplashPattern *pattern, SplashColorPtr cSrc,
		unsigned char aInput, bool usesShape,
		bool nonIsolatedGroup,
		bool knockout = false, unsigned char knockoutOpacity = 255);
  void pipeRun(SplashPipe *pipe);
  void pipeRunSimpleMono1(SplashPipe *pipe);
  void pipeRunSimpleMono8(SplashPipe *pipe);
  void pipeRunSimpleRGB8(SplashPipe *pipe);
  void pipeRunSimpleXBGR8(SplashPipe *pipe);
  void pipeRunSimpleBGR8(SplashPipe *pipe);
  void pipeRunSimpleCMYK8(SplashPipe *pipe);
  void pipeRunSimpleDeviceN8(SplashPipe *pipe);
  void pipeRunAAMono1(SplashPipe *pipe);
  void pipeRunAAMono8(SplashPipe *pipe);
  void pipeRunAARGB8(SplashPipe *pipe);
  void pipeRunAAXBGR8(SplashPipe *pipe);
  void pipeRunAABGR8(SplashPipe *pipe);
  void pipeRunAACMYK8(SplashPipe *pipe);
  void pipeRunAADeviceN8(SplashPipe *pipe);
  void pipeSetXY(SplashPipe *pipe, int x, int y);
  void pipeIncX(SplashPipe *pipe);
  void drawPixel(SplashPipe *pipe, int x, int y, bool noClip);
  void drawAAPixelInit();
  void drawAAPixel(SplashPipe *pipe, int x, int y);
  void drawSpan(SplashPipe *pipe, int x0, int x1, int y, bool noClip);
  void drawAALine(SplashPipe *pipe, int x0, int x1, int y, bool adjustLine = false, unsigned char lineOpacity = 0);
  void transform(const SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
		 SplashCoord *xo, SplashCoord *yo);
  void strokeNarrow(SplashPath *path);
  void strokeWide(SplashPath *path, SplashCoord w);
  SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix,
			  SplashCoord flatness);
  void flattenCurve(SplashCoord x0, SplashCoord y0,
		    SplashCoord x1, SplashCoord y1,
		    SplashCoord x2, SplashCoord y2,
		    SplashCoord x3, SplashCoord y3,
		    SplashCoord *matrix, SplashCoord flatness2,
		    SplashPath *fPath);
  SplashPath *makeDashedPath(SplashPath *xPath);
  void getBBoxFP(SplashPath *path, SplashCoord *xMinA, SplashCoord *yMinA, SplashCoord *xMaxA, SplashCoord *yMaxA);
  SplashError fillWithPattern(SplashPath *path, bool eo,
			      SplashPattern *pattern, SplashCoord alpha);
  bool pathAllOutside(SplashPath *path);
  void fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, bool noclip);
  void arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
			      int srcWidth, int srcHeight,
			      SplashCoord *mat, bool glyphMode);
  SplashBitmap *scaleMask(SplashImageMaskSource src, void *srcData,
			  int srcWidth, int srcHeight,
			  int scaledWidth, int scaledHeight);
  void scaleMaskYdXd(SplashImageMaskSource src, void *srcData,
		     int srcWidth, int srcHeight,
		     int scaledWidth, int scaledHeight,
		     SplashBitmap *dest);
  void scaleMaskYdXu(SplashImageMaskSource src, void *srcData,
		     int srcWidth, int srcHeight,
		     int scaledWidth, int scaledHeight,
		     SplashBitmap *dest);
  void scaleMaskYuXd(SplashImageMaskSource src, void *srcData,
		     int srcWidth, int srcHeight,
		     int scaledWidth, int scaledHeight,
		     SplashBitmap *dest);
  void scaleMaskYuXu(SplashImageMaskSource src, void *srcData,
		     int srcWidth, int srcHeight,
		     int scaledWidth, int scaledHeight,
		     SplashBitmap *dest);
  void blitMask(SplashBitmap *src, int xDest, int yDest,
		SplashClipResult clipRes);
  SplashError arbitraryTransformImage(SplashImageSource src, SplashICCTransform tf, void *srcData,
			       SplashColorMode srcMode, int nComps,
			       bool srcAlpha,
			       int srcWidth, int srcHeight,
                               SplashCoord *mat, bool interpolate, bool tilingPattern = false);
  SplashBitmap *scaleImage(SplashImageSource src, void *srcData,
			   SplashColorMode srcMode, int nComps,
			   bool srcAlpha, int srcWidth, int srcHeight,
			   int scaledWidth, int scaledHeight, bool interpolate, bool tilingPattern = false);
  void scaleImageYdXd(SplashImageSource src, void *srcData,
		      SplashColorMode srcMode, int nComps,
		      bool srcAlpha, int srcWidth, int srcHeight,
		      int scaledWidth, int scaledHeight,
		      SplashBitmap *dest);
  void scaleImageYdXu(SplashImageSource src, void *srcData,
		      SplashColorMode srcMode, int nComps,
		      bool srcAlpha, int srcWidth, int srcHeight,
		      int scaledWidth, int scaledHeight,
		      SplashBitmap *dest);
  void scaleImageYuXd(SplashImageSource src, void *srcData,
		      SplashColorMode srcMode, int nComps,
		      bool srcAlpha, int srcWidth, int srcHeight,
		      int scaledWidth, int scaledHeight,
		      SplashBitmap *dest);
  void scaleImageYuXu(SplashImageSource src, void *srcData,
		      SplashColorMode srcMode, int nComps,
		      bool srcAlpha, int srcWidth, int srcHeight,
		      int scaledWidth, int scaledHeight,
		      SplashBitmap *dest);
  void scaleImageYuXuBilinear(SplashImageSource src, void *srcData,
		      SplashColorMode srcMode, int nComps,
		      bool srcAlpha, int srcWidth, int srcHeight,
		      int scaledWidth, int scaledHeight,
		      SplashBitmap *dest);
  void vertFlipImage(SplashBitmap *img, int width, int height,
		     int nComps);
  void blitImage(SplashBitmap *src, bool srcAlpha, int xDest, int yDest,
		 SplashClipResult clipRes);
  void blitImageClipped(SplashBitmap *src, bool srcAlpha,
			int xSrc, int ySrc, int xDest, int yDest,
			int w, int h);
  void dumpPath(SplashPath *path);
  void dumpXPath(SplashXPath *path);

  static SplashPipeResultColorCtrl pipeResultColorNoAlphaBlend[];
  static SplashPipeResultColorCtrl pipeResultColorAlphaNoBlend[];
  static SplashPipeResultColorCtrl pipeResultColorAlphaBlend[];
  static int pipeNonIsoGroupCorrection[];

  SplashBitmap *bitmap;
  SplashState *state;
  SplashBitmap *aaBuf;
  int aaBufY;
  SplashBitmap *alpha0Bitmap;	// for non-isolated groups, this is the
				//   bitmap containing the alpha0 values
  int alpha0X, alpha0Y;		// offset within alpha0Bitmap
  SplashCoord aaGamma[splashAASize * splashAASize + 1];
  SplashCoord minLineWidth;
  SplashThinLineMode thinLineMode;
  SplashClipResult opClipRes;
  bool vectorAntialias;
  bool inShading;
  bool debugMode;
};

#endif
