{-# LANGUAGE ScopedTypeVariables, MultiParamTypeClasses, FlexibleInstances, CPP #-} -- The following is all rather brittle: We need to pre-process this file with GHC -- in order to get the __GLASGOW_HASKELL__ macro (which we should replace with a -- version test of the array package). At the same time we need to version of -- Cairo and the macros for testing it. We sneakily get the version from the -- internal cairo-version.h file but we have to define the testing macros ourselves. #include<cairo-features.h> -- GTK-2.12 doesn't have cairo-version.h, but defines the appropriate VERSION -- variables in cairo-features.h instead. So only include this when necessary. #ifndef CAIRO_VERSION_MAJOR #include<cairo-version.h> #endif #define CAIRO_VERSION_ENCODE(major, minor, micro) ( \ ((major) * 10000) \ + ((minor) * 100) \ + ((micro) * 1)) #define CAIRO_VERSION CAIRO_VERSION_ENCODE( \ CAIRO_VERSION_MAJOR, \ CAIRO_VERSION_MINOR, \ CAIRO_VERSION_MICRO) #define CAIRO_CHECK_VERSION(major,minor,micro) \ (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(major,minor,micro)) ----------------------------------------------------------------------------- -- | -- Module : Graphics.Rendering.Cairo -- Copyright : (c) Paolo Martini 2005, (c) Abraham Egnor 2004, (c) Aetion Technologies LLC 2004 -- License : BSD-style (see cairo/COPYRIGHT) -- -- Maintainer : p.martini@neuralnoise.com -- Stability : experimental -- Portability : portable -- -- The Cairo 2D graphics library. -- -- Cairo is a 2D graphics library with support for multiple output devices. -- Currently supported output targets include the X Window System, win32, and -- image buffers. Experimental backends include OpenGL (through glitz), Quartz, -- XCB, PostScript and PDF file output. -- -- Cairo is designed to produce consistent output on all output media while -- taking advantage of display hardware acceleration when available (eg. -- through the X Render Extension). -- -- The cairo API provides operations similar to the drawing operators of -- PostScript and PDF. Operations in cairo including stroking and filling cubic -- Bezier splines, transforming and compositing translucent images, and -- antialiased text rendering. All drawing operations can be transformed by any -- affine transformation (scale, rotation, shear, etc.) -- -- Cairo is free software and is available to be redistributed and\/or modified -- under the terms of either the GNU Lesser General Public License (LGPL) -- version 2.1 or the Mozilla Public License (MPL) version 1.1. -- -- For more information see <http://cairographics.org> -- -- * Note the Haskell bindings do not support all the possible cairo backends -- because it would require bindings for the associated technology (eg X11, -- glitz, etc) however bindings to other backends may be implemented -- externally. For example, Gtk2Hs provides a binding to the backend for X11 -- (and win32 on Windows). ----------------------------------------------------------------------------- module Graphics.Rendering.Cairo ( -- * Drawing renderWith , save , restore , status , withTargetSurface , pushGroup , pushGroupWithContent , popGroupToSource , setSourceRGB , setSourceRGBA , setSource , setSourceSurface , getSource , setAntialias , setDash , setFillRule , getFillRule , setLineCap , getLineCap , setLineJoin , getLineJoin , setLineWidth , getLineWidth , setMiterLimit , getMiterLimit , setOperator , getOperator , setTolerance , getTolerance , clip , clipPreserve , resetClip , fill , fillPreserve , fillExtents , inFill , mask , maskSurface , paint , paintWithAlpha , stroke , strokePreserve , strokeExtents , inStroke , copyPage , showPage -- ** Paths , getCurrentPoint , newPath , closePath , arc , arcNegative , curveTo , lineTo , moveTo , rectangle , textPath , relCurveTo , relLineTo , relMoveTo -- ** Patterns , withRGBPattern , withRGBAPattern , withPatternForSurface , withGroupPattern , withLinearPattern , withRadialPattern , patternAddColorStopRGB , patternAddColorStopRGBA , patternSetMatrix , patternGetMatrix , patternSetExtend , patternGetExtend , patternSetFilter , patternGetFilter -- ** Transformations , translate , scale , rotate , transform , setMatrix , getMatrix , identityMatrix , userToDevice , userToDeviceDistance , deviceToUser , deviceToUserDistance -- ** Text , selectFontFace , setFontSize , setFontMatrix , getFontMatrix , setFontOptions , showText , fontExtents , textExtents -- * Fonts -- ** Font options , fontOptionsCreate , fontOptionsCopy , fontOptionsMerge , fontOptionsHash , fontOptionsEqual , fontOptionsSetAntialias , fontOptionsGetAntialias , fontOptionsSetSubpixelOrder , fontOptionsGetSubpixelOrder , fontOptionsSetHintStyle , fontOptionsGetHintStyle , fontOptionsSetHintMetrics , fontOptionsGetHintMetrics -- * Surfaces , withSimilarSurface , createSimilarSurface , renderWithSimilarSurface , surfaceGetFontOptions , surfaceFinish , surfaceFlush , surfaceMarkDirty , surfaceMarkDirtyRectangle , surfaceSetDeviceOffset -- ** Image surfaces , withImageSurface , withImageSurfaceForData #if CAIRO_CHECK_VERSION(1,6,0) , formatStrideForWidth #endif , createImageSurfaceForData , createImageSurface , imageSurfaceGetWidth , imageSurfaceGetHeight #if CAIRO_CHECK_VERSION(1,2,0) , imageSurfaceGetFormat , imageSurfaceGetStride #if __GLASGOW_HASKELL__ >= 606 , imageSurfaceGetData #endif , SurfaceData , imageSurfaceGetPixels #endif #ifdef CAIRO_HAS_PNG_FUNCTIONS -- ** PNG support , withImageSurfaceFromPNG , imageSurfaceCreateFromPNG , surfaceWriteToPNG #endif #ifdef CAIRO_HAS_PDF_SURFACE -- ** PDF surfaces , withPDFSurface #if CAIRO_CHECK_VERSION(1,2,0) , pdfSurfaceSetSize #endif #endif #ifdef CAIRO_HAS_PS_SURFACE -- ** PS surfaces , withPSSurface #if CAIRO_CHECK_VERSION(1,2,0) , psSurfaceSetSize #endif #endif #ifdef CAIRO_HAS_SVG_SURFACE -- ** SVG surfaces , withSVGSurface #endif -- * Utilities , liftIO , version , versionString -- * Types , Render , Matrix , Surface , Pattern , Status(..) , Operator(..) , Antialias(..) , FillRule(..) , LineCap(..) , LineJoin(..) , ScaledFont , FontFace , Glyph , TextExtents(..) , FontExtents(..) , FontSlant(..) , FontWeight(..) , SubpixelOrder(..) , HintStyle(..) , HintMetrics(..) , FontOptions , Path , Content(..) , Format(..) , Extend(..) , Filter(..) ) where import Control.Monad (unless, when) import Control.Monad.Reader (ReaderT(runReaderT), ask, MonadIO, liftIO) import Control.Exception (bracket) import Foreign.Ptr (Ptr, nullPtr, castPtr) import Foreign.Storable (Storable(..)) import Foreign.ForeignPtr ( touchForeignPtr ) #if __GLASGOW_HASKELL__ >= 606 import qualified Data.ByteString as BS #endif import Data.Ix -- internal module of GHC import Data.Array.Base ( MArray, newArray, newArray_, unsafeRead, unsafeWrite, #if __GLASGOW_HASKELL__ < 605 HasBounds, bounds #else getBounds #endif #if __GLASGOW_HASKELL__ >= 608 ,getNumElements #endif ) import Graphics.Rendering.Cairo.Internal (imageSurfaceCreateFromPNG) import Graphics.Rendering.Cairo.Types import qualified Graphics.Rendering.Cairo.Internal as Internal import Graphics.Rendering.Cairo.Internal (Render(..), bracketR) liftRender0 :: (Cairo -> IO a) -> Render a liftRender0 f = ask >>= \context -> liftIO (f context) liftRender1 :: (Cairo -> a -> IO b) -> a -> Render b liftRender1 f a = ask >>= \context -> liftIO (f context a) liftRender2 :: (Cairo -> a -> b -> IO c) -> a -> b -> Render c liftRender2 f a b = ask >>= \context -> liftIO (f context a b) liftRender3 :: (Cairo -> a -> b -> c -> IO d) -> a -> b -> c -> Render d liftRender3 f a b c = ask >>= \context -> liftIO (f context a b c) liftRender4 :: (Cairo -> a -> b -> c -> d -> IO e) -> a -> b -> c -> d -> Render e liftRender4 f a b c d = ask >>= \context -> liftIO (f context a b c d) liftRender5 :: (Cairo -> a -> b -> c -> d -> e -> IO f) -> a -> b -> c -> d -> e -> Render f liftRender5 f a b c d e = ask >>= \context -> liftIO (f context a b c d e) liftRender6 :: (Cairo -> a -> b -> c -> d -> e -> f -> IO g) -> a -> b -> c -> d -> e -> f -> Render g liftRender6 f a b c d e g = ask >>= \context -> liftIO (f context a b c d e g) -- | Creates a new Render context with all graphics state parameters set to -- default values and with the given surface as a target surface. The target -- surface should be constructed with a backend-specific function such as -- 'withImageSurface' (or any other with\<backend\>Surface variant). -- renderWith :: (MonadIO m) => Surface -- ^ the target surface for the Render context -> Render a -> m a renderWith surface (Render m) = liftIO $ bracket (Internal.create surface) (\context -> do status <- Internal.status context Internal.destroy context unless (status == StatusSuccess) $ fail =<< Internal.statusToString status) (\context -> runReaderT m context) -- | Makes a copy of the current state and saves it on an internal stack of -- saved states. When 'restore' is called, the saved state is restored. -- Multiple calls to 'save' and 'restore' can be nested; each call to 'restore' -- restores the state from the matching paired 'save'. -- save :: Render () save = liftRender0 Internal.save -- | Restores to the state saved by a preceding call to 'save' and removes that -- state from the stack of saved states. -- restore :: Render () restore = liftRender0 Internal.restore -- | Ask for the status of the current 'Render' monad. -- status :: Render Status status = liftRender0 Internal.status -- | Gets the target surface for the Render context as passed to 'renderWith'. -- withTargetSurface :: (Surface -> Render a) -> Render a withTargetSurface f = do context <- ask surface <- liftIO $ Internal.getTarget context f surface -- | Like @pushGroupWithContent ContentColorAlpha@, but more convenient. pushGroup :: Render () pushGroup = liftRender0 Internal.pushGroup -- | Temporarily redirects drawing to an intermediate surface known as a group. -- The redirection lasts until the group is completed by a call to -- 'withGroupPattern' or 'popGroupToSource'. These calls provide the result of -- any drawing to the group as a pattern (either as an explicit object, or set -- as the source pattern). This group functionality can be convenient for -- performing intermediate compositing. One common use of a group is to render -- objects as opaque within the group (so that they occlude each other), and -- then blend the result with translucence onto the destination. -- -- Groups can be nested arbitrarily deeply by making balanced calls to -- 'pushGroupWithContent' and 'withGroupPattern'. As a side effect, -- 'pushGroupWithContent' calls 'save' and 'withGroupPattern' calls 'restore', -- so that any changes to the graphics state will not be visible outside the -- group. -- -- As an example, here is how one might fill and stroke a path with -- translucence, but without any portion of the fill being visible under the -- stroke: -- -- > pushGroup -- > setSource fillPattern -- > fillPreserve -- > setSource strokePattern -- > stroke -- > popGroupToSource -- > paintWithAlpha alpha pushGroupWithContent :: Content -> Render () pushGroupWithContent = liftRender1 Internal.pushGroupWithContent -- | Like @withGroupPattern setSource@, but more convenient. popGroupToSource :: Render () popGroupToSource = liftRender0 Internal.popGroupToSource -- | Sets the source pattern within the context to an opaque color. This opaque -- color will then be used for any subsequent drawing operation until a new source -- pattern is set. -- -- The color components are floating point numbers in the range 0 to 1. If the -- values passed in are outside that range, they will be clamped. -- setSourceRGB :: Double -- ^ red component of colour -> Double -- ^ green component of colour -> Double -- ^ blue compoment of colour -> Render () setSourceRGB = liftRender3 Internal.setSourceRGB -- | Sets the source pattern within the context to a translucent color. This -- color will then be used for any subsequent drawing operation until a new -- source pattern is set. -- -- The color and alpha components are floating point numbers in the range 0 to -- 1. If the values passed in are outside that range, they will be clamped. -- setSourceRGBA :: Double -- ^ red component of color -> Double -- ^ green component of color -> Double -- ^ blue component of color -> Double -- ^ alpha component of color -> Render () setSourceRGBA = liftRender4 Internal.setSourceRGBA -- | Sets the source pattern within the context to source. This pattern will -- then be used for any subsequent drawing operation until a new source pattern -- is set. -- -- Note: The pattern's transformation matrix will be locked to the user space -- in effect at the time of 'setSource'. This means that further -- modifications of the current transformation matrix will not affect the source -- pattern. See 'setMatrix'. -- setSource :: Pattern -- ^ a 'Pattern' to be used as the source for subsequent drawing -- operations. -> Render () setSource = liftRender1 Internal.setSource -- | This is a convenience function for creating a pattern from surface and -- setting it as the source in the context with 'setSource'. -- -- The x and y parameters give the user-space coordinate at which the surface -- origin should appear. (The surface origin is its upper-left corner before any -- transformation has been applied.) The x and y patterns are negated and then -- set as translation values in the pattern matrix. -- -- Other than the initial translation pattern matrix, as described above, all -- other pattern attributes, (such as its extend mode), are set to the default -- values as in 'patternCreateForSurface'. The resulting pattern can be queried -- with 'getSource' so that these attributes can be modified if desired, (eg. to -- create a repeating pattern with 'patternSetExtent'. -- setSourceSurface :: Surface -- ^ a surface to be used to set the source pattern -> Double -- ^ user-space X coordinate for surface origin -> Double -- ^ user-space Y coordinate for surface origin -> Render () setSourceSurface = liftRender3 Internal.setSourceSurface -- | Gets the current source pattern. -- getSource :: Render Pattern getSource = liftRender0 Internal.getSource -- | Set the antialiasing mode of the rasterizer used for drawing shapes. This -- value is a hint, and a particular backend may or may not support a particular -- value. At the current time, no backend supports 'AntialiasSubpixel' when -- drawing shapes. -- -- Note that this option does not affect text rendering, instead see -- 'fontOptionsSetAntilias'. -- setAntialias :: Antialias -- ^ the new antialiasing mode -> Render () setAntialias = liftRender1 Internal.setAntialias -- | Gets the current shape antialiasing mode, as set by 'setAntialias'. -- getAntialias :: Render Antialias getAntialias = liftRender0 Internal.getAntialias -- | Sets the dash pattern to be used by 'stroke'. A dash pattern is specified -- by dashes, a list of positive values. Each value provides the user-space -- length of altenate "on" and "off" portions of the stroke. The offset -- specifies an offset into the pattern at which the stroke begins. -- -- If @dashes@ is @[]@ then dashing is disabled. -- If @dashes@ is @[a]@ a symmetric pattern is assumed with alternating on and -- off portions of the size specified by the single value in dashes. -- If any value in @dashes@ is negative, or if all values are 0, then context -- will be put into an error state with a status of 'StatusInvalidDash'. -- setDash :: [Double] -- ^ @dashes@ a list specifying alternate lengths of on and off -- portions of the stroke -> Double -- ^ an offset into the dash pattern at which the stroke should -- start -> Render () setDash = liftRender2 Internal.setDash -- | Set the current fill rule within the cairo context. The fill rule is used -- to determine which regions are inside or outside a complex (potentially -- self-intersecting) path. The current fill rule affects both 'fill' and -- 'clip'. See 'FillRule' for details on the semantics of each available fill -- rule. -- setFillRule :: FillRule -- ^ a fill rule -> Render () setFillRule = liftRender1 Internal.setFillRule -- | Gets the current fill rule, as set by 'setFillrule'. -- getFillRule :: Render FillRule getFillRule = liftRender0 Internal.getFillRule -- | Sets the current line cap style within the cairo context. See 'LineCap' -- for details about how the available line cap styles are drawn. -- -- As with the other stroke parameters, the current line cap style is examined -- by 'stroke', 'strokeExtents', and 'strokeToPath', but does not have any -- effect during path construction. -- setLineCap :: LineCap -- ^ a line cap style -> Render () setLineCap = liftRender1 Internal.setLineCap -- | Gets the current line cap style, as set by 'setLineCap'. -- getLineCap :: Render LineCap getLineCap = liftRender0 Internal.getLineCap -- | Sets the current line join style within the cairo context. See 'LineJoin' -- for details about how the available line join styles are drawn. -- -- As with the other stroke parameters, the current line join style is examined -- by 'stroke', 'strokeExtents', and 'strokeToPath', but does not have any -- effect during path construction. -- setLineJoin :: LineJoin -- ^ a line joint style -> Render () setLineJoin = liftRender1 Internal.setLineJoin -- | Gets the current line join style, as set by 'setLineJoin'. -- getLineJoin :: Render LineJoin getLineJoin = liftRender0 Internal.getLineJoin -- | Sets the current line width within the cairo context. The line width -- specifies the diameter of a pen that is circular in user-space. -- -- As with the other stroke parameters, the current line cap style is examined -- by 'stroke', 'strokeExtents', and 'strokeToPath', but does not have any -- effect during path construction. -- setLineWidth :: Double -- ^ a line width -> Render () setLineWidth = liftRender1 Internal.setLineWidth -- | Gets the current line width, as set by 'setLineWidth'. -- getLineWidth :: Render Double getLineWidth = liftRender0 Internal.getLineWidth -- | -- setMiterLimit :: Double -- ^ - -> Render () setMiterLimit = liftRender1 Internal.setMiterLimit -- | Gets the current miter limit, as set by 'setMiterLimit'. -- getMiterLimit :: Render Double getMiterLimit = liftRender0 Internal.getMiterLimit -- | Sets the compositing operator to be used for all drawing operations. -- See 'Operator' for details on the semantics of each available compositing -- operator. -- setOperator :: Operator -- ^ a compositing operator -> Render () setOperator = liftRender1 Internal.setOperator -- | Gets the current compositing operator for a cairo context. -- getOperator :: Render Operator getOperator = liftRender0 Internal.getOperator -- | Sets the tolerance used when converting paths into trapezoids. Curved -- segments of the path will be subdivided until the maximum deviation between -- the original path and the polygonal approximation is less than tolerance. -- The default value is 0.1. A larger value will give better performance, -- a smaller value, better appearance. (Reducing the value from the default -- value of 0.1 is unlikely to improve appearance significantly.) -- setTolerance :: Double -- ^ the tolerance, in device units (typically pixels) -> Render () setTolerance = liftRender1 Internal.setTolerance -- | Gets the current tolerance value, as set by 'setTolerance'. -- getTolerance :: Render Double getTolerance = liftRender0 Internal.getTolerance -- | Establishes a new clip region by intersecting the current clip region with -- the current path as it would be filled by 'fill' and according to the current -- fill rule (see 'setFillRule'). -- -- After 'clip', the current path will be cleared from the cairo context. -- -- The current clip region affects all drawing operations by effectively masking -- out any changes to the surface that are outside the current clip region. -- -- Calling 'clip' can only make the clip region smaller, never larger. But the -- current clip is part of the graphics state, so a temporary restriction of the -- clip region can be achieved by calling 'clip' within a 'save'/'restore' pair. -- The only other means of increasing the size of the clip region is 'resetClip'. -- clip :: Render () clip = liftRender0 Internal.clip -- | Establishes a new clip region by intersecting the current clip region with -- the current path as it would be filled by 'fill' and according to the current -- fill rule (see 'setFillRule'). -- -- Unlike 'clip', cairoClipPreserve preserves the path within the cairo context. -- -- The current clip region affects all drawing operations by effectively masking -- out any changes to the surface that are outside the current clip region. -- -- Calling 'clip' can only make the clip region smaller, never larger. But the -- current clip is part of the graphics state, so a temporary restriction of the -- clip region can be achieved by calling 'clip' within a 'save'/'restore' pair. -- The only other means of increasing the size of the clip region is 'resetClip'. -- clipPreserve :: Render () clipPreserve = liftRender0 Internal.clipPreserve -- | Reset the current clip region to its original, unrestricted state. That is, -- set the clip region to an infinitely large shape containing the target -- surface. Equivalently, if infinity is too hard to grasp, one can imagine the -- clip region being reset to the exact bounds of the target surface. -- -- Note that code meant to be reusable should not call 'resetClip' as it will -- cause results unexpected by higher-level code which calls 'clip'. Consider -- using 'save' and 'restore' around 'clip' as a more robust means of -- temporarily restricting the clip region. -- resetClip :: Render () resetClip = liftRender0 Internal.resetClip -- | A drawing operator that fills the current path according to the current -- fill rule, (each sub-path is implicitly closed before being filled). -- After 'fill', the current path will be cleared from the cairo context. -- -- See 'setFillRule' and 'fillPreserve'. -- fill :: Render () fill = liftRender0 Internal.fill -- | A drawing operator that fills the current path according to the current -- fill rule, (each sub-path is implicitly closed before being filled). -- Unlike 'fill', 'fillPreserve' preserves the path within the cairo context. -- -- See 'setFillRule' and 'fill'. -- fillPreserve :: Render () fillPreserve = liftRender0 Internal.fillPreserve -- | -- fillExtents :: Render (Double,Double,Double,Double) fillExtents = liftRender0 Internal.fillExtents -- | -- inFill :: Double -> Double -> Render Bool inFill = liftRender2 Internal.inFill -- | A drawing operator that paints the current source using the alpha channel -- of pattern as a mask. (Opaque areas of mask are painted with the source, -- transparent areas are not painted.) -- mask :: Pattern -- ^ a 'Pattern' -> Render () mask = liftRender1 Internal.mask -- | A drawing operator that paints the current source using the alpha channel -- of surface as a mask. (Opaque areas of surface are painted with the source, -- transparent areas are not painted.) -- maskSurface :: Surface -- ^ a 'Surface' -> Double -- ^ X coordinate at which to place the origin of surface -> Double -- ^ Y coordinate at which to place the origin of surface -> Render () maskSurface = liftRender3 Internal.maskSurface -- | A drawing operator that paints the current source everywhere within the -- current clip region. -- paint :: Render () paint = liftRender0 Internal.paint -- | A drawing operator that paints the current source everywhere within the -- current clip region using a mask of constant alpha value alpha. The effect -- is similar to 'paint', but the drawing is faded out using the alpha value. -- paintWithAlpha :: Double -- ^ alpha value, between 0 (transparent) and 1 (opaque) -> Render () paintWithAlpha = liftRender1 Internal.paintWithAlpha -- | A drawing operator that strokes the current path according to the current -- line width, line join, line cap, and dash settings. After issuing 'stroke', -- the current path will be cleared from the 'Render' monad. -- -- See 'setLineWidth', 'setLineJoin', 'setLineCap', 'setDash', and 'strokePreserve'. -- stroke :: Render () stroke = liftRender0 Internal.stroke -- | A drawing operator that strokes the current path according to the current -- line width, line join, line cap, and dash settings. Unlike 'stroke', -- 'strokePreserve' preserves the path within the 'Render' monad. -- -- See 'setLineWidth', 'setLineJoin', 'setLineCap', 'setDash', and 'strokePreserve'. -- strokePreserve :: Render () strokePreserve = liftRender0 Internal.strokePreserve -- | -- strokeExtents :: Render (Double,Double,Double,Double) strokeExtents = liftRender0 Internal.strokeExtents -- | -- inStroke :: Double -> Double -> Render Bool inStroke = liftRender2 Internal.inStroke -- | -- copyPage :: Render () copyPage = liftRender0 Internal.copyPage -- | -- showPage :: Render () showPage = liftRender0 Internal.showPage -- | Gets the current point of the current path, which is conceptually the final -- point reached by the path so far. -- -- The current point is returned in the user-space coordinate system. If there -- is no defined current point then x and y will both be set to 0.0. -- -- Most path construction functions alter the current point. See the following -- for details on how they affect the current point: 'newPath', 'moveTo', -- 'lineTo', 'curveTo', 'arc', 'relMoveTo', 'relLineTo', 'relCurveTo', -- 'arcNegative', 'textPath', 'strokeToPath'. -- getCurrentPoint :: Render (Double,Double) getCurrentPoint = liftRender0 Internal.getCurrentPoint -- | Clears the current path. After this call there will be no current point. -- newPath :: Render () newPath = liftRender0 Internal.newPath -- | Adds a line segment to the path from the current point to the beginning of -- the current subpath, (the most recent point passed to 'moveTo'), and closes -- this subpath. -- -- The behavior of 'closePath' is distinct from simply calling 'lineTo' with the -- equivalent coordinate in the case of stroking. When a closed subpath is -- stroked, there are no caps on the ends of the subpath. Instead, their is a -- line join connecting the final and initial segments of the subpath. -- closePath :: Render () closePath = liftRender0 Internal.closePath -- | Adds a circular arc of the given radius to the current path. The arc is -- centered at (@xc@, @yc@), begins at @angle1@ and proceeds in the direction of -- increasing angles to end at @angle2@. If @angle2@ is less than @angle1@ it -- will be progressively increased by @2*pi@ until it is greater than @angle1@. -- -- If there is a current point, an initial line segment will be added to the -- path to connect the current point to the beginning of the arc. -- -- Angles are measured in radians. An angle of 0 is in the direction of the -- positive X axis (in user-space). An angle of @pi/2@ radians (90 degrees) is in -- the direction of the positive Y axis (in user-space). Angles increase in the -- direction from the positive X axis toward the positive Y axis. So with the -- default transformation matrix, angles increase in a clockwise direction. -- -- (To convert from degrees to radians, use @degrees * (pi \/ 180)@.) -- -- This function gives the arc in the direction of increasing angles; see -- 'arcNegative' to get the arc in the direction of decreasing angles. -- -- The arc is circular in user-space. To achieve an elliptical arc, you can -- scale the current transformation matrix by different amounts in the X and Y -- directions. For example, to draw an ellipse in the box given by x, y, width, -- height: -- -- > save -- > translate (x + width / 2) (y + height / 2) -- > scale (1 / (height / 2.)) (1 / (width / 2)) -- > arc 0 0 1 0 (2 * pi) -- > restore -- arc :: Double -- ^ @xc@ - X position of the center of the arc -> Double -- ^ @yc@ - Y position of the center of the arc -> Double -- ^ @radius@ - the radius of the arc -> Double -- ^ @angle1@ - the start angle, in radians -> Double -- ^ @angle2@ - the end angle, in radians -> Render () arc = liftRender5 Internal.arc -- | Adds a circular arc of the given radius to the current path. The arc is -- centered at (@xc@, @yc@), begins at @angle1@ and proceeds in the direction of -- decreasing angles to end at @angle2@. If @angle2@ is greater than @angle1@ it -- will be progressively decreased by 2*@pi@ until it is greater than @angle1@. -- -- See 'arc' for more details. This function differs only in the direction of -- the arc between the two angles. -- arcNegative :: Double -- ^ @xc@ - X position of the center of the arc -> Double -- ^ @yc@ - Y position of the center of the arc -> Double -- ^ @radius@ - the radius of the arc -> Double -- ^ @angle1@ - the start angle, in radians -> Double -- ^ @angle2@ - the end angle, in radians -> Render () arcNegative = liftRender5 Internal.arcNegative -- | Adds a cubic Bezier spline to the path from the current point to position -- (@x3@, @y3@) in user-space coordinates, using (@x1@, @y1@) and (@x2@, @y2@) -- as the control points. After this call the current point will be (@x3@, @y3@). -- curveTo :: Double -- ^ @x1@ - the X coordinate of the first control point -> Double -- ^ @y1@ - the Y coordinate of the first control point -> Double -- ^ @x2@ - the X coordinate of the second control point -> Double -- ^ @y2@ - the Y coordinate of the second control point -> Double -- ^ @x3@ - the X coordinate of the end of the curve -> Double -- ^ @y3@ - the Y coordinate of the end of the curve -> Render () curveTo = liftRender6 Internal.curveTo -- | Adds a line to the path from the current point to position (@x@, @y@) in -- user-space coordinates. After this call the current point will be (@x@, @y@). -- lineTo :: Double -- ^ @x@ - the X coordinate of the end of the new line -> Double -- ^ @y@ - the Y coordinate of the end of the new line -> Render () lineTo = liftRender2 Internal.lineTo -- | If the current subpath is not empty, begin a new subpath. After this call -- the current point will be (@x@, @y@). -- moveTo :: Double -- ^ @x@ - the X coordinate of the new position -> Double -- ^ @y@ - the Y coordinate of the new position -> Render () moveTo = liftRender2 Internal.moveTo -- | Adds a closed-subpath rectangle of the given size to the current path at -- position (@x@, @y@) in user-space coordinates. -- rectangle :: Double -- ^ @x@ - the X coordinate of the top left corner of the rectangle -> Double -- ^ @y@ - the Y coordinate of the top left corner of the rectangle -> Double -- ^ @width@ - the width of the rectangle -> Double -- ^ @height@ - the height of the rectangle -> Render () rectangle = liftRender4 Internal.rectangle -- | Render text at the current path. -- -- * See 'showText' for why you should use Gtk functions. -- textPath :: String -- ^ - -> Render () textPath = liftRender1 Internal.textPath -- | Relative-coordinate version of 'curveTo'. All offsets are relative to the -- current point. Adds a cubic Bezier spline to the path from the current point -- to a point offset from the current point by (@dx3@, @dy3@), using points -- offset by (@dx1@, @dy1@) and (@dx2@, @dy2@) as the control points. After this -- call the current point will be offset by (@dx3@, @dy3@). -- -- Given a current point of (x, y), relCurveTo @dx1@ @dy1@ @dx2@ @dy2@ @dx3@ @dy3@ -- is logically equivalent to curveTo (x + @dx1@) (y + @dy1@) (x + @dx2@) (y + @dy2@) (x + @dx3@) (y + @dy3@). -- relCurveTo :: Double -- ^ @dx1@ - the X offset to the first control point -> Double -- ^ @dy1@ - the Y offset to the first control point -> Double -- ^ @dx2@ - the X offset to the second control point -> Double -- ^ @dy2@ - the Y offset to the second control point -> Double -- ^ @dx3@ - the X offset to the end of the curve -> Double -- ^ @dy3@ - the Y offset to the end of the curve -> Render () relCurveTo = liftRender6 Internal.relCurveTo -- | Relative-coordinate version of 'lineTo'. Adds a line to the path from the -- current point to a point that is offset from the current point by (@dx@, @dy@) -- in user space. After this call the current point will be offset by (@dx@, @dy@). -- -- Given a current point of (x, y), relLineTo @dx@ @dy@ is logically equivalent -- to lineTo (x + @dx@) (y + @dy@). -- relLineTo :: Double -- ^ @dx@ - the X offset to the end of the new line -> Double -- ^ @dy@ - the Y offset to the end of the new line -> Render () relLineTo = liftRender2 Internal.relLineTo -- | If the current subpath is not empty, begin a new subpath. After this call -- the current point will offset by (x, y). -- -- Given a current point of (x, y), relMoveTo @dx@ @dy@ is logically equivalent -- to moveTo (x + @dx@) (y + @dy@) -- relMoveTo :: Double -- ^ @dx@ - the X offset -> Double -- ^ @dy@ - the Y offset -> Render () relMoveTo = liftRender2 Internal.relMoveTo -- | Creates a new 'Pattern' corresponding to an opaque color. The color -- components are floating point numbers in the range 0 to 1. If the values -- passed in are outside that range, they will be clamped. -- -- For example to create a solid red pattern: -- -- > withRBGPattern 1 0 0 $ do -- > ... -- > ... -- withRGBPattern :: Double -- ^ red component of the color -> Double -- ^ green component of the color -> Double -- ^ blue component of the color -> (Pattern -> Render a) -- ^ a nested render action using the pattern -> Render a withRGBPattern r g b f = bracketR (Internal.patternCreateRGB r g b) (\pattern -> do status <- Internal.patternStatus pattern liftIO $ Internal.patternDestroy pattern unless (status == StatusSuccess) $ fail =<< Internal.statusToString status) (\pattern -> f pattern) -- | Creates a new 'Pattern' corresponding to a translucent color. The color -- components are floating point numbers in the range 0 to 1. If the values -- passed in are outside that range, they will be clamped. -- -- For example to create a solid red pattern at 50% transparency: -- -- > withRBGPattern 1 0 0 0.5 $ do -- > ... -- > ... -- withRGBAPattern :: Double -- ^ red component of color -> Double -- ^ green component of color -> Double -- ^ blue component of color -> Double -- ^ alpha component of color -> (Pattern -> Render a) -- ^ a nested render action using the pattern -> Render a withRGBAPattern r g b a f = bracketR (Internal.patternCreateRGBA r g b a) (\pattern -> do status <- Internal.patternStatus pattern liftIO $ Internal.patternDestroy pattern unless (status == StatusSuccess) $ fail =<< Internal.statusToString status) (\pattern -> f pattern) -- | Create a new 'Pattern' for the given surface. -- withPatternForSurface :: Surface -> (Pattern -> Render a) -- ^ a nested render action using the pattern -> Render a withPatternForSurface surface f = bracketR (Internal.patternCreateForSurface surface) (\pattern -> do status <- Internal.patternStatus pattern liftIO $ Internal.patternDestroy pattern unless (status == StatusSuccess) $ fail =<< Internal.statusToString status) (\pattern -> f pattern) -- | Pop the current group from the group stack and use it as a pattern. The -- group should be populated first by calling 'pushGroup' or -- 'pushGroupWithContent' and doing some drawing operations. This also calls -- 'restore' to balance the 'save' called in 'pushGroup'. withGroupPattern :: (Pattern -> Render a) -- ^ a nested render action using the pattern -> Render a withGroupPattern f = do context <- ask bracketR (Internal.popGroup context) (\pattern -> do status <- Internal.patternStatus pattern liftIO $ Internal.patternDestroy pattern unless (status == StatusSuccess) $ fail =<< Internal.statusToString status) f -- | Create a new linear gradient 'Pattern' along the line defined by @(x0, y0)@ -- and @(x1, y1)@. Before using the gradient pattern, a number of color stops -- should be defined using 'patternAddColorStopRGB' and 'patternAddColorStopRGBA'. -- -- * Note: The coordinates here are in pattern space. For a new pattern, -- pattern space is identical to user space, but the relationship between the -- spaces can be changed with 'patternSetMatrix'. -- withLinearPattern :: Double -- ^ @x0@ - x coordinate of the start point -> Double -- ^ @y0@ - y coordinate of the start point -> Double -- ^ @x1@ - x coordinate of the end point -> Double -- ^ @y1@ - y coordinate of the end point -> (Pattern -> Render a) -- ^ a nested render action using the pattern -> Render a withLinearPattern x0 y0 x1 y1 f = bracketR (Internal.patternCreateLinear x0 y0 x1 y1) (\pattern -> do status <- Internal.patternStatus pattern liftIO $ Internal.patternDestroy pattern unless (status == StatusSuccess) $ fail =<< Internal.statusToString status) (\pattern -> f pattern) -- | Creates a new radial gradient 'Pattern' between the two circles defined by -- @(x0, y0, c0)@ and @(x1, y1, c0)@. Before using the gradient pattern, a -- number of color stops should be defined using 'patternAddColorStopRGB' -- or 'patternAddColorStopRGBA'. -- -- * Note: The coordinates here are in pattern space. For a new pattern, -- pattern space is identical to user space, but the relationship between the -- spaces can be changed with 'patternSetMatrix'. -- withRadialPattern :: Double -- ^ @cx0@ - x coordinate for the center of the start circle -> Double -- ^ @cy0@ - y coordinate for the center of the start circle -> Double -- ^ @radius0@ - radius of the start cirle -> Double -- ^ @cx1@ - x coordinate for the center of the end circle -> Double -- ^ @cy1@ - y coordinate for the center of the end circle -> Double -- ^ @radius1@ - radius of the end circle -> (Pattern -> Render a) -- ^ a nested render action using the pattern -> Render a withRadialPattern cx0 cy0 radius0 cx1 cy1 radius1 f = bracketR (Internal.patternCreateRadial cx0 cy0 radius0 cx1 cy1 radius1) (\pattern -> do status <- Internal.patternStatus pattern liftIO $ Internal.patternDestroy pattern unless (status == StatusSuccess) $ fail =<< Internal.statusToString status) (\pattern -> f pattern) -- | Adds an opaque color stop to a gradient pattern. The offset specifies the -- location along the gradient's control vector. For example, a linear gradient's -- control vector is from (x0,y0) to (x1,y1) while a radial gradient's control -- vector is from any point on the start circle to the corresponding point on -- the end circle. -- -- The color is specified in the same way as in 'setSourceRGB'. -- -- Note: If the pattern is not a gradient pattern, (eg. a linear or radial -- pattern), then the pattern will be put into an error status with a status of -- 'StatusPatternTypeMismatch'. -- patternAddColorStopRGB :: MonadIO m => Pattern -- ^ a 'Pattern' -> Double -- ^ an offset in the range [0.0 .. 1.0] -> Double -- ^ red component of color -> Double -- ^ green component of color -> Double -- ^ blue component of color -> m () patternAddColorStopRGB p offset r g b = liftIO $ Internal.patternAddColorStopRGB p offset r g b -- | Adds a translucent color stop to a gradient pattern. The offset specifies -- the location along the gradient's control vector. For example, a linear -- gradient's control vector is from (x0,y0) to (x1,y1) while a radial gradient's -- control vector is from any point on the start circle to the corresponding -- point on the end circle. -- -- The color is specified in the same way as in setSourceRGBA. -- -- Note: If the pattern is not a gradient pattern, (eg. a linear or radial -- pattern), then the pattern will be put into an error status with a status of -- 'StatusPatternTypeMismatch'. -- patternAddColorStopRGBA :: MonadIO m => Pattern -- ^ a 'Pattern' -> Double -- ^ an offset in the range [0.0 .. 1.0] -> Double -- ^ red component of color -> Double -- ^ green component of color -> Double -- ^ blue component of color -> Double -- ^ alpha component of color -> m () patternAddColorStopRGBA p offset r g b a = liftIO $ Internal.patternAddColorStopRGBA p offset r g b a -- | Sets the pattern's transformation matrix to matrix. This matrix is a -- transformation from user space to pattern space. -- -- When a pattern is first created it always has the identity matrix for its -- transformation matrix, which means that pattern space is initially identical -- to user space. -- -- Important: Please note that the direction of this transformation matrix is -- from user space to pattern space. This means that if you imagine the flow -- from a pattern to user space (and on to device space), then coordinates in -- that flow will be transformed by the inverse of the pattern matrix. -- -- Also, please note the discussion of the user-space locking semantics of 'setSource'. -- patternSetMatrix :: MonadIO m => Pattern -- ^ a 'Pattern' -> Matrix -- ^ a 'Matrix' -> m () patternSetMatrix p m = liftIO $ Internal.patternSetMatrix p m -- | Get the pattern's transformation matrix. -- patternGetMatrix :: MonadIO m => Pattern -- ^ a 'Pattern' -> m Matrix patternGetMatrix p = liftIO $ Internal.patternGetMatrix p -- | -- patternSetExtend :: MonadIO m => Pattern -- ^ a 'Pattern' -> Extend -- ^ an 'Extent' -> m () patternSetExtend p e = liftIO $ Internal.patternSetExtend p e -- | -- patternGetExtend :: MonadIO m => Pattern -- ^ a 'Pattern' -> m Extend patternGetExtend p = liftIO $ Internal.patternGetExtend p -- | -- patternSetFilter :: MonadIO m => Pattern -- ^ a 'Pattern' -> Filter -- ^ a 'Filter' -> m () patternSetFilter p f = liftIO $ Internal.patternSetFilter p f -- | -- patternGetFilter :: MonadIO m => Pattern -- ^ a 'Pattern' -> m Filter patternGetFilter p = liftIO $ Internal.patternGetFilter p -- | Modifies the current transformation matrix (CTM) by translating the -- user-space origin by @(tx, ty)@. This offset is interpreted as a user-space -- coordinate according to the CTM in place before the new call to 'translate'. -- In other words, the translation of the user-space origin takes place after -- any existing transformation. -- translate :: Double -- ^ @tx@ - amount to translate in the X direction -> Double -- ^ @ty@ - amount to translate in the Y direction -> Render () translate = liftRender2 Internal.translate -- | Modifies the current transformation matrix (CTM) by scaling the X and Y -- user-space axes by sx and sy respectively. The scaling of the axes takes -- place after any existing transformation of user space. -- scale :: Double -- ^ @sx@ - scale factor for the X dimension -> Double -- ^ @sy@ - scale factor for the Y dimension -> Render () scale = liftRender2 Internal.scale -- | Modifies the current transformation matrix (CTM) by rotating the user-space -- axes by @angle@ radians. The rotation of the axes takes places after any -- existing transformation of user space. The rotation direction for positive -- angles is from the positive X axis toward the positive Y axis. -- rotate :: Double -- ^ @angle@ - angle (in radians) by which the user-space axes will -- be rotated -> Render () rotate = liftRender1 Internal.rotate -- | Modifies the current transformation matrix (CTM) by applying matrix as an -- additional transformation. The new transformation of user space takes place -- after any existing transformation. -- transform :: Matrix -- ^ @matrix@ - a transformation to be applied to the user-space axes -> Render () transform = liftRender1 Internal.transform -- | Modifies the current transformation matrix (CTM) by setting it equal to -- @matrix@. setMatrix :: Matrix -- ^ @matrix@ - a transformation matrix from user space to device space -> Render () setMatrix = liftRender1 Internal.setMatrix -- | Gets the current transformation matrix, as set by 'setMatrix'. -- getMatrix :: Render Matrix getMatrix = liftRender0 Internal.getMatrix -- | Resets the current transformation matrix (CTM) by setting it equal to the -- identity matrix. That is, the user-space and device-space axes will be -- aligned and one user-space unit will transform to one device-space unit. -- identityMatrix :: Render () identityMatrix = liftRender0 Internal.identityMatrix -- | Transform a coordinate from user space to device space by multiplying the -- given point by the current transformation matrix (CTM). -- userToDevice :: Double -- ^ X value of coordinate -> Double -- ^ Y value of coordinate -> Render (Double,Double) userToDevice = liftRender2 Internal.userToDevice -- | Transform a distance vector from user space to device space. This function -- is similar to 'userToDevice' except that the translation components of the -- CTM will be ignored when transforming @(dx,dy)@. -- userToDeviceDistance :: Double -- ^ @dx@ - X component of a distance vector -> Double -- ^ @dy@ - Y component of a distance vector -> Render (Double,Double) userToDeviceDistance = liftRender2 Internal.userToDeviceDistance -- | Transform a coordinate from device space to user space by multiplying the -- given point by the inverse of the current transformation matrix (CTM). -- deviceToUser :: Double -- ^ X value of coordinate -> Double -- ^ Y value of coordinate -> Render (Double,Double) deviceToUser = liftRender2 Internal.deviceToUser -- | Transform a distance vector from device space to user space. This function -- is similar to 'deviceToUser' except that the translation components of the -- inverse CTM will be ignored when transforming @(dx,dy)@. -- deviceToUserDistance :: Double -- ^ @dx@ - X component of a distance vector -> Double -- ^ @dy@ - Y component of a distance vector -> Render (Double,Double) deviceToUserDistance = liftRender2 Internal.deviceToUserDistance -- | Selects a family and style of font from a simplified description as a -- @family@ name, @slant@ and @weight@. This function is meant to be used only -- for applications with simple font needs: Cairo doesn't provide for operations -- such as listing all available fonts on the system, and it is expected that -- most applications will need to use a more comprehensive font handling and -- text layout library in addition to cairo. -- selectFontFace :: String -- ^ @family@ - a font family name -> FontSlant -- ^ @slant@ - the slant for the font -> FontWeight -- ^ @weight@ - the weight of the font -> Render () selectFontFace = liftRender3 Internal.selectFontFace -- | Sets the current font matrix to a scale by a factor of @size@, replacing -- any font matrix previously set with 'setFontSize' or 'setFontMatrix'. This -- results in a font size of size user space units. (More precisely, this matrix -- will result in the font's em-square being a size by size square in user space.) -- setFontSize :: Double -- ^ @size@ - the new font size, in user space units -> Render () setFontSize = liftRender1 Internal.setFontSize -- | Sets the current font matrix to @matrix@. The font matrix gives a -- transformation from the design space of the font (in this space, the -- em-square is 1 unit by 1 unit) to user space. Normally, a simple scale is -- used (see 'setFontSize'), but a more complex font matrix can be used to shear -- the font or stretch it unequally along the two axes. -- setFontMatrix :: Matrix -- ^ @matrix@ - a 'Matrix' describing a transform to be applied to -- the current font. -> Render () setFontMatrix = liftRender1 Internal.setFontMatrix -- | Gets the current font matrix, as set by 'setFontMatrix' -- getFontMatrix :: Render Matrix getFontMatrix = liftRender0 Internal.getFontMatrix -- | Sets a set of custom font rendering options. Rendering options are -- derived by merging these options with the options derived from underlying -- surface; if the value in @options@ has a default value (like -- 'AntialiasDefault'), then the value from the surface is used. -- setFontOptions :: FontOptions -> Render () setFontOptions = liftRender1 Internal.setFontOptions -- | A drawing operator that generates the shape from a string of Unicode -- characters, rendered according to the current font face, font size (font -- matrix), and font options. -- -- This function first computes a set of glyphs for the string of text. The -- first glyph is placed so that its origin is at the current point. The origin -- of each subsequent glyph is offset from that of the previous glyph by the -- advance values of the previous glyph. -- -- After this call the current point is moved to the origin of where the next -- glyph would be placed in this same progression. That is, the current point -- will be at the origin of the final glyph offset by its advance values. This -- allows for easy display of a single logical string with multiple calls to -- 'showText'. -- -- NOTE: The 'showText' function call is part of what the cairo designers call -- the \"toy\" text API. It is convenient for short demos and simple programs, -- but it is not expected to be adequate for the most serious of text-using -- applications. -- showText :: String -- ^ a string of text -> Render () showText = liftRender1 Internal.showText -- | Gets the font extents for the currently selected font. -- fontExtents :: Render FontExtents fontExtents = liftRender0 Internal.fontExtents -- | Gets the extents for a string of text. The extents describe a user-space -- rectangle that encloses the \"inked\" portion of the text, (as it would be -- drawn by 'showText'). Additionally, the 'textExtentsXadvance' and -- 'textExtentsYadvance' values indicate the amount by which the current point -- would be advanced by 'showText'. -- -- Note that whitespace characters do not directly contribute to the size of -- the rectangle ('textExtentsWidth' and 'textExtentsHeight'). They do contribute -- indirectly by changing the position of non-whitespace characters. -- In particular, trailing whitespace characters are likely to not affect the -- size of the rectangle, though they will affect the 'textExtentsXadvance' and -- 'textExtentsYadvance' values. -- textExtents :: String -- ^ a string of text -> Render TextExtents textExtents = liftRender1 Internal.textExtents -- | Allocates a new font options object with all options initialized to default -- values. -- fontOptionsCreate :: MonadIO m => m FontOptions fontOptionsCreate = liftIO $ Internal.fontOptionsCreate -- | Allocates a new font options object copying the option values from @original@. -- fontOptionsCopy :: MonadIO m => FontOptions -- ^ @original@ -> m FontOptions fontOptionsCopy a = liftIO $ Internal.fontOptionsCopy a -- | Merges non-default options from @other@ into @options@, replacing existing -- values. This operation can be thought of as somewhat similar to compositing -- @other@ onto @options@ with the operation of 'OperationOver'. -- fontOptionsMerge :: MonadIO m => FontOptions -- ^ @options@ -> FontOptions -- ^ @other@ -> m () fontOptionsMerge a b = liftIO $ Internal.fontOptionsMerge a b -- | Compute a hash for the font options object; this value will be useful when -- storing an object containing a 'FontOptions' in a hash table. -- fontOptionsHash :: MonadIO m => FontOptions -> m Int fontOptionsHash a = liftIO $ Internal.fontOptionsHash a -- | Compares two font options objects for equality. -- fontOptionsEqual :: MonadIO m => FontOptions -> FontOptions -> m Bool fontOptionsEqual a b = liftIO $ Internal.fontOptionsEqual a b -- | Sets the antiliasing mode for the font options object. This specifies the -- type of antialiasing to do when rendering text. -- fontOptionsSetAntialias :: MonadIO m => FontOptions -> Antialias -> m () fontOptionsSetAntialias a b = liftIO $ Internal.fontOptionsSetAntialias a b -- | Gets the antialising mode for the font options object. -- fontOptionsGetAntialias :: MonadIO m => FontOptions -> m Antialias fontOptionsGetAntialias a = liftIO $ Internal.fontOptionsGetAntialias a -- | Sets the subpixel order for the font options object. The subpixel order -- specifies the order of color elements within each pixel on the display device -- when rendering with an antialiasing mode of 'AntialiasSubpixel'. -- See the documentation for 'SubpixelOrder' for full details. -- fontOptionsSetSubpixelOrder :: MonadIO m => FontOptions -> SubpixelOrder-> m () fontOptionsSetSubpixelOrder a b = liftIO $ Internal.fontOptionsSetSubpixelOrder a b -- | Gets the subpixel order for the font options object. -- See the documentation for 'SubpixelOrder' for full details. -- fontOptionsGetSubpixelOrder :: MonadIO m => FontOptions -> m SubpixelOrder fontOptionsGetSubpixelOrder a = liftIO $ Internal.fontOptionsGetSubpixelOrder a -- | Sets the hint style for font outlines for the font options object. -- This controls whether to fit font outlines to the pixel grid, and if so, -- whether to optimize for fidelity or contrast. See the documentation for -- 'HintStyle' for full details. -- fontOptionsSetHintStyle :: MonadIO m => FontOptions -> HintStyle -> m () fontOptionsSetHintStyle a b = liftIO $ Internal.fontOptionsSetHintStyle a b -- | Gets the hint style for font outlines for the font options object. -- See the documentation for 'HintStyle' for full details. -- fontOptionsGetHintStyle :: MonadIO m => FontOptions -> m HintStyle fontOptionsGetHintStyle a = liftIO $ Internal.fontOptionsGetHintStyle a -- | Sets the metrics hinting mode for the font options object. This controls -- whether metrics are quantized to integer values in device units. See the -- documentation for 'HintMetrics' for full details. -- fontOptionsSetHintMetrics :: MonadIO m => FontOptions -> HintMetrics -> m () fontOptionsSetHintMetrics a b = liftIO $ Internal.fontOptionsSetHintMetrics a b -- | Gets the metrics hinting mode for the font options object. See the -- documentation for 'HintMetrics' for full details. -- fontOptionsGetHintMetrics :: MonadIO m => FontOptions -> m HintMetrics fontOptionsGetHintMetrics a = liftIO $ Internal.fontOptionsGetHintMetrics a -- | Create a temporary surface that is as compatible as possible with an -- existing surface. The new surface will use the same backend as other unless -- that is not possible for some reason. -- withSimilarSurface :: Surface -- ^ an existing surface used to select the backend of the new surface -> Content -- ^ the content type for the new surface (color, color+alpha or alpha only) -> Int -- ^ width of the new surface, (in device-space units) -> Int -- ^ height of the new surface (in device-space units) -> (Surface -> IO a) -> IO a withSimilarSurface surface contentType width height f = bracket (Internal.surfaceCreateSimilar surface contentType width height) (\surface' -> do status <- Internal.surfaceStatus surface' Internal.surfaceDestroy surface' unless (status == StatusSuccess) $ Internal.statusToString status >>= fail) (\surface' -> f surface') -- | Like 'withSimilarSurface' but creates a Surface that is managed by the -- Haskell memory manager rather than only being temporaily allocated. This -- is more flexible and allows you to create surfaces that persist, which -- can be very useful, for example to cache static elements in an animation. -- -- However you should be careful because surfaces can be expensive resources -- and the Haskell memory manager cannot guarantee when it will release them. -- You can manually release the resources used by a surface with -- 'surfaceFinish'. -- createSimilarSurface :: Surface -- ^ an existing surface used to select the backend of the new surface -> Content -- ^ the content type for the new surface (color, color+alpha or alpha only) -> Int -- ^ width of the surface, in pixels -> Int -- ^ height of the surface, in pixels -> IO Surface createSimilarSurface surface contentType width height = do surface <- Internal.surfaceCreateSimilar surface contentType width height Internal.manageSurface surface return surface -- | Create a temporary surface that is compatible with the current target -- surface (like a combination of 'withTargetSurface' and 'withSimilarSurface'). -- -- This is useful for drawing to a temporary surface and then compositing it -- into the main suface. For example, the following code draws to a temporary -- surface and then uses that as a mask: -- -- > renderWithSimilarSurface ContentAlpha 200 200 $ \tmpSurface -> do -- > renderWith tmpSurface $ do -- > ... -- draw onto the temporary surface -- > -- > -- use the temporary surface as a mask, filling it with the -- > -- current source which in this example is transparent red. -- > setSourceRGBA 1 0 0 0.5 -- > setOperator Operator{something} -- think of something clever to do -- > maskSurface tmpSurface 0 0) -- renderWithSimilarSurface :: Content -- ^ the content type for the new surface -- (color, colour+alpha or alpha only) -> Int -- ^ width of the new surface, (in device-space units) -> Int -- ^ height of the new surface, (in device-space units) -> (Surface -> Render a) -- ^ this action draws on the main surface, -- possibly making use of the temporary surface -- (which gets destroyed afterwards). -> Render a renderWithSimilarSurface contentType width height render = withTargetSurface $ \surface -> bracketR (Internal.surfaceCreateSimilar surface contentType width height) (\surface' -> do status <- Internal.surfaceStatus surface' Internal.surfaceDestroy surface' unless (status == StatusSuccess) $ Internal.statusToString status >>= fail) (\surface' -> render surface') -- | This function finishes the surface and drops all references to external -- resources. For example, for the Xlib backend it means that cairo will no -- longer access the drawable, which can be freed. After calling 'surfaceFinish' -- the only valid operations on a surface are getting and setting user data and -- referencing and destroying it. Further drawing to the surface will not affect -- the surface but will instead trigger a 'StatusSurfaceFinished' error. -- -- When the last call to 'surfaceDestroy' decreases the reference count to zero, -- cairo will call 'surfaceFinish' if it hasn't been called already, before -- freeing the resources associated with the surface. -- surfaceFinish :: MonadIO m => Surface -> m () surfaceFinish surface = liftIO $ do status <- Internal.surfaceStatus surface Internal.surfaceFinish surface unless (status == StatusSuccess) $ Internal.statusToString status >>= fail -- | Do any pending drawing for the surface and also restore any temporary -- modification's cairo has made to the surface's state. This function must be -- called before switching from drawing on the surface with cairo to drawing on -- it directly with native APIs. If the surface doesn't support direct access, -- then this function does nothing. -- surfaceFlush :: MonadIO m => Surface -> m () surfaceFlush a = liftIO $ Internal.surfaceFlush a -- | Retrieves the default font rendering options for the surface. This allows -- display surfaces to report the correct subpixel order for rendering on them, -- print surfaces to disable hinting of metrics and so forth. The result can -- then be used with 'scaledFontCreate'. -- surfaceGetFontOptions :: Surface -> Render FontOptions surfaceGetFontOptions surface = do fontOptions <- fontOptionsCreate liftIO $ Internal.surfaceGetFontOptions surface fontOptions return fontOptions -- | Tells cairo that drawing has been done to surface using means other than -- cairo, and that cairo should reread any cached areas. Note that you must call -- 'surfaceFlush' before doing such drawing. -- surfaceMarkDirty :: MonadIO m => Surface -> m () surfaceMarkDirty a = liftIO $ Internal.surfaceMarkDirty a -- | Like 'surfaceMarkDirty', but drawing has been done only to the specified -- rectangle, so that cairo can retain cached contents for other parts of the -- surface. -- surfaceMarkDirtyRectangle :: MonadIO m => Surface -- ^ a 'Surface' -> Int -- ^ X coordinate of dirty rectangle -> Int -- ^ Y coordinate of dirty rectangle -> Int -- ^ width of dirty rectangle -> Int -- ^ height of dirty rectangle -> m () surfaceMarkDirtyRectangle a b c d e = liftIO $ Internal.surfaceMarkDirtyRectangle a b c d e -- | Sets an offset that is added to the device coordinates determined by the -- CTM when drawing to surface. One use case for this function is when we want -- to create a 'Surface' that redirects drawing for a portion of an -- onscreen surface to an offscreen surface in a way that is completely -- invisible to the user of the cairo API. Setting a transformation via -- 'translate' isn't sufficient to do this, since functions like 'deviceToUser' -- will expose the hidden offset. -- -- Note that the offset only affects drawing to the surface, not using the -- surface in a surface pattern. -- surfaceSetDeviceOffset :: MonadIO m => Surface -- ^ a 'Surface' -> Double -- ^ the offset in the X direction, in device units -> Double -- ^ the offset in the Y direction, in device units -> m () surfaceSetDeviceOffset a b c = liftIO $ Internal.surfaceSetDeviceOffset a b c #if CAIRO_CHECK_VERSION(1,6,0) -- | This function provides a stride value that will respect all alignment -- requirements of the accelerated image-rendering code within cairo. -- formatStrideForWidth :: Format -- ^ format of pixels in the surface to create -> Int -- ^ width of the surface, in pixels -> Int -- ^ the stride (number of bytes necessary to store one line) -- or @-1@ if the format is invalid or the width is too large formatStrideForWidth = Internal.formatStrideForWidth #endif -- | Creates an image surface of the specified format and dimensions. -- The initial contents of the surface is undefined; you must explicitely -- clear the buffer, using, for example, 'rectangle' and 'fill' if you want it -- cleared. -- withImageSurface :: Format -- ^ format of pixels in the surface to create -> Int -- ^ width of the surface, in pixels -> Int -- ^ height of the surface, in pixels -> (Surface -> IO a) -- ^ an action that may use the surface. The surface is -- only valid within in this action. -> IO a withImageSurface format width height f = bracket (Internal.imageSurfaceCreate format width height) (\surface -> do status <- Internal.surfaceStatus surface Internal.surfaceDestroy surface unless (status == StatusSuccess) $ Internal.statusToString status >>= fail) (\surface -> f surface) -- | Like 'withImageSurface' but creates a Surface that is managed by the -- Haskell memory manager rather than only being temporaily allocated. This -- is more flexible and allows you to create surfaces that persist, which -- can be very useful, for example to cache static elements in an animation. -- -- However you should be careful because surfaces can be expensive resources -- and the Haskell memory manager cannot guarantee when it will release them. -- You can manually release the resources used by a surface with -- 'surfaceFinish'. -- createImageSurface :: Format -- ^ format of pixels in the surface to create -> Int -- ^ width of the surface, in pixels -> Int -- ^ height of the surface, in pixels -> IO Surface createImageSurface format width height = do surface <- Internal.imageSurfaceCreate format width height Internal.manageSurface surface return surface -- | Like 'withImageSurface' but creating a surface to target external -- data pointed to by 'PixelData'. -- withImageSurfaceForData :: PixelData -- ^ pointer to pixel data -> Format -- ^ format of pixels in the surface to create -> Int -- ^ width of the surface, in pixels -> Int -- ^ height of the surface, in pixels -> Int -- ^ size of stride between rows in the surface to create -> (Surface -> IO a) -- ^ an action that may use the surface. The surface is -- only valid within this action -> IO a withImageSurfaceForData pixels format width height stride f = bracket (Internal.imageSurfaceCreateForData pixels format width height stride) (\surface -> do status <- Internal.surfaceStatus surface Internal.surfaceDestroy surface unless (status == StatusSuccess) $ Internal.statusToString status >>= fail) (\surface -> f surface) -- | Like 'createImageSurface' but creating a surface to target external -- data pointed to by 'PixelData'. -- createImageSurfaceForData :: PixelData -- ^ pointer to pixel data -> Format -- ^ format of pixels in the surface to create -> Int -- ^ width of the surface, in pixels -> Int -- ^ height of the surface, in pixels -> Int -- ^ size of stride between rows in the surface to create -> IO Surface createImageSurfaceForData pixels format width height stride = do surface <- Internal.imageSurfaceCreateForData pixels format width height stride Internal.manageSurface surface return surface -- | Get the width of the image surface in pixels. -- imageSurfaceGetWidth :: MonadIO m => Surface -> m Int imageSurfaceGetWidth a = liftIO $ Internal.imageSurfaceGetWidth a -- | Get the height of the image surface in pixels. -- imageSurfaceGetHeight :: MonadIO m => Surface -> m Int imageSurfaceGetHeight a = liftIO $ Internal.imageSurfaceGetHeight a #if CAIRO_CHECK_VERSION(1,2,0) -- | Get the number of bytes from the start of one row to the start of the -- next. If the image data contains no padding, then this is equal to -- the pixel depth * the width. imageSurfaceGetStride :: MonadIO m => Surface -> m Int imageSurfaceGetStride = liftIO . Internal.imageSurfaceGetStride -- | Get the format of the surface. -- imageSurfaceGetFormat :: MonadIO m => Surface -> m Format imageSurfaceGetFormat a = liftIO $ Internal.imageSurfaceGetFormat a #if __GLASGOW_HASKELL__ >= 606 -- | Return a ByteString of the image data for a surface. In order to remain -- safe the returned ByteString is a copy of the data. This is a little -- slower than returning a pointer into the image surface object itself, but -- much safer imageSurfaceGetData :: Surface -> IO BS.ByteString imageSurfaceGetData a = do height <- Internal.imageSurfaceGetHeight a stride <- Internal.imageSurfaceGetStride a ptr <- Internal.imageSurfaceGetData a #if __GLASGOW_HASKELL__ < 608 BS.copyCStringLen (castPtr ptr, height * stride) #else BS.packCStringLen (castPtr ptr, height * stride) #endif #endif -- | Retrieve the internal array of raw image data. -- -- * Image data in an image surface is stored in memory in uncompressed, -- packed format. Rows in the image are stored top to bottom, and in each -- row pixels are stored from left to right. There may be padding at the end -- of a row. The value returned by 'imageSurfaceGetStride' indicates the -- number of bytes between rows. -- -- * The returned array is a flat representation of a three dimensional array: -- x-coordiante, y-coordinate and several channels for each color. The -- format depends on the 'Format' of the surface: -- -- 'FormatARGB32': each pixel is 32 bits with alpha in the upper 8 bits, -- followed by 8 bits for red, green and blue. Pre-multiplied alpha is used. -- (That is, 50% transparent red is 0x80800000, not 0x80ff0000.) -- -- 'FormatRGB24': each pixel is 32 bits with the upper 8 bits being unused, -- followed by 8 bits for red, green and blue. -- -- 'FormatA8': each pixel is 8 bits holding an alpha value -- -- 'FormatA1': each pixel is one bit where pixels are packed into 32 bit -- quantities. The ordering depends on the endianes of the platform. On a -- big-endian machine, the first pixel is in the uppermost bit, on a -- little-endian machine the first pixel is in the least-significant bit. -- -- * To read or write a specific pixel use the formula: -- @p = y * (rowstride `div` 4) + x@ for the pixel and force the array to -- have 32-bit words or integers. -- -- * Calling this function without explicitly giving it a type will often lead -- to a compiler error since the type parameter @e@ is underspecified. If -- this happens the function can be explicitly typed: -- @surData <- (imageSurfaceGetPixels pb :: IO (SurfaceData Int Word32))@ -- -- * If modifying an image through Haskell\'s array interface is not fast -- enough, it is possible to use 'unsafeRead' and 'unsafeWrite' which have -- the same type signatures as 'readArray' and 'writeArray'. Note that these -- are internal functions that might change with GHC. -- -- * After each write access to the array, you need to inform Cairo that -- about the area that has changed using 'surfaceMarkDirty'. -- -- * The function will return an error if the surface is not an image -- surface of if 'surfaceFinish' has been called on the surface. -- imageSurfaceGetPixels :: Storable e => Surface -> IO (SurfaceData Int e) imageSurfaceGetPixels pb = do pixPtr_ <- Internal.imageSurfaceGetData pb when (pixPtr_==nullPtr) $ do fail "imageSurfaceGetPixels: image surface not available" fmt <- imageSurfaceGetFormat pb let bits = case fmt of FormatARGB32 -> 32 FormatRGB24 -> 32 FormatA8 -> 8 FormatA1 -> 1 h <- imageSurfaceGetHeight pb r <- imageSurfaceGetStride pb let pixPtr = castPtr pixPtr_ let bytes = h*((r*bits)+7) `div` 8 return (mkSurfaceData pb pixPtr bytes) -- | An array that stores the raw pixel data of an image 'Surface'. -- data SurfaceData i e = SurfaceData !Surface {-# UNPACK #-} !(Ptr e) !(i,i) {-# UNPACK #-} !Int mkSurfaceData :: Storable e => Surface -> Ptr e -> Int -> SurfaceData Int e mkSurfaceData pb (ptr :: Ptr e) size = SurfaceData pb ptr (0, count) count where count = fromIntegral (size `div` sizeOf (undefined :: e)) #if __GLASGOW_HASKELL__ < 605 instance HasBounds SurfaceData where bounds (SurfaceData pb ptr bd cnt) = bd #endif -- | 'SurfaceData' is a mutable array. instance Storable e => MArray SurfaceData e IO where newArray (l,u) e = error "Graphics.Rendering.Cairo.newArray: not implemented" newArray_ (l,u) = error "Graphics.Rendering.Cairo.newArray_: not implemented" {-# INLINE unsafeRead #-} unsafeRead (SurfaceData (Surface pb) pixPtr _ _) idx = do e <- peekElemOff pixPtr idx touchForeignPtr pb return e {-# INLINE unsafeWrite #-} unsafeWrite (SurfaceData (Surface pb) pixPtr _ _) idx elem = do pokeElemOff pixPtr idx elem touchForeignPtr pb #if __GLASGOW_HASKELL__ >= 605 {-# INLINE getBounds #-} getBounds (SurfaceData _ _ bd _) = return bd #endif #if __GLASGOW_HASKELL__ >= 608 {-# INLINE getNumElements #-} getNumElements (SurfaceData _ _ _ count) = return count #endif #endif #ifdef CAIRO_HAS_PDF_SURFACE -- | Creates a PostScript surface of the specified size in points to -- be written to @filename@. -- -- Note that the size of individual pages of the PostScript output can -- vary. See 'psSurfaceSetSize'. -- withPDFSurface :: FilePath -- ^ @filename@ - a filename for the PS output (must be writable) -> Double -- ^ width of the surface, in points (1 point == 1\/72.0 inch) -> Double -- ^ height of the surface, in points (1 point == 1\/72.0 inch) -> (Surface -> IO a) -- ^ an action that may use the surface. The surface is -- only valid within in this action. -> IO a withPDFSurface filename width height f = do surface <- Internal.pdfSurfaceCreate filename width height ret <- f surface Internal.surfaceDestroy surface return ret #if CAIRO_CHECK_VERSION(1,2,0) -- | Changes the size of a PDF surface for the current (and -- subsequent) pages. -- -- This function should only be called before any drawing operations -- have been performed on the current page. The simplest way to do -- this is to call this function immediately after creating the -- surface or immediately after completing a page with either -- 'showPage' or 'copyPage'. -- pdfSurfaceSetSize :: MonadIO m => Surface -> Double -> Double -> m () pdfSurfaceSetSize s x y = liftIO $ Internal.pdfSurfaceSetSize s x y #endif #endif #ifdef CAIRO_HAS_PNG_FUNCTIONS -- | Creates a new image surface and initializes the contents to the given PNG -- file. -- withImageSurfaceFromPNG :: FilePath -> (Surface -> IO a) -> IO a withImageSurfaceFromPNG filename f = bracket (Internal.imageSurfaceCreateFromPNG filename) (\surface -> do status <- Internal.surfaceStatus surface Internal.surfaceDestroy surface unless (status == StatusSuccess) $ Internal.statusToString status >>= fail) (\surface -> f surface) -- | Writes the contents of surface to a new file @filename@ as a PNG image. -- surfaceWriteToPNG :: Surface -- ^ a 'Surface' -> FilePath -- ^ @filename@ - the name of a file to write to -> IO () surfaceWriteToPNG surface filename = do status <- Internal.surfaceWriteToPNG surface filename unless (status == StatusSuccess) $ fail =<< Internal.statusToString status return () #endif #ifdef CAIRO_HAS_PS_SURFACE -- | Creates a PostScript surface of the specified size in points to -- be written to @filename@. -- -- Note that the size of individual pages of the PostScript output can -- vary. See 'psSurfaceSetSize'. -- withPSSurface :: FilePath -- ^ @filename@ - a filename for the PS output (must be writable) -> Double -- ^ width of the surface, in points (1 point == 1\/72.0 inch) -> Double -- ^ height of the surface, in points (1 point == 1\/72.0 inch) -> (Surface -> IO a) -- ^ an action that may use the surface. The surface is -- only valid within in this action. -> IO a withPSSurface filename width height f = bracket (Internal.psSurfaceCreate filename width height) (\surface -> do status <- Internal.surfaceStatus surface Internal.surfaceDestroy surface unless (status == StatusSuccess) $ Internal.statusToString status >>= fail) (\surface -> f surface) #if CAIRO_CHECK_VERSION(1,2,0) -- | Changes the size of a PostScript surface for the current (and -- subsequent) pages. -- -- This function should only be called before any drawing operations -- have been performed on the current page. The simplest way to do -- this is to call this function immediately after creating the -- surface or immediately after completing a page with either -- 'showPage' or 'copyPage'. -- psSurfaceSetSize :: MonadIO m => Surface -> Double -> Double -> m () psSurfaceSetSize s x y = liftIO $ Internal.psSurfaceSetSize s x y #endif #endif #ifdef CAIRO_HAS_SVG_SURFACE -- | Creates a SVG surface of the specified size in points -- be written to @filename@. -- withSVGSurface :: FilePath -- ^ @filename@ - a filename for the SVG output (must be writable) -> Double -- ^ width of the surface, in points (1 point == 1\/72.0 inch) -> Double -- ^ height of the surface, in points (1 point == 1\/72.0 inch) -> (Surface -> IO a) -- ^ an action that may use the surface. The surface is -- only valid within in this action. -> IO a withSVGSurface filename width height f = bracket (Internal.svgSurfaceCreate filename width height) (\surface -> do status <- Internal.surfaceStatus surface Internal.surfaceDestroy surface unless (status == StatusSuccess) $ Internal.statusToString status >>= fail) (\surface -> f surface) #endif -- | Returns the version of the cairo library encoded in a single integer. -- version :: Int version = Internal.version -- | Returns the version of the cairo library as a human-readable string of the -- form \"X.Y.Z\". -- versionString :: String versionString = Internal.versionString