Updating the changelog in the VERSION file, and version_sync.
[shapes.git] / source / corefont.cc
blobe965eb3a15b4d5f34e4a186128cee0152fabdee4
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
6 * any later version.
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"
20 #include "globals.h"
21 #include "charconverters.h"
22 #include "autoonoff.h"
23 #include "ast.h"
24 #include "glyphlist.h"
25 #include "config.h"
27 using namespace Shapes;
30 namespace Shapes
32 namespace Lang
34 class Core_makeglyph : public Lang::CoreFunction
36 Lang::Type3Glyph::Kind kind_;
37 public:
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 );
46 virtual void
47 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
49 args.applyDefaults( );
51 size_t argsi = 0;
52 typedef const Lang::Length WidthType;
53 RefCountPtr< WidthType > widthX = Helpers::down_cast_CoreArgument< WidthType >( title_, args, argsi, callLoc );
55 ++argsi;
56 typedef const Lang::Drawable2D GlyphType;
57 RefCountPtr< GlyphType > glyph = Helpers::down_cast_CoreArgument< GlyphType >( title_, args, argsi, callLoc );
59 ++argsi;
60 typedef const Lang::String CodeType;
61 RefCountPtr< CodeType > codeStringUTF8 = Helpers::down_cast_CoreArgument< CodeType >( title_, args, argsi, callLoc, true );
63 ++argsi;
64 typedef const Lang::Symbol NameType;
65 RefCountPtr< NameType > nameUTF8 = RefCountPtr< NameType >( NullPtr< NameType >( ) );
66 RefCountPtr< CodeType > nameStringUTF8 = codeStringUTF8;
68 try
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 );
72 goto foundNameType;
74 catch( const NonLocalExit::NotThisType & ball )
76 // Never mind, but see below!
79 try
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 ) );
83 goto foundNameType;
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( ) ) );
92 foundNameType:
94 // Convert the character code string to a number:
95 size_t code = 0;
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 );
106 char * outbuf = 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." );
127 else
129 std::ostringstream msg;
130 msg << "iconv failed with an unrecognized error code: " << errno ;
131 throw Exceptions::InternalError( strrefdup( msg ) );
134 *outbuf = '\0';
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( );
150 const char * dst;
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 );
157 else
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.
168 char * outbuf = buf;
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." );
189 else
191 std::ostringstream msg;
192 msg << "iconv failed with an unrecognized error code: " << errno ;
193 throw Exceptions::InternalError( strrefdup( msg ) );
196 *outbuf = '\0';
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_,
211 code,
212 name,
213 glyph,
214 widthX->get( ),
215 llcorner.x_,
216 llcorner.y_,
217 urcorner.x_,
218 urcorner.y_ ) ),
219 evalState );
227 void
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 ) ) );