1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
13 #include "gfxMatrix.h"
14 #include "gfxPattern.h"
17 #include "mozilla/EnumSet.h"
18 #include "mozilla/gfx/2D.h"
20 typedef struct _cairo cairo_t
;
21 class GlyphBufferAzure
;
25 struct RectCornerRadii
;
30 } // namespace mozilla
35 * This is the main class for doing actual drawing. It is initialized using
36 * a surface and can be drawn on. It manages various state information like
37 * a current transformation matrix (CTM), a current path, current color,
40 * All drawing happens by creating a path and then stroking or filling it.
41 * The functions like Rectangle and Arc do not do any drawing themselves.
42 * When a path is drawn (stroked or filled), it is filled/stroked with a
43 * pattern set by SetPattern or SetColor.
45 * Note that the gfxContext takes coordinates in device pixels,
46 * as opposed to app units.
48 class gfxContext final
{
49 typedef mozilla::gfx::CapStyle CapStyle
;
50 typedef mozilla::gfx::CompositionOp CompositionOp
;
51 typedef mozilla::gfx::JoinStyle JoinStyle
;
52 typedef mozilla::gfx::FillRule FillRule
;
53 typedef mozilla::gfx::Float Float
;
54 typedef mozilla::gfx::Path Path
;
55 typedef mozilla::gfx::Pattern Pattern
;
56 typedef mozilla::gfx::Rect Rect
;
57 typedef mozilla::gfx::RectCornerRadii RectCornerRadii
;
58 typedef mozilla::gfx::Size Size
;
60 NS_INLINE_DECL_REFCOUNTING(gfxContext
)
64 * Initialize this context from a DrawTarget.
65 * Strips any transform from aTarget.
66 * aTarget will be flushed in the gfxContext's destructor.
67 * If aTarget is null or invalid, nullptr is returned. The caller
68 * is responsible for handling this scenario as appropriate.
70 static already_AddRefed
<gfxContext
> CreateOrNull(
71 mozilla::gfx::DrawTarget
* aTarget
,
72 const mozilla::gfx::Point
& aDeviceOffset
= mozilla::gfx::Point());
75 * Create a new gfxContext wrapping aTarget and preserving aTarget's
76 * transform. Note that the transform is moved from aTarget to the resulting
77 * gfxContext, aTarget will no longer have its transform.
78 * If aTarget is null or invalid, nullptr is returned. The caller
79 * is responsible for handling this scenario as appropriate.
81 static already_AddRefed
<gfxContext
> CreatePreservingTransformOrNull(
82 mozilla::gfx::DrawTarget
* aTarget
);
84 mozilla::gfx::DrawTarget
* GetDrawTarget() { return mDT
; }
87 * Returns the DrawTarget if it's actually a TextDrawTarget.
89 mozilla::layout::TextDrawTarget
* GetTextDrawer();
94 // XXX document exactly what bits are saved
103 * Fill the current path according to the current settings.
105 * Does not consume the current path.
108 void Fill(const Pattern
& aPattern
);
111 * Forgets the current path.
116 * Closes the path, i.e. connects the last drawn point to the first one.
118 * Filling a path will implicitly close it.
123 * Returns the current path.
125 already_AddRefed
<Path
> GetPath();
128 * Sets the given path as the current path.
130 void SetPath(Path
* path
);
133 * Moves the pen to a new point without drawing a line.
135 void MoveTo(const gfxPoint
& pt
);
138 * Draws a line from the current point to pt.
142 void LineTo(const gfxPoint
& pt
);
146 * Draws a line from start to end.
148 void Line(const gfxPoint
& start
,
149 const gfxPoint
& end
); // XXX snapToPixels option?
152 * Draws the rectangle given by rect.
154 void Rectangle(const gfxRect
& rect
) { return Rectangle(rect
, false); }
155 void SnappedRectangle(const gfxRect
& rect
) { return Rectangle(rect
, true); }
158 void Rectangle(const gfxRect
& rect
, bool snapToPixels
);
162 ** Transformation Matrix manipulation
166 * Post-multiplies 'other' onto the current CTM, i.e. this
167 * matrix's transformation will take place before the previously set
170 void Multiply(const gfxMatrix
& other
);
171 void Multiply(const mozilla::gfx::Matrix
& other
);
174 * Replaces the current transformation matrix with matrix.
176 void SetMatrix(const mozilla::gfx::Matrix
& matrix
);
177 void SetMatrixDouble(const gfxMatrix
& matrix
);
180 * Returns the current transformation matrix.
182 mozilla::gfx::Matrix
CurrentMatrix() const;
183 gfxMatrix
CurrentMatrixDouble() const;
186 * Converts a point from device to user coordinates using the inverse
187 * transformation matrix.
189 gfxPoint
DeviceToUser(const gfxPoint
& point
) const;
192 * Converts a size from device to user coordinates. This does not apply
193 * translation components of the matrix.
195 Size
DeviceToUser(const Size
& size
) const;
198 * Converts a rectangle from device to user coordinates; this has the
199 * same effect as using DeviceToUser on both the rectangle's point and
202 gfxRect
DeviceToUser(const gfxRect
& rect
) const;
205 * Converts a point from user to device coordinates using the transformation
208 gfxPoint
UserToDevice(const gfxPoint
& point
) const;
211 * Converts a size from user to device coordinates. This does not apply
212 * translation components of the matrix.
214 Size
UserToDevice(const Size
& size
) const;
217 * Converts a rectangle from user to device coordinates. The
218 * resulting rectangle is the minimum device-space rectangle that
219 * encloses the user-space rectangle given.
221 gfxRect
UserToDevice(const gfxRect
& rect
) const;
224 * Takes the given rect and tries to align it to device pixels. If
225 * this succeeds, the method will return true, and the rect will
226 * be in device coordinates (already transformed by the CTM). If it
227 * fails, the method will return false, and the rect will not be
230 * aOptions parameter:
231 * If IgnoreScale is set, then snapping will take place even if the CTM
232 * has a scale applied. Snapping never takes place if there is a rotation
235 * If PrioritizeSize is set, the rect's dimensions will first be snapped
236 * and then its position aligned to device pixels, rather than snapping
237 * the position of each edge independently.
239 enum class SnapOption
: uint8_t {
243 using SnapOptions
= mozilla::EnumSet
<SnapOption
>;
244 bool UserToDevicePixelSnapped(gfxRect
& rect
, SnapOptions aOptions
= {}) const;
247 * Takes the given point and tries to align it to device pixels. If
248 * this succeeds, the method will return true, and the point will
249 * be in device coordinates (already transformed by the CTM). If it
250 * fails, the method will return false, and the point will not be
253 * If ignoreScale is true, then snapping will take place even if
254 * the CTM has a scale applied. Snapping never takes place if
255 * there is a rotation in the CTM.
257 bool UserToDevicePixelSnapped(gfxPoint
& pt
, bool ignoreScale
= false) const;
264 * Set a solid color to use for drawing. This color is in the device color
265 * space and is not transformed.
267 void SetDeviceColor(const mozilla::gfx::DeviceColor
& aColor
);
270 * Gets the current color. It's returned in the device color space.
271 * returns false if there is something other than a color
272 * set as the current source (pattern, surface, etc)
274 bool GetDeviceColor(mozilla::gfx::DeviceColor
& aColorOut
);
277 * Returns true if color is neither opaque nor transparent (i.e. alpha is not
278 * 0 or 1), and false otherwise. If true, aColorOut is set on output.
280 bool HasNonOpaqueNonTransparentColor(mozilla::gfx::DeviceColor
& aColorOut
) {
281 return GetDeviceColor(aColorOut
) && 0.f
< aColorOut
.a
&& aColorOut
.a
< 1.f
;
285 * Set a solid color in the sRGB color space to use for drawing.
286 * If CMS is not enabled, the color is treated as a device-space color
287 * and this call is identical to SetDeviceColor().
289 void SetColor(const mozilla::gfx::sRGBColor
& aColor
);
292 * Uses a pattern for drawing.
294 void SetPattern(gfxPattern
* pattern
);
297 * Get the source pattern (solid color, normal pattern, surface, etc)
299 already_AddRefed
<gfxPattern
> GetPattern();
305 * Paints the current source surface/pattern everywhere in the current
308 void Paint(Float alpha
= 1.0);
311 ** Painting with a Mask
314 * Like Paint, except that it only draws the source where pattern is
317 void Mask(mozilla::gfx::SourceSurface
* aSurface
, mozilla::gfx::Float aAlpha
,
318 const mozilla::gfx::Matrix
& aTransform
);
319 void Mask(mozilla::gfx::SourceSurface
* aSurface
,
320 const mozilla::gfx::Matrix
& aTransform
) {
321 Mask(aSurface
, 1.0f
, aTransform
);
323 void Mask(mozilla::gfx::SourceSurface
* surface
, float alpha
= 1.0f
,
324 const mozilla::gfx::Point
& offset
= mozilla::gfx::Point());
330 void SetDash(const Float
* dashes
, int ndash
, Float offset
);
331 // Return true if dashing is set, false if it's not enabled or the
332 // context is in an error state. |offset| can be nullptr to mean
334 bool CurrentDash(FallibleTArray
<Float
>& dashes
, Float
* offset
) const;
337 * Sets the line width that's used for line drawing.
339 void SetLineWidth(Float width
);
342 * Returns the currently set line width.
346 Float
CurrentLineWidth() const;
349 * Sets the line caps, i.e. how line endings are drawn.
351 void SetLineCap(CapStyle cap
);
352 CapStyle
CurrentLineCap() const;
355 * Sets the line join, i.e. how the connection between two lines is
358 void SetLineJoin(JoinStyle join
);
359 JoinStyle
CurrentLineJoin() const;
361 void SetMiterLimit(Float limit
);
362 Float
CurrentMiterLimit() const;
365 * Sets the operator used for all further drawing. The operator affects
366 * how drawing something will modify the destination. For example, the
367 * OVER operator will do alpha blending of source and destination, while
368 * SOURCE will replace the destination with the source.
370 void SetOp(CompositionOp op
);
371 CompositionOp
CurrentOp() const;
373 void SetAntialiasMode(mozilla::gfx::AntialiasMode mode
);
374 mozilla::gfx::AntialiasMode
CurrentAntialiasMode() const;
381 * Clips all further drawing to the current path.
382 * This does not consume the current path.
387 * Helper functions that will create a rect path and call Clip().
388 * Any current path will be destroyed by these functions!
390 void Clip(const Rect
& rect
);
391 void Clip(const gfxRect
& rect
); // will clip to a rect
392 void SnappedClip(const gfxRect
& rect
); // snap rect and clip to the result
393 void Clip(Path
* aPath
);
397 enum ClipExtentsSpace
{
403 * According to aSpace, this function will return the current bounds of
404 * the clip region in user space or device space.
406 gfxRect
GetClipExtents(ClipExtentsSpace aSpace
= eUserSpace
) const;
409 * Returns true if the given rectangle is fully contained in the current clip.
410 * This is conservative; it may return false even when the given rectangle is
411 * fully contained by the current clip.
413 bool ClipContainsRect(const gfxRect
& aRect
);
416 * Exports the current clip using the provided exporter.
418 bool ExportClip(ClipExporter
& aExporter
);
423 void PushGroupForBlendBack(
424 gfxContentType content
, mozilla::gfx::Float aOpacity
= 1.0f
,
425 mozilla::gfx::SourceSurface
* aMask
= nullptr,
426 const mozilla::gfx::Matrix
& aMaskTransform
= mozilla::gfx::Matrix());
428 void PopGroupAndBlend();
430 mozilla::gfx::Point
GetDeviceOffset() const;
431 void SetDeviceOffset(const mozilla::gfx::Point
& aOffset
);
433 #ifdef MOZ_DUMP_PAINTING
435 * Debug functions to encode the current surface as a PNG and export it.
439 * Writes a binary PNG file.
441 void WriteAsPNG(const char* aFile
);
444 * Write as a PNG encoded Data URL to stdout.
446 void DumpAsDataURI();
449 * Copy a PNG encoded Data URL to the clipboard.
451 void CopyAsDataURI();
456 * Initialize this context from a DrawTarget.
457 * Strips any transform from aTarget.
458 * aTarget will be flushed in the gfxContext's destructor. Use the static
459 * ContextForDrawTargetNoTransform() when you want this behavior, as that
460 * version deals with null DrawTarget better.
463 mozilla::gfx::DrawTarget
* aTarget
,
464 const mozilla::gfx::Point
& aDeviceOffset
= mozilla::gfx::Point());
467 friend class PatternFromState
;
468 friend class GlyphBufferAzure
;
470 typedef mozilla::gfx::Matrix Matrix
;
471 typedef mozilla::gfx::DrawTarget DrawTarget
;
472 typedef mozilla::gfx::sRGBColor sRGBColor
;
473 typedef mozilla::gfx::DeviceColor DeviceColor
;
474 typedef mozilla::gfx::StrokeOptions StrokeOptions
;
475 typedef mozilla::gfx::PathBuilder PathBuilder
;
476 typedef mozilla::gfx::SourceSurface SourceSurface
;
480 : op(mozilla::gfx::CompositionOp::OP_OVER
),
481 color(0, 0, 0, 1.0f
),
482 aaMode(mozilla::gfx::AntialiasMode::SUBPIXEL
),
483 patternTransformChanged(false)
486 mContentChanged(false)
491 mozilla::gfx::CompositionOp op
;
493 RefPtr
<gfxPattern
> pattern
;
500 CopyableTArray
<PushedClip
> pushedClips
;
501 CopyableTArray
<Float
> dashPattern
;
502 StrokeOptions strokeOptions
;
503 RefPtr
<DrawTarget
> drawTarget
;
504 mozilla::gfx::AntialiasMode aaMode
;
505 bool patternTransformChanged
;
506 Matrix patternTransform
;
507 DeviceColor fontSmoothingBackgroundColor
;
508 // This is used solely for using minimal intermediate surface size.
509 mozilla::gfx::Point deviceOffset
;
511 // Whether the content of this AzureState changed after construction.
512 bool mContentChanged
;
516 // This ensures mPath contains a valid path (in user space!)
518 // This ensures mPathBuilder contains a valid PathBuilder (in user space!)
519 void EnsurePathBuilder();
520 CompositionOp
GetOp();
521 void ChangeTransform(const mozilla::gfx::Matrix
& aNewMatrix
,
522 bool aUpdatePatternTransform
= true);
523 Rect
GetAzureDeviceSpaceClipBounds() const;
524 Matrix
GetDTTransform() const;
527 bool mTransformChanged
;
528 Matrix mPathTransform
;
530 RefPtr
<PathBuilder
> mPathBuilder
;
533 nsTArray
<AzureState
> mStateStack
;
535 AzureState
& CurrentState() { return mStateStack
[mStateStack
.Length() - 1]; }
536 const AzureState
& CurrentState() const {
537 return mStateStack
[mStateStack
.Length() - 1];
540 RefPtr
<DrawTarget
> mDT
;
544 * Sentry helper class for functions with multiple return points that need to
545 * call Save() on a gfxContext and have Restore() called automatically on the
546 * gfxContext before they return.
548 class gfxContextAutoSaveRestore
{
550 gfxContextAutoSaveRestore() : mContext(nullptr) {}
552 explicit gfxContextAutoSaveRestore(gfxContext
* aContext
)
553 : mContext(aContext
) {
557 ~gfxContextAutoSaveRestore() { Restore(); }
559 void SetContext(gfxContext
* aContext
) {
560 NS_ASSERTION(!mContext
, "Not going to call Restore() on some context!!!");
565 void EnsureSaved(gfxContext
* aContext
) {
566 MOZ_ASSERT(!mContext
|| mContext
== aContext
, "wrong context");
581 gfxContext
* mContext
;
585 * Sentry helper class for functions with multiple return points that need to
586 * back up the current matrix of a context and have it automatically restored
587 * before they return.
589 class gfxContextMatrixAutoSaveRestore
{
591 gfxContextMatrixAutoSaveRestore() : mContext(nullptr) {}
593 explicit gfxContextMatrixAutoSaveRestore(gfxContext
* aContext
)
594 : mContext(aContext
), mMatrix(aContext
->CurrentMatrix()) {}
596 ~gfxContextMatrixAutoSaveRestore() {
598 mContext
->SetMatrix(mMatrix
);
602 void SetContext(gfxContext
* aContext
) {
603 NS_ASSERTION(!mContext
, "Not going to restore the matrix on some context!");
605 mMatrix
= aContext
->CurrentMatrix();
610 mContext
->SetMatrix(mMatrix
);
615 const mozilla::gfx::Matrix
& Matrix() {
616 MOZ_ASSERT(mContext
, "mMatrix doesn't contain a useful matrix");
620 bool HasMatrix() const { return !!mContext
; }
623 gfxContext
* mContext
;
624 mozilla::gfx::Matrix mMatrix
;
627 class DrawTargetAutoDisableSubpixelAntialiasing
{
629 typedef mozilla::gfx::DrawTarget DrawTarget
;
631 DrawTargetAutoDisableSubpixelAntialiasing(DrawTarget
* aDT
, bool aDisable
)
632 : mSubpixelAntialiasingEnabled(false) {
635 mSubpixelAntialiasingEnabled
= mDT
->GetPermitSubpixelAA();
636 mDT
->SetPermitSubpixelAA(false);
639 ~DrawTargetAutoDisableSubpixelAntialiasing() {
641 mDT
->SetPermitSubpixelAA(mSubpixelAntialiasingEnabled
);
646 RefPtr
<DrawTarget
> mDT
;
647 bool mSubpixelAntialiasingEnabled
;
650 /* This class lives on the stack and allows gfxContext users to easily, and
651 * performantly get a gfx::Pattern to use for drawing in their current context.
653 class PatternFromState
{
655 explicit PatternFromState(gfxContext
* aContext
)
656 : mContext(aContext
), mPattern(nullptr) {}
657 ~PatternFromState() {
659 mPattern
->~Pattern();
663 operator mozilla::gfx::Pattern
&();
667 mozilla::AlignedStorage2
<mozilla::gfx::ColorPattern
> mColorPattern
;
668 mozilla::AlignedStorage2
<mozilla::gfx::SurfacePattern
> mSurfacePattern
;
671 gfxContext
* mContext
;
672 mozilla::gfx::Pattern
* mPattern
;
675 /* This interface should be implemented to handle exporting the clip from a
678 class ClipExporter
: public mozilla::gfx::PathSink
{
680 virtual void BeginClip(const mozilla::gfx::Matrix
& aMatrix
) = 0;
681 virtual void EndClip() = 0;
684 #endif /* GFX_CONTEXT_H */