/***********************************************************************
*
* Copyright (c) 2012-2016 Barbara Geller
* Copyright (c) 2012-2016 Ansel Sermersheim
* Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
* Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
*
* This file is part of CopperSpice.
*
* CopperSpice is free software: you can redistribute it and/or 
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation.
*
* CopperSpice is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with CopperSpice.  If not, see 
* <http://www.gnu.org/licenses/>.
*
***********************************************************************/

#ifndef QPAINTENGINE_H
#define QPAINTENGINE_H

#include <QtCore/qnamespace.h>
#include <QtCore/qscopedpointer.h>
#include <QtGui/qpainter.h>

QT_BEGIN_NAMESPACE

class QFontEngine;
class QLineF;
class QPaintDevice;
class QPaintEnginePrivate;
class QPainterPath;
class QPointF;
class QPolygonF;
class QRectF;
struct QGlyphLayout;
class QTextItemInt;
class QPaintEngineState;

class Q_GUI_EXPORT QTextItem
{

 public:
   enum RenderFlag {
      RightToLeft = 0x1,
      Overline = 0x10,
      Underline = 0x20,
      StrikeOut = 0x40,

      Dummy = 0xffffffff
   };
   using RenderFlags = QFlags<RenderFlag>;
   qreal descent() const;
   qreal ascent() const;
   qreal width() const;

   RenderFlags renderFlags() const;
   QString text() const;
   QFont font() const;
};
Q_DECLARE_TYPEINFO(QTextItem, Q_PRIMITIVE_TYPE);


class Q_GUI_EXPORT QPaintEngine
{
   Q_DECLARE_PRIVATE(QPaintEngine)

 public:
   enum PaintEngineFeature {
      PrimitiveTransform          = 0x00000001, // Can transform primitives brushes
      PatternTransform            = 0x00000002, // Can transform pattern brushes
      PixmapTransform             = 0x00000004, // Can transform pixmaps
      PatternBrush                = 0x00000008, // Can fill with pixmaps and standard patterns
      LinearGradientFill          = 0x00000010, // Can fill gradient areas
      RadialGradientFill          = 0x00000020, // Can render radial gradients
      ConicalGradientFill         = 0x00000040, // Can render conical gradients
      AlphaBlend                  = 0x00000080, // Can do source over alpha blend
      PorterDuff                  = 0x00000100, // Can do general porter duff compositions
      PainterPaths                = 0x00000200, // Can fill, outline and clip paths
      Antialiasing                = 0x00000400, // Can antialias lines
      BrushStroke                 = 0x00000800, // Can render brush based pens
      ConstantOpacity             = 0x00001000, // Can render at constant opacity
      MaskedBrush                 = 0x00002000, // Can fill with textures that has an alpha channel or mask
      PerspectiveTransform        = 0x00004000, // Can do perspective transformations
      BlendModes                  = 0x00008000, // Can do extended Porter&Duff composition
      ObjectBoundingModeGradients = 0x00010000, // Can do object bounding mode gradients
      RasterOpModes               = 0x00020000, // Can do logical raster operations
      PaintOutsidePaintEvent      = 0x20000000, // Engine is capable of painting outside paint events
      /*                          0x10000000, // Used for emulating
                                  QGradient::StretchToDevice,
                                  defined in qpainter.cpp

                                  0x40000000, // Used internally for emulating opaque backgrounds
      */

      AllFeatures               = 0xffffffff  // For convenience
   };
   using PaintEngineFeatures = QFlags<PaintEngineFeature>;

   enum DirtyFlag {
      DirtyPen                = 0x0001,
      DirtyBrush              = 0x0002,
      DirtyBrushOrigin        = 0x0004,
      DirtyFont               = 0x0008,
      DirtyBackground         = 0x0010,
      DirtyBackgroundMode     = 0x0020,
      DirtyTransform          = 0x0040,
      DirtyClipRegion         = 0x0080,
      DirtyClipPath           = 0x0100,
      DirtyHints              = 0x0200,
      DirtyCompositionMode    = 0x0400,
      DirtyClipEnabled        = 0x0800,
      DirtyOpacity            = 0x1000,

      AllDirty                = 0xffff
   };
   using DirtyFlags = QFlags<DirtyFlag>;

   enum PolygonDrawMode {
      OddEvenMode,
      WindingMode,
      ConvexMode,
      PolylineMode
   };

   explicit QPaintEngine(PaintEngineFeatures features = 0);
   virtual ~QPaintEngine();

   bool isActive() const {
      return active;
   }
   void setActive(bool newState) {
      active = newState;
   }

   virtual bool begin(QPaintDevice *pdev) = 0;
   virtual bool end() = 0;

   virtual void updateState(const QPaintEngineState &state) = 0;

   virtual void drawRects(const QRect *rects, int rectCount);
   virtual void drawRects(const QRectF *rects, int rectCount);

   virtual void drawLines(const QLine *lines, int lineCount);
   virtual void drawLines(const QLineF *lines, int lineCount);

   virtual void drawEllipse(const QRectF &r);
   virtual void drawEllipse(const QRect &r);

   virtual void drawPath(const QPainterPath &path);

   virtual void drawPoints(const QPointF *points, int pointCount);
   virtual void drawPoints(const QPoint *points, int pointCount);

   virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode);
   virtual void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode);

   virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) = 0;
   virtual void drawTextItem(const QPointF &p, const QTextItem &textItem);
   virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s);
   virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
                          Qt::ImageConversionFlags flags = Qt::AutoColor);

   void setPaintDevice(QPaintDevice *device);
   QPaintDevice *paintDevice() const;

   void setSystemClip(const QRegion &baseClip);
   QRegion systemClip() const;

   void setSystemRect(const QRect &rect);
   QRect systemRect() const;

#ifdef Q_OS_WIN
   virtual HDC getDC() const;
   virtual void releaseDC(HDC hdc) const;
#endif

   virtual QPoint coordinateOffset() const;

   enum Type {
      X11,
      Windows,
      QuickDraw, CoreGraphics, MacPrinter,
      QWindowSystem,
      PostScript,
      OpenGL,
      Picture,
      SVG,
      Raster,
      Direct3D,
      Pdf,
      OpenVG,
      OpenGL2,
      PaintBuffer,
      Blitter,

      User = 50,    // first user type id
      MaxUser = 100 // last user type id
   };
   virtual Type type() const = 0;

   inline void fix_neg_rect(int *x, int *y, int *w, int *h);

   inline bool testDirty(DirtyFlags df);
   inline void setDirty(DirtyFlags df);
   inline void clearDirty(DirtyFlags df);

   bool hasFeature(PaintEngineFeatures feature) const {
      return (gccaps & feature) != 0;
   }

   QPainter *painter() const;

   void syncState();
   inline bool isExtended() const {
      return extended;
   }

 protected:
   QPaintEngine(QPaintEnginePrivate &data, PaintEngineFeatures devcaps = 0);

   QPaintEngineState *state;
   PaintEngineFeatures gccaps;

   uint active : 1;
   uint selfDestruct : 1;
   uint extended : 1;

   QScopedPointer<QPaintEnginePrivate> d_ptr;

 private:
   void setAutoDestruct(bool autoDestr) {
      selfDestruct = autoDestr;
   }
   bool autoDestruct() const {
      return selfDestruct;
   }
   Q_DISABLE_COPY(QPaintEngine)

   friend class QPainterReplayer;
   friend class QFontEngineBox;
   friend class QFontEngineMac;
   friend class QFontEngineWin;

#ifndef QT_NO_FREETYPE
   friend class QFontEngineFT;
#endif

#ifndef QT_NO_QWS_QPF
   friend class QFontEngineQPF1;
#endif

#ifndef QT_NO_QWS_QPF2
   friend class QFontEngineQPF;
#endif

   friend class QPSPrintEngine;
   friend class QMacPrintEngine;
   friend class QMacPrintEnginePrivate;

#ifdef Q_WS_QWS
   friend class QtopiaPrintEngine;
   friend class QtopiaPrintEnginePrivate;
   friend class QProxyFontEngine;
#endif

#ifdef Q_WS_QPA
   friend class QFontEngineQPA;
#endif

   friend class QPainter;
   friend class QPainterPrivate;
   friend class QWidget;
   friend class QWidgetPrivate;
   friend class QWin32PaintEngine;
   friend class QWin32PaintEnginePrivate;
   friend class QMacCGContext;
   friend class QPreviewPaintEngine;
   friend class QX11GLPixmapData;
};


class Q_GUI_EXPORT QPaintEngineState
{
 public:
   QPaintEngine::DirtyFlags state() const {
      return dirtyFlags;
   }

   QPen pen() const;
   QBrush brush() const;
   QPointF brushOrigin() const;
   QBrush backgroundBrush() const;
   Qt::BGMode backgroundMode() const;
   QFont font() const;
   QMatrix matrix() const;
   QTransform transform() const;

   Qt::ClipOperation clipOperation() const;
   QRegion clipRegion() const;
   QPainterPath clipPath() const;
   bool isClipEnabled() const;

   QPainter::RenderHints renderHints() const;
   QPainter::CompositionMode compositionMode() const;
   qreal opacity() const;

   QPainter *painter() const;

   bool brushNeedsResolving() const;
   bool penNeedsResolving() const;

 protected:
   friend class QPaintEngine;
   friend class QRasterPaintEngine;
   friend class QWidget;
   friend class QPainter;
   friend class QPainterPrivate;
   friend class QMacPrintEnginePrivate;

   QPaintEngine::DirtyFlags dirtyFlags;
};

//
// inline functions
//

inline void QPaintEngine::fix_neg_rect(int *x, int *y, int *w, int *h)
{
   if (*w < 0) {
      *w = -*w;
      *x -= *w - 1;
   }
   if (*h < 0) {
      *h = -*h;
      *y -= *h - 1;
   }
}

inline bool QPaintEngine::testDirty(DirtyFlags df)
{
   Q_ASSERT(state);
   return ((state->dirtyFlags & df) != 0);
}

inline void QPaintEngine::setDirty(DirtyFlags df)
{
   Q_ASSERT(state);
   state->dirtyFlags |= df;
}

inline void QPaintEngine::clearDirty(DirtyFlags df)
{
   Q_ASSERT(state);
   state->dirtyFlags &= ~static_cast<uint>(df);
}

Q_DECLARE_OPERATORS_FOR_FLAGS(QTextItem::RenderFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QPaintEngine::PaintEngineFeatures)
Q_DECLARE_OPERATORS_FOR_FLAGS(QPaintEngine::DirtyFlags)

QT_END_NAMESPACE

#endif // QPAINTENGINE_H
