# ifndef Magnum_Text_AbstractFont_h
# define Magnum_Text_AbstractFont_h
/*
This file is part of Magnum .
Copyright © 2010 , 2011 , 2012 , 2013 , 2014 , 2015 , 2016 , 2017 , 2018 , 2019
Vladimír Vondruš < mosra @ centrum . cz >
Permission is hereby granted , free of charge , to any person obtaining a
copy of this software and associated documentation files ( the " Software " ) ,
to deal in the Software without restriction , including without limitation
the rights to use , copy , modify , merge , publish , distribute , sublicense ,
and / or sell copies of the Software , and to permit persons to whom the
Software is furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE .
*/
/** @file
* @ brief Class @ ref Magnum : : Text : : AbstractFont , @ ref Magnum : : Text : : AbstractLayouter
*/
# include <string>
# include <vector>
# include <tuple>
# include <Corrade/PluginManager/AbstractPlugin.h>
# include "Magnum/Magnum.h"
# include "Magnum/Text/Text.h"
# include "Magnum/Text/visibility.h"
# ifdef MAGNUM_BUILD_DEPRECATED
# include <Corrade/Containers/PointerStl.h>
# endif
namespace Magnum { namespace Text {
/**
@ brief Features supported by a font implementation
@ m_since_latest
@ see @ ref FontFeatures , @ ref AbstractFont : : features ( )
*/
enum class FontFeature : UnsignedByte {
/** Opening fonts from raw data using @ref AbstractFont::openData() */
OpenData = 1 < < 0 ,
/**
* Specifying callbacks for loading additional files referenced from the
* main file using @ ref AbstractFont : : setFileCallback ( ) . If the font
* doesn ' t expose this feature , the format is either single - file or loading
* via callbacks is not supported .
*
* See @ ref Text - AbstractFont - usage - callbacks and particular font plugin
* documentation for more information .
* @ m_since { 2019 , 10 }
*/
FileCallback = 1 < < 1 ,
# ifdef MAGNUM_BUILD_DEPRECATED
/**
* The format is multi - file , thus @ ref AbstractFont : : openSingleData ( )
* convenience function cannot be used .
* @ m_deprecated_since { 2019 , 10 } Obsolete , use file callbacks
* instead .
*/
MultiFile CORRADE_DEPRECATED_ENUM ( " obsolete, use file callbacks instead " ) = FileCallback ,
# endif
/**
* The font contains prepared glyph cache .
*
* @ see @ ref AbstractFont : : fillGlyphCache ( ) ,
* @ ref AbstractFont : : createGlyphCache ( )
*/
PreparedGlyphCache = 1 < < 2
} ;
/**
@ brief Set of features supported by a font implementation
@ m_since_latest
@ see @ ref AbstractFont : : features ( )
*/
typedef Containers : : EnumSet < FontFeature > FontFeatures ;
CORRADE_ENUMSET_OPERATORS ( FontFeatures )
/** @debugoperatorenum{FontFeature} */
MAGNUM_TEXT_EXPORT Debug & operator < < ( Debug & debug , FontFeature value ) ;
/** @debugoperatorenum{FontFeatures} */
MAGNUM_TEXT_EXPORT Debug & operator < < ( Debug & debug , FontFeatures value ) ;
/**
@ brief Base for font plugins
Provides interface for opening fonts , filling glyph cache and layouting the
glyphs .
@ section Text - AbstractFont - usage Usage
Fonts are most commonly implemented as plugins . For example , loading a font
from the filesystem using the @ ref StbTrueTypeFont plugin and prerendering all
needed glyphs can be done like this , completely with all error handling :
@ snippet MagnumText . cpp AbstractFont - usage
See @ ref plugins for more information about general plugin usage and ` * Font `
classes in the @ ref Text namespace for available font plugins . See
@ ref GlyphCache for more information about glyph caches and @ ref Renderer for
information about actual text rendering .
@ subsection Text - AbstractFont - usage - callbacks Loading data from memory , using file callbacks
Besides loading data directly from the filesystem using @ ref openFile ( ) like
shown above , it ' s possible to use @ ref openData ( ) to import data from memory .
Note that the particular importer implementation must support
@ ref FontFeature : : OpenData for this method to work .
Some font formats consist of more than one file and in that case you may want
to intercept those references and load them in a custom way as well . For font
plugins that advertise support for this with @ ref FontFeature : : FileCallback
this is done by specifying a file loading callback using @ ref setFileCallback ( ) .
The callback gets a filename , @ ref InputFileCallbackPolicy and an user
pointer as parameters ; returns a non - owning view on the loaded data or a
@ ref Corrade : : Containers : : NullOpt " Containers::NullOpt " to indicate the file
loading failed . For example , loading a memory - mapped font could look like
below . Note that the file loading callback affects @ ref openFile ( ) as
well - - - you don ' t have to load the top - level file manually and pass it to
@ ref openData ( ) , any font plugin supporting the callback feature handles that
correctly .
@ snippet MagnumText . cpp AbstractFont - usage - callbacks
For importers that don ' t support @ ref FontFeature : : FileCallback directly , the
base @ ref openFile ( ) implementation will use the file callback to pass the
loaded data through to @ ref openData ( ) , in case the importer supports at least
@ ref FontFeature : : OpenData . If the importer supports neither
@ ref FontFeature : : FileCallback nor @ ref FontFeature : : OpenData ,
@ ref setFileCallback ( ) doesn ' t allow the callbacks to be set .
The input file callback signature is the same for @ ref Text : : AbstractFont and
@ ref Trade : : AbstractImporter to allow code reuse .
@ section Text - AbstractFont - subclassing Subclassing
The plugin implements @ ref doFeatures ( ) , @ ref doClose ( ) , @ ref doLayout ( ) ,
either @ ref doCreateGlyphCache ( ) or @ ref doFillGlyphCache ( ) and one or more of
` doOpen * ( ) ` functions . See also @ ref AbstractLayouter for more information .
You don ' t need to do most of the redundant sanity checks , these things are
checked by the implementation :
- Functions @ ref doOpenData ( ) and @ ref doOpenFile ( ) are called after the
previous file was closed , function @ ref doClose ( ) is called only if there
is any file opened .
- Function @ ref doOpenData ( ) is called only if @ ref FontFeature : : OpenData is
supported .
- The @ ref doSetFileCallback ( ) function is called only if
@ ref FontFeature : : FileCallback is supported and there is no file opened .
- All ` do * ( ) ` implementations working on opened file are called only if
there is any file opened .
*/
class MAGNUM_TEXT_EXPORT AbstractFont : public PluginManager : : AbstractPlugin {
public :
# ifdef MAGNUM_BUILD_DEPRECATED
/** @brief @copybrief FontFeature
* @ m_deprecated_since_latest Use @ ref FontFeature instead .
*/
typedef CORRADE_DEPRECATED ( " use FontFeature instead " ) FontFeature Feature ;
/** @brief @copybrief FontFeatures
* @ m_deprecated_since_latest Use @ ref FontFeatures instead .
*/
typedef CORRADE_DEPRECATED ( " use FontFeatures instead " ) FontFeatures Features ;
# endif
/**
* @ brief Plugin interface
*
* @ code { . cpp }
* " cz.mosra.magnum.Text.AbstractFont/0.3 "
* @ endcode
*/
static std : : string pluginInterface ( ) ;
# ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
/**
* @ brief Plugin search paths
*
* First looks in ` magnum / fonts / ` or ` magnum - d / fonts / ` next to the
* executable ( or , in case of Windows and a non - static build , next to
* the DLL of the @ ref Text library ) and as a fallback in
* ` magnum / fonts / ` or ` magnum - d / fonts / ` in the runtime install location
* ( ` lib [ 64 ] / ` on Unix - like systems , ` bin / ` on Windows ) . The
* system - wide plugin search directory is configurable using the
* ` MAGNUM_PLUGINS_DIR ` CMake variables , see @ ref building for more
* information .
*
* Not defined on platforms without
* @ ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT " dynamic plugin support " .
*/
static std : : vector < std : : string > pluginSearchPaths ( ) ;
# endif
/** @brief Default constructor */
explicit AbstractFont ( ) ;
/** @brief Plugin manager constructor */
explicit AbstractFont ( PluginManager : : AbstractManager & manager , const std : : string & plugin ) ;
/** @brief Features supported by this font */
FontFeatures features ( ) const { return doFeatures ( ) ; }
/**
* @ brief File opening callback function
* @ m_since { 2019 , 10 }
*
* @ see @ ref Text - AbstractFont - usage - callbacks
*/
auto fileCallback ( ) const - > Containers : : Optional < Containers : : ArrayView < const char > > ( * ) ( const std : : string & , InputFileCallbackPolicy , void * ) { return _fileCallback ; }
/**
* @ brief File opening callback user data
* @ m_since { 2019 , 10 }
*
* @ see @ ref Text - AbstractFont - usage - callbacks
*/
void * fileCallbackUserData ( ) const { return _fileCallbackUserData ; }
/**
* @ brief Set file opening callback
* @ m_since { 2019 , 10 }
*
* In case the font plugin supports @ ref FontFeature : : FileCallback ,
* files opened through @ ref openFile ( ) will be loaded through the
* provided callback . Besides that , all external files referenced by
* the top - level file will be loaded through the callback function as
* well , usually on demand . The callback function gets a filename ,
* @ ref InputFileCallbackPolicy and the @ p userData pointer as input
* and returns a non - owning view on the loaded data as output or a
* @ ref Corrade : : Containers : : NullOpt if loading failed - - - because
* empty files might also be valid in some circumstances , @ cpp nullptr @ ce
* can ' t be used to indicate a failure .
*
* In case the font plugin doesn ' t support @ ref FontFeature : : FileCallback
* but supports at least @ ref FontFeature : : OpenData , a file opened
* through @ ref openFile ( ) will be internally loaded through the
* provided callback and then passed to @ ref openData ( ) . First the file
* is loaded with @ ref InputFileCallbackPolicy : : LoadTemporary passed to
* the callback , then the returned memory view is passed to
* @ ref openData ( ) ( sidestepping the potential @ ref openFile ( )
* implementation of that particular font plugin ) and after that the
* callback is called again with @ ref InputFileCallbackPolicy : : Close
* because the semantics of @ ref openData ( ) don ' t require the data to
* be alive after . In case you need a different behavior , use
* @ ref openData ( ) directly .
*
* In case @ p callback is @ cpp nullptr @ ce , the current callback ( if
* any ) is reset . This function expects that the font plugin supports
* either @ ref FontFeature : : FileCallback or @ ref FontFeature : : OpenData .
* If a font plugin supports neither , callbacks can ' t be used .
*
* It ' s expected that this function is called * before * a file is
* opened . It ' s also expected that the loaded data are kept in scope
* for as long as the font plugin needs them , based on the value of
* @ ref InputFileCallbackPolicy . Documentation of particular importers
* provides more information about the expected callback behavior .
*
* Following is an example of setting up a file loading callback for
* fetching compiled - in resources from @ ref Corrade : : Utility : : Resource .
* See the overload below for a more convenient type - safe way to pass
* the user data pointer .
*
* @ snippet MagnumText . cpp AbstractFont - setFileCallback
*
* @ see @ ref Text - AbstractFont - usage - callbacks
*/
void setFileCallback ( Containers : : Optional < Containers : : ArrayView < const char > > ( * callback ) ( const std : : string & , InputFileCallbackPolicy , void * ) , void * userData = nullptr ) ;
/**
* @ brief Set file opening callback
* @ m_since { 2019 , 10 }
*
* Equivalent to calling the above with a lambda wrapper that casts
* @ cpp void * @ ce back to @ cpp T * @ ce and dereferences it in order to
* pass it to @ p callback . Example usage :
*
* @ snippet MagnumText . cpp AbstractFont - setFileCallback - template
*
* @ see @ ref Text - AbstractFont - usage - callbacks
*/
# ifdef DOXYGEN_GENERATING_OUTPUT
template < class T > void setFileCallback ( Containers : : Optional < Containers : : ArrayView < const char > > ( * callback ) ( const std : : string & , InputFileCallbackPolicy , T & ) , T & userData ) ;
# else
/* Otherwise the user would be forced to use the + operator to convert
a lambda to a function pointer and ( besides being weird and
annoying ) it ' s also not portable because it doesn ' t work on MSVC
2015 and older versions of MSVC 2017. */
template < class Callback , class T > void setFileCallback ( Callback callback , T & userData ) ;
# endif
/** @brief Whether any file is opened */
bool isOpened ( ) const { return doIsOpened ( ) ; }
/**
* @ brief Open font from raw data
* @ param data File data
* @ param size Font size
*
* Closes previous file , if it was opened , and tries to open given
* file . Available only if @ ref FontFeature : : OpenData is supported .
* Returns @ cpp true @ ce on success , @ cpp false @ ce otherwise .
* @ see @ ref features ( ) , @ ref openFile ( )
*/
bool openData ( Containers : : ArrayView < const char > data , Float size ) ;
# ifdef MAGNUM_BUILD_DEPRECATED
/** @brief @copybrief openData(Containers::ArrayView<const char>, Float)
* @ m_deprecated_since { 2019 , 10 } Use @ ref openFile ( ) with
* @ ref setFileCallback ( ) for opening multi - file fonts instead .
*/
CORRADE_DEPRECATED ( " use openFile() with setFileCallback() for opening multi-file fonts instead " ) bool openData ( const std : : vector < std : : pair < std : : string , Containers : : ArrayView < const char > > > & data , Float size ) ;
/** @brief @copybrief openData(Containers::ArrayView<const char>, Float)
* @ m_deprecated_since { 2019 , 10 } Use @ ref openData ( Containers : : ArrayView < const char > , Float )
* instead .
*/
CORRADE_DEPRECATED ( " use openData(Containers::ArrayView<const char>, Float) instead " ) bool openSingleData ( Containers : : ArrayView < const char > data , Float size ) ;
# endif
/**
* @ brief Open font from file
* @ param filename Font file
* @ param size Font size
*
* Closes previous file , if it was opened , and tries to open given
* file . If the plugin has @ ref FontFeature : : MultiFile , the function
* will use additional files in given path , all sharing common basename
* derived from @ p filename . Returns @ cpp true @ ce on success ,
* @ cpp false @ ce otherwise .
*/
bool openFile ( const std : : string & filename , Float size ) ;
/** @brief Close font */
void close ( ) ;
/**
* @ brief Font size
*
* Returns scale in which @ ref lineHeight ( ) , @ ref ascent ( ) ,
* @ ref descent ( ) and @ ref glyphAdvance ( ) is returned . Expects that a
* font is opened .
*/
Float size ( ) const ;
/**
* @ brief Font ascent
*
* Distance from baseline to top , scaled to font size . Positive value .
* Expects that a font is opened .
* @ see @ ref size ( ) , @ ref descent ( ) , @ ref lineHeight ( )
*/
Float ascent ( ) const ;
/**
* @ brief Font descent
*
* Distance from baseline to bottom , scalled to font size . Negative
* value . Expects that a font is opened .
* @ see @ ref size ( ) , @ ref ascent ( ) , @ ref lineHeight ( )
*/
Float descent ( ) const ;
/**
* @ brief Line height
*
* Returns line height scaled to font size . Expects that a font is
* opened .
* @ see @ ref size ( ) , @ ref ascent ( ) , @ ref descent ( )
*/
Float lineHeight ( ) const ;
/**
* @ brief Glyph ID for given character
*
* Expects that a font is opened .
* @ note This function is meant to be used only for font observations
* and conversions . In performance - critical code the @ ref layout ( )
* function should be used instead .
*/
UnsignedInt glyphId ( char32_t character ) ;
/**
* @ brief Glyph advance
* @ param glyph Glyph ID
*
* Returns glyph advance scaled to font size . Expects that a font is
* opened .
* @ note This function is meant to be used only for font observations
* and conversions . In performance - critical code the @ ref layout ( )
* function should be used instead .
* @ see @ ref glyphId ( ) , @ ref size ( )
*/
Vector2 glyphAdvance ( UnsignedInt glyph ) ;
/**
* @ brief Fill glyph cache with given character set
* @ param cache Glyph cache instance
* @ param characters UTF - 8 characters to render
*
* Fills the cache with given characters . Fonts having
* @ ref FontFeature : : PreparedGlyphCache do not support partial glyph
* cache filling , use @ ref createGlyphCache ( ) instead . Expects that a
* font is opened .
*/
void fillGlyphCache ( AbstractGlyphCache & cache , const std : : string & characters ) ;
/**
* @ brief Create glyph cache
*
* Configures and fills glyph cache with the contents of whole font .
* Available only if @ ref FontFeature : : PreparedGlyphCache is supported .
* Other fonts support only partial glyph cache filling , see
* @ ref fillGlyphCache ( ) . Expects that a font is opened .
*/
Containers : : Pointer < AbstractGlyphCache > createGlyphCache ( ) ;
/**
* @ brief Layout the text using font ' s own layouter
* @ param cache Glyph cache
* @ param size Font size
* @ param text Text to layout
*
* Note that the layouters support rendering of single - line text only .
* See @ ref Renderer class for more advanced text layouting . Expects
* that a font is opened .
* @ see @ ref fillGlyphCache ( ) , @ ref createGlyphCache ( )
*/
Containers : : Pointer < AbstractLayouter > layout ( const AbstractGlyphCache & cache , Float size , const std : : string & text ) ;
protected :
/**
* @ brief Font metrics
*
* @ see @ ref doOpenFile ( ) , @ ref doOpenData ( )
*/
struct Metrics {
# ifndef DOXYGEN_GENERATING_OUTPUT
/* Otherwise GCC 4.8 loudly complains about missing initializers */
constexpr /*implicit*/ Metrics ( ) noexcept : size { } , ascent { } , descent { } , lineHeight { } { }
constexpr /*implicit*/ Metrics ( Float size , Float ascent , Float descent , Float lineHeight ) noexcept : size { size } , ascent { ascent } , descent { descent } , lineHeight { lineHeight } { }
# endif
/**
* Font size
* @ see @ ref size ( )
*/
Float size ;
/**
* Font ascent
* @ see @ ref ascent ( )
*/
Float ascent ;
/**
* Font descent
* @ see @ ref descent ( )
*/
Float descent ;
/**
* Line height
* @ see @ ref lineHeight ( )
*/
Float lineHeight ;
} ;
protected :
/**
* @ brief Implementation for @ ref openFile ( )
*
* Return metrics of opened font on successful opening , zeros
* otherwise . If @ ref FontFeature : : OpenData is supported , default
* implementation opens the file and calls @ ref doOpenData ( ) with its
* contents . It is allowed to call this function from your
* @ ref doOpenFile ( ) implementation - - - in particular , this
* implementation will also correctly handle callbacks set through
* @ ref setFileCallback ( ) .
*
* This function is not called when file callbacks are set through
* @ ref setFileCallback ( ) and @ ref FontFeature : : FileCallback is not
* supported - - - instead , file is loaded though the callback and data
* passed through to @ ref doOpenData ( ) .
*/
virtual Metrics doOpenFile ( const std : : string & filename , Float size ) ;
private :
/** @brief Implementation for @ref features() */
virtual FontFeatures doFeatures ( ) const = 0 ;
/**
* @ brief Implementation for @ ref setFileCallback ( )
*
* Useful when the font plugin needs to modify some internal state on
* callback setup . Default implementation does nothing and this
* function doesn ' t need to be implemented - - - the callback function
* and user data pointer are available through @ ref fileCallback ( ) and
* @ ref fileCallbackUserData ( ) .
*/
virtual void doSetFileCallback ( Containers : : Optional < Containers : : ArrayView < const char > > ( * callback ) ( const std : : string & , InputFileCallbackPolicy , void * ) , void * userData ) ;
/** @brief Implementation for @ref isOpened() */
virtual bool doIsOpened ( ) const = 0 ;
/**
* @ brief Implementation for @ ref openData ( )
*
* Return metrics of opened font on successful opening , zeros
* otherwise .
*/
virtual Metrics doOpenData ( Containers : : ArrayView < const char > data , Float size ) ;
/** @brief Implementation for @ref close() */
virtual void doClose ( ) = 0 ;
/** @brief Implementation for @ref glyphId() */
virtual UnsignedInt doGlyphId ( char32_t character ) = 0 ;
/** @brief Implementation for @ref glyphAdvance() */
virtual Vector2 doGlyphAdvance ( UnsignedInt glyph ) = 0 ;
/**
* @ brief Implementation for @ ref fillGlyphCache ( )
*
* The string is converted from UTF - 8 to UTF - 32 , unique characters are
* * not * removed .
*/
virtual void doFillGlyphCache ( AbstractGlyphCache & cache , const std : : u32string & characters ) ;
/** @brief Implementation for @ref createGlyphCache() */
virtual Containers : : Pointer < AbstractGlyphCache > doCreateGlyphCache ( ) ;
/** @brief Implementation for @ref layout() */
virtual Containers : : Pointer < AbstractLayouter > doLayout ( const AbstractGlyphCache & cache , Float size , const std : : string & text ) = 0 ;
Containers : : Optional < Containers : : ArrayView < const char > > ( * _fileCallback ) ( const std : : string & , InputFileCallbackPolicy , void * ) { } ;
void * _fileCallbackUserData { } ;
/* Used by the templated version only */
struct FileCallbackTemplate {
void ( * callback ) ( ) ;
const void * userData ;
/* GCC 4.8 complains loudly about missing initializers otherwise */
} _fileCallbackTemplate { nullptr , nullptr } ;
Float _size { } , _ascent { } , _descent { } , _lineHeight { } ;
} ;
/**
@ brief Base for text layouters
Returned by @ ref AbstractFont : : layout ( ) .
@ section Text - AbstractLayouter - subclassing Subclassing
Plugin creates private subclass ( no need to expose it to end users ) and
implements @ ref doRenderGlyph ( ) . Bounds checking on @ p i is done automatically
in the wrapping @ ref renderGlyph ( ) function .
*/
class MAGNUM_TEXT_EXPORT AbstractLayouter {
public :
/** @brief Copying is not allowed */
AbstractLayouter ( const AbstractLayouter & ) = delete ;
/** @brief Moving is not allowed */
AbstractLayouter ( AbstractLayouter & & ) = delete ;
virtual ~ AbstractLayouter ( ) ;
/** @brief Copying is not allowed */
AbstractLayouter & operator = ( const AbstractLayouter & ) = delete ;
/** @brief Moving is not allowed */
AbstractLayouter & operator = ( const AbstractLayouter & & ) = delete ;
/** @brief Count of glyphs in laid out text */
UnsignedInt glyphCount ( ) const { return _glyphCount ; }
/**
* @ brief Render glyph
* @ param i Glyph index
* @ param cursorPosition Cursor position
* @ param rectangle Bounding rectangle
*
* The function returns pair of quad position and texture coordinates ,
* advances @ p cursorPosition to next character and updates @ p rectangle
* with extended bounds .
*/
std : : pair < Range2D , Range2D > renderGlyph ( UnsignedInt i , Vector2 & cursorPosition , Range2D & rectangle ) ;
protected :
/**
* @ brief Constructor
* @ param glyphCount Count of glyphs in laid out text
*/
explicit AbstractLayouter ( UnsignedInt glyphCount ) ;
# ifdef DOXYGEN_GENERATING_OUTPUT
protected :
# else
private :
# endif
/**
* @ brief Implementation for @ ref renderGlyph ( )
* @ param i Glyph index
*
* Return quad position ( relative to current cursor position ) , texture
* coordinates and advance to next glyph .
*/
virtual std : : tuple < Range2D , Range2D , Vector2 > doRenderGlyph ( UnsignedInt i ) = 0 ;
# ifdef DOXYGEN_GENERATING_OUTPUT
private :
# endif
UnsignedInt _glyphCount ;
} ;
# ifndef DOXYGEN_GENERATING_OUTPUT
template < class Callback , class T > void AbstractFont : : setFileCallback ( Callback callback , T & userData ) {
/* Don't try to wrap a null function pointer. Need to cast first because
MSVC ( even 2017 ) can ' t apply ! to a lambda . Ugh . */
const auto callbackPtr = static_cast < Containers : : Optional < Containers : : ArrayView < const char > > ( * ) ( const std : : string & , InputFileCallbackPolicy , T & ) > ( callback ) ;
if ( ! callbackPtr ) return setFileCallback ( nullptr ) ;
_fileCallbackTemplate = { reinterpret_cast < void ( * ) ( ) > ( callbackPtr ) , static_cast < const void * > ( & userData ) } ;
setFileCallback ( [ ] ( const std : : string & filename , const InputFileCallbackPolicy flags , void * const userData ) {
auto & s = * reinterpret_cast < FileCallbackTemplate * > ( userData ) ;
return reinterpret_cast < Containers : : Optional < Containers : : ArrayView < const char > > ( * ) ( const std : : string & , InputFileCallbackPolicy , T & ) > ( s . callback ) ( filename , flags , * static_cast < T * > ( const_cast < void * > ( s . userData ) ) ) ;
} , & _fileCallbackTemplate ) ;
}
# endif
} }
# endif