Example: Changed glyph-outline.shape for use with FontConfig.
[shapes.git] / source / corefont.cc
blob2629737622cba05ab5d934708b932284775fad58
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::Character CodeType;
61 RefCountPtr< CodeType > codeArg = 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 >( ) );
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 ];
72 char * dst = charBuf;
73 size_t charBufAvail = charBufSize - 1;
74 codeArg->val_.encode_UTF8( & dst, & charBufAvail );
75 *dst = '\0';
76 nameStringUTF8 = RefCountPtr< const Lang::String >( new Lang::String( strrefdup( charBuf ) ) );
79 try
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 );
83 goto foundNameType;
85 catch( const NonLocalExit::NotThisType & ball )
87 // Never mind, but see below!
90 try
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 ) );
94 goto foundNameType;
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( ) ) );
103 foundNameType:
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( );
119 const char * dst;
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 );
126 else
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.
137 char * outbuf = buf;
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." );
158 else
160 std::ostringstream msg;
161 msg << "iconv failed with an unrecognized error code: " << errno ;
162 throw Exceptions::InternalError( strrefdup( msg ) );
165 *outbuf = '\0';
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_,
180 code,
181 name,
182 glyph,
183 widthX->get( ),
184 llcorner.x_,
185 llcorner.y_,
186 urcorner.x_,
187 urcorner.y_ ) ),
188 evalState );
196 void
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 ) ) );