michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef GFX_CONTEXT_H michael@0: #define GFX_CONTEXT_H michael@0: michael@0: #include "gfxTypes.h" michael@0: michael@0: #include "gfxASurface.h" michael@0: #include "gfxPoint.h" michael@0: #include "gfxRect.h" michael@0: #include "gfxMatrix.h" michael@0: #include "gfxPattern.h" michael@0: #include "gfxPath.h" michael@0: #include "nsTArray.h" michael@0: #include "nsAutoPtr.h" michael@0: michael@0: #include "mozilla/gfx/2D.h" michael@0: michael@0: typedef struct _cairo cairo_t; michael@0: struct GlyphBufferAzure; michael@0: template class FallibleTArray; michael@0: michael@0: /** michael@0: * This is the main class for doing actual drawing. It is initialized using michael@0: * a surface and can be drawn on. It manages various state information like michael@0: * a current transformation matrix (CTM), a current path, current color, michael@0: * etc. michael@0: * michael@0: * All drawing happens by creating a path and then stroking or filling it. michael@0: * The functions like Rectangle and Arc do not do any drawing themselves. michael@0: * When a path is drawn (stroked or filled), it is filled/stroked with a michael@0: * pattern set by SetPattern, SetColor or SetSource. michael@0: * michael@0: * Note that the gfxContext takes coordinates in device pixels, michael@0: * as opposed to app units. michael@0: */ michael@0: class gfxContext { michael@0: NS_INLINE_DECL_REFCOUNTING(gfxContext) michael@0: michael@0: public: michael@0: /** michael@0: * Initialize this context from a surface. michael@0: */ michael@0: gfxContext(gfxASurface *surface); michael@0: michael@0: /** michael@0: * Initialize this context from a DrawTarget. michael@0: * Strips any transform from aTarget. michael@0: * aTarget will be flushed in the gfxContext's destructor. michael@0: */ michael@0: gfxContext(mozilla::gfx::DrawTarget *aTarget, michael@0: const mozilla::gfx::Point& aDeviceOffset = mozilla::gfx::Point()); michael@0: michael@0: ~gfxContext(); michael@0: michael@0: /** michael@0: * Create a new gfxContext wrapping aTarget and preserving aTarget's michael@0: * transform. Note that the transform is moved from aTarget to the resulting michael@0: * gfxContext, aTarget will no longer have its transform. michael@0: */ michael@0: static already_AddRefed ContextForDrawTarget(mozilla::gfx::DrawTarget* aTarget); michael@0: michael@0: /** michael@0: * Return the surface that this gfxContext was created with michael@0: */ michael@0: gfxASurface *OriginalSurface(); michael@0: michael@0: /** michael@0: * Return the current transparency group target, if any, along michael@0: * with its device offsets from the top. If no group is michael@0: * active, returns the surface the gfxContext was created with, michael@0: * and 0,0 in dx,dy. michael@0: */ michael@0: already_AddRefed CurrentSurface(gfxFloat *dx, gfxFloat *dy); michael@0: already_AddRefed CurrentSurface() { michael@0: return CurrentSurface(nullptr, nullptr); michael@0: } michael@0: michael@0: /** michael@0: * Return the raw cairo_t object. michael@0: * XXX this should go away at some point. michael@0: */ michael@0: cairo_t *GetCairo(); michael@0: michael@0: mozilla::gfx::DrawTarget *GetDrawTarget() { return mDT; } michael@0: michael@0: /** michael@0: * Returns true if the cairo context is in an error state. michael@0: */ michael@0: bool HasError(); michael@0: michael@0: /** michael@0: ** State michael@0: **/ michael@0: // XXX document exactly what bits are saved michael@0: void Save(); michael@0: void Restore(); michael@0: michael@0: /** michael@0: ** Paths & Drawing michael@0: **/ michael@0: michael@0: /** michael@0: * Stroke the current path using the current settings (such as line michael@0: * width and color). michael@0: * A path is set up using functions such as Line, Rectangle and Arc. michael@0: * michael@0: * Does not consume the current path. michael@0: */ michael@0: void Stroke(); michael@0: /** michael@0: * Fill the current path according to the current settings. michael@0: * michael@0: * Does not consume the current path. michael@0: */ michael@0: void Fill(); michael@0: michael@0: /** michael@0: * Fill the current path according to the current settings and michael@0: * with |aOpacity|. michael@0: * michael@0: * Does not consume the current path. michael@0: */ michael@0: void FillWithOpacity(gfxFloat aOpacity); michael@0: michael@0: /** michael@0: * Forgets the current path. michael@0: */ michael@0: void NewPath(); michael@0: michael@0: /** michael@0: * Closes the path, i.e. connects the last drawn point to the first one. michael@0: * michael@0: * Filling a path will implicitly close it. michael@0: */ michael@0: void ClosePath(); michael@0: michael@0: /** michael@0: * Copies the current path and returns the copy. michael@0: */ michael@0: already_AddRefed CopyPath(); michael@0: michael@0: /** michael@0: * Appends the given path to the current path. michael@0: */ michael@0: void SetPath(gfxPath* path); michael@0: michael@0: /** michael@0: * Moves the pen to a new point without drawing a line. michael@0: */ michael@0: void MoveTo(const gfxPoint& pt); michael@0: michael@0: /** michael@0: * Creates a new subpath starting at the current point. michael@0: * Equivalent to MoveTo(CurrentPoint()). michael@0: */ michael@0: void NewSubPath(); michael@0: michael@0: /** michael@0: * Returns the current point in the current path. michael@0: */ michael@0: gfxPoint CurrentPoint(); michael@0: michael@0: /** michael@0: * Draws a line from the current point to pt. michael@0: * michael@0: * @see MoveTo michael@0: */ michael@0: void LineTo(const gfxPoint& pt); michael@0: michael@0: /** michael@0: * Draws a cubic Bézier curve with control points pt1, pt2 and pt3. michael@0: */ michael@0: void CurveTo(const gfxPoint& pt1, const gfxPoint& pt2, const gfxPoint& pt3); michael@0: michael@0: /** michael@0: * Draws a quadratic Bézier curve with control points pt1, pt2 and pt3. michael@0: */ michael@0: void QuadraticCurveTo(const gfxPoint& pt1, const gfxPoint& pt2); michael@0: michael@0: /** michael@0: * Draws a clockwise arc (i.e. a circle segment). michael@0: * @param center The center of the circle michael@0: * @param radius The radius of the circle michael@0: * @param angle1 Starting angle for the segment michael@0: * @param angle2 Ending angle michael@0: */ michael@0: void Arc(const gfxPoint& center, gfxFloat radius, michael@0: gfxFloat angle1, gfxFloat angle2); michael@0: michael@0: /** michael@0: * Draws a counter-clockwise arc (i.e. a circle segment). michael@0: * @param center The center of the circle michael@0: * @param radius The radius of the circle michael@0: * @param angle1 Starting angle for the segment michael@0: * @param angle2 Ending angle michael@0: */ michael@0: michael@0: void NegativeArc(const gfxPoint& center, gfxFloat radius, michael@0: gfxFloat angle1, gfxFloat angle2); michael@0: michael@0: // path helpers michael@0: /** michael@0: * Draws a line from start to end. michael@0: */ michael@0: void Line(const gfxPoint& start, const gfxPoint& end); // XXX snapToPixels option? michael@0: michael@0: /** michael@0: * Draws the rectangle given by rect. michael@0: * @param snapToPixels ? michael@0: */ michael@0: void Rectangle(const gfxRect& rect, bool snapToPixels = false); michael@0: void SnappedRectangle(const gfxRect& rect) { return Rectangle(rect, true); } michael@0: michael@0: /** michael@0: * Draw an ellipse at the center corner with the given dimensions. michael@0: * It extends dimensions.width / 2.0 in the horizontal direction michael@0: * from the center, and dimensions.height / 2.0 in the vertical michael@0: * direction. michael@0: */ michael@0: void Ellipse(const gfxPoint& center, const gfxSize& dimensions); michael@0: michael@0: /** michael@0: * Draw a polygon from the given points michael@0: */ michael@0: void Polygon(const gfxPoint *points, uint32_t numPoints); michael@0: michael@0: /* michael@0: * Draw a rounded rectangle, with the given outer rect and michael@0: * corners. The corners specify the radii of the two axes of an michael@0: * ellipse (the horizontal and vertical directions given by the michael@0: * width and height, respectively). By default the ellipse is michael@0: * drawn in a clockwise direction; if draw_clockwise is false, michael@0: * then it's drawn counterclockwise. michael@0: */ michael@0: void RoundedRectangle(const gfxRect& rect, michael@0: const gfxCornerSizes& corners, michael@0: bool draw_clockwise = true); michael@0: michael@0: /** michael@0: ** Transformation Matrix manipulation michael@0: **/ michael@0: michael@0: /** michael@0: * Adds a translation to the current matrix. This translation takes place michael@0: * before the previously set transformations. michael@0: */ michael@0: void Translate(const gfxPoint& pt); michael@0: michael@0: /** michael@0: * Adds a scale to the current matrix. This scaling takes place before the michael@0: * previously set transformations. michael@0: */ michael@0: void Scale(gfxFloat x, gfxFloat y); michael@0: michael@0: /** michael@0: * Adds a rotation around the origin to the current matrix. This rotation michael@0: * takes place before the previously set transformations. michael@0: * michael@0: * @param angle The angle in radians. michael@0: */ michael@0: void Rotate(gfxFloat angle); michael@0: michael@0: /** michael@0: * Post-multiplies 'other' onto the current CTM, i.e. this michael@0: * matrix's transformation will take place before the previously set michael@0: * transformations. michael@0: */ michael@0: void Multiply(const gfxMatrix& other); michael@0: /** michael@0: * As "Multiply", but also nudges any entries in the resulting matrix that michael@0: * are close to an integer to that integer, to correct for michael@0: * compounded rounding errors. michael@0: */ michael@0: void MultiplyAndNudgeToIntegers(const gfxMatrix& other); michael@0: michael@0: /** michael@0: * Replaces the current transformation matrix with matrix. michael@0: */ michael@0: void SetMatrix(const gfxMatrix& matrix); michael@0: michael@0: /** michael@0: * Sets the transformation matrix to the identity matrix. michael@0: */ michael@0: void IdentityMatrix(); michael@0: michael@0: /** michael@0: * Returns the current transformation matrix. michael@0: */ michael@0: gfxMatrix CurrentMatrix() const; michael@0: michael@0: /** michael@0: * Snap components of the current matrix that are close to integers michael@0: * to integers. In particular, components that are integral when michael@0: * converted to single precision are set to those integers. michael@0: */ michael@0: void NudgeCurrentMatrixToIntegers(); michael@0: michael@0: /** michael@0: * Converts a point from device to user coordinates using the inverse michael@0: * transformation matrix. michael@0: */ michael@0: gfxPoint DeviceToUser(const gfxPoint& point) const; michael@0: michael@0: /** michael@0: * Converts a size from device to user coordinates. This does not apply michael@0: * translation components of the matrix. michael@0: */ michael@0: gfxSize DeviceToUser(const gfxSize& size) const; michael@0: michael@0: /** michael@0: * Converts a rectangle from device to user coordinates; this has the michael@0: * same effect as using DeviceToUser on both the rectangle's point and michael@0: * size. michael@0: */ michael@0: gfxRect DeviceToUser(const gfxRect& rect) const; michael@0: michael@0: /** michael@0: * Converts a point from user to device coordinates using the transformation michael@0: * matrix. michael@0: */ michael@0: gfxPoint UserToDevice(const gfxPoint& point) const; michael@0: michael@0: /** michael@0: * Converts a size from user to device coordinates. This does not apply michael@0: * translation components of the matrix. michael@0: */ michael@0: gfxSize UserToDevice(const gfxSize& size) const; michael@0: michael@0: /** michael@0: * Converts a rectangle from user to device coordinates. The michael@0: * resulting rectangle is the minimum device-space rectangle that michael@0: * encloses the user-space rectangle given. michael@0: */ michael@0: gfxRect UserToDevice(const gfxRect& rect) const; michael@0: michael@0: /** michael@0: * Takes the given rect and tries to align it to device pixels. If michael@0: * this succeeds, the method will return true, and the rect will michael@0: * be in device coordinates (already transformed by the CTM). If it michael@0: * fails, the method will return false, and the rect will not be michael@0: * changed. michael@0: * michael@0: * If ignoreScale is true, then snapping will take place even if michael@0: * the CTM has a scale applied. Snapping never takes place if michael@0: * there is a rotation in the CTM. michael@0: */ michael@0: bool UserToDevicePixelSnapped(gfxRect& rect, bool ignoreScale = false) const; michael@0: michael@0: /** michael@0: * Takes the given point and tries to align it to device pixels. If michael@0: * this succeeds, the method will return true, and the point will michael@0: * be in device coordinates (already transformed by the CTM). If it michael@0: * fails, the method will return false, and the point will not be michael@0: * changed. michael@0: * michael@0: * If ignoreScale is true, then snapping will take place even if michael@0: * the CTM has a scale applied. Snapping never takes place if michael@0: * there is a rotation in the CTM. michael@0: */ michael@0: bool UserToDevicePixelSnapped(gfxPoint& pt, bool ignoreScale = false) const; michael@0: michael@0: /** michael@0: * Attempts to pixel snap the rectangle, add it to the current michael@0: * path, and to set pattern as the current painting source. This michael@0: * should be used for drawing filled pixel-snapped rectangles (like michael@0: * images), because the CTM at the time of the SetPattern call needs michael@0: * to have a snapped translation, or you get smeared images. michael@0: */ michael@0: void PixelSnappedRectangleAndSetPattern(const gfxRect& rect, gfxPattern *pattern); michael@0: michael@0: /** michael@0: ** Painting sources michael@0: **/ michael@0: michael@0: /** michael@0: * Set a solid color to use for drawing. This color is in the device color space michael@0: * and is not transformed. michael@0: */ michael@0: void SetDeviceColor(const gfxRGBA& c); michael@0: michael@0: /** michael@0: * Gets the current color. It's returned in the device color space. michael@0: * returns false if there is something other than a color michael@0: * set as the current source (pattern, surface, etc) michael@0: */ michael@0: bool GetDeviceColor(gfxRGBA& c); michael@0: michael@0: /** michael@0: * Set a solid color in the sRGB color space to use for drawing. michael@0: * If CMS is not enabled, the color is treated as a device-space color michael@0: * and this call is identical to SetDeviceColor(). michael@0: */ michael@0: void SetColor(const gfxRGBA& c); michael@0: michael@0: /** michael@0: * Uses a surface for drawing. This is a shorthand for creating a michael@0: * pattern and setting it. michael@0: * michael@0: * @param offset from the source surface, to use only part of it. michael@0: * May need to make it negative. michael@0: */ michael@0: void SetSource(gfxASurface *surface, const gfxPoint& offset = gfxPoint(0.0, 0.0)); michael@0: michael@0: /** michael@0: * Uses a pattern for drawing. michael@0: */ michael@0: void SetPattern(gfxPattern *pattern); michael@0: michael@0: /** michael@0: * Get the source pattern (solid color, normal pattern, surface, etc) michael@0: */ michael@0: already_AddRefed GetPattern(); michael@0: michael@0: /** michael@0: ** Painting michael@0: **/ michael@0: /** michael@0: * Paints the current source surface/pattern everywhere in the current michael@0: * clip region. michael@0: */ michael@0: void Paint(gfxFloat alpha = 1.0); michael@0: michael@0: /** michael@0: ** Painting with a Mask michael@0: **/ michael@0: /** michael@0: * Like Paint, except that it only draws the source where pattern is michael@0: * non-transparent. michael@0: */ michael@0: void Mask(gfxPattern *pattern); michael@0: michael@0: /** michael@0: * Shorthand for creating a pattern and calling the pattern-taking michael@0: * variant of Mask. michael@0: */ michael@0: void Mask(gfxASurface *surface, const gfxPoint& offset = gfxPoint(0.0, 0.0)); michael@0: michael@0: void Mask(mozilla::gfx::SourceSurface *surface, const mozilla::gfx::Point& offset = mozilla::gfx::Point()); michael@0: michael@0: /** michael@0: ** Shortcuts michael@0: **/ michael@0: michael@0: /** michael@0: * Creates a new path with a rectangle from 0,0 to size.w,size.h michael@0: * and calls cairo_fill. michael@0: */ michael@0: void DrawSurface(gfxASurface *surface, const gfxSize& size); michael@0: michael@0: /** michael@0: ** Line Properties michael@0: **/ michael@0: michael@0: typedef enum { michael@0: gfxLineSolid, michael@0: gfxLineDashed, michael@0: gfxLineDotted michael@0: } gfxLineType; michael@0: michael@0: void SetDash(gfxLineType ltype); michael@0: void SetDash(gfxFloat *dashes, int ndash, gfxFloat offset); michael@0: // Return true if dashing is set, false if it's not enabled or the michael@0: // context is in an error state. |offset| can be nullptr to mean michael@0: // "don't care". michael@0: bool CurrentDash(FallibleTArray& dashes, gfxFloat* offset) const; michael@0: // Returns 0.0 if dashing isn't enabled. michael@0: gfxFloat CurrentDashOffset() const; michael@0: michael@0: /** michael@0: * Sets the line width that's used for line drawing. michael@0: */ michael@0: void SetLineWidth(gfxFloat width); michael@0: michael@0: /** michael@0: * Returns the currently set line width. michael@0: * michael@0: * @see SetLineWidth michael@0: */ michael@0: gfxFloat CurrentLineWidth() const; michael@0: michael@0: enum GraphicsLineCap { michael@0: LINE_CAP_BUTT, michael@0: LINE_CAP_ROUND, michael@0: LINE_CAP_SQUARE michael@0: }; michael@0: /** michael@0: * Sets the line caps, i.e. how line endings are drawn. michael@0: */ michael@0: void SetLineCap(GraphicsLineCap cap); michael@0: GraphicsLineCap CurrentLineCap() const; michael@0: michael@0: enum GraphicsLineJoin { michael@0: LINE_JOIN_MITER, michael@0: LINE_JOIN_ROUND, michael@0: LINE_JOIN_BEVEL michael@0: }; michael@0: /** michael@0: * Sets the line join, i.e. how the connection between two lines is michael@0: * drawn. michael@0: */ michael@0: void SetLineJoin(GraphicsLineJoin join); michael@0: GraphicsLineJoin CurrentLineJoin() const; michael@0: michael@0: void SetMiterLimit(gfxFloat limit); michael@0: gfxFloat CurrentMiterLimit() const; michael@0: michael@0: /** michael@0: ** Fill Properties michael@0: **/ michael@0: michael@0: enum FillRule { michael@0: FILL_RULE_WINDING, michael@0: FILL_RULE_EVEN_ODD michael@0: }; michael@0: void SetFillRule(FillRule rule); michael@0: FillRule CurrentFillRule() const; michael@0: michael@0: /** michael@0: ** Operators and Rendering control michael@0: **/ michael@0: michael@0: // define enum for operators (clear, src, dst, etc) michael@0: enum GraphicsOperator { michael@0: OPERATOR_CLEAR, michael@0: OPERATOR_SOURCE, michael@0: michael@0: OPERATOR_OVER, michael@0: OPERATOR_IN, michael@0: OPERATOR_OUT, michael@0: OPERATOR_ATOP, michael@0: michael@0: OPERATOR_DEST, michael@0: OPERATOR_DEST_OVER, michael@0: OPERATOR_DEST_IN, michael@0: OPERATOR_DEST_OUT, michael@0: OPERATOR_DEST_ATOP, michael@0: michael@0: OPERATOR_XOR, michael@0: OPERATOR_ADD, michael@0: OPERATOR_SATURATE, michael@0: michael@0: OPERATOR_MULTIPLY, michael@0: OPERATOR_SCREEN, michael@0: OPERATOR_OVERLAY, michael@0: OPERATOR_DARKEN, michael@0: OPERATOR_LIGHTEN, michael@0: OPERATOR_COLOR_DODGE, michael@0: OPERATOR_COLOR_BURN, michael@0: OPERATOR_HARD_LIGHT, michael@0: OPERATOR_SOFT_LIGHT, michael@0: OPERATOR_DIFFERENCE, michael@0: OPERATOR_EXCLUSION, michael@0: OPERATOR_HUE, michael@0: OPERATOR_SATURATION, michael@0: OPERATOR_COLOR, michael@0: OPERATOR_LUMINOSITY michael@0: }; michael@0: /** michael@0: * Sets the operator used for all further drawing. The operator affects michael@0: * how drawing something will modify the destination. For example, the michael@0: * OVER operator will do alpha blending of source and destination, while michael@0: * SOURCE will replace the destination with the source. michael@0: * michael@0: * Note that if the flag FLAG_SIMPLIFY_OPERATORS is set on this michael@0: * gfxContext, the actual operator set might change for optimization michael@0: * purposes. Check the comments below around that flag. michael@0: */ michael@0: void SetOperator(GraphicsOperator op); michael@0: GraphicsOperator CurrentOperator() const; michael@0: michael@0: /** michael@0: * MODE_ALIASED means that only pixels whose centers are in the drawn area michael@0: * should be modified, and they should be modified to take the value drawn michael@0: * at the pixel center. michael@0: */ michael@0: enum AntialiasMode { michael@0: MODE_ALIASED, michael@0: MODE_COVERAGE michael@0: }; michael@0: void SetAntialiasMode(AntialiasMode mode); michael@0: AntialiasMode CurrentAntialiasMode() const; michael@0: michael@0: /** michael@0: ** Clipping michael@0: **/ michael@0: michael@0: /** michael@0: * Clips all further drawing to the current path. michael@0: * This does not consume the current path. michael@0: */ michael@0: void Clip(); michael@0: michael@0: /** michael@0: * Undoes any clipping. Further drawings will only be restricted by the michael@0: * surface dimensions. michael@0: */ michael@0: void ResetClip(); michael@0: michael@0: /** michael@0: * Helper functions that will create a rect path and call Clip(). michael@0: * Any current path will be destroyed by these functions! michael@0: */ michael@0: void Clip(const gfxRect& rect); // will clip to a rect michael@0: michael@0: /** michael@0: * This will ensure that the surface actually has its clip set. michael@0: * Useful if you are doing native drawing. michael@0: */ michael@0: void UpdateSurfaceClip(); michael@0: michael@0: /** michael@0: * This will return the current bounds of the clip region in user michael@0: * space. michael@0: */ michael@0: gfxRect GetClipExtents(); michael@0: michael@0: /** michael@0: * Returns true if the given rectangle is fully contained in the current clip. michael@0: * This is conservative; it may return false even when the given rectangle is michael@0: * fully contained by the current clip. michael@0: */ michael@0: bool ClipContainsRect(const gfxRect& aRect); michael@0: michael@0: /** michael@0: * Groups michael@0: */ michael@0: void PushGroup(gfxContentType content = gfxContentType::COLOR); michael@0: /** michael@0: * Like PushGroup, but if the current surface is gfxContentType::COLOR and michael@0: * content is gfxContentType::COLOR_ALPHA, makes the pushed surface gfxContentType::COLOR michael@0: * instead and copies the contents of the current surface to the pushed michael@0: * surface. This is good for pushing opacity groups, since blending the michael@0: * group back to the current surface with some alpha applied will give michael@0: * the correct results and using an opaque pushed surface gives better michael@0: * quality and performance. michael@0: * This API really only makes sense if you do a PopGroupToSource and michael@0: * immediate Paint with OPERATOR_OVER. michael@0: */ michael@0: void PushGroupAndCopyBackground(gfxContentType content = gfxContentType::COLOR); michael@0: already_AddRefed PopGroup(); michael@0: void PopGroupToSource(); michael@0: michael@0: /** michael@0: ** Hit Testing - check if given point is in the current path michael@0: **/ michael@0: bool PointInFill(const gfxPoint& pt); michael@0: bool PointInStroke(const gfxPoint& pt); michael@0: michael@0: /** michael@0: ** Extents - returns user space extent of current path michael@0: **/ michael@0: gfxRect GetUserPathExtent(); michael@0: gfxRect GetUserFillExtent(); michael@0: gfxRect GetUserStrokeExtent(); michael@0: michael@0: mozilla::gfx::Point GetDeviceOffset() const; michael@0: michael@0: /** michael@0: ** Flags michael@0: **/ michael@0: michael@0: enum { michael@0: /* If this flag is set, operators other than CLEAR, SOURCE, or michael@0: * OVER will be converted to OVER before being sent to cairo. michael@0: * michael@0: * This is most useful with a printing surface, where michael@0: * operators such as ADD are used to avoid seams for on-screen michael@0: * display, but where such errors aren't noticeable in print. michael@0: * This approach is currently used in border rendering. michael@0: * michael@0: * However, when printing complex renderings such as SVG, michael@0: * care should be taken to clear this flag. michael@0: */ michael@0: FLAG_SIMPLIFY_OPERATORS = (1 << 0), michael@0: /** michael@0: * When this flag is set, snapping to device pixels is disabled. michael@0: * It simply never does anything. michael@0: */ michael@0: FLAG_DISABLE_SNAPPING = (1 << 1), michael@0: /** michael@0: * Disable copying of backgrounds in PushGroupAndCopyBackground. michael@0: */ michael@0: FLAG_DISABLE_COPY_BACKGROUND = (1 << 2) michael@0: }; michael@0: michael@0: void SetFlag(int32_t aFlag) { mFlags |= aFlag; } michael@0: void ClearFlag(int32_t aFlag) { mFlags &= ~aFlag; } michael@0: int32_t GetFlags() const { return mFlags; } michael@0: michael@0: bool IsCairo() const { return !mDT; } michael@0: michael@0: // Work out whether cairo will snap inter-glyph spacing to pixels. michael@0: void GetRoundOffsetsToPixels(bool *aRoundX, bool *aRoundY); michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: /** michael@0: * Debug functions to encode the current surface as a PNG and export it. michael@0: */ michael@0: michael@0: /** michael@0: * Writes a binary PNG file. michael@0: */ michael@0: void WriteAsPNG(const char* aFile); michael@0: michael@0: /** michael@0: * Write as a PNG encoded Data URL to stdout. michael@0: */ michael@0: void DumpAsDataURL(); michael@0: michael@0: /** michael@0: * Copy a PNG encoded Data URL to the clipboard. michael@0: */ michael@0: void CopyAsDataURL(); michael@0: #endif michael@0: michael@0: static mozilla::gfx::UserDataKey sDontUseAsSourceKey; michael@0: michael@0: private: michael@0: friend class GeneralPattern; michael@0: friend struct GlyphBufferAzure; michael@0: michael@0: typedef mozilla::gfx::Matrix Matrix; michael@0: typedef mozilla::gfx::DrawTarget DrawTarget; michael@0: typedef mozilla::gfx::Color Color; michael@0: typedef mozilla::gfx::StrokeOptions StrokeOptions; michael@0: typedef mozilla::gfx::Float Float; michael@0: typedef mozilla::gfx::Rect Rect; michael@0: typedef mozilla::gfx::CompositionOp CompositionOp; michael@0: typedef mozilla::gfx::Path Path; michael@0: typedef mozilla::gfx::PathBuilder PathBuilder; michael@0: typedef mozilla::gfx::SourceSurface SourceSurface; michael@0: michael@0: struct AzureState { michael@0: AzureState() michael@0: : op(mozilla::gfx::CompositionOp::OP_OVER) michael@0: , opIsClear(false) michael@0: , color(0, 0, 0, 1.0f) michael@0: , clipWasReset(false) michael@0: , fillRule(mozilla::gfx::FillRule::FILL_WINDING) michael@0: , aaMode(mozilla::gfx::AntialiasMode::SUBPIXEL) michael@0: , patternTransformChanged(false) michael@0: {} michael@0: michael@0: mozilla::gfx::CompositionOp op; michael@0: bool opIsClear; michael@0: Color color; michael@0: nsRefPtr pattern; michael@0: nsRefPtr sourceSurfCairo; michael@0: mozilla::RefPtr sourceSurface; michael@0: mozilla::gfx::Point sourceSurfaceDeviceOffset; michael@0: Matrix surfTransform; michael@0: Matrix transform; michael@0: struct PushedClip { michael@0: mozilla::RefPtr path; michael@0: Rect rect; michael@0: Matrix transform; michael@0: }; michael@0: nsTArray pushedClips; michael@0: nsTArray dashPattern; michael@0: bool clipWasReset; michael@0: mozilla::gfx::FillRule fillRule; michael@0: StrokeOptions strokeOptions; michael@0: mozilla::RefPtr drawTarget; michael@0: mozilla::RefPtr parentTarget; michael@0: mozilla::gfx::AntialiasMode aaMode; michael@0: bool patternTransformChanged; michael@0: Matrix patternTransform; michael@0: // This is used solely for using minimal intermediate surface size. michael@0: mozilla::gfx::Point deviceOffset; michael@0: }; michael@0: michael@0: // This ensures mPath contains a valid path (in user space!) michael@0: void EnsurePath(); michael@0: // This ensures mPathBuilder contains a valid PathBuilder (in user space!) michael@0: void EnsurePathBuilder(); michael@0: void FillAzure(mozilla::gfx::Float aOpacity); michael@0: void PushClipsToDT(mozilla::gfx::DrawTarget *aDT); michael@0: CompositionOp GetOp(); michael@0: void ChangeTransform(const mozilla::gfx::Matrix &aNewMatrix, bool aUpdatePatternTransform = true); michael@0: Rect GetAzureDeviceSpaceClipBounds(); michael@0: Matrix GetDeviceTransform() const; michael@0: Matrix GetDTTransform() const; michael@0: void PushNewDT(gfxContentType content); michael@0: michael@0: bool mPathIsRect; michael@0: bool mTransformChanged; michael@0: Matrix mPathTransform; michael@0: Rect mRect; michael@0: mozilla::RefPtr mPathBuilder; michael@0: mozilla::RefPtr mPath; michael@0: Matrix mTransform; michael@0: nsTArray mStateStack; michael@0: michael@0: AzureState &CurrentState() { return mStateStack[mStateStack.Length() - 1]; } michael@0: const AzureState &CurrentState() const { return mStateStack[mStateStack.Length() - 1]; } michael@0: michael@0: cairo_t *mCairo; michael@0: cairo_t *mRefCairo; michael@0: nsRefPtr mSurface; michael@0: int32_t mFlags; michael@0: michael@0: mozilla::RefPtr mDT; michael@0: mozilla::RefPtr mOriginalDT; michael@0: }; michael@0: michael@0: /** michael@0: * Sentry helper class for functions with multiple return points that need to michael@0: * call Save() on a gfxContext and have Restore() called automatically on the michael@0: * gfxContext before they return. michael@0: */ michael@0: class gfxContextAutoSaveRestore michael@0: { michael@0: public: michael@0: gfxContextAutoSaveRestore() : mContext(nullptr) {} michael@0: michael@0: gfxContextAutoSaveRestore(gfxContext *aContext) : mContext(aContext) { michael@0: mContext->Save(); michael@0: } michael@0: michael@0: ~gfxContextAutoSaveRestore() { michael@0: if (mContext) { michael@0: mContext->Restore(); michael@0: } michael@0: } michael@0: michael@0: void SetContext(gfxContext *aContext) { michael@0: NS_ASSERTION(!mContext, "Not going to call Restore() on some context!!!"); michael@0: mContext = aContext; michael@0: mContext->Save(); michael@0: } michael@0: michael@0: void Reset(gfxContext *aContext) { michael@0: // Do the equivalent of destroying and re-creating this object. michael@0: NS_PRECONDITION(aContext, "must provide a context"); michael@0: if (mContext) { michael@0: mContext->Restore(); michael@0: } michael@0: mContext = aContext; michael@0: mContext->Save(); michael@0: } michael@0: michael@0: private: michael@0: gfxContext *mContext; michael@0: }; michael@0: michael@0: /** michael@0: * Sentry helper class for functions with multiple return points that need to michael@0: * back up the current path of a context and have it automatically restored michael@0: * before they return. This class assumes that the transformation matrix will michael@0: * be the same when Save and Restore are called. The calling function must michael@0: * ensure that this is the case or the path will be copied incorrectly. michael@0: */ michael@0: class gfxContextPathAutoSaveRestore michael@0: { michael@0: public: michael@0: gfxContextPathAutoSaveRestore() : mContext(nullptr) {} michael@0: michael@0: gfxContextPathAutoSaveRestore(gfxContext *aContext, bool aSave = true) : mContext(aContext) michael@0: { michael@0: if (aSave) michael@0: Save(); michael@0: } michael@0: michael@0: ~gfxContextPathAutoSaveRestore() michael@0: { michael@0: Restore(); michael@0: } michael@0: michael@0: void SetContext(gfxContext *aContext, bool aSave = true) michael@0: { michael@0: mContext = aContext; michael@0: if (aSave) michael@0: Save(); michael@0: } michael@0: michael@0: /** michael@0: * If a path is already saved, does nothing. Else copies the current path michael@0: * so that it may be restored. michael@0: */ michael@0: void Save() michael@0: { michael@0: if (!mPath && mContext) { michael@0: mPath = mContext->CopyPath(); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * If no path is saved, does nothing. Else replaces the context's path with michael@0: * a copy of the saved one, and clears the saved path. michael@0: */ michael@0: void Restore() michael@0: { michael@0: if (mPath) { michael@0: mContext->SetPath(mPath); michael@0: mPath = nullptr; michael@0: } michael@0: } michael@0: michael@0: private: michael@0: gfxContext *mContext; michael@0: michael@0: nsRefPtr mPath; michael@0: }; michael@0: michael@0: /** michael@0: * Sentry helper class for functions with multiple return points that need to michael@0: * back up the current matrix of a context and have it automatically restored michael@0: * before they return. michael@0: */ michael@0: class gfxContextMatrixAutoSaveRestore michael@0: { michael@0: public: michael@0: gfxContextMatrixAutoSaveRestore() : michael@0: mContext(nullptr) michael@0: { michael@0: } michael@0: michael@0: gfxContextMatrixAutoSaveRestore(gfxContext *aContext) : michael@0: mContext(aContext), mMatrix(aContext->CurrentMatrix()) michael@0: { michael@0: } michael@0: michael@0: ~gfxContextMatrixAutoSaveRestore() michael@0: { michael@0: if (mContext) { michael@0: mContext->SetMatrix(mMatrix); michael@0: } michael@0: } michael@0: michael@0: void SetContext(gfxContext *aContext) michael@0: { michael@0: NS_ASSERTION(!mContext, "Not going to restore the matrix on some context!"); michael@0: mContext = aContext; michael@0: mMatrix = aContext->CurrentMatrix(); michael@0: } michael@0: michael@0: void Restore() michael@0: { michael@0: if (mContext) { michael@0: mContext->SetMatrix(mMatrix); michael@0: } michael@0: } michael@0: michael@0: const gfxMatrix& Matrix() michael@0: { michael@0: MOZ_ASSERT(mContext, "mMatrix doesn't contain a useful matrix"); michael@0: return mMatrix; michael@0: } michael@0: michael@0: private: michael@0: gfxContext *mContext; michael@0: gfxMatrix mMatrix; michael@0: }; michael@0: michael@0: michael@0: class gfxContextAutoDisableSubpixelAntialiasing { michael@0: public: michael@0: gfxContextAutoDisableSubpixelAntialiasing(gfxContext *aContext, bool aDisable) michael@0: { michael@0: if (aDisable) { michael@0: if (aContext->IsCairo()) { michael@0: mSurface = aContext->CurrentSurface(); michael@0: if (!mSurface) { michael@0: return; michael@0: } michael@0: mSubpixelAntialiasingEnabled = mSurface->GetSubpixelAntialiasingEnabled(); michael@0: mSurface->SetSubpixelAntialiasingEnabled(false); michael@0: } else { michael@0: mDT = aContext->GetDrawTarget(); michael@0: michael@0: mSubpixelAntialiasingEnabled = mDT->GetPermitSubpixelAA(); michael@0: mDT->SetPermitSubpixelAA(false); michael@0: } michael@0: } michael@0: } michael@0: ~gfxContextAutoDisableSubpixelAntialiasing() michael@0: { michael@0: if (mSurface) { michael@0: mSurface->SetSubpixelAntialiasingEnabled(mSubpixelAntialiasingEnabled); michael@0: } else if (mDT) { michael@0: mDT->SetPermitSubpixelAA(mSubpixelAntialiasingEnabled); michael@0: } michael@0: } michael@0: michael@0: private: michael@0: nsRefPtr mSurface; michael@0: mozilla::RefPtr mDT; michael@0: bool mSubpixelAntialiasingEnabled; michael@0: }; michael@0: michael@0: #endif /* GFX_CONTEXT_H */