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::Character CodeType
;
61 RefCountPtr
< CodeType
> codeArg
= Helpers::down_cast_CoreArgument
< CodeType
>( title_
, args
, argsi
, callLoc
, true );
64 typedef const Lang::Symbol NameType
;
65 RefCountPtr
< NameType
> nameUTF8
= RefCountPtr
< NameType
>( NullPtr
< NameType
>( ) );
67 RefCountPtr
< const Lang::String
> nameStringUTF8
= RefCountPtr
< const Lang::String
>( NullPtr
< const Lang::String
>( ) );
68 if( codeArg
!= NullPtr
< CodeType
>( ) )
70 const size_t charBufSize
= 10;
71 char charBuf
[ charBufSize
];
73 size_t charBufAvail
= charBufSize
- 1;
74 codeArg
->val_
.encode_UTF8( & dst
, & charBufAvail
);
76 nameStringUTF8
= RefCountPtr
< const Lang::String
>( new Lang::String( strrefdup( charBuf
) ) );
81 // If the argument is void, this goes through with nameUTF8 being null. We will then refer to nameStringUTF8 as set above.
82 nameUTF8
= Helpers::try_cast_CoreArgument
< NameType
>( args
.getValue( argsi
), true );
85 catch( const NonLocalExit::NotThisType
& ball
)
87 // Never mind, but see below!
92 // 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.
93 nameStringUTF8
= Helpers::try_cast_CoreArgument
< const Lang::String
>( args
.getValue( argsi
) );
96 catch( const NonLocalExit::NotThisType
& ball
)
98 // Never mind, but see below!
101 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, argsi
, Helpers::typeSetString( Lang::Symbol::staticTypeName( ), Lang::String::staticTypeName( ) ) );
105 unsigned char code
= 0;
106 if( codeArg
!= NullPtr
< CodeType
>( ) )
108 code
= codeArg
->val_
.get_MacRoman( );
111 RefCountPtr
< const char > name
= RefCountPtr
< const char >( NullPtr
< const char >( ) );
112 if( nameUTF8
== NullPtr
< NameType
>( ) )
114 if( nameStringUTF8
== NullPtr
< const Lang::String
>( ) )
116 throw Exceptions::CoreRequirement( "At least one of <char> and <name> must be specified.", title_
, callLoc
);
118 const FontMetrics::GlyphList
& glyphList
= Helpers::requireGlyphList( );
120 if( ! glyphList
.UTF8_to_name( nameStringUTF8
->val_
.getPtr( ), & dst
) )
122 throw Exceptions::CoreOutOfRange( title_
, args
, 2, "When no name is given, characters without default names are not allowed. Please refer to the glyph list." );
124 name
= strrefdup( dst
);
128 // Ensure that the glyph name is legal
129 iconv_t converter
= Helpers::requireUTF8ToASCIIConverter( );
131 const char * inbuf
= nameUTF8
->name( ).getPtr( );
133 size_t bufSize
= strlen( inbuf
);
134 char * buf
= new char[ bufSize
+ 1 ];
135 name
= RefCountPtr
< const char >( buf
); // this will delete the buffer if it becomes unused.
138 size_t inbytesleft
= bufSize
;
139 size_t outbytesleft
= bufSize
;
140 // The ICONV_CAST macro is defined in config.h.
141 size_t count
= iconv( converter
,
142 ICONV_CAST( & inbuf
), & inbytesleft
,
143 & outbuf
, & outbytesleft
);
144 if( count
== (size_t)(-1) )
146 if( errno
== EILSEQ
)
148 throw Exceptions::CoreOutOfRange( title_
, args
, 3, "A non-ASCII character was found in a glyph name." );
150 else if( errno
== EINVAL
)
152 throw Exceptions::MiscellaneousRequirement( "It is suspected that glyph's name ended with an incomplete multibyte character." );
154 else if( errno
== E2BIG
)
156 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to ASCII conversion was too small." );
160 std::ostringstream msg
;
161 msg
<< "iconv failed with an unrecognized error code: " << errno
;
162 throw Exceptions::InternalError( strrefdup( msg
) );
168 // Find boudning box:
169 RefCountPtr
< const Lang::ElementaryPath2D
> theBBox
= glyph
->bbox( Lang::Drawable2D::BOUNDING
);
170 Concrete::Coords2D
llcorner( 0, 0 );
171 Concrete::Coords2D
urcorner( 0, 0 );
172 if( ! theBBox
->boundingRectangle( & llcorner
, & urcorner
) )
174 std::string
strTitle( title_
);
175 throw Exceptions::InternalError( strrefdup( strTitle
+ ": The glyph has no bounding box!" ) );
178 Kernel::ContRef cont
= evalState
->cont_
;
179 cont
->takeValue( Kernel::ValueRef( new Lang::Type3Glyph( kind_
,
197 Kernel::registerCore_font( Kernel::Environment
* env
)
199 env
->initDefineCoreFunction( new Lang::Core_makeglyph( "basicglyph", Lang::Type3Glyph::BASIC
) );
200 env
->initDefineCoreFunction( new Lang::Core_makeglyph( "coloredglyph", Lang::Type3Glyph::COLORED
) );
202 env
->initDefine( "FONT_TIMES_ROMAN", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::TIMES_ROMAN
) ) );
203 env
->initDefine( "FONT_TIMES_BOLD", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::TIMES_BOLD
) ) );
204 env
->initDefine( "FONT_TIMES_ITALIC", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::TIMES_ITALIC
) ) );
205 env
->initDefine( "FONT_TIMES_BOLDITALIC", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::TIMES_BOLDITALIC
) ) );
206 env
->initDefine( "FONT_HELVETICA", Lang::THE_FONT_HELVETICA
);
207 env
->initDefine( "FONT_HELVETICA_BOLD", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::HELVETICA_BOLD
) ) );
208 env
->initDefine( "FONT_HELVETICA_OBLIQUE", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::HELVETICA_OBLIQUE
) ) );
209 env
->initDefine( "FONT_HELVETICA_BOLDOBLIQUE", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::HELVETICA_BOLDOBLIQUE
) ) );
210 env
->initDefine( "FONT_COURIER", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::COURIER
) ) );
211 env
->initDefine( "FONT_COURIER_BOLD", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::COURIER_BOLD
) ) );
212 env
->initDefine( "FONT_COURIER_OBLIQUE", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::COURIER_OBLIQUE
) ) );
213 env
->initDefine( "FONT_COURIER_BOLDOBLIQUE", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::COURIER_BOLDOBLIQUE
) ) );
214 env
->initDefine( "FONT_SYMBOL", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::SYMBOL
) ) );
215 env
->initDefine( "FONT_ZAPFDINGBATS", RefCountPtr
< const Lang::Font
>( new Lang::PDFStandardFont( BuiltInFonts::ZAPFDINGBATS
) ) );