//------------------------------------------------------------------------------
// emPainter.h
//
// Copyright (C) 2001,2003-2010,2014,2016-2017,2020,2022 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 emModel_h
#include <emCore/emModel.h>
#endif
#ifndef emStroke_h
#include <emCore/emStroke.h>
#endif
#ifndef emStrokeEnd_h
#include <emCore/emStrokeEnd.h>
#endif
#ifndef emTexture_h
#include <emCore/emTexture.h>
#endif
#ifndef emThread_h
#include <emCore/emThread.h>
#endif
class emCoreConfig;
class emFontCache;
//==============================================================================
//================================= 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.
class UserSpaceLeaveGuard {
public:
// RAII helper for the user space mutex: Calls LeaveUserSpace()
// on construction and undoes that on destruction.
UserSpaceLeaveGuard(const emPainter & painter);
~UserSpaceLeaveGuard();
private:
const emPainter * PainterIfUnlocked;
};
//--------------------------- Painting areas ---------------------------
void Clear(const emTexture & texture=emColor::BLACK,
emColor canvasColor=0) const;
// Like PaintRect on the whole clipping rectangle.
void PaintRect(double x, double y, double w, double h,
const emTexture & texture, emColor canvasColor=0) const;
// Paint a rectangle.
// Arguments:
// x,y,w,h - Upper-left corner and size of the rectangle.
// texture - The texture by which to fill the rectangle.
// canvasColor - Please read the general comments more above.
void PaintPolygon(const double xy[], int n, const emTexture & texture,
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 should not be any crossings in the edges, otherwise
// areas may be painted multiple times or be canceled out.
// 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.
// texture - The texture by which to fill the polygon.
// 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 used for painting the first polygon, and
// color2 must be the color 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 PaintBezier(const double xy[], int n, const emTexture & texture,
emColor canvasColor=0) const;
// Paint the area of a closed path made of cubic Bezier curves.
// Arguments:
// xy[] - Coordinates of the support polygon of the
// Bezier curves. The array elements are:
// x0, y0, x1, y1, x2, y2, ..., x(n-1), y(n-1)
// Each cubic Bezier curve is defined by four
// points in the support polygon. The last
// support point of a curve is also the first of
// the next curve. And because the path is
// closed, the first point of the first curve is
// also the last point of the last curve.
// n - Number of points in the support polygon. This
// must be a multiple of three (n = 3, 6, 9,
// ...).
// texture - The texture by which to fill the area.
// canvasColor - Please read the general comments more above.
void PaintEllipse(double x, double y, double w, double h,
const emTexture & texture,
emColor canvasColor=0) const;
// Paint an ellipse.
// Arguments:
// x,y,w,h - Upper-left corner and size of the bounding
// rectangle of the ellipse.
// texture - The texture by which to fill the ellipse.
// canvasColor - Please read the general comments more above.
void PaintEllipseSector(double x, double y, double w, double h,
double startAngle, double rangeAngle,
const emTexture & texture,
emColor canvasColor=0) const;
// Paint 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.
// texture - The texture by which to fill the ellipse.
// canvasColor - Please read the general comments more above.
void PaintRoundRect(double x, double y, double w, double h,
double rx, double ry, const emTexture & texture,
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.
// texture - The texture by which to fill the round
// rectangle.
// canvasColor - Please read the general comments more above.
//--------------------- Painting non-closed lines ----------------------
void PaintLine(double x1, double y1, double x2, double y2,
double thickness, const emStroke & stroke,
const emStrokeEnd & strokeStart=emStrokeEnd(),
const emStrokeEnd & strokeEnd=emStrokeEnd(),
emColor canvasColor=0) const;
// Paint a straight 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.
// stroke - Style of the stroke (color, rounding, dashes).
// strokeStart - Style of the beginning of the stroke.
// strokeEnd - Style of the end of the stroke.
// canvasColor - Please read the general comments more above.
void PaintPolyline(const double xy[], int n, double thickness,
const emStroke & stroke,
const emStrokeEnd & strokeStart=emStrokeEnd(),
const emStrokeEnd & strokeEnd=emStrokeEnd(),
emColor canvasColor=0) const;
// Paint a series of connected straight lines.
// Arguments:
// xy[] - Coordinates of the line vertices. The
// array elements are:
// x0, y0, x1, y1, x2, y2, ..., x(n-1), y(n-1)
// n - Number of vertices.
// thickness - Width of the stroke.
// stroke - Style of the stroke (color, rounding, dashes).
// strokeStart - Style of the beginning of the stroke.
// strokeEnd - Style of the end of the stroke.
// canvasColor - Please read the general comments more above.
void PaintBezierLine(const double xy[], int n, double thickness,
const emStroke & stroke,
const emStrokeEnd & strokeStart=emStrokeEnd(),
const emStrokeEnd & strokeEnd=emStrokeEnd(),
emColor canvasColor=0) const;
// Paint a curved line made of cubic Bezier curves.
// Arguments:
// xy[] - Coordinates of the support polygon of the
// Bezier curves. The array elements are:
// x0, y0, x1, y1, x2, y2, ..., x(n-1), y(n-1)
// Each cubic Bezier curve is defined by four
// points in the support polygon. The last
// support point of a curve is also the first of
// the next curve.
// n - Number of points in the support polygon. This
// must be a multiple of three plus one (n = 4,
// 7, 10, ...).
// thickness - Width of the stroke.
// stroke - Style of the stroke (color, rounding, dashes).
// strokeStart - Style of the beginning of the stroke.
// strokeEnd - Style of the end of the stroke.
// canvasColor - Please read the general comments more above.
void PaintEllipseArc(double x, double y, double w, double h,
double startAngle, double rangeAngle,
double thickness, const emStroke & stroke,
const emStrokeEnd & strokeStart=emStrokeEnd(),
const emStrokeEnd & strokeEnd=emStrokeEnd(),
emColor canvasColor=0) const;
// Paint the arc 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 arc in degrees. Zero
// points to the right, 90 points down...
// rangeAngle - Range angle of the arc.
// thickness - Width of the stroke.
// stroke - Style of the stroke (color, rounding, dashes).
// strokeStart - Style of the beginning of the stroke.
// strokeEnd - Style of the end of the stroke.
// canvasColor - Please read the general comments more above.
//----------------------- Painting closed lines ------------------------
void PaintRectOutline(double x, double y, double w, double h,
double thickness, const emStroke & stroke,
emColor canvasColor=0) const;
void PaintPolygonOutline(const double xy[], int n, double thickness,
const emStroke & stroke,
emColor canvasColor=0) const;
void PaintBezierOutline(const double xy[], int n, double thickness,
const emStroke & stroke,
emColor canvasColor=0) const;
void PaintEllipseOutline(double x, double y, double w, double h,
double thickness, const emStroke & stroke,
emColor canvasColor=0) const;
void PaintEllipseSectorOutline(double x, double y, double w, double h,
double startAngle, double rangeAngle,
double thickness, const emStroke & stroke,
emColor canvasColor=0) const;
void PaintRoundRectOutline(double x, double y, double w, double h,
double rx, double ry, double thickness,
const emStroke & stroke,
emColor canvasColor=0) const;
// These are like PaintRect, PaintPolygon, PaintBezier,
// PaintEllipse, PaintEllipseSector and PaintRoundRect, but the
// objects are outlined instead of being filled. The thickness
// argument is the width of the stroke. The stroke argument
// describes the color, rounding of corners, and optional
// dashes. The lines are centered on the boundary of the
// objects.
//------------------------ Painting from images ------------------------
void PaintImage(double x, double y, double w, double h,
const emImage & img, int alpha=255,
emColor canvasColor=0,
emTexture::ExtensionType extension=
emTexture::EXTEND_EDGE_OR_ZERO) const;
void PaintImage(double x, double y, double w, double h,
const emImage & img, int srcX, int srcY, int srcW,
int srcH, int alpha=255, emColor canvasColor=0,
emTexture::ExtensionType extension=
emTexture::EXTEND_EDGE_OR_ZERO) const;
// Paint a rectangle from an image or from a sub-image. This is
// like PaintRect(..) with an emImageTexture. Please see
// emImageTexture for details.
// 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.
// extension - Please read the comments on
// emTexture::ExtensionType.
void PaintImageColored(double x, double y, double w, double h,
const emImage & img, emColor color1,
emColor color2, emColor canvasColor=0,
emTexture::ExtensionType extension=
emTexture::EXTEND_EDGE_OR_ZERO) const;
void PaintImageColored(double x, double y, double w, double h,
const emImage & img, int srcX, int srcY,
int srcW, int srcH, emColor color1,
emColor color2, emColor canvasColor=0,
emTexture::ExtensionType extension=
emTexture::EXTEND_EDGE_OR_ZERO) const;
// Paint a rectangle from an image or sub-image, with coloring.
// This is like PaintRect(..) with an emImageColoredTexture.
// Please see emImageColoredTexture for details.
// 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.
// color1 - The color of the beginning of the gradient
// (where the image values are zero).
// color2 - The color of the end of the gradient
// (where the image values are 255).
// canvasColor - Please read the general comments more above.
// extension - Please read the comments on
// emTexture::ExtensionType.
void PaintBorderImage(
double x, double y, double w, double h,
double l, double t, double r, double b,
const emImage & img,
int srcL, int srcT, int srcR, int 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,
int srcX, int srcY, int srcW, int srcH,
int srcL, int srcT, int srcR, int srcB,
int alpha=255, emColor canvasColor=0,
int whichSubRects=0757
) const;
void PaintBorderImageColored(
double x, double y, double w, double h,
double l, double t, double r, double b,
const emImage & img,
int srcL, int srcT, int srcR, int srcB,
emColor color1, emColor color2, emColor canvasColor=0,
int whichSubRects=0757
) const;
void PaintBorderImageColored(
double x, double y, double w, double h,
double l, double t, double r, double b,
const emImage & img,
int srcX, int srcY, int srcW, int srcH,
int srcL, int srcT, int srcR, int srcB,
emColor color1, emColor color2, emColor canvasColor=0,
int whichSubRects=0757
) const;
// Like PaintImage and PaintImageColored, 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.
// color1 - The color of the beginning of the gradient
// (where the image values are zero).
// color2 - The color of the end of the gradient
// (where the image values are 255).
// 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.
//------------------------- Deprecated methods -------------------------
EM_DEPRECATED(
void PaintEllipse(double x, double y, double w, double h,
double startAngle, double rangeAngle,
const emTexture & texture,
emColor canvasColor=0) const
);
enum LineCap {
LC_FLAT,
LC_SQUARE,
LC_ROUND
};
EM_DEPRECATED(
void PaintLine(double x1, double y1, double x2, double y2,
double thickness, LineCap cap1, LineCap cap2,
emColor color, emColor canvasColor=0) const
);
EM_DEPRECATED(
void PaintEllipseOutline(double x, double y, double w, double h,
double startAngle, double rangeAngle,
double thickness, emColor color,
emColor canvasColor=0) const
);
//----------------------------------------------------------------------
private:
friend class UserSpaceLeaveGuard;
void PaintPolylineWithArrows(
const double xy[], int n, double nx1, double ny1, double nx2,
double ny2, double thickness, const emStroke & stroke,
const emStrokeEnd & strokeStart, const emStrokeEnd & strokeEnd,
emColor canvasColor
) const;
void PaintPolylineWithArrowsAlterBuf(
double xy[], int n, double nx1, double ny1, double nx2,
double ny2, double thickness, const emStroke & stroke,
const emStrokeEnd & strokeStart, const emStrokeEnd & strokeEnd,
emColor canvasColor
) const;
static double CalculateLinePointMinMaxRadius(
double thickness, const emStroke & stroke,
const emStrokeEnd & strokeStart,
const emStrokeEnd & strokeEnd
);
static double CutLineAtArrow(
double x1, double y1, double x2, double y2, double thickness,
const emStroke & stroke, const emStrokeEnd & strokeEnd
);
void PaintArrow(
double x, double y, double nx, double ny, double thickness,
const emStroke & stroke, const emStrokeEnd & strokeEnd,
emColor canvasColor
) const;
void PaintPolylineWithoutArrows(
const double xy[], int n, double thickness,
const emStroke & stroke, const emStrokeEnd & strokeStart,
const emStrokeEnd & strokeEnd, emColor canvasColor
) const;
void PaintDashedPolyline(
const double xy[], int n, double thickness,
const emStroke & stroke, const emStrokeEnd & strokeStart,
const emStrokeEnd & strokeEnd, emColor canvasColor
) const;
void PaintSolidPolyline(
const double xy[], int n, double thickness,
const emStroke & stroke, const emStrokeEnd & strokeStart,
const emStrokeEnd & strokeEnd, emColor canvasColor
) const;
enum OptimizedPixelFormatIndex {
OPFI_NONE = -1,
OPFI_8888_0BGR = 0,
OPFI_8888_0RGB = 1,
OPFI_8888_BGR0 = 2,
OPFI_8888_RGB0 = 3
};
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
OptimizedPixelFormatIndex OPFIndex;
};
class SharedModel : public emModel {
public:
static emRef<SharedModel> Acquire(emRootContext & rootContext);
emRef<emCoreConfig> CoreConfig;
emRef<emFontCache> FontCache;
emPainter::SharedPixelFormat * PixelFormatList;
# if EM_HAVE_X86_INTRINSICS
bool CanCpuDoAvx2;
# endif
void RemoveUnusedPixelFormats();
private:
SharedModel(emContext & context, const emString & name);
virtual ~SharedModel();
};
class ScanlineTool;
void * Map;
int BytesPerRow;
SharedPixelFormat * PixelFormat;
double ClipX1, ClipY1, ClipX2, ClipY2;
double OriginX, OriginY, ScaleX, ScaleY;
emThreadMiniMutex * UserSpaceMutex;
bool * USMLockedByThisThread;
emRef<SharedModel> Model;
static const emStrokeEnd ButtEnd;
static const emStrokeEnd CapEnd;
static const emStrokeEnd NoEnd;
static const double CharBoxTallness;
static const double CircleQuality;
static const double MaxMiter;
static const double ArrowBaseSize;
static const double ArrowNotch;
static const double MaxDashes;
static const double MinRelSegLen;
};
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 emPainter::UserSpaceLeaveGuard::UserSpaceLeaveGuard(
const emPainter & painter
)
{
PainterIfUnlocked=NULL;
if (painter.USMLockedByThisThread && *painter.USMLockedByThisThread) {
*painter.USMLockedByThisThread=false;
painter.UserSpaceMutex->Unlock();
PainterIfUnlocked=&painter;
}
}
inline emPainter::UserSpaceLeaveGuard::~UserSpaceLeaveGuard()
{
if (PainterIfUnlocked) {
PainterIfUnlocked->UserSpaceMutex->Lock();
*PainterIfUnlocked->USMLockedByThisThread=true;
}
}
inline void emPainter::PaintPolygonOutline(
const double xy[], int n, double thickness, const emStroke & stroke,
emColor canvasColor
) const
{
PaintPolyline(
xy,n,thickness,stroke,
#ifdef EM_NO_DATA_EXPORT
emStrokeEnd::NO_END,emStrokeEnd::NO_END,
#else
NoEnd,NoEnd,
#endif
canvasColor
);
}
inline void emPainter::PaintBezierOutline(
const double xy[], int n, double thickness, const emStroke & stroke,
emColor canvasColor
) const
{
PaintBezierLine(
xy,n,thickness,stroke,
#ifdef EM_NO_DATA_EXPORT
emStrokeEnd::NO_END,emStrokeEnd::NO_END,
#else
NoEnd,NoEnd,
#endif
canvasColor
);
}
inline void emPainter::PaintImage(
double x, double y, double w, double h, const emImage & img,
int alpha, emColor canvasColor, emTexture::ExtensionType extension
) const
{
PaintRect(
x,y,w,h,
emImageTexture(x,y,w,h,img,alpha,extension),
canvasColor
);
}
inline void emPainter::PaintImage(
double x, double y, double w, double h, const emImage & img, int srcX,
int srcY, int srcW, int srcH, int alpha, emColor canvasColor,
emTexture::ExtensionType extension
) const
{
PaintRect(
x,y,w,h,
emImageTexture(x,y,w,h,img,srcX,srcY,srcW,srcH,alpha,extension),
canvasColor
);
}
inline void emPainter::PaintImageColored(
double x, double y, double w, double h, const emImage & img,
emColor color1, emColor color2, emColor canvasColor,
emTexture::ExtensionType extension
) const
{
PaintRect(
x,y,w,h,
emImageColoredTexture(x,y,w,h,img,color1,color2,extension),
canvasColor
);
}
inline void emPainter::PaintImageColored(
double x, double y, double w, double h, const emImage & img,
int srcX, int srcY, int srcW, int srcH,
emColor color1, emColor color2, emColor canvasColor,
emTexture::ExtensionType extension
) const
{
PaintRect(
x,y,w,h,
emImageColoredTexture(x,y,w,h,img,srcX,srcY,srcW,srcH,
color1,color2,extension),
canvasColor
);
}
inline void emPainter::PaintBorderImage(
double x, double y, double w, double h, double l, double t, double r,
double b, const emImage & img, int srcL, int srcT, int srcR, int 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
);
}
inline void emPainter::PaintBorderImageColored(
double x, double y, double w, double h, double l, double t, double r,
double b, const emImage & img, int srcL, int srcT, int srcR, int srcB,
emColor color1, emColor color2, emColor canvasColor, int whichSubRects
) const
{
PaintBorderImageColored(
x,y,w,h,l,t,r,b,img,0,0,img.GetWidth(),img.GetHeight(),
srcL,srcT,srcR,srcB,color1,color2,canvasColor,whichSubRects
);
}
inline void emPainter::PaintPolylineWithoutArrows(
const double xy[], int n, double thickness, const emStroke & stroke,
const emStrokeEnd & strokeStart, const emStrokeEnd & strokeEnd,
emColor canvasColor
) const
{
if (stroke.DashType!=emStroke::SOLID) {
PaintDashedPolyline(xy,n,thickness,stroke,strokeStart,strokeEnd,canvasColor);
}
else {
PaintSolidPolyline(xy,n,thickness,stroke,strokeStart,strokeEnd,canvasColor);
}
}
#endif