//------------------------------------------------------------------------------
// emPainter.h
//
// Copyright (C) 2001,2003-2010,2014,2016-2017 Oliver Hamann.
//
// Homepage: http://eaglemode.sourceforge.net/
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License version 3 as published by the
// Free Software Foundation.
//
// This program 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 General Public License version 3 for
// more details.
//
// You should have received a copy of the GNU General Public License version 3
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

#ifndef emPainter_h
#define emPainter_h

#ifndef emFontCache_h
#include <emCore/emFontCache.h>
#endif


//==============================================================================
//================================= emPainter ==================================
//==============================================================================

class emPainter {

public:

        // Class with methods for painting pixel graphics with full
        // anti-aliasing and alpha blending. The anti-aliasing has been driven
        // very far here. Therefore the interface looks like for painting vector
        // graphics. But there is one topic a programmer should know about:
        //
        // "Canvas Color"
        // ==============
        //
        // Every paint method has an argument called canvasColor. For getting
        // best results, this argument has to be set carefully:
        //
        // Quick instructions
        // ------------------
        //
        // Whenever painting something over a uni-colored area, and if that
        // color is known, it should be given as the argument canvasColor.
        // Otherwise a non-opaque color should be given (e.g. 0).
        //
        // When wondering whether an area is uni-colored or not, you should not
        // care about rasterization by pixels. Just imagine all paint operations
        // would go to infinite pixel resolution.
        //
        // More details
        // ------------
        //
        // With a non-opaque canvas color, the classic formula for blending is
        // used:
        //
        //   targetNew = targetOld * (100% - alpha) + source * alpha
        //
        // Clearly: For anti-aliasing, the intersection of the area of the
        // painted object and the area of each pixel is calculated. This results
        // in an additional alpha value for each individual pixel. This
        // anti-alias-alpha-value is simply multiplied with the general alpha
        // value of the operation.
        //
        // Now, the problem is when painting two objects which are cutting the
        // same pixel. The resulting pixel value will not be correct. Here is an
        // example: Lets paint two white rectangles on black background. The
        // rectangles are not overlapping, but they have a common edge, which
        // runs through the center of a pixel (each rectangle gets 50% of the
        // pixel). When painting the first rectangle, the formula says for that
        // pixel: black * (100% - 50%) + white * 50%, which results "50% white".
        // That is correct. But when painting the second rectangle, we have:
        // 50% white * (100% - 50%) + white * 50%, which results 75% white. But
        // it should be 100%!
        //
        // With an opaque canvas color, the formula for blending is:
        //
        //   targetNew = targetOld + (source - canvasColor) * alpha
        //
        // This is faster, because it allows some pretty optimizations. But the
        // main advantage is that this formula does not make the error described
        // above. In our example, the first rectangle would result equal for the
        // considered pixel: black + (white - black) * 50% = 50% white. And when
        // painting the second rectangle, the formula says: 50% white + (white -
        // black) * 50% = 100% white, which is correct now. The formula is even
        // correct when working with other colors than just black and white,
        // when having alpha blending by the source, and when many painted
        // objects fall into a pixel.
        //
        // Of course, there are a lot of situation where the canvas color
        // technique cannot be used, because the painted areas are not
        // uni-colored, or their color is not known. But these are often
        // situations where the errors are not so spectacular. However, a last
        // chance could be the method PaintEdgeCorrection (read there).

        emPainter();
                // Construct a painter which paints nowhere.

        emPainter(const emPainter & painter);
                // Construct a painter by copying all the settings from another
                // painter.
                // Arguments:
                //   painter - A painter whose settings are to be copied.

        emPainter(const emPainter & painter, double clipX1, double clipY1,
                  double clipX2, double clipY2);
                // Construct a painter by copying all the settings from another
                // painter, but intersect the clipping rectangle with a given
                // clipping rectangle.
                // Arguments:
                //   painter   - A painter whose settings are to be copied.
                //   clipX1,clipY1,clipX2,clipY2 - The clipping rectangle in
                //               pixel coordinates. It will be intersected with
                //               the clipping rectangle from the source painter.

        emPainter(const emPainter & painter, double clipX1, double clipY1,
                  double clipX2, double clipY2, double originX,
                  double originY, double scaleX,double scaleY);
                // Construct a painter by copying all the settings from another
                // painter, but intersect the clipping rectangle with a given
                // clipping rectangle, and set another transformation.
                // Arguments:
                //   painter         - A painter whose settings are to be
                //                     copied.
                //   clipX1,clipY1,clipX2,clipY2 - The clipping rectangle in
                //                     pixel coordinates. It will be intersected
                //                     with the clipping rectangle from the
                //                     source painter.
                //   originX,originY - The new origin (see SetOrigin).
                //   scaleX,scaleY   - The new scale factors (see SetScaling).

        emPainter(emRootContext & rootContext, void * map, int bytesPerRow,
                  int bytesPerPixel, emUInt32 redMask, emUInt32 greenMask,
                  emUInt32 blueMask, double clipX1, double clipY1,
                  double clipX2, double clipY2, double originX=0,
                  double originY=0, double scaleX=1, double scaleY=1,
                  emThreadMiniMutex * userSpaceMutex=NULL,
                  bool * usmLockedByThisThread=NULL);
                // Construct a painter from scratch. The output bitmap is
                // addressed with:
                //   pixelValue = ((TYPE*)(map+y*bytesPerRow)))[x]
                // Where:
                //   x is the X-coordinate of the pixel in the range of
                //   (int)clipX1 to (int)ceil(clipX2)-1.
                //   y is the Y-coordinate of the pixel in the range of
                //   (int)clipY1 to (int)ceil(clipY2)-1.
                //   TYPE is an 8, 16 or 32-bit integer type, according to
                //   bytesPerPixel.
                //   pixelValue is the pixel color consisting of three
                //   channels, according to redMask, greenMask and blueMask.
                // Arguments:
                //   rootContext     - The root context.
                //   map             - Pointer to the output bitmap.
                //   bytesPerRow     - Size of a row in the map, in bytes.
                //   bytesPerPixel   - Size of a pixel in the map, in bytes.
                //                     This must be 1, 2 or 4.
                //   redMask         - A bit mask which denotes the red channel
                //                     within a pixel value.
                //   greenMask       - A bit mask which denotes the green
                //                     channel within a pixel value.
                //   blueMask        - A bit mask which denotes the blue channel
                //                     within a pixel value.
                //   clipX1,clipY1,clipX2,clipY2 - The clipping rectangle (see
                //                     SetClipping).
                //   originX,originY - The origin (see SetOrigin).
                //   scaleX,scaleY   - The scale factors (see SetScaling).
                //   userSpaceMutex  - See SetUserSpaceMutex.
                //   usmLockedByThisThread - See SetUserSpaceMutex.

        // Even have a look at emImage::PreparePainter

        ~emPainter();
                // Destructor.

        emPainter & operator = (const emPainter & painter);
                // Copy all the settings from another painter to this painter.

        double GetClipX1() const;
        double GetClipY1() const;
        double GetClipX2() const;
        double GetClipY2() const;
        void SetClipping(double clipX1, double clipY1, double clipX2,
                         double clipY2);
                // Get or set the clipping rectangle. It is in pixel
                // coordinates. Note that these can be fractional numbers - a
                // paint operation on a partly clipped pixel will result in an
                // appropriate blending operation.

        double GetUserClipX1() const;
        double GetUserClipY1() const;
        double GetUserClipX2() const;
        double GetUserClipY2() const;
                // Get the clipping rectangle in user coordinates.

        double GetOriginX() const;
        double GetOriginY() const;
        double GetScaleX() const;
        double GetScaleY() const;
        void SetOrigin(double originX, double originY);
        void SetScaling(double scaleX, double scaleY);
        void SetTransformation(double originX, double originY,
                               double scaleX, double scaleY);
                // Get or set the user coordinate system, which is used by all
                // the painting methods. The transformation of user coordinates
                // to pixel coordinates is:
                //   xPixels = xUser * ScaleX + OriginX
                //   yPixels = yUser * ScaleY + OriginY
                // The scale factors must be positive!

        double RoundX(double x) const;
        double RoundY(double y) const;
        double RoundDownX(double x) const;
        double RoundDownY(double y) const;
        double RoundUpX(double x) const;
        double RoundUpY(double y) const;
                // Round user coordinates to pixel boundary.

        void SetUserSpaceMutex(
                emThreadMiniMutex * userSpaceMutex,
                bool * usmLockedByThisThread
        );
                // Set the pointer to the user space mutex, and the pointer to a
                // variable which always says whether the mutex is currently
                // locked by the thread which owns this emPainter. Both pointers
                // can be NULL for single-threaded mode. This method is normally
                // only to be called by emViewRenderer.

        bool LeaveUserSpace() const;
                // Unlock the user space mutex. Returns true if it was locked.
                // In multi-threaded mode, each thread has it's own emPainter on
                // an own output region. The mutex is unlocked when a thread is
                // deeply in a paint method of emPainter, so that the low-level
                // painting can happen concurrently. Normally, the mutex is
                // always locked while one thread is in some code which "uses"
                // emPainter (i.e. emPanel::Paint implementation), so that the
                // user code must not be so thread-safe. But advanced user code
                // which is fully thread-safe, may call LeaveUserSpace() and
                // EnterUserSpace() in order to be concurrent. All paint methods
                // of emPainter can be called with or without having the mutex
                // locked, and they always return with the same lock state as
                // they were called.

        bool EnterUserSpace() const;
                // Lock the user space mutex. Returns true if it was unlocked.


        //-------------------- Painting areas in uni-color ---------------------

        void Clear(emColor color=emColor::BLACK, emColor canvasColor=0) const;
                // Like PaintRect on the whole clipping rectangle.

        void PaintRect(double x, double y, double w, double h,
                       emColor color, emColor canvasColor=0) const;
                // Paint a rectangle.
                // Arguments:
                //   x,y,w,h     - Upper-left corner and size of the rectangle.
                //   color       - The color (alpha part is used for blending).
                //   canvasColor - Please read the general comments more above.

        void PaintPolygon(const double xy[], int n, emColor color,
                          emColor canvasColor=0) const;
                // Paint a polygon. The polygon may have holes, and it does not
                // matter whether the edges run clockwise or counterclockwise.
                // But there must not be any crossings in the edges.
                // Arguments:
                //   xy[]        - Coordinates of the polygon vertices. The
                //                 array elements are:
                //                 x0, y0, x1, y1, x2, y2, ..., x(n-1), y(n-1)
                //   n           - Number of vertices.
                //   color       - The color (alpha part is used for blending).
                //   canvasColor - Please read the general comments more above.

        void PaintEdgeCorrection(double x1, double y1, double x2, double y2,
                                 emColor color1, emColor color2) const;
                // If you don't have a canvas color when painting adjacent
                // polygons (or rectangles), this method can be helpful in
                // reducing the visual errors at the edges. Just call this to
                // paint the correction over the contact edge of two polygons
                // which have already been painted without canvas color. color1
                // must be the color argument used for painting the first
                // polygon, and color2 must be the color argument used for the
                // other polygon which has been painted later. (x1,y1) and
                // (x2,y2) are the vertices of the contact edge, but the order
                // is important: When looking from (x1,y1) to (x2,y2), the first
                // polygon must be on the left.

        void PaintEllipse(double x, double y, double w, double h,
                          emColor color, emColor canvasColor=0) const;
        void PaintEllipse(double x, double y, double w, double h,
                          double startAngle, double rangeAngle,
                          emColor color, emColor canvasColor=0) const;
                // Paint an ellipse or a sector of an ellipse.
                // Arguments:
                //   x,y,w,h     - Upper-left corner and size of the bounding
                //                 rectangle of the ellipse.
                //   startAngle  - Start angle of the sector in degrees. Zero
                //                 points to the right, 90 points down...
                //   rangeAngle  - Range angle of the sector.
                //   color       - The color (alpha part is used for blending).
                //   canvasColor - Please read the general comments more above.

        void PaintRoundRect(double x, double y, double w, double h,
                            double rx, double ry, emColor color,
                            emColor canvasColor=0) const;
                // Paint a rectangle with elliptic corners.
                // Arguments:
                //   x,y,w,h     - Upper-left corner and size of the rectangle.
                //   rx,ry       - Radiuses of the ellipses.
                //   color       - The color (alpha part is used for blending).
                //   canvasColor - Please read the general comments more above.


        //-------------------- Painting lines in uni-color ---------------------

        enum LineCap {
                LC_FLAT,
                LC_SQUARE,
                LC_ROUND
        };
        void PaintLine(double x1, double y1, double x2, double y2,
                       double thickness, LineCap cap1, LineCap cap2,
                       emColor color, emColor canvasColor=0) const;
                // Paint a line.
                // Arguments:
                //   x1,y1       - Coordinates of the first end of the line.
                //   x2,y2       - Coordinates of the other end of the line.
                //   thickness   - Width of the stroke.
                //   cap1,cap2   - How to paint the endings:
                //                  LC_FLAT: Do not extend the ending.
                //                  LC_SQUARE: Extend by thickness/2.
                //                  LC_ROUND: Have a semicircle.
                //   color       - The color (alpha part is used for blending).
                //   canvasColor - Please read the general comments more above.

        void PaintRectOutline(double x, double y, double w, double h,
                              double thickness, emColor color,
                              emColor canvasColor=0) const;
        void PaintPolygonOutline(const double xy[], int n, double thickness,
                                 emColor color, emColor canvasColor=0) const;
        void PaintEllipseOutline(double x, double y, double w, double h,
                                 double thickness, emColor color,
                                 emColor canvasColor=0) const;
        void PaintEllipseOutline(double x, double y, double w, double h,
                                 double startAngle, double rangeAngle,
                                 double thickness, emColor color,
                                 emColor canvasColor=0) const;
        void PaintRoundRectOutline(double x, double y, double w, double h,
                                   double rx, double ry, double thickness,
                                   emColor color, emColor canvasColor=0) const;
                // These are like PaintRect, PaintPolygon, PaintEllipse and
                // PaintRoundRect, but the objects are outlined instead of being
                // filled. The argument thickness is the width of the stroke.
                // The lines are centered on the boundary of the objects. The
                // second version of PaintEllipseOutline paints just an arc
                // (instead of the outline of a pie).
                // ??? BUG: PaintPolygonOutline currently always ignores the
                // canvasColor, and it does not produce correct results if the
                // alpha channel of the color is not 255.


        //------------------------ Painting from images ------------------------

        void PaintShape(double x, double y, double w, double h,
                        const emImage & img, int channel=0,
                        emColor color=emColor::WHITE,
                        emColor canvasColor=0) const;
        void PaintShape(double x, double y, double w, double h,
                        const emImage & img, double srcX, double srcY,
                        double srcW, double srcH, int channel=0,
                        emColor color=emColor::WHITE,
                        emColor canvasColor=0) const;
                // Paint a rectangle from one channel of an image or sub-image.
                // This is just like PaintRect, but the image channel is used as
                // an additional alpha channel for blending.
                // Arguments:
                //   x,y,w,h     - Upper-left corner and size of the target
                //                 rectangle.
                //   img         - The image.
                //   srcX,srcY,srcW,srcH - Upper-left corner and size of the
                //                 source rectangle on the image. If these
                //                 arguments are missing, the whole image is
                //                 taken.
                //   channel     - The desired channel of the image.
                //   color       - The color (alpha part is used for blending).
                //   canvasColor - Please read the general comments more above.

        void PaintImage(double x, double y, double w, double h,
                        const emImage & img, int alpha=255,
                        emColor canvasColor=0) const;
        void PaintImage(double x, double y, double w, double h,
                        const emImage & img, double srcX, double srcY,
                        double srcW, double srcH, int alpha=255,
                        emColor canvasColor=0) const;
                // Paint a rectangle from an image or from a sub-image.
                // Arguments:
                //   x,y,w,h     - Upper-left corner and size of the target
                //                 rectangle.
                //   img         - The image. If the image has an alpha channel,
                //                 it is used for blending.
                //   srcX,srcY,srcW,srcH - Upper-left corner and size of the
                //                 source rectangle on the image. If these
                //                 arguments are missing, the whole image is
                //                 taken.
                //   alpha       - An additional alpha value for blending
                //                 (0-255).
                //   canvasColor - Please read the general comments more above.

        void PaintBorderShape(
                double x, double y, double w, double h,
                double l, double t, double r, double b,
                const emImage & img,
                double srcL, double srcT, double srcR, double srcB,
                int channel=0,
                emColor color=emColor::WHITE, emColor canvasColor=0,
                int whichSubRects=0757
        ) const;
        void PaintBorderShape(
                double x, double y, double w, double h,
                double l, double t, double r, double b,
                const emImage & img,
                double srcX, double srcY, double srcW, double srcH,
                double srcL, double srcT, double srcR, double srcB,
                int channel=0,
                emColor color=emColor::WHITE, emColor canvasColor=0,
                int whichSubRects=0757
        ) const;
        void PaintBorderImage(
                double x, double y, double w, double h,
                double l, double t, double r, double b,
                const emImage & img,
                double srcL, double srcT, double srcR, double srcB,
                int alpha=255, emColor canvasColor=0,
                int whichSubRects=0757
        ) const;
        void PaintBorderImage(
                double x, double y, double w, double h,
                double l, double t, double r, double b,
                const emImage & img,
                double srcX, double srcY, double srcW, double srcH,
                double srcL, double srcT, double srcR, double srcB,
                int alpha=255, emColor canvasColor=0,
                int whichSubRects=0757
        ) const;
                // Like PaintShape and PaintImage, but with a special type of
                // scaling, typically used for painting borders. The rectangle
                // is divided into a grid of nine sub-rectangles: four corners,
                // four edges and an inner rectangle. The operation allows to
                // change the height of the upper and lower edges and the width
                // of the left and right edges, in relation to the size of the
                // whole rectangle. The other sub-rectangles are adapted
                // accordingly.
                // Arguments:
                //   x,y,w,h     - Upper-left corner and size of the target
                //                 rectangle.
                //   l,t,r,b     - Thickness of the left, top, right and bottom
                //                 edges on the target.
                //   img         - The image.
                //   srcX,srcY,srcW,srcH - Upper-left corner and size of the
                //                 source rectangle on the image. If these
                //                 arguments are missing, the whole image is
                //                 taken.
                //   srcL,srcT,srcR,srcB - Thickness of the left, top, right
                //                 and bottom edges on the image.
                //   channel     - The desired channel of the image.
                //   color       - The color (alpha part is used for blending).
                //   alpha       - An additional alpha value for blending
                //                 (0-255).
                //   canvasColor - Please read the general comments more above.
                //   whichSubRects - Which of the 9 sub-rectangles are to be
                //                 painted. This is a bit mask. Bit numbers are:
                //                  8 = upper left | 5 = upper | 2 = upper right
                //                  7 = left       | 4 = inner | 1 = right
                //                  6 = lower left | 3 = lower | 0 = lower right
                //                 The default of 0757 means to paint just the
                //                 corners and edges, not the inner part.


        //--------------------------- Painting texts ---------------------------

        void PaintText(double x, double y, const char * text, double charHeight,
                       double widthScale, emColor color, emColor canvasColor=0,
                       int textLen=INT_MAX) const;
                // Paint a single line of raw text. Any formattings are not
                // interpreted.
                // Arguments:
                //   x,y         - Upper-left corner of the first character.
                //   text        - The character string, terminated by a
                //                 null-character or through the textLen
                //                 argument.
                //   charHeight  - The character height. This includes ascenders
                //                 and descenders.
                //   widthScale  - Factor for making the characters wider (>1.0)
                //                 or less wide (<1.0).
                //   color       - The color (alpha part is used for blending).
                //   canvasColor - Please read the general comments more above.
                //   textLen     - Length of the character string if not
                //                 null-terminated.

        void PaintTextBoxed(double x, double y, double w, double h,
                            const char * text, double maxCharHeight,
                            emColor color, emColor canvasColor=0,
                            emAlignment boxAlignment=EM_ALIGN_CENTER,
                            emAlignment textAlignment=EM_ALIGN_LEFT,
                            double minWidthScale=0.5, bool formatted=true,
                            double relLineSpace=0.0, int textLen=INT_MAX) const;
                // Paint a text fitted into a rectangle, with or without
                // formatting.
                // Arguments:
                //   x,y,w,h       - Upper-left corner and size of the
                //                   rectangle.
                //   text          - The character string, terminated by a
                //                   null-character or through the textLen
                //                   argument.
                //   maxCharHeight - The maximum character height. This includes
                //                   ascenders and descenders. The actual
                //                   character height may get smaller, so that
                //                   the text fits into the rectangle.
                //   color         - The color (alpha part is used for
                //                   blending).
                //   canvasColor   - Please read the general comments more
                //                   above.
                //   boxAlignment  - How to align the text as a whole within the
                //                   rectangle.
                //   textAlignment - How to align individual lines within the
                //                   text horizontally. The top and bottom flags
                //                   are ignored here.
                //   minWidthScale - Minimum factor for making the characters
                //                   wider (>1.0) or less wide (<1.0). The
                //                   implicit maximum is the maximum of 1.0 and
                //                   minWidthScale. The maximum is preferred,
                //                   but for fitting the text into the
                //                   rectangle, the factor may get smaller down
                //                   to minWidthScale.
                //   formatted     - Whether to interpret formatting characters
                //                   (new-line and tabulator).
                //   relLineSpace  - Vertical space between text lines, in units
                //                   of character heights.
                //   textLen       - Length of the character string if not
                //                   null-terminated.

        static double GetTextSize(const char * text, double charHeight,
                                  bool formatted=true, double relLineSpace=0.0,
                                  double * pHeight=NULL, int textLen=INT_MAX);
                // Calculate the width and height of a text.
                // Arguments:
                //   text         - The character string, terminated by a
                //                  null-character or through the textLen
                //                  argument.
                //   charHeight   - The character height. This includes
                //                  ascenders and descenders.
                //   formatted    - Whether to interpret formatting characters
                //                  (new-line and tabulator).
                //   relLineSpace - Vertical space between text lines, in units
                //                  of character heights.
                //   pHeight      - Pointer for returning the height of the
                //                  text, or NULL.
                //   textLen      - Length of the character string if not
                //                  null-terminated.
                // Returns: The width of the text.


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

private:

        struct SharedPixelFormat {
                SharedPixelFormat * Next;
                int RefCount;
                int BytesPerPixel;
                emUInt32 RedRange,GreenRange,BlueRange;
                int RedShift,GreenShift,BlueShift;
                void * RedHash;   // Index bits: rrrrrrrraaaaaaaa or aaaaaaaarrrrrrrr
                void * GreenHash; // Index bits: ggggggggaaaaaaaa or aaaaaaaagggggggg
                void * BlueHash;  // Index bits: bbbbbbbbaaaaaaaa or aaaaaaaabbbbbbbb
        };

        void * Map;
        int BytesPerRow;
        SharedPixelFormat * PixelFormat;
        double ClipX1, ClipY1, ClipX2, ClipY2;
        double OriginX, OriginY, ScaleX, ScaleY;
        emThreadMiniMutex * UserSpaceMutex;
        bool * USMLockedByThisThread;
        emRef<emFontCache> FontCache;

        static const double CharBoxTallness;

        static const unsigned ImageDownscaleQuality;
                // Quality of downscaling images. Higher value means more
                // quality but less performance: Before interpolation, the
                // source is downscaled by integer-nearest-pixel to about:
                // sizeOfSource <= ImageDownscaleQuality * sizeOfTarget

        static const double CircleQuality;
};

inline emPainter::~emPainter()
{
        if (PixelFormat) PixelFormat->RefCount--;
        // Do not free unused shared pixel formats here. So, it can be re-used
        // quickly on next construction.
}

inline double emPainter::GetClipX1() const
{
        return ClipX1;
}

inline double emPainter::GetClipY1() const
{
        return ClipY1;
}

inline double emPainter::GetClipX2() const
{
        return ClipX2;
}

inline double emPainter::GetClipY2() const
{
        return ClipY2;
}

inline void emPainter::SetClipping(double clipX1, double clipY1,
                                   double clipX2, double clipY2)
{
        ClipX1=clipX1;
        ClipY1=clipY1;
        ClipX2=clipX2;
        ClipY2=clipY2;
}

inline double emPainter::GetUserClipX1() const
{
        return (ClipX1-OriginX)/ScaleX;
}

inline double emPainter::GetUserClipY1() const
{
        return (ClipY1-OriginY)/ScaleY;
}

inline double emPainter::GetUserClipX2() const
{
        return (ClipX2-OriginX)/ScaleX;
}

inline double emPainter::GetUserClipY2() const
{
        return (ClipY2-OriginY)/ScaleY;
}

inline double emPainter::GetOriginX() const
{
        return OriginX;
}

inline double emPainter::GetOriginY() const
{
        return OriginY;
}

inline double emPainter::GetScaleX() const
{
        return ScaleX;
}

inline double emPainter::GetScaleY() const
{
        return ScaleY;
}

inline void emPainter::SetOrigin(double originX, double originY)
{
        OriginX=originX;
        OriginY=originY;
}

inline void emPainter::SetScaling(double scaleX, double scaleY)
{
        ScaleX=scaleX;
        ScaleY=scaleY;
}

inline void emPainter::SetTransformation(
        double originX, double originY, double scaleX, double scaleY
)
{
        OriginX=originX;
        OriginY=originY;
        ScaleX=scaleX;
        ScaleY=scaleY;
}

inline bool emPainter::LeaveUserSpace() const
{
        if (USMLockedByThisThread && *USMLockedByThisThread) {
                *USMLockedByThisThread=false;
                UserSpaceMutex->Unlock();
                return true;
        }
        return false;
}

inline bool emPainter::EnterUserSpace() const
{
        if (USMLockedByThisThread && !*USMLockedByThisThread) {
                UserSpaceMutex->Lock();
                *USMLockedByThisThread=true;
                return true;
        }
        return false;
}

inline void emPainter::PaintShape(
        double x, double y, double w, double h, const emImage & img,
        int channel, emColor color, emColor canvasColor
) const
{
        PaintShape(x,y,w,h,img,0,0,img.GetWidth(),img.GetHeight(),
                   channel,color,canvasColor);
}

inline void emPainter::PaintImage(
        double x, double y, double w, double h, const emImage & img,
        int alpha, emColor canvasColor
) const
{
        PaintImage(x,y,w,h,img,0,0,img.GetWidth(),img.GetHeight(),alpha,
                   canvasColor);
}

inline void emPainter::PaintBorderShape(
        double x, double y, double w, double h, double l, double t, double r,
        double b, const emImage & img, double srcL, double srcT, double srcR,
        double srcB, int channel, emColor color, emColor canvasColor,
        int whichSubRects
) const
{
        PaintBorderShape(
                x,y,w,h,l,t,r,b,img,0,0,img.GetWidth(),img.GetHeight(),
                srcL,srcT,srcR,srcB,channel,color,canvasColor,whichSubRects
        );
}

inline void emPainter::PaintBorderImage(
        double x, double y, double w, double h, double l, double t, double r,
        double b, const emImage & img, double srcL, double srcT, double srcR,
        double srcB, int alpha, emColor canvasColor, int whichSubRects
) const
{
        PaintBorderImage(
                x,y,w,h,l,t,r,b,img,0,0,img.GetWidth(),img.GetHeight(),
                srcL,srcT,srcR,srcB,alpha,canvasColor,whichSubRects
        );
}


#endif