    {-# LANGUAGE CPP          #-}
    {-# LANGUAGE TypeFamilies #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Diagrams.Backend.Cairo
    -- Copyright   :  (c) 2011 Diagrams-cairo team (see LICENSE)
    -- License     :  BSD-style (see LICENSE)
    -- Maintainer  :  diagrams-discuss@googlegroups.com
    --
    -- A full-featured rendering backend for diagrams using the
    -- cairo rendering engine.
    --
    -- To invoke the cairo backend, you have three options.
    --
    -- * You can use the "Diagrams.Backend.Cairo.CmdLine" module to create
    --   standalone executables which output images when invoked.
    --
    -- * You can use the 'renderCairo' function provided by this module,
    --   which gives you more flexible programmatic control over when and
    --   how images are output (making it easy to, for example, write a
    --   single program that outputs multiple images, or one that outputs
    --   images dynamically based on user input, and so on).
    --
    -- * Finally, for the most flexibility, you can directly
    --   use methods from the
    --   'Diagrams.Core.Types.Backend' instance for @Cairo@.  In particular,
    --   'Diagrams.Core.Types.renderDia' has the generic type
    --
    -- > renderDia :: b -> Options b v n -> QDiagram b v n m -> Result b v n
    --
    -- (omitting a few type class constraints).  @b@ represents the
    -- backend type, @v@ the vector space, @n@ the numeric field, and @m@
    -- the type of monoidal query annotations on the diagram.  'Options'
    -- and 'Result' are associated data and type families, respectively,
    -- which yield the type of option records and rendering results
    -- specific to any particular backend.  For @b ~ Cairo@, @v ~ V2@, and
    -- @n ~ Double@, we have
    --
    -- > data family Options Cairo V2 Double = CairoOptions
    -- >          { _cairoFileName     :: String             -- ^ The name of the file you want generated
    -- >          , _cairoSizeSpec     :: SizeSpec V2 Double -- ^ The requested size of the output
    -- >          , _cairoOutputType   :: OutputType         -- ^ the output format and associated options
    -- >          , _cairoBypassAdjust :: Bool               -- ^ Should the 'adjustDia' step be bypassed during rendering?
    -- >          }
    --
    -- @
    -- type family Result Cairo V2 Double = (IO (), 'Graphics.Rendering.Cairo.Render' ())
    -- @
    --
    -- So the type of 'renderDia' resolves to
    --
    -- @
    -- renderDia :: Cairo -> Options Cairo V2 Double -> QQDiagram Cairo V2 Double Any m -> (IO (), 'Graphics.Rendering.Cairo.Render' ())
    -- @
    --
    -- which you could call like so:
    --
    -- @
    -- renderDia Cairo (CairoOptions \"foo.png\" (Width 250) PNG False) (myDiagram :: QDiagram Cairo V2 Double Any)
    -- @
    --
    -- This would return a pair; the first element is an @IO ()@ action
    -- which will write out @foo.png@ to disk, and the second is a cairo
    -- rendering action which can be used, for example, to directly draw
    -- to a Gtk window.  Note the type annotation on @myDiagram@ which may
    -- be necessary to fix the type variable @m@; this example uses the
    -- type synonym @Diagram b = QDiagram b (V b) (N b) Any@ to fix @m = Any@
    -- and fix @v@ and @n@ to backend specific types.
    --
    -----------------------------------------------------------------------------
    module Diagrams.Backend.Cairo

      ( -- * Rendering
        renderCairo

        -- * Cairo-supported output formats
      , OutputType(..)

        -- * Cairo-specific options
        -- $CairoOptions

    -- The below CPP hack is needed because GHC 7.0.x has a bug regarding
    -- (re?)export of data family constructors; in particular the below
    -- export causes the error "Not in scope: type constructor or class
    -- `Options'" even though
    -- http://www.haskell.org/haskellwiki/GHC/Type_families#Import_and_export
    -- seems to indicate it should be supported.  When using 7.0.x one
    -- must import Diagrams.Backend.Cairo.Internal in order to bring
    -- CairoOptions into scope.
    -- GHC 7.4.0 regression?
    #if __GLASGOW_HASKELL__ >= 702 && __GLASGOW_HASKELL__ < 704
      , Options(..)
    #endif

        -- * Backend token
      , Cairo(..)
      , B
      ) where

    import           System.FilePath                 (takeExtension)

    import           Diagrams.Backend.Cairo.Internal
    import           Diagrams.Prelude

    -- $CairoOptions
    --
    -- Unfortunately, Haddock does not yet support documentation for
    -- associated data families, so we must just provide it manually.
    -- This module defines
    --
    -- > data family Options Cairo V2 Double = CairoOptions
    -- >   { _cairoFileName   :: String     -- ^ The name of the file you want generated
    -- >   , _cairoSizeSpec   :: SizeSpec V2 Double -- ^ The requested size of the output
    -- >   , _cairoOutputType :: OutputType -- ^ the output format and associated options
    -- >   , _cairoBypassAdjust  :: Bool    -- ^ Should the 'adjustDia' step be bypassed during rendering?
    -- >   }
    --
    -- See the documentation at the top of "Diagrams.Backend.Cairo" for
    -- information on how to make use of this.

    -- | Render a diagram using the cairo backend, writing to the given
    --   output file and using the requested size.  The output type (PNG,
    --   PS, PDF, or SVG) is determined automatically from the output file
    --   extension.
    --
    --   This function is provided as a convenience; if you need more
    --   flexibility than it provides, you can call 'renderDia' directly,
    --   as described above.
    renderCairo :: FilePath -> SizeSpec V2 Double -> QDiagram Cairo V2 Double Any -> IO ()
    renderCairo :: FilePath
    -> SizeSpec V2 Double -> QDiagram Cairo V2 Double Any -> IO ()
    renderCairo FilePath
    outFile SizeSpec V2 Double
    sizeSpec QDiagram Cairo V2 Double Any
    d
      = (IO (), Render ()) -> IO ()
    forall a b. (a, b) -> a
    fst (Cairo
    -> Options Cairo V2 Double
    -> QDiagram Cairo V2 Double Any
    -> Result Cairo V2 Double
    forall b (v :: * -> *) n m.
    (Backend b v n, HasLinearMap v, Metric v, Typeable n,
     OrderedField n, Monoid' m) =>
    b -> Options b v n -> QDiagram b v n m -> Result b v n
    renderDia Cairo
    Cairo (FilePath
    -> SizeSpec V2 Double
    -> OutputType
    -> Bool
    -> Options Cairo V2 Double
    CairoOptions FilePath
    outFile SizeSpec V2 Double
    sizeSpec OutputType
    outTy Bool
    False) QDiagram Cairo V2 Double Any
    d)
      where
        outTy :: OutputType
    outTy =
          case FilePath -> FilePath
    takeExtension FilePath
    outFile of
            FilePath
    ".png" -> OutputType
    PNG
            FilePath
    ".ps"  -> OutputType
    PS
            FilePath
    ".pdf" -> OutputType
    PDF
            FilePath
    ".svg" -> OutputType
    SVG
            FilePath
    _      -> OutputType
    PNG