1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008 Henrik Tidefelt
19 #include "shapescore.h"
21 #include "charconverters.h"
22 #include "autoonoff.h"
24 #include "glyphlist.h"
27 using namespace Shapes
;
34 class Core_makeglyph
: public Lang::CoreFunction
36 Lang::Type3Glyph::Kind kind_
;
38 Core_makeglyph( const char * title
, Lang::Type3Glyph::Kind kind
)
39 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) ), kind_( kind
)
41 formals_
->appendEvaluatedCoreFormal( "width", Kernel::THE_SLOT_VARIABLE
);
42 formals_
->appendEvaluatedCoreFormal( "glyph", Kernel::THE_SLOT_VARIABLE
);
43 formals_
->appendEvaluatedCoreFormal( "char", Kernel::THE_VOID_VARIABLE
);
44 formals_
->appendEvaluatedCoreFormal( "name", Kernel::THE_VOID_VARIABLE
);
47 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
49 args
.applyDefaults( );
52 typedef const Lang::Length WidthType
;
53 RefCountPtr
< WidthType
> widthX
= Helpers::down_cast_CoreArgument
< WidthType
>( title_
, args
, argsi
, callLoc
);
56 typedef const Lang::Drawable2D GlyphType
;
57 RefCountPtr
< GlyphType
> glyph
= Helpers::down_cast_CoreArgument
< GlyphType
>( title_
, args
, argsi
, callLoc
);
60 typedef const Lang::String CodeType
;
61 RefCountPtr
< CodeType
> codeStringUTF8
= Helpers::down_cast_CoreArgument
< CodeType
>( title_
, args
, argsi
, callLoc
, true );
64 typedef const Lang::Symbol NameType
;
65 RefCountPtr
< NameType
> nameUTF8
= RefCountPtr
< NameType
>( NullPtr
< NameType
>( ) );
66 RefCountPtr
< CodeType
> nameStringUTF8
= codeStringUTF8
;
70 // If the argument is void, this goes through with nameUTF8 being null. We will then refer to nameStringUTF8 as set above.
71 nameUTF8
= Helpers::try_cast_CoreArgument
< NameType
>( args
.getValue( argsi
), true );
74 catch( const NonLocalExit::NotThisType
& ball
)
76 // Never mind, but see below!
81 // If we reach here, the value is present, but not a Symbol. Hence we require that it be a string value for the name that replaces the default value being that of codeStringUTF8.
82 nameStringUTF8
= Helpers::try_cast_CoreArgument
< CodeType
>( args
.getValue( argsi
) );
85 catch( const NonLocalExit::NotThisType
& ball
)
87 // Never mind, but see below!
90 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, argsi
, Helpers::typeSetString( Lang::Symbol::staticTypeName( ), Lang::String::staticTypeName( ) ) );
94 // Convert the character code string to a number:
96 if( codeStringUTF8
!= NullPtr
< CodeType
>( ) )
98 iconv_t converter
= Helpers::requireUTF8ToMacRomanConverter( );
100 const char * inbuf
= codeStringUTF8
->val_
.getPtr( );
102 size_t bufSize
= strlen( inbuf
);
103 char * buf
= new char[ bufSize
+ 1 ];
104 DeleteOnExit
< char > bufDeleter( buf
);
107 size_t inbytesleft
= bufSize
;
108 size_t outbytesleft
= bufSize
;
109 // The ICONV_CAST macro is defined in config.h.
110 size_t count
= iconv( converter
,
111 ICONV_CAST( & inbuf
), & inbytesleft
,
112 & outbuf
, & outbytesleft
);
113 if( count
== (size_t)(-1) )
115 if( errno
== EILSEQ
)
117 throw Exceptions::MiscellaneousRequirement( "It is suspected that one of the UFT-8 character cannot be used as a character code in a font with MacRoman encoding." );
119 else if( errno
== EINVAL
)
121 throw Exceptions::MiscellaneousRequirement( "It is suspected that glyph's character code ended with an incomplete multibyte character." );
123 else if( errno
== E2BIG
)
125 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to MacRoman conversion was too small." );
129 std::ostringstream msg
;
130 msg
<< "iconv failed with an unrecognized error code: " << errno
;
131 throw Exceptions::InternalError( strrefdup( msg
) );
135 if( strlen( buf
) != 1 )
137 throw Exceptions::CoreRequirement( "The glyph's character code must be a string with exactly one character, or not be specified at all.", title_
, callLoc
);
139 code
= *reinterpret_cast< const unsigned char * >( buf
);
142 RefCountPtr
< const char > name
= RefCountPtr
< const char >( NullPtr
< const char >( ) );
143 if( nameUTF8
== NullPtr
< NameType
>( ) )
145 if( nameStringUTF8
== NullPtr
< CodeType
>( ) )
147 throw Exceptions::CoreRequirement( "At least one of <char> and <name> must be specified.", title_
, callLoc
);
149 const FontMetrics::GlyphList
& glyphList
= Helpers::requireGlyphList( );
151 if( ! glyphList
.UTF8_to_name( nameStringUTF8
->val_
.getPtr( ), & dst
) )
153 throw Exceptions::CoreOutOfRange( title_
, args
, 2, "When no name is given, characters without default names are not allowed. Please refer to the glyph list." );
155 name
= strrefdup( dst
);
159 // Ensure that the glyph name is legal
160 iconv_t converter
= Helpers::requireUTF8ToASCIIConverter( );
162 const char * inbuf
= nameUTF8
->name( ).getPtr( );
164 size_t bufSize
= strlen( inbuf
);
165 char * buf
= new char[ bufSize
+ 1 ];
166 name
= RefCountPtr
< const char >( buf
); // this will delete the buffer if it becomes unused.
169 size_t inbytesleft
= bufSize
;
170 size_t outbytesleft
= bufSize
;
171 // The ICONV_CAST macro is defined in config.h.
172 size_t count
= iconv( converter
,
173 ICONV_CAST( & inbuf
), & inbytesleft
,
174 & outbuf
, & outbytesleft
);
175 if( count
== (size_t)(-1) )
177 if( errno
== EILSEQ
)
179 throw Exceptions::CoreOutOfRange( title_
, args
, 3, "A non-ASCII character was found in a glyph name." );
181 else if( errno
== EINVAL
)
183 throw Exceptions::MiscellaneousRequirement( "It is suspected that glyph's name ended with an incomplete multibyte character." );
185 else if( errno
== E2BIG
)
187 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to ASCII conversion was too small." );
191 std::ostringstream msg
;
192 msg
<< "iconv failed with an unrecognized error code: " << errno
;
193 throw Exceptions::InternalError( strrefdup( msg
) );
199 // Find boudning box:
200 RefCountPtr
< const Lang::ElementaryPath2D
> theBBox
= glyph
->bbox( Lang::Drawable2D::BOUNDING
);
201 Concrete::Coords2D
llcorner( 0, 0 );
202 Concrete::Coords2D
urcorner( 0, 0 );
203 if( ! theBBox
->boundingRectangle( & llcorner
, & urcorner
) )
205 std::string
strTitle( title_
);
206 throw Exceptions::InternalError( strrefdup( strTitle
+ ": The glyph has no bounding box!" ) );
209 Kernel::ContRef cont
= evalState
->cont_
;
210 cont
->takeValue( Kernel::ValueRef( new Lang::Type3Glyph( kind_
,
228 Kernel::registerCore_font( Kernel::Environment
* env
)
230 env
->initDefineCoreFunction( new Lang::Core_makeglyph( "basicglyph", Lang::Type3Glyph::BASIC
) );
231 env
->initDefineCoreFunction( new Lang::Core_makeglyph( "coloredglyph", Lang::Type3Glyph::COLORED
) );
233 env
->initDefine( "FONT_TIMES_ROMAN", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::TIMES_ROMAN
) ) );
234 env
->initDefine( "FONT_TIMES_BOLD", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::TIMES_BOLD
) ) );
235 env
->initDefine( "FONT_TIMES_ITALIC", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::TIMES_ITALIC
) ) );
236 env
->initDefine( "FONT_TIMES_BOLDITALIC", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::TIMES_BOLDITALIC
) ) );
237 env
->initDefine( "FONT_HELVETICA", Lang::THE_FONT_HELVETICA
);
238 env
->initDefine( "FONT_HELVETICA_BOLD", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::HELVETICA_BOLD
) ) );
239 env
->initDefine( "FONT_HELVETICA_OBLIQUE", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::HELVETICA_OBLIQUE
) ) );
240 env
->initDefine( "FONT_HELVETICA_BOLDOBLIQUE", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::HELVETICA_BOLDOBLIQUE
) ) );
241 env
->initDefine( "FONT_COURIER", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::COURIER
) ) );
242 env
->initDefine( "FONT_COURIER_BOLD", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::COURIER_BOLD
) ) );
243 env
->initDefine( "FONT_COURIER_OBLIQUE", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::COURIER_OBLIQUE
) ) );
244 env
->initDefine( "FONT_COURIER_BOLDOBLIQUE", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::COURIER_BOLDOBLIQUE
) ) );
245 env
->initDefine( "FONT_SYMBOL", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::SYMBOL
) ) );
246 env
->initDefine( "FONT_ZAPFDINGBATS", RefCountPtr
< const Lang::Font
>( new Lang::Font( BuiltInFonts::ZAPFDINGBATS
) ) );