Merge branch 'gh/maint-clean' into ht/-include
[shapes.git] / source / coreconstruct.cc
blobf8da9257e9e0fb27fbee707c225f6864f215fad6
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, 2009, 2010 Henrik Tidefelt
19 #include <cmath>
21 #include "Shapes_Helpers_decls.h"
23 #include "singlelistrange.h"
25 #include "shapescore.h"
26 #include "globals.h"
27 #include "shapesexceptions.h"
28 #include "consts.h"
29 #include "simplepdfi.h"
30 #include "simplepdfo.h"
31 #include "astfun.h"
32 #include "tagtypes.h"
33 #include "multipage.h"
34 #include "charconverters.h"
35 #include "pagecontentstates.h"
36 #include "texlabelmanager.h"
37 #include "autoonoff.h"
38 #include "timetypes.h"
39 #include "shapesscanner.h"
40 #include "rasterloaders.h"
41 #include "glyphlist.h"
42 #include "warn.h"
43 #include "config.h"
45 #ifdef HAVE_FT2
46 #include <ft2build.h>
47 #include FT_FREETYPE_H
48 #endif
49 #ifdef HAVE_FONTCONFIG
50 #include <fontconfig/fontconfig.h>
51 #endif
53 #include <iostream>
54 #include <sstream>
55 #include <fstream>
56 #include <vector>
57 #include <stdio.h>
58 #include <ctime>
60 using namespace Shapes;
63 namespace Shapes
65 namespace Helpers
67 RasterLoader_PNG theRasterLoader_PNG;
68 RasterLoader_JPEG theRasterLoader_JPEG;
69 #ifdef HAVE_FONTCONFIG
70 class AutoDestroyFcPattern
72 FcPattern * pat_;
73 public:
74 AutoDestroyFcPattern( FcPattern * pat )
75 : pat_( pat )
76 { }
77 ~AutoDestroyFcPattern( )
79 if( pat_ != 0 )
81 FcPatternDestroy( pat_ );
84 void deactivate( )
86 pat_ = 0;
89 class AutoDestroyFcFontSet
91 FcFontSet * set_;
92 public:
93 AutoDestroyFcFontSet( FcFontSet * set )
94 : set_( set )
95 { }
96 ~AutoDestroyFcFontSet( )
98 if( set_ != 0 )
100 FcFontSetDestroy( set_ );
103 void deactivate( )
105 set_ = 0;
108 #endif
111 namespace Lang
114 class Core_tag : public Lang::CoreFunction
116 public:
117 Core_tag( const char * title )
118 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
120 formals_->appendEvaluatedCoreFormal( "key", Kernel::THE_SLOT_VARIABLE );
121 formals_->appendEvaluatedCoreFormal( "obj", Kernel::THE_SLOT_VARIABLE );
122 formals_->appendEvaluatedCoreFormal( "transform", Kernel::THE_TRUE_VARIABLE ); // this argument means "transform if applicable"
123 formals_->appendEvaluatedCoreFormal( "draw", Kernel::THE_TRUE_VARIABLE ); // this argument means "draw if applicable"
126 virtual void
127 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
129 args.applyDefaults( );
131 typedef const Lang::Symbol KeyType;
132 RefCountPtr< KeyType > key = Helpers::down_cast_CoreArgument< KeyType >( title_, args, 0, callLoc );
133 bool tryTransform = Helpers::down_cast_CoreArgument< const Lang::Boolean >( title_, args, 2, callLoc )->val_;
134 bool tryDraw = Helpers::down_cast_CoreArgument< const Lang::Boolean >( title_, args, 3, callLoc )->val_;
136 if( tryDraw && ! tryTransform )
138 throw Exceptions::CoreOutOfRange( title_, args, 3, "A tagged object which does not transform cannot be drawn." );
141 size_t argsi = 1;
143 if( tryDraw )
147 typedef const Lang::Drawable2D ArgType;
149 RefCountPtr< ArgType > obj = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
151 Kernel::ContRef cont = evalState->cont_;
152 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::TaggedDrawable2D( key, obj ) ),
153 evalState );
154 return;
156 catch( const NonLocalExit::NotThisType & ball )
158 // Never mind, see below
163 typedef const Lang::Drawable3D ArgType;
165 RefCountPtr< ArgType > obj = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
167 Kernel::ContRef cont = evalState->cont_;
168 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::TaggedDrawable3D( key, obj ) ),
169 evalState );
170 return;
172 catch( const NonLocalExit::NotThisType & ball )
174 // Never mind, see below
178 if( tryTransform )
182 typedef const Lang::Geometric2D ArgType;
184 RefCountPtr< ArgType > obj = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
186 Kernel::ContRef cont = evalState->cont_;
187 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::TaggedGeometric2D( key, obj ) ),
188 evalState );
189 return;
191 catch( const NonLocalExit::NotThisType & ball )
193 // Never mind, see below
198 typedef const Lang::Geometric3D ArgType;
200 RefCountPtr< ArgType > obj = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi ) );
202 Kernel::ContRef cont = evalState->cont_;
203 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::TaggedGeometric3D( key, obj ) ),
204 evalState );
205 return;
207 catch( const NonLocalExit::NotThisType & ball )
209 // Never mind, see below
214 // As a last resort, we tag any value.
215 // We return a Drawable2D. Use immerse to make it 3D.
216 Kernel::ContRef cont = evalState->cont_;
217 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::TaggedValue2D( key, args.getValue( argsi ) ) ),
218 evalState );
223 // This function is in this file just because it i so related to Core_tag.
224 class Core_find : public Lang::CoreFunction
226 public:
227 Core_find( const char * title )
228 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
230 formals_->appendEvaluatedCoreFormal( "container", Kernel::THE_SLOT_VARIABLE );
231 formals_->appendEvaluatedCoreFormal( "key", Kernel::THE_SLOT_VARIABLE );
234 virtual void
235 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
237 args.applyDefaults( );
239 typedef const Lang::Symbol KeyType;
240 RefCountPtr< KeyType > key = Helpers::down_cast_CoreArgument< KeyType >( title_, args, 1, callLoc );
242 size_t argsi = 0;
246 typedef const Lang::Drawable2D ContainerType;
248 RefCountPtr< ContainerType > container = Helpers::try_cast_CoreArgument< ContainerType >( args.getValue( argsi ) );
250 if( ! container->findOneTag( evalState, key->getKey( ), Lang::THE_2D_IDENTITY ) )
252 throw Exceptions::CoreOutOfRange( title_, args, 1, "Key not found." );
254 return;
256 catch( const NonLocalExit::NotThisType & ball )
258 // Never mind, see below
263 typedef const Lang::Drawable3D ContainerType;
265 RefCountPtr< ContainerType > container = Helpers::try_cast_CoreArgument< ContainerType >( args.getValue( argsi ) );
267 if( ! container->findOneTag( evalState, key->getKey( ), Lang::THE_3D_IDENTITY ) )
269 throw Exceptions::CoreOutOfRange( title_, args, 1, "Key not found." );
271 return;
273 catch( const NonLocalExit::NotThisType & ball )
275 // Never mind, see below
278 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, argsi, Helpers::typeSetString( Lang::Drawable2D::staticTypeName( ), Lang::Drawable3D::staticTypeName( ) ) );
282 // This function is in this file just because it i so related to Core_tag.
283 class Core_findall : public Lang::CoreFunction
285 public:
286 Core_findall( const char * title )
287 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
289 formals_->appendEvaluatedCoreFormal( "container", Kernel::THE_SLOT_VARIABLE );
290 formals_->appendEvaluatedCoreFormal( "key", Kernel::THE_SLOT_VARIABLE );
293 virtual void
294 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
296 args.applyDefaults( );
298 typedef const Lang::Symbol KeyType;
299 RefCountPtr< KeyType > key = Helpers::down_cast_CoreArgument< KeyType >( title_, args, 1, callLoc );
301 size_t argsi = 0;
305 typedef const Lang::Drawable2D ContainerType;
307 RefCountPtr< ContainerType > container = Helpers::try_cast_CoreArgument< ContainerType >( args.getValue( argsi ) );
309 std::vector< Kernel::ValueRef > * dst = new std::vector< Kernel::ValueRef >;
310 container->findTags( dst, evalState->dyn_, key->getKey( ), Lang::THE_2D_IDENTITY );
312 Kernel::ContRef cont = evalState->cont_;
313 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::VectorFunction( dst ) ),
314 evalState );
315 return;
317 catch( const NonLocalExit::NotThisType & ball )
319 // Never mind, see below
324 typedef const Lang::Drawable3D ContainerType;
326 RefCountPtr< ContainerType > container = Helpers::try_cast_CoreArgument< ContainerType >( args.getValue( argsi ) );
328 std::vector< Kernel::ValueRef > * dst = new std::vector< Kernel::ValueRef >;
329 container->findTags( dst, evalState->dyn_, key->getKey( ), Lang::THE_3D_IDENTITY );
331 Kernel::ContRef cont = evalState->cont_;
332 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::VectorFunction( dst ) ),
333 evalState );
334 return;
336 catch( const NonLocalExit::NotThisType & ball )
338 // Never mind, see below
341 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, argsi, Helpers::typeSetString( Lang::Drawable2D::staticTypeName( ), Lang::Drawable3D::staticTypeName( ) ) );
345 class Core_phong : public Lang::CoreFunction
347 public:
348 Core_phong( const char * title ) : CoreFunction( title ) { }
349 virtual void
350 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
352 const size_t ARITY = 1;
353 CHECK_ARITY( args, ARITY, title_ );
355 typedef const Lang::Float ArgType;
356 double exponent = Helpers::down_cast_CoreArgument< ArgType >( title_, args, 0, callLoc )->val_;
357 if( exponent < 0 )
359 throw Exceptions::CoreOutOfRange( title_, args, 0, "The Phong exponent should be greater than 0." );
362 Kernel::ContRef cont = evalState->cont_;
363 cont->takeValue( Kernel::ValueRef( new Lang::SpecularReflectionTerm( 1., exponent ) ),
364 evalState );
368 class Core_cons : public Lang::CoreFunction
370 public:
371 Core_cons( const char * title )
372 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), false ) )
374 formals_->appendEvaluatedCoreFormal( "car", Kernel::THE_SLOT_VARIABLE );
375 formals_->appendEvaluatedCoreFormal( "cdr", Kernel::THE_SLOT_VARIABLE );
377 virtual void
378 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
380 const size_t ARITY = 2;
381 CHECK_ARITY( args, ARITY, title_ );
383 Kernel::ContRef cont = evalState->cont_;
384 cont->takeValue( Kernel::ValueRef( new Lang::ConsPair( args.getHandle( 0 ),
385 args.getHandle( 1 ) ) ),
386 evalState );
390 class Core_list : public Lang::CoreFunction
392 public:
393 Core_list( const char * title ) : CoreFunction( title ) { }
394 virtual void
395 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
397 RefCountPtr< const Lang::SingleList > res = Lang::THE_CONS_NULL;
398 if( ! args.empty( ) )
400 for( size_t i = args.size( ) - 1; ; --i )
402 res = RefCountPtr< const Lang::SingleList >( new Lang::SingleListPair( args.getHandle( i ), res ) );
403 if( i == 0 )
405 break;
410 Kernel::ContRef cont = evalState->cont_;
411 cont->takeValue( res,
412 evalState );
416 class Core_unlist : public Lang::CoreFunction
418 Kernel::UnnamedStructureFactory argListFactory_;
419 public:
420 Core_unlist( const char * title ) : CoreFunction( title ) { }
421 virtual void
422 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
424 const size_t ARITY = 1;
425 CHECK_ARITY( args, ARITY, title_ );
427 typedef const Lang::SingleList ArgType;
429 Kernel::ContRef cont = evalState->cont_;
430 cont->takeValue( argListFactory_.build( Helpers::down_cast_CoreArgument< ArgType >( title_, args, 0, callLoc ) ),
431 evalState );
435 class Core_isnull : public Lang::CoreFunction
437 public:
438 Core_isnull( const char * title ) : CoreFunction( title ) { }
439 virtual void
440 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
442 const size_t ARITY = 1;
443 CHECK_ARITY( args, ARITY, title_ );
445 RefCountPtr< const Lang::Value > aUntyped = args.getValue( 0 );
447 Kernel::ContRef cont = evalState->cont_;
448 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::Boolean( dynamic_cast< const Lang::SingleListNull * >( args.getValue( 0 ).getPtr( ) ) != 0 ) ),
449 evalState );
453 class Core_span : public Lang::CoreFunction
455 public:
456 Core_span( const char * title )
457 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), false ) )
459 formals_->appendEvaluatedCoreFormal( "begin", Kernel::THE_VOID_VARIABLE );
460 formals_->appendEvaluatedCoreFormal( "end", Kernel::THE_VOID_VARIABLE );
461 formals_->appendEvaluatedCoreFormal( "step", Kernel::THE_VOID_VARIABLE );
462 formals_->appendEvaluatedCoreFormal( "count", Kernel::THE_VOID_VARIABLE );
464 virtual void
465 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
467 args.applyDefaults( );
469 Kernel::ContRef cont = evalState->cont_;
470 cont->takeValue( Kernel::ValueRef( new Lang::Span( args.getHandle( 0 ), args.getHandle( 1 ), args.getHandle( 2 ), args.getHandle( 3 ) ) ),
471 evalState );
475 class Core_affinetransform : public Lang::CoreFunction
477 public:
478 Core_affinetransform( const char * title ) : CoreFunction( title ) { }
479 virtual void
480 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
482 const size_t ARITY = 3;
483 CHECK_ARITY( args, ARITY, title_ );
485 typedef const Lang::FloatPair ArgType0;
486 typedef const Lang::FloatPair ArgType1;
487 typedef const Lang::Coords2D ArgType2;
489 RefCountPtr< ArgType0 > argx = Helpers::down_cast_CoreArgument< ArgType0 >( title_, args, 0, callLoc );
490 RefCountPtr< ArgType1 > argy = Helpers::down_cast_CoreArgument< ArgType1 >( title_, args, 1, callLoc );
491 RefCountPtr< ArgType2 > arg1 = Helpers::down_cast_CoreArgument< ArgType2 >( title_, args, 2, callLoc );
493 Kernel::ContRef cont = evalState->cont_;
494 cont->takeValue( Kernel::ValueRef( new Lang::Transform2D( argx->x_, argx->y_, argy->x_, argy->y_, arg1->x_.get( ), arg1->y_.get( ) ) ),
495 evalState );
499 class Core_affinetransform3D : public Lang::CoreFunction
501 public:
502 Core_affinetransform3D( const char * title ) : CoreFunction( title ) { }
503 virtual void
504 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
506 const size_t ARITY = 4;
507 CHECK_ARITY( args, ARITY, title_ );
509 typedef const Lang::FloatTriple ArgType0;
510 typedef const Lang::FloatTriple ArgType1;
511 typedef const Lang::FloatTriple ArgType2;
512 typedef const Lang::Coords3D ArgType3;
514 RefCountPtr< ArgType0 > argx = Helpers::down_cast_CoreArgument< ArgType0 >( title_, args, 0, callLoc );
515 RefCountPtr< ArgType1 > argy = Helpers::down_cast_CoreArgument< ArgType1 >( title_, args, 1, callLoc );
516 RefCountPtr< ArgType2 > argz = Helpers::down_cast_CoreArgument< ArgType2 >( title_, args, 2, callLoc );
517 RefCountPtr< ArgType3 > arg1 = Helpers::down_cast_CoreArgument< ArgType3 >( title_, args, 3, callLoc );
519 Kernel::ContRef cont = evalState->cont_;
520 cont->takeValue( Kernel::ValueRef( new Lang::Transform3D( argx->x_, argx->y_, argx->z_,
521 argy->x_, argy->y_, argy->z_,
522 argz->x_, argz->y_, argz->z_,
523 arg1->x_.get( ), arg1->y_.get( ), arg1->z_.get( ) ) ),
524 evalState );
528 class Core_shift : public Lang::CoreFunction
530 public:
531 Core_shift( const char * title ) : CoreFunction( title ) { }
532 virtual void
533 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
535 const size_t ARITY = 1;
536 CHECK_ARITY( args, ARITY, title_ );
538 Kernel::ContRef cont = evalState->cont_;
540 size_t i = 0;
543 typedef const Lang::Coords2D ArgType1;
544 RefCountPtr< ArgType1 > arg1 = Helpers::try_cast_CoreArgument< ArgType1 >( args.getValue( i ) );
545 cont->takeValue( Kernel::ValueRef( new Lang::Transform2D( 1, 0, 0, 1, arg1->x_.get( ), arg1->y_.get( ) ) ),
546 evalState );
547 return;
549 catch( const NonLocalExit::NotThisType & ball )
551 // Never mind, see below
556 typedef const Lang::Coords3D ArgType1;
557 RefCountPtr< ArgType1 > arg1 = Helpers::try_cast_CoreArgument< ArgType1 >( args.getValue( i ) );
558 cont->takeValue( Kernel::ValueRef( new Lang::Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, arg1->x_.get( ), arg1->y_.get( ), arg1->z_.get( ) ) ),
559 evalState );
560 return;
562 catch( const NonLocalExit::NotThisType & ball )
564 // Never mind, see below
567 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, i, Helpers::typeSetString( Lang::Coords2D::staticTypeName( ), Lang::Coords3D::staticTypeName( ) ) );
571 class Core_rotate : public Lang::CoreFunction
573 public:
574 Core_rotate( const char * title )
575 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
577 formals_->appendEvaluatedCoreFormal( "angle", Kernel::THE_SLOT_VARIABLE );
579 virtual void
580 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
582 args.applyDefaults( );
584 size_t i = 0;
586 typedef const Lang::Float ArgType1;
587 RefCountPtr< ArgType1 > arg1 = Helpers::down_cast_CoreArgument< ArgType1 >( title_, args, i, callLoc );
589 double c = cos( arg1->val_ );
590 double s = sin( arg1->val_ );
591 Kernel::ContRef cont = evalState->cont_;
592 cont->takeValue( Kernel::ValueRef( new Lang::Transform2D( c, s, -s, c, 0, 0 ) ),
593 evalState );
597 class Core_rotate3d : public Lang::CoreFunction
599 public:
600 Core_rotate3d( const char * title )
601 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
603 formals_->appendEvaluatedCoreFormal( "dir", Kernel::THE_SLOT_VARIABLE );
604 formals_->appendEvaluatedCoreFormal( "angle", Kernel::THE_SLOT_VARIABLE );
606 virtual void
607 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
609 args.applyDefaults( );
611 size_t i = 0;
613 typedef const Lang::FloatTriple ArgType1;
614 RefCountPtr< ArgType1 > dir = Helpers::down_cast_CoreArgument< ArgType1 >( title_, args, i, callLoc );
615 if( dir->x_ == 0 && dir->y_ == 0 && dir->z_ == 0 )
617 throw Exceptions::CoreOutOfRange( title_, args, i, "The rotation direction is degenerate, that is (0,0,0)." );
620 ++i;
622 typedef const Lang::Float ArgType2;
623 RefCountPtr< ArgType2 > angle = Helpers::down_cast_CoreArgument< ArgType2 >( title_, args, i, callLoc );
625 double r = sqrt( dir->x_ * dir->x_ + dir->y_ * dir->y_ + dir->z_ * dir->z_ );
626 double x = dir->x_ / r;
627 double y = dir->y_ / r;
628 double z = dir->z_ / r;
629 double x2 = x * x;
630 double y2 = y * y;
631 double z2 = z * z;
632 double c = cos( angle->val_ );
633 double s = sin( angle->val_ );
634 Kernel::ContRef cont = evalState->cont_;
635 cont->takeValue( Kernel::ValueRef( new Lang::Transform3D( x2+(y2+z2)*c, x*y*(1-c)+z*s, x*z*(1-c)-y*s,
636 x*y*(1-c)-z*s, y2+(x2+z2)*c, y*z*(1-c)+x*s,
637 x*z*(1-c)+y*s, y*z*(1-c)-x*s, z2+(x2+y2)*c,
638 0, 0, 0 ) ),
639 evalState );
643 class Core_scale : public Lang::CoreFunction
645 public:
646 Core_scale( const char * title )
647 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
649 Kernel::VariableHandle one( new Kernel::Variable( RefCountPtr< const Lang::Value >( new Lang::Float( 1 ) ) ) );
651 formals_->appendEvaluatedCoreFormal( "r", one );
652 formals_->appendEvaluatedCoreFormal( "x", one );
653 formals_->appendEvaluatedCoreFormal( "y", one );
655 virtual void
656 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
658 args.applyDefaults( );
660 typedef const Lang::Float ArgType;
661 RefCountPtr< ArgType > argr = Helpers::down_cast_CoreArgument< ArgType >( title_, args, 0, callLoc );
662 RefCountPtr< ArgType > argx = Helpers::down_cast_CoreArgument< ArgType >( title_, args, 1, callLoc );
663 RefCountPtr< ArgType > argy = Helpers::down_cast_CoreArgument< ArgType >( title_, args, 2, callLoc );
665 Kernel::ContRef cont = evalState->cont_;
666 cont->takeValue( Kernel::ValueRef( new Lang::Transform2D( argr->val_ * argx->val_, 0,
667 0, argr->val_ * argy->val_,
668 0, 0 ) ),
669 evalState );
673 class Core_scale3d : public Lang::CoreFunction
675 public:
676 Core_scale3d( const char * title )
677 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
679 Kernel::VariableHandle one( new Kernel::Variable( RefCountPtr< const Lang::Value >( new Lang::Float( 1 ) ) ) );
681 formals_->appendEvaluatedCoreFormal( "r", one );
682 formals_->appendEvaluatedCoreFormal( "x", one );
683 formals_->appendEvaluatedCoreFormal( "y", one );
684 formals_->appendEvaluatedCoreFormal( "z", one );
686 virtual void
687 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
689 args.applyDefaults( );
691 typedef const Lang::Float ArgType;
692 RefCountPtr< ArgType > argr = Helpers::down_cast_CoreArgument< ArgType >( title_, args, 0, callLoc );
693 RefCountPtr< ArgType > argx = Helpers::down_cast_CoreArgument< ArgType >( title_, args, 1, callLoc );
694 RefCountPtr< ArgType > argy = Helpers::down_cast_CoreArgument< ArgType >( title_, args, 2, callLoc );
695 RefCountPtr< ArgType > argz = Helpers::down_cast_CoreArgument< ArgType >( title_, args, 3, callLoc );
697 Kernel::ContRef cont = evalState->cont_;
698 cont->takeValue( Kernel::ValueRef( new Lang::Transform3D( argr->val_ * argx->val_, 0, 0,
699 0, argr->val_ * argy->val_, 0,
700 0, 0, argr->val_ * argz->val_,
701 0, 0, 0 ) ),
702 evalState );
706 class Core_inverse : public Lang::CoreFunction
708 public:
709 Core_inverse( const char * title ) : CoreFunction( title ) { }
710 virtual void
711 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
713 const size_t ARITY = 1;
714 CHECK_ARITY( args, ARITY, title_ );
717 typedef const Lang::Transform2D ArgType;
718 ArgType * tf = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
719 if( tf != 0 )
721 double det = tf->xx_ * tf->yy_ - tf->xy_ * tf->yx_;
722 if( fabs( det ) < Computation::SINGULAR_TRANSFORM_LIMIT )
724 throw Exceptions::CoreOutOfRange( title_, args, 0, "Singular transforms cannot be inverted." );
726 double idet = 1 / det;
727 double ixx = idet * tf->yy_;
728 double ixy = - idet * tf->xy_;
729 double iyx = - idet * tf->yx_;
730 double iyy = idet * tf->xx_;
731 Kernel::ContRef cont = evalState->cont_;
732 cont->takeValue( Kernel::ValueRef( new Lang::Transform2D( ixx, iyx,
733 ixy, iyy,
734 -( ixx * tf->xt_ + ixy * tf->yt_ ), -( iyx * tf->xt_ + iyy * tf->yt_ ) ) ),
735 evalState );
736 return;
741 typedef const Lang::Transform3D ArgType;
742 ArgType * tf = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
743 if( tf != 0 )
745 double det =
746 tf->xx_ * ( tf->yy_ * tf->zz_ - tf->yz_ * tf->zy_ )
747 - tf->xy_ * ( tf->yx_ * tf->zz_ - tf->yz_ * tf->zx_ )
748 + tf->xz_ * ( tf->yx_ * tf->zy_ - tf->yy_ * tf->zx_ );
749 if( fabs( det ) < Computation::SINGULAR_TRANSFORM_LIMIT )
751 throw Exceptions::CoreOutOfRange( title_, args, 0, "Singular transforms cannot be inverted." );
753 double idet = 1 / det;
754 double ixx = idet * ( tf->yy_ * tf->zz_ - tf->yz_ * tf->zy_ );
755 double ixy = - idet * ( tf->xy_ * tf->zz_ - tf->xz_ * tf->zy_ );
756 double ixz = idet * ( tf->xy_ * tf->yz_ - tf->xz_ * tf->yy_ );
757 double iyx = - idet * ( tf->yx_ * tf->zz_ - tf->yz_ * tf->zx_ );
758 double iyy = idet * ( tf->xx_ * tf->zz_ - tf->xz_ * tf->zx_ );
759 double iyz = - idet * ( tf->xx_ * tf->yz_ - tf->xz_ * tf->yx_ );
760 double izx = idet * ( tf->yx_ * tf->zy_ - tf->yy_ * tf->zx_ );
761 double izy = - idet * ( tf->xx_ * tf->zy_ - tf->xy_ * tf->zx_ );
762 double izz = idet * ( tf->xx_ * tf->yy_ - tf->xy_ * tf->yx_ );
763 Kernel::ContRef cont = evalState->cont_;
764 cont->takeValue( Kernel::ValueRef( new Lang::Transform3D( ixx, iyx, izx,
765 ixy, iyy, izy,
766 ixz, iyz, izz,
767 -( ixx * tf->xt_ + ixy * tf->yt_ + ixz * tf->zt_ ),
768 -( iyx * tf->xt_ + iyy * tf->yt_ + iyz * tf->zt_ ),
769 -( izx * tf->xt_ + izy * tf->yt_ + izz * tf->zt_ ) ) ),
770 evalState );
771 return;
775 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, 0, Helpers::typeSetString( Lang::Transform2D::staticTypeName( ), Lang::Transform3D::staticTypeName( ) ) );
779 class Core_formxo : public Lang::CoreFunction
781 public:
782 Core_formxo( const char * title ) : CoreFunction( title ) { }
783 virtual void
784 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
786 const size_t ARITY = 1;
787 CHECK_ARITY( args, ARITY, title_ );
789 typedef const Lang::Drawable2D ArgType;
790 RefCountPtr< ArgType > arg = Helpers::down_cast_CoreArgument< ArgType >( title_, args, 0, callLoc );
792 RefCountPtr< const Lang::ElementaryPath2D > theBBox = arg->bbox( Lang::Drawable2D::BOUNDING );
793 Concrete::Coords2D llcorner( 0, 0 );
794 Concrete::Coords2D urcorner( 0, 0 );
795 if( ! theBBox->boundingRectangle( & llcorner, & urcorner ) )
797 std::string strTitle( title_ );
798 throw Exceptions::InternalError( strrefdup( strTitle + ": The object has no bounding box!" ) );
802 RefCountPtr< SimplePDF::PDF_Stream_out > form;
803 RefCountPtr< SimplePDF::PDF_Object > indirection = SimplePDF::indirect( form, & Kernel::theIndirectObjectCount );
805 RefCountPtr< SimplePDF::PDF_Resources > resources;
806 (*form)[ "Resources" ] = SimplePDF::indirect( resources, & Kernel::theIndirectObjectCount );
808 (*form)[ "Subtype" ] = SimplePDF::newName( "Form" );
809 (*form)[ "FormType" ] = SimplePDF::newInt( 1 );
810 (*form)[ "BBox" ] = RefCountPtr< SimplePDF::PDF_Vector >( new SimplePDF::PDF_Vector( llcorner.x_.offtype< 1, 0 >( ), llcorner.y_.offtype< 1, 0 >( ),
811 urcorner.x_.offtype< 1, 0 >( ), urcorner.y_.offtype< 1, 0 >( ) ) );
813 /* There's a possibility of adding a transformation matrix entry in the dictionary here, but it is not used, not even
814 * for transformed drawables.
816 // (*markForm)[ "Matrix" ] = RefCountPtr<PDF_Object>( new PDF_Vector( 1, 0, 0, 1, -30, -30 ) );
818 Kernel::PageContentStates pdfState( resources );
819 arg->shipout( form->data, & pdfState, Lang::Transform2D( 1, 0, 0, 1, 0, 0 ) );
822 Lang::XObject * res = new Lang::XObject( indirection,
823 theBBox );
824 res->setDebugStr( "user form" );
825 Kernel::ContRef cont = evalState->cont_;
826 cont->takeValue( Kernel::ValueRef( res ),
827 evalState );
831 class Core_transparencygroup : public Lang::CoreFunction
833 public:
834 Core_transparencygroup( const char * title )
835 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
837 formals_->appendEvaluatedCoreFormal( "content", Kernel::THE_SLOT_VARIABLE );
838 formals_->appendEvaluatedCoreFormal( "isolated", Kernel::THE_FALSE_VARIABLE );
839 formals_->appendEvaluatedCoreFormal( "knockout", Kernel::THE_FALSE_VARIABLE );
841 virtual void
842 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
844 args.applyDefaults( );
846 typedef const Lang::Group2D ArgType0;
847 typedef const Lang::Boolean ArgType1;
848 typedef const Lang::Boolean ArgType2;
849 RefCountPtr< ArgType0 > content = Helpers::down_cast_CoreArgument< ArgType0 >( title_, args, 0, callLoc );
850 RefCountPtr< ArgType1 > isolated = Helpers::down_cast_CoreArgument< ArgType1 >( title_, args, 1, callLoc );
851 RefCountPtr< ArgType2 > knockout = Helpers::down_cast_CoreArgument< ArgType2 >( title_, args, 2, callLoc );
853 RefCountPtr< const Lang::ColorSpace > blendSpace = evalState->dyn_->getBlendSpace( );
855 Kernel::ContRef cont = evalState->cont_;
856 cont->takeValue( Helpers::newTransparencyGroup( content, isolated->val_, knockout->val_, blendSpace ),
857 evalState );
861 class Core_importRasterImage : public Lang::CoreFunction
863 std::map< const char *, const Helpers::RasterLoader *, charPtrLess > loaders_;
864 public:
865 Core_importRasterImage( const char * title )
866 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
868 formals_->appendEvaluatedCoreFormal( "filename", Kernel::THE_SLOT_VARIABLE );
869 formals_->appendEvaluatedCoreFormal( "resolution", Helpers::newValHandle( new Lang::Length( Concrete::Length( 1 ) ) ) );
870 formals_->appendEvaluatedCoreFormal( "override", Kernel::THE_TRUE_VARIABLE );
871 formals_->appendEvaluatedCoreFormal( "kind", Kernel::THE_VOID_VARIABLE );
873 loaders_[ "png" ] = & Helpers::theRasterLoader_PNG;
874 loaders_[ "PNG" ] = & Helpers::theRasterLoader_PNG;
876 loaders_[ "jpg" ] = & Helpers::theRasterLoader_JPEG;
877 loaders_[ "JPG" ] = & Helpers::theRasterLoader_JPEG;
878 loaders_[ "jpeg" ] = & Helpers::theRasterLoader_JPEG;
879 loaders_[ "JPEG" ] = & Helpers::theRasterLoader_JPEG;
881 /* It would seem natural to also support "JIF"-images, but currently the JPEG library we use won't open such files.
884 virtual void
885 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
887 args.applyDefaults( );
889 size_t argsi = 0;
891 typedef const Lang::String ArgType;
892 RefCountPtr< ArgType > filename = Helpers::down_cast_CoreArgument< ArgType >( title_, args, argsi, callLoc );
893 size_t argsi_filename = argsi;
895 std::string full_filename;
898 full_filename = Ast::theShapesScanner.searchFile( filename->val_.getPtr( ), true ); /* true means that errors should be handled in "runtime mode". */
900 catch( RefCountPtr< const char > & msg )
902 throw Exceptions::CoreOutOfRange( title_, args, argsi_filename, msg );
905 RefCountPtr< std::ifstream > iFile( new std::ifstream( full_filename.c_str( ) ) );
906 if( ! iFile->good( ) )
908 std::ostringstream msg;
909 msg << "Failed to open file for input: " << full_filename.c_str( ) ;
910 throw Exceptions::CoreOutOfRange( title_, args, argsi_filename, strrefdup( msg ) );
913 ++argsi;
914 typedef const Lang::Length ResolutionType;
915 Concrete::Length resolution = Helpers::down_cast_CoreArgument< ResolutionType >( title_, args, argsi, callLoc )->get( );
916 if( resolution <= Concrete::ZERO_LENGTH )
918 throw Exceptions::CoreOutOfRange( title_, args, argsi, strrefdup( "The resolution must be positive." ) );
921 ++argsi;
922 typedef const Lang::Boolean OverrideType;
923 bool override = Helpers::down_cast_CoreArgument< OverrideType >( title_, args, argsi, callLoc )->val_;
925 ++argsi;
926 typedef const Lang::Symbol KindType;
927 RefCountPtr< KindType > kind = Helpers::down_cast_CoreArgument< KindType >( title_, args, argsi, callLoc, true );
928 const Helpers::RasterLoader * loader = 0;
929 if( kind == NullPtr< KindType >( ) )
931 const char * begin = filename->val_.getPtr( );
932 const char * ext = filename->val_.getPtr( ) + filename->bytecount_ - 1;
933 for( ; ext > begin; --ext )
935 if( *ext == '.' )
937 typedef typeof loaders_ MapType;
938 MapType::const_iterator i = loaders_.find( ext + 1 );
939 if( i == loaders_.end( ) )
941 std::ostringstream msg;
942 msg << "Filename extension '" << ext << "' has no associated raster loader." ;
943 throw Exceptions::CoreOutOfRange( title_, args, argsi_filename, strrefdup( msg ) );
945 loader = i->second;
946 break;
949 if( loader == 0 )
951 std::ostringstream msg;
952 msg << "Filename without extension must be combined with explicit file kind: " << filename->val_.getPtr( ) ;
953 throw Exceptions::CoreOutOfRange( title_, args, argsi_filename, strrefdup( msg ) );
956 else
958 static Lang::Symbol PNG( "PNG" );
959 static Lang::Symbol JPEG( "JPEG" );
960 if( *kind == PNG )
962 loader = & Helpers::theRasterLoader_PNG;
964 else if( *kind == JPEG )
966 loader = & Helpers::theRasterLoader_JPEG;
968 else
970 std::ostringstream msg;
971 msg << "The only allowed file kind symbols are { " ;
972 PNG.show( msg );
973 msg << ", " ;
974 JPEG.show( msg );
975 msg << " }." ;
976 throw Exceptions::CoreOutOfRange( title_, args, argsi, strrefdup( msg ) );
980 Kernel::ContRef cont = evalState->cont_;
981 cont->takeValue( loader->load( iFile, full_filename, resolution, override, title_, callLoc ),
982 evalState );
986 class Core_vector : public Lang::CoreFunction
988 public:
989 Core_vector( const char * title ) : CoreFunction( title ) { }
990 virtual void
991 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
993 std::vector< RefCountPtr< const Lang::Value > > * res = new std::vector< RefCountPtr< const Lang::Value > >;
994 res->reserve( args.size( ) );
996 for( size_t i = 0; i != args.size( ); ++i )
998 res->push_back( args.getValue( i ) );
1001 Kernel::ContRef cont = evalState->cont_;
1002 cont->takeValue( Kernel::ValueRef( new Lang::VectorFunction( res ) ),
1003 evalState );
1007 class Core_interpolate : public Lang::CoreFunction
1009 public:
1010 Core_interpolate( const char * title )
1011 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1013 formals_->appendEvaluatedCoreFormal( "function", Kernel::THE_SLOT_VARIABLE );
1014 formals_->appendEvaluatedCoreFormal( "domain", Kernel::THE_SLOT_VARIABLE );
1015 formals_->appendEvaluatedCoreFormal( "size", Kernel::THE_SLOT_VARIABLE );
1016 formals_->appendEvaluatedCoreFormal( "range", Kernel::THE_SLOT_VARIABLE );
1017 formals_->appendEvaluatedCoreFormal( "encode", Kernel::THE_VOID_VARIABLE );
1018 formals_->appendEvaluatedCoreFormal( "decode", Kernel::THE_VOID_VARIABLE );
1020 virtual void
1021 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1023 args.applyDefaults( );
1025 throw Exceptions::NotImplemented( "Core_interpolate::call" );
1029 class Core_importPDFpages : public Lang::CoreFunction
1031 public:
1032 Core_importPDFpages( const char * title ) : CoreFunction( title ) { }
1033 virtual void
1034 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1036 const size_t ARITY = 1;
1037 CHECK_ARITY( args, ARITY, title_ );
1039 typedef const Lang::String ArgType;
1040 RefCountPtr< ArgType > arg = Helpers::down_cast_CoreArgument< ArgType >( title_, args, 0, callLoc );
1042 std::string filename;
1045 filename = Ast::theShapesScanner.searchFile( arg->val_.getPtr( ), true ); /* true means that errors should be handled in "runtime mode". */
1047 catch( RefCountPtr< const char > & msg )
1049 throw Exceptions::CoreOutOfRange( title_, args, 0, msg );
1052 RefCountPtr< std::ifstream > iFile( new std::ifstream( filename.c_str( ) ) );
1053 if( ! iFile->good( ) )
1055 std::ostringstream msg;
1056 msg << "Failed to open file for input: " << arg->val_.getPtr( ) ;
1057 throw Exceptions::CoreOutOfRange( title_, args, 0, strrefdup( msg ) );
1059 RefCountPtr< SimplePDF::PDF_in > pdfi( new SimplePDF::PDF_in( iFile ) );
1061 RefCountPtr< const std::vector< RefCountPtr< const Lang::XObject > > > typedRes = RefCountPtr< const std::vector< RefCountPtr< const Lang::XObject > > >( NullPtr< std::vector< RefCountPtr< const Lang::XObject > > >( ) );
1064 typedRes = Kernel::thePDFImporter.addPagesAsXObjects( pdfi );
1066 catch( const char * ball )
1068 throw Exceptions::InternalError( strrefdup( ( std::string( "An error occurred while importing " ) + arg->val_.getPtr( ) + ": " + ball ).c_str( ) ) );
1071 std::vector< RefCountPtr< const Lang::Value > > * untypedRes = new std::vector< RefCountPtr< const Lang::Value > >;
1072 untypedRes->reserve( typedRes->size( ) );
1073 typedef typeof *typedRes ListType;
1074 for( ListType::const_iterator i = typedRes->begin( ); i != typedRes->end( ); ++i )
1076 untypedRes->push_back( *i );
1079 Kernel::ContRef cont = evalState->cont_;
1080 cont->takeValue( Kernel::ValueRef( new Lang::VectorFunction( untypedRes ) ),
1081 evalState );
1085 namespace Implementation
1087 double
1088 svg_path_strtod( const char ** src )
1090 const char * start = *src;
1091 char * endp;
1092 double res = strtod( start, & endp );
1093 *src = endp;
1094 if( **src != ' ' )
1096 for( ; *start == ' '; ++start )
1098 throw std::string( start, strchr( start, ' ' ) - start );
1100 return res;
1103 class Core_svg_path : public Lang::CoreFunction
1105 public:
1106 Core_svg_path( const char * title )
1107 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1109 formals_->appendEvaluatedCoreFormal( "d", Kernel::THE_SLOT_VARIABLE );
1110 formals_->appendEvaluatedCoreFormal( "xunit", Helpers::newValHandle( new Lang::Length( Concrete::Length( 1 ) ) ) );
1111 formals_->appendEvaluatedCoreFormal( "yunit", Helpers::newValHandle( new Lang::Length( Concrete::Length( 1 ) ) ) );
1112 formals_->appendEvaluatedCoreFormal( "multi", Kernel::THE_VOID_VARIABLE );
1113 formals_->appendEvaluatedCoreFormal( "singletons", Kernel::THE_TRUE_VARIABLE );
1115 virtual void
1116 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1118 args.applyDefaults( );
1120 size_t argsi = 0;
1121 typedef const Lang::String StrType;
1122 RefCountPtr< StrType > arg = Helpers::down_cast_CoreArgument< StrType >( title_, args, argsi, callLoc );
1124 typedef const Lang::Length ScaleType;
1125 ++argsi;
1126 Concrete::Length dx = Helpers::down_cast_CoreArgument< ScaleType >( title_, args, argsi, callLoc )->get( );
1127 ++argsi;
1128 Concrete::Length dy = Helpers::down_cast_CoreArgument< ScaleType >( title_, args, argsi, callLoc )->get( );
1130 typedef const Lang::Boolean FlagType;
1131 ++argsi;
1132 RefCountPtr< FlagType > multi = Helpers::down_cast_CoreArgument< FlagType >( title_, args, argsi, callLoc, true );
1133 ++argsi;
1134 bool singletons = Helpers::down_cast_CoreArgument< FlagType >( title_, args, argsi, callLoc )->val_;
1136 RefCountPtr< char > buf = RefCountPtr< char >( new char[ 2 * strlen( arg->val_.getPtr( ) + 1 ) ] );
1138 /* Get rid of any whitespace that isn't a plain space, and make sure every number is terminated by whitespace.
1140 char * dst = buf.getPtr( );
1141 for( const char * src = arg->val_.getPtr( ); *src != '\0'; ++src, ++dst )
1143 switch( *src )
1145 case '\t':
1146 case '\n':
1147 case ',':
1148 *dst = ' ';
1149 continue;
1151 if( ( 'A' <= *src && *src <= 'Z' ) || ( 'a' <= *src && *src <= 'z' ) )
1153 /* Insert whitespace before command to ensure command is not immediately following number.
1155 *dst = ' ';
1156 ++dst;
1158 *dst = *src;
1160 *dst = ' ';
1161 ++dst;
1162 *dst = '\0';
1165 RefCountPtr< Lang::MultiPath2D > multiPath = RefCountPtr< Lang::MultiPath2D >( new Lang::MultiPath2D );
1166 RefCountPtr< Lang::ElementaryPath2D > elemPath = RefCountPtr< Lang::ElementaryPath2D >( NullPtr< Lang::ElementaryPath2D >( ) );
1170 char cmd = '\0';
1171 Concrete::PathPoint2D originPathPoint( new Concrete::Coords2D( 0, 0 ) );
1172 Concrete::PathPoint2D * first = & originPathPoint;
1173 Concrete::PathPoint2D * last = & originPathPoint;
1174 const char * srcEnd = buf.getPtr( ) + strlen( buf.getPtr( ) );
1175 for( const char * src = buf.getPtr( ); src < srcEnd; ++src )
1177 for( ; *src == ' '; ++src )
1179 if( *src == '\0' )
1181 break;
1183 switch( *src )
1185 case 'M':
1186 case 'm':
1187 case 'Z':
1188 case 'z':
1189 case 'L':
1190 case 'l':
1191 case 'H':
1192 case 'h':
1193 case 'V':
1194 case 'v':
1195 case 'C':
1196 case 'c':
1197 case 'S':
1198 case 's':
1200 cmd = *src;
1201 ++src;
1202 break;
1204 case 'Q':
1205 case 'q':
1206 case 'T':
1207 case 't':
1208 case 'A':
1209 case 'a':
1211 throw Exceptions::CoreOutOfRange( title_, args, 0, strrefdup( std::string( "SVG path command not compatible with cubic splines: " ) + *src ) );
1214 switch( cmd )
1216 case 'M':
1218 if( elemPath != NullPtr< Lang::ElementaryPath2D >( ) && ( singletons || elemPath->duration( ) >= 1 ) )
1220 multiPath->push_back( elemPath );
1222 Concrete::Length x = dx * Implementation::svg_path_strtod( & src );
1223 Concrete::Length y = - dy * Implementation::svg_path_strtod( & src );
1224 first = new Concrete::PathPoint2D( new Concrete::Coords2D( x, y ) );
1225 last = first;
1226 elemPath = RefCountPtr< Lang::ElementaryPath2D >( new Lang::ElementaryPath2D );
1227 elemPath->push_back( last );
1228 cmd = 'L';
1229 break;
1231 case 'm':
1233 if( elemPath != NullPtr< Lang::ElementaryPath2D >( ) && ( singletons || elemPath->duration( ) >= 1 ) )
1235 multiPath->push_back( elemPath );
1237 Concrete::Length x = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1238 Concrete::Length y = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1239 first = new Concrete::PathPoint2D( new Concrete::Coords2D( x, y ) );
1240 last = first;
1241 elemPath = RefCountPtr< Lang::ElementaryPath2D >( new Lang::ElementaryPath2D );
1242 elemPath->push_back( last );
1243 cmd = 'l';
1244 break;
1246 case 'Z':
1248 elemPath->close( );
1249 last = first;
1250 break;
1252 case 'z':
1254 elemPath->close( );
1255 last = first;
1256 break;
1258 case 'L':
1260 Concrete::Length x = dx * Implementation::svg_path_strtod( & src );
1261 Concrete::Length y = - dy * Implementation::svg_path_strtod( & src );
1262 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x, y ) );
1263 elemPath->push_back( last );
1264 break;
1266 case 'l':
1268 Concrete::Length x = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1269 Concrete::Length y = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1270 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x, y ) );
1271 elemPath->push_back( last );
1272 break;
1274 case 'H':
1276 Concrete::Length x = dx * Implementation::svg_path_strtod( & src );
1277 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x, last->mid_->y_ ) );
1278 elemPath->push_back( last );
1279 break;
1281 case 'h':
1283 Concrete::Length x = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1284 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x, last->mid_->y_ ) );
1285 elemPath->push_back( last );
1286 break;
1288 case 'V':
1290 Concrete::Length y = - dy * Implementation::svg_path_strtod( & src );
1291 last = new Concrete::PathPoint2D( new Concrete::Coords2D( last->mid_->x_, y ) );
1292 elemPath->push_back( last );
1293 break;
1295 case 'v':
1297 Concrete::Length y = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1298 last = new Concrete::PathPoint2D( new Concrete::Coords2D( last->mid_->x_, y ) );
1299 elemPath->push_back( last );
1300 break;
1302 case 'C':
1304 Concrete::Length x1 = dx * Implementation::svg_path_strtod( & src );
1305 Concrete::Length y1 = - dy * Implementation::svg_path_strtod( & src );
1306 Concrete::Length x2 = dx * Implementation::svg_path_strtod( & src );
1307 Concrete::Length y2 = - dy * Implementation::svg_path_strtod( & src );
1308 Concrete::Length x3 = dx * Implementation::svg_path_strtod( & src );
1309 Concrete::Length y3 = - dy * Implementation::svg_path_strtod( & src );
1310 last->front_ = new Concrete::Coords2D( x1, y1 );
1311 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x3, y3 ) );
1312 last->rear_ = new Concrete::Coords2D( x2, y2 );
1313 elemPath->push_back( last );
1314 break;
1316 case 'c':
1318 Concrete::Length x1 = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1319 Concrete::Length y1 = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1320 Concrete::Length x2 = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1321 Concrete::Length y2 = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1322 Concrete::Length x3 = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1323 Concrete::Length y3 = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1324 last->front_ = new Concrete::Coords2D( x1, y1 );
1325 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x3, y3 ) );
1326 last->rear_ = new Concrete::Coords2D( x2, y2 );
1327 elemPath->push_back( last );
1328 break;
1330 case 'S':
1332 Concrete::Length x2 = dx * Implementation::svg_path_strtod( & src );
1333 Concrete::Length y2 = - dy * Implementation::svg_path_strtod( & src );
1334 Concrete::Length x3 = dx * Implementation::svg_path_strtod( & src );
1335 Concrete::Length y3 = - dy * Implementation::svg_path_strtod( & src );
1336 last->front_ = new Concrete::Coords2D( 2 * *(last->mid_) - *(last->rear_) );
1337 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x3, y3 ) );
1338 last->rear_ = new Concrete::Coords2D( x2, y2 );
1339 elemPath->push_back( last );
1340 break;
1342 case 's':
1344 Concrete::Length x2 = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1345 Concrete::Length y2 = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1346 Concrete::Length x3 = last->mid_->x_ + dx * Implementation::svg_path_strtod( & src );
1347 Concrete::Length y3 = last->mid_->y_ - dy * Implementation::svg_path_strtod( & src );
1348 last->front_ = new Concrete::Coords2D( 2 * *(last->mid_) - *(last->rear_) );
1349 last = new Concrete::PathPoint2D( new Concrete::Coords2D( x3, y3 ) );
1350 last->rear_ = new Concrete::Coords2D( x2, y2 );
1351 elemPath->push_back( last );
1352 break;
1354 case '\0':
1355 throw Exceptions::CoreOutOfRange( title_, args, 0, "Malformed SVG path string (failed to initialize command character)." );
1356 default:
1358 throw Exceptions::InternalError( "While reading SVG path string: Command character out of range." );
1363 catch( const std::string & badNumber )
1365 throw Exceptions::CoreOutOfRange( title_, args, 0, strrefdup( std::string( "Ill-formed number: " ) + badNumber ) );
1368 if( elemPath != NullPtr< Lang::ElementaryPath2D >( ) && ( singletons || elemPath->duration( ) >= 1 ) )
1370 multiPath->push_back( RefCountPtr< const Lang::Path2D >( elemPath ) );
1373 if( multiPath->size( ) == 0 )
1375 throw Exceptions::CoreOutOfRange( title_, args, 0, "No path was produced." );
1377 if( multiPath->size( ) == 1 )
1379 Kernel::ContRef cont = evalState->cont_;
1380 if( multi != NullPtr< FlagType >( ) && multi->val_ )
1382 cont->takeValue( Kernel::ValueRef( multiPath ),
1383 evalState );
1385 else
1387 cont->takeValue( Kernel::ValueRef( multiPath->front( ) ),
1388 evalState );
1391 else
1393 if( multi != NullPtr< FlagType >( ) && ! multi->val_ )
1395 throw Exceptions::CoreOutOfRange( title_, args, 0, "More than one sub-path conflicts with false for <multi>." );
1397 Kernel::ContRef cont = evalState->cont_;
1398 cont->takeValue( Kernel::ValueRef( multiPath ),
1399 evalState );
1404 class Core_sprintf : public Lang::CoreFunction
1406 public:
1407 Core_sprintf( const char * title ) : CoreFunction( title ) { }
1408 virtual void
1409 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1411 if( args.empty( ) )
1413 throw Exceptions::CoreArityMismatch( title_, 1, args.size( ) );
1415 typedef typeof args ArgListType;
1416 size_t i = 0;
1417 typedef const Lang::String Arg1Type;
1418 RefCountPtr< Arg1Type > arg1 = Helpers::down_cast_CoreArgument< Arg1Type >( title_, args, i, callLoc );
1420 /* snprintf( 0, 0, ... ) does not seem to work properly on some systems.
1421 * Therefore, I resort to the use of a dummy string, and "n = 1".
1423 char * res = 0;
1424 int status;
1425 char dummy[1];
1426 switch( args.size( ) )
1428 case 1:
1430 size_t sz = snprintf( dummy, 1, arg1->val_.getPtr( ), 0 ); /* The final 0 is just a dummy argument that makes the compiler relax. */
1431 res = new char[ sz + 1 ];
1432 status = sprintf( res, arg1->val_.getPtr( ), 0 ); /* The final 0 is just a dummy argument that makes the compiler relax. */
1434 break;
1435 case 2:
1437 ++i;
1439 typedef const Lang::String Arg2Type;
1440 Arg2Type * arg2 = dynamic_cast< Arg2Type * >( args.getValue( i ).getPtr( ) );
1441 if( arg2 != 0 )
1443 size_t sz = snprintf( dummy, 1, arg1->val_.getPtr( ), arg2->val_.getPtr( ) );
1444 res = new char[ sz + 1 ];
1445 status = sprintf( res, arg1->val_.getPtr( ), arg2->val_.getPtr( ) );
1446 break;
1450 typedef const Lang::Float Arg2Type;
1451 Arg2Type * arg2 = dynamic_cast< Arg2Type * >( args.getValue( i ).getPtr( ) );
1452 if( arg2 != 0 )
1454 size_t sz = snprintf( dummy, 1, arg1->val_.getPtr( ), arg2->val_ );
1455 res = new char[ sz + 1 ];
1456 status = sprintf( res, arg1->val_.getPtr( ), arg2->val_ );
1457 break;
1461 typedef const Lang::Integer Arg2Type;
1462 Arg2Type * arg2 = dynamic_cast< Arg2Type * >( args.getValue( i ).getPtr( ) );
1463 if( arg2 != 0 )
1465 size_t sz = snprintf( dummy, 1, arg1->val_.getPtr( ), arg2->val_ );
1466 res = new char[ sz + 1 ];
1467 status = sprintf( res, arg1->val_.getPtr( ), arg2->val_ );
1468 break;
1472 typedef const Lang::ChronologicalTime Arg2Type;
1473 Arg2Type * arg2 = dynamic_cast< Arg2Type * >( args.getValue( i ).getPtr( ) );
1474 if( arg2 != 0 )
1476 const char * fmt = arg1->val_.getPtr( );
1477 const struct tm * tmp = arg2->temporary_localtime( );
1478 size_t sz = strlen( fmt ) * 2;
1479 res = new char[ sz ];
1480 while( strftime( res, sz, fmt, tmp ) == 0 )
1482 delete res;
1483 sz *= 2;
1484 res = new char[ sz ];
1486 status = 0; // Here, I'd like to check some error condition instead...
1487 break;
1490 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, i, Interaction::SEVERAL_TYPES );
1492 break;
1493 default:
1494 throw Exceptions::CoreOutOfRange( title_, args, 0, "The number of arguments is out of the implemented range." );
1497 if( res == 0 )
1499 throw Exceptions::InternalError( "Failed to assign to res in sprintf." );
1502 if( status < 0 )
1504 std::ostringstream oss;
1505 oss << "Call to library routine returned negative value indicating an error: " << status << ".";
1506 throw Exceptions::CoreOutOfRange( title_, args, 0, strrefdup( oss ) );
1509 Kernel::ContRef cont = evalState->cont_;
1510 cont->takeValue( Kernel::ValueRef( new Lang::String( res, false ) ),
1511 evalState );
1515 class Core_strftime : public Lang::CoreFunction
1517 public:
1518 Core_strftime( const char * title ) : CoreFunction( title ) { }
1519 virtual void
1520 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1522 const size_t ARITY = 0;
1523 CHECK_ARITY( args, ARITY, title_ );
1525 time_t t;
1526 tm * timeInfo;
1527 t = time( 0 );
1528 timeInfo = localtime( & t );
1529 std::ostringstream res;
1530 res << timeInfo->tm_hour << ":" << timeInfo->tm_min << ":" << timeInfo->tm_sec ;
1532 Kernel::ContRef cont = evalState->cont_;
1533 cont->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( res ) ) ),
1534 evalState );
1538 class Core_ambient_light : public Lang::CoreFunction
1540 public:
1541 Core_ambient_light( const char * title )
1542 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1544 formals_->appendEvaluatedCoreFormal( "color", Kernel::THE_SLOT_VARIABLE );
1546 virtual void
1547 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1549 args.applyDefaults( );
1552 typedef const Lang::Gray ArgType;
1553 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1554 if( col != 0 )
1556 Kernel::ContRef cont = evalState->cont_;
1557 cont->takeValue( Kernel::ValueRef( new Lang::AmbientLightGray( col->components( ) ) ),
1558 evalState );
1559 return;
1564 typedef const Lang::RGB ArgType;
1565 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1566 if( col != 0 )
1568 Kernel::ContRef cont = evalState->cont_;
1569 cont->takeValue( Kernel::ValueRef( new Lang::AmbientLightRGB( col->components( ) ) ),
1570 evalState );
1571 return;
1575 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, 0, Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
1579 class Core_specular_light : public Lang::CoreFunction
1581 public:
1582 Core_specular_light( const char * title )
1583 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1585 formals_->appendEvaluatedCoreFormal( "color", Kernel::THE_SLOT_VARIABLE );
1586 formals_->appendEvaluatedCoreFormal( "radius", Helpers::newValHandle( new Lang::Length( HUGE_VAL ) ) );
1587 formals_->appendEvaluatedCoreFormal( "shadows", Kernel::THE_FALSE_VARIABLE );
1589 virtual void
1590 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1592 args.applyDefaults( );
1594 typedef const Lang::Length RadiusType;
1595 RefCountPtr< RadiusType > radius = Helpers::down_cast_CoreArgument< RadiusType >( title_, args, 1, callLoc );
1596 typedef const Lang::Boolean ShadowsType;
1597 RefCountPtr< ShadowsType > shadows = Helpers::down_cast_CoreArgument< ShadowsType >( title_, args, 2, callLoc );
1600 typedef const Lang::Gray ArgType;
1601 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1602 if( col != 0 )
1604 Kernel::ContRef cont = evalState->cont_;
1605 cont->takeValue( Kernel::ValueRef( new Lang::SpecularLightGray( Concrete::Coords3D( 0, 0, 0 ),
1606 col->components( ),
1607 radius->get( ),
1608 shadows->val_ ) ),
1609 evalState );
1610 return;
1615 typedef const Lang::RGB ArgType;
1616 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1617 if( col != 0 )
1619 Kernel::ContRef cont = evalState->cont_;
1620 cont->takeValue( Kernel::ValueRef( new Lang::SpecularLightRGB( Concrete::Coords3D( 0, 0, 0 ),
1621 col->components( ),
1622 radius->get( ),
1623 shadows->val_ ) ),
1624 evalState );
1625 return;
1629 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, 0, Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
1633 class Core_distant_light : public Lang::CoreFunction
1635 public:
1636 Core_distant_light( const char * title )
1637 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1639 formals_->appendEvaluatedCoreFormal( "color", Kernel::THE_SLOT_VARIABLE );
1640 formals_->appendEvaluatedCoreFormal( "shadows", Kernel::THE_FALSE_VARIABLE );
1642 virtual void
1643 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1645 args.applyDefaults( );
1647 typedef const Lang::Boolean ShadowsType;
1648 RefCountPtr< ShadowsType > shadows = Helpers::down_cast_CoreArgument< ShadowsType >( title_, args, 1, callLoc );
1651 typedef const Lang::Gray ArgType;
1652 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1653 if( col != 0 )
1655 Kernel::ContRef cont = evalState->cont_;
1656 cont->takeValue( Kernel::ValueRef( new Lang::DistantLightGray( Concrete::UnitFloatTriple( 0., 0., -1. ),
1657 col->components( ),
1658 shadows->val_ ) ),
1659 evalState );
1660 return;
1665 typedef const Lang::RGB ArgType;
1666 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1667 if( col != 0 )
1669 Kernel::ContRef cont = evalState->cont_;
1670 cont->takeValue( Kernel::ValueRef( new Lang::DistantLightRGB( Concrete::UnitFloatTriple( 0., 0., -1. ),
1671 col->components( ),
1672 shadows->val_ ) ),
1673 evalState );
1674 return;
1678 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, 0, Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
1682 class Core_textrenderingmode : public Lang::CoreFunction
1684 public:
1685 Core_textrenderingmode( const char * title )
1686 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1688 formals_->appendEvaluatedCoreFormal( "fill", Kernel::THE_FALSE_VARIABLE );
1689 formals_->appendEvaluatedCoreFormal( "stroke", Kernel::THE_FALSE_VARIABLE );
1691 virtual void
1692 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1694 args.applyDefaults( );
1696 typedef const Lang::Boolean FlagType;
1697 RefCountPtr< FlagType > fill = Helpers::down_cast_CoreArgument< FlagType >( title_, args, 0, callLoc );
1698 RefCountPtr< FlagType > stroke = Helpers::down_cast_CoreArgument< FlagType >( title_, args, 1, callLoc );
1700 Kernel::ContRef cont = evalState->cont_;
1701 cont->takeValue( Kernel::ValueRef( new Lang::TextRenderingMode( fill->val_, stroke->val_, false ) ),
1702 evalState );
1706 class Core_manualkern : public Lang::CoreFunction
1708 public:
1709 Core_manualkern( const char * title ) : CoreFunction( title ) { }
1710 virtual void
1711 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1713 // Note that res is _not_ yet const. We use a RefCountPtr to take care of memory deallocation in case some argument has the wrong type and
1714 // the result is not used.
1715 RefCountPtr< Lang::KernedText > res( new Lang::KernedText( evalState->dyn_->getTextState( ), evalState->dyn_->getGraphicsState( ) ) );
1717 for( size_t i = 0; i != args.size( ); ++i )
1721 typedef const Lang::String ArgType;
1722 res->pushString( Helpers::try_cast_CoreArgument< ArgType >( args.getValue( i ) ) );
1723 continue;
1725 catch( const NonLocalExit::NotThisType & ball )
1727 // Never mind, see below
1732 typedef const Lang::Float ArgType;
1733 res->pushKerning( Helpers::try_cast_CoreArgument< ArgType >( args.getValue( i ) )->val_ );
1734 continue;
1736 catch( const NonLocalExit::NotThisType & ball )
1738 // Never mind, see below
1743 typedef const Lang::KernedText ArgType;
1744 Helpers::try_cast_CoreArgument< ArgType >( args.getValue( i ) )->push( res.getPtr( ) );
1745 continue;
1747 catch( const NonLocalExit::NotThisType & ball )
1749 // Never mind, see below
1752 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, i, Helpers::typeSetString( Lang::String::staticTypeName( ), Lang::Float::staticTypeName( ), Lang::KernedText::staticTypeName( ) ) );
1755 Kernel::ContRef cont = evalState->cont_;
1756 cont->takeValue( res,
1757 evalState );
1761 class Core_automatickern : public Lang::CoreFunction
1763 public:
1764 Core_automatickern( const char * title ) : CoreFunction( title ) { }
1765 virtual void
1766 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1768 iconv_t converter = Helpers::requireUTF8ToUCS4Converter( );
1769 iconv_t backconverter = Helpers::requireUCS4ToUTF8Converter( );
1771 RefCountPtr< const FontMetrics::FontMetric > metrics = evalState->dyn_->getTextState( )->font_->metrics( );
1772 if( metrics->horizontalMetrics_ == NullPtr< FontMetrics::WritingDirectionMetrics >( ) )
1774 throw Exceptions::FontMetricsError( evalState->dyn_->getTextState( )->font_->fontName( ), strrefdup( "No horizontal metrics defined." ) );
1777 // Note that res is _not_ yet const. We use a RefCountPtr to take care of memory deallocation in case some argument has the wrong type and
1778 // the result is not used.
1779 RefCountPtr< Lang::KernedText > res( new Lang::KernedText( evalState->dyn_->getTextState( ), evalState->dyn_->getGraphicsState( ) ) );
1781 std::ostringstream pendingChars;
1782 Kernel::UnicodeCodePoint prevChar( 0 );
1783 double pendingKerning = 0;
1785 const size_t backbufSize = 5;
1786 char backbuf[ backbufSize ];
1788 for( size_t i = 0; i != args.size( ); ++i )
1792 typedef const Lang::String ArgType;
1793 RefCountPtr< ArgType > str = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( i ) );
1795 const char * inbuf = str->val_.getPtr( );
1796 size_t inbytesleft = strlen( inbuf );
1798 size_t bufSize = 4 * inbytesleft;
1799 char * buf = new char[ bufSize ];
1800 DeleteOnExit< char > bufDeleter( buf );
1802 char * outbuf = buf;
1803 size_t outbytesleft = bufSize;
1804 // The ICONV_CAST macro is defined in config.h.
1805 size_t count = iconv( converter,
1806 ICONV_CAST( & inbuf ), & inbytesleft,
1807 & outbuf, & outbytesleft );
1808 if( count == (size_t)(-1) )
1810 if( errno == EILSEQ )
1812 throw Exceptions::MiscellaneousRequirement( "It is suspected that one of the UFT-8 characters used in showed text has no UCS-4 representation." );
1814 else if( errno == EINVAL )
1816 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
1818 else if( errno == E2BIG )
1820 throw Exceptions::InternalError( "Core_automatickern: The buffer allocated for UTF-8 to UCS-4 conversion was too small." );
1822 else
1824 std::ostringstream msg;
1825 msg << "iconv failed with an unrecognized error code: " << errno ;
1826 throw Exceptions::InternalError( strrefdup( msg ) );
1829 for( const char * src = buf; src != outbuf; src += 4 )
1831 Kernel::UnicodeCodePoint currentChar;
1832 currentChar.decode_UCS4( src );
1833 double currentKerning = pendingKerning - metrics->getHorizontalKernPairXByCode( prevChar, currentChar );
1834 prevChar = currentChar;
1835 pendingKerning = 0;
1836 if( currentKerning != 0 )
1838 if( ! pendingChars.str( ).empty( ) )
1840 res->pushString( RefCountPtr< const Lang::String >( new Lang::String( strrefdup( pendingChars ) ) ) );
1841 pendingChars.str( "" );
1843 res->pushKerning( currentKerning );
1846 // Copy the current (multibyte) character to the character queue
1848 const char * inbuf = src;
1849 char * outbuf = backbuf;
1850 size_t inbytesleft = 4;
1851 size_t outbytesleft = backbufSize;
1852 // The ICONV_CAST macro is defined in config.h.
1853 size_t count = iconv( backconverter,
1854 ICONV_CAST( & inbuf ), & inbytesleft,
1855 & outbuf, & outbytesleft );
1856 if( count == (size_t)(-1) )
1858 if( errno == EILSEQ )
1860 throw Exceptions::ExternalError( "A character converted from UTF-8 could not be converted back to UFT-8." );
1862 else if( errno == EINVAL )
1864 throw Exceptions::ExternalError( "A character converted from UTF-8 was deemed incomplete." );
1866 else if( errno == E2BIG )
1868 throw Exceptions::InternalError( "The buffer allocated for conversion of a single character back to UTF-8 was too small." );
1870 else
1872 std::ostringstream msg;
1873 msg << "iconv failed with an unrecognized error code: " << errno ;
1874 throw Exceptions::InternalError( strrefdup( msg ) );
1877 *outbuf = '\0';
1878 pendingChars << backbuf ;
1881 continue;
1883 catch( const NonLocalExit::NotThisType & ball )
1885 // Never mind, see below
1890 typedef const Lang::Float ArgType;
1891 pendingKerning += Helpers::try_cast_CoreArgument< ArgType >( args.getValue( i ) )->val_;
1892 continue;
1894 catch( const NonLocalExit::NotThisType & ball )
1896 // Never mind, see below
1899 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, i, Helpers::typeSetString( Lang::String::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
1902 if( ! pendingChars.str( ).empty( ) )
1904 res->pushString( RefCountPtr< const Lang::String >( new Lang::String( strrefdup( pendingChars ) ) ) );
1905 pendingChars.str( "" );
1908 Kernel::ContRef cont = evalState->cont_;
1909 cont->takeValue( res,
1910 evalState );
1914 class Core_newrandom : public Lang::CoreFunction
1916 public:
1917 Core_newrandom( const char * title )
1918 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1920 formals_->appendEvaluatedCoreFormal( "seed", Kernel::THE_SLOT_VARIABLE );
1921 formals_->appendEvaluatedCoreFormal( "size", Helpers::newValHandle( new Lang::Integer( 32 ) ) );
1923 virtual void
1924 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1926 args.applyDefaults( );
1928 typedef const Lang::Integer SizeType;
1929 Lang::Integer::ValueType sz = Helpers::down_cast_CoreArgument< SizeType >( title_, args, 1, callLoc )->val_;
1930 if( sz < 8 )
1932 throw Exceptions::CoreOutOfRange( title_, args, 1, "The size must be at least 8." );
1934 if( sz > 256 )
1936 throw Exceptions::CoreOutOfRange( title_, args, 1, "The size must at most 256." );
1939 size_t argsi = 0;
1943 typedef const Lang::ChronologicalTime SeedType;
1945 RefCountPtr< SeedType > seed = Helpers::try_cast_CoreArgument< SeedType >( args.getValue( argsi ) );
1947 Kernel::ContRef cont = evalState->cont_;
1948 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::HotRandomSeed( sz, seed->val( ) ) ),
1949 evalState );
1950 return;
1952 catch( const NonLocalExit::NotThisType & ball )
1954 // Never mind, see below
1959 typedef const Lang::Integer SeedType;
1961 RefCountPtr< SeedType > seed = Helpers::try_cast_CoreArgument< SeedType >( args.getValue( argsi ) );
1963 Kernel::ContRef cont = evalState->cont_;
1964 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::HotRandomSeed( sz, seed->val_ ) ),
1965 evalState );
1966 return;
1968 catch( const NonLocalExit::NotThisType & ball )
1970 // Never mind, see below
1973 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, argsi, Helpers::typeSetString( Lang::Integer::staticTypeName( ), Lang::ChronologicalTime::staticTypeName( ) ) );
1977 class Core_devrandom : public Lang::CoreFunction
1979 public:
1980 Core_devrandom( const char * title )
1981 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
1983 formals_->appendCoreStateFormal( "device" );
1984 formals_->appendEvaluatedCoreFormal( "size", Helpers::newValHandle( new Lang::Integer( 32 ) ) );
1986 virtual void
1987 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1989 args.applyDefaults( );
1991 typedef const Lang::Integer SizeType;
1992 Lang::Integer::ValueType sz = Helpers::down_cast_CoreArgument< SizeType >( title_, args, 0, callLoc )->val_;
1993 if( sz < 8 )
1995 throw Exceptions::CoreOutOfRange( title_, args, 0, "The size must be at least 8." );
1997 if( sz > 256 )
1999 throw Exceptions::CoreOutOfRange( title_, args, 0, "The size must at most 256." );
2002 typedef Kernel::WarmRandomDevice GeneratorType;
2003 GeneratorType * gen = Helpers::down_cast_CoreState< GeneratorType >( title_, args, 0, callLoc );
2005 Kernel::ContRef cont = evalState->cont_;
2006 cont->takeValue( RefCountPtr< const Lang::Value >( new Lang::HotRandomSeed( static_cast< size_t >( sz ), gen ) ),
2007 evalState );
2011 class Core_destination : public Lang::CoreFunction
2013 public:
2014 Core_destination( const char * title )
2015 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
2017 formals_->appendEvaluatedCoreFormal( "remote", Kernel::THE_FALSE_VARIABLE );
2018 formals_->appendEvaluatedCoreFormal( "name", Kernel::THE_VOID_VARIABLE );
2019 formals_->appendEvaluatedCoreFormal( "level", Kernel::THE_VOID_VARIABLE );
2020 formals_->appendEvaluatedCoreFormal( "text", Kernel::THE_VOID_VARIABLE );
2021 formals_->appendEvaluatedCoreFormal( "open", Kernel::THE_FALSE_VARIABLE );
2022 formals_->appendEvaluatedCoreFormal( "bold", Kernel::THE_FALSE_VARIABLE );
2023 formals_->appendEvaluatedCoreFormal( "italic", Kernel::THE_FALSE_VARIABLE );
2024 formals_->appendEvaluatedCoreFormal( "color", Helpers::newValHandle( new Lang::RGB( Concrete::RGB( 0, 0, 0 ) ) ) );
2025 formals_->appendEvaluatedCoreFormal( "sides", Kernel::THE_VOID_VARIABLE );
2026 formals_->appendEvaluatedCoreFormal( "target", Kernel::THE_VOID_VARIABLE );
2027 formals_->appendEvaluatedCoreFormal( "fittobbox", Kernel::THE_VOID_VARIABLE );
2028 formals_->appendEvaluatedCoreFormal( "zoom", Kernel::THE_VOID_VARIABLE );
2029 formals_->appendEvaluatedCoreFormal( "transform", Kernel::THE_TRUE_VARIABLE );
2031 virtual void
2032 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2034 args.applyDefaults( );
2036 size_t argsi = 0;
2037 const size_t remove_i = argsi;
2038 typedef const Lang::Boolean RemoteType;
2039 bool remote = Helpers::down_cast_CoreArgument< RemoteType >( title_, args, argsi, callLoc )->val_;
2041 ++argsi;
2042 typedef const Lang::String NameType;
2043 RefCountPtr< NameType > nameVal = Helpers::down_cast_CoreArgument< NameType >( title_, args, argsi, callLoc, true );
2044 RefCountPtr< const char > name = RefCountPtr< const char >( NullPtr< const char >( ) );
2045 if( nameVal != NullPtr< NameType >( ) )
2047 const SimplePDF::PDF_Version::Version STRINGDESTS_VERSION = SimplePDF::PDF_Version::PDF_1_2;
2048 if( Kernel::the_PDF_version.greaterOrEqual( STRINGDESTS_VERSION ) )
2050 name = nameVal->val_;
2052 else
2054 Kernel::the_PDF_version.message( STRINGDESTS_VERSION, "The naming of a destination was ignored." );
2055 // Note that this will leave name being null, and hence generate further errors if remote_.
2058 if( nameVal == NullPtr< NameType >( ) ) // Note why this is not an else clause!
2060 if( remote )
2062 throw Exceptions::CoreOutOfRange( title_, args, remove_i, "The destination cannot be remote if no name is given." );
2066 ++argsi;
2067 const size_t outlineLevel_i = argsi;
2068 typedef const Lang::Integer OutlineLevelType;
2069 RefCountPtr< OutlineLevelType > levelVal = Helpers::down_cast_CoreArgument< OutlineLevelType >( title_, args, argsi, callLoc, true );
2070 int outlineLevel = -1; // This will remain negative only if the level is not present.
2071 if( levelVal != NullPtr< OutlineLevelType >( ) )
2073 outlineLevel = levelVal->val_;
2074 if( outlineLevel < 0 )
2076 throw Exceptions::CoreOutOfRange( title_, args, argsi, "The outline level must be non-negative." );
2080 ++argsi;
2081 typedef const Lang::String OutlineTextType;
2082 RefCountPtr< OutlineTextType > textVal = Helpers::down_cast_CoreArgument< OutlineTextType >( title_, args, argsi, callLoc, true );
2083 RefCountPtr< const char > outlineText = RefCountPtr< const char >( NullPtr< const char >( ) );
2084 if( textVal != NullPtr< OutlineTextType >( ) )
2086 outlineText = textVal->val_;
2088 else
2090 if( outlineLevel >= 0 )
2092 throw Exceptions::CoreOutOfRange( title_, args, outlineLevel_i, "Without an outline text, it is not allowed to make an outline item." );
2096 ++argsi;
2097 typedef const Lang::Boolean OutlineOpenType;
2098 bool outlineOpen = Helpers::down_cast_CoreArgument< OutlineOpenType >( title_, args, argsi, callLoc )->val_;
2100 ++argsi;
2101 typedef const Lang::Boolean OutlineBoldType;
2102 bool outlineBold = Helpers::down_cast_CoreArgument< OutlineBoldType >( title_, args, argsi, callLoc )->val_;
2104 ++argsi;
2105 typedef const Lang::Boolean OutlineItalicType;
2106 bool outlineItalic = Helpers::down_cast_CoreArgument< OutlineItalicType >( title_, args, argsi, callLoc )->val_;
2108 ++argsi;
2109 typedef const Lang::RGB OutlineColorType;
2110 Concrete::RGB outlineColor = Helpers::down_cast_CoreArgument< OutlineColorType >( title_, args, argsi, callLoc )->components( );
2112 ++argsi;
2113 const size_t sidesMode_i = argsi;
2114 typedef const Lang::Symbol SidesModeType;
2115 RefCountPtr< SidesModeType > sidesVal = Helpers::down_cast_CoreArgument< SidesModeType >( title_, args, argsi, callLoc, true );
2117 ++argsi;
2118 const size_t target_i = argsi;
2119 typedef const Lang::Drawable2D TargetType;
2120 RefCountPtr< TargetType > target = Helpers::down_cast_CoreArgument< TargetType >( title_, args, argsi, callLoc, true );
2122 Lang::DocumentDestination::Sides sides = Lang::DocumentDestination::PAGE; // Defaults to false, unless a target is given.
2123 if( target != NullPtr< TargetType >( ) )
2125 sides = Lang::DocumentDestination::TOPLEFT;
2126 if( remote )
2128 throw Exceptions::CoreOutOfRange( title_, args, target_i, "The target can not be specified for remote destinations." );
2131 static Lang::Symbol SIDES_TopLeft( "topleft" );
2132 static Lang::Symbol SIDES_Page( "page" );
2133 static Lang::Symbol SIDES_Top( "top" );
2134 static Lang::Symbol SIDES_Left( "left" );
2135 static Lang::Symbol SIDES_Rectangle( "rectangle" );
2136 if( sidesVal != NullPtr< SidesModeType >( ) )
2138 if( *sidesVal == SIDES_TopLeft )
2140 sides = Lang::DocumentDestination::TOPLEFT;
2142 else if( *sidesVal == SIDES_Page )
2144 if( target != NullPtr< TargetType >( ) )
2146 throw Exceptions::CoreOutOfRange( title_, args, sidesMode_i, "The sides mode cannot be page when a target object is present." );
2148 sides = Lang::DocumentDestination::PAGE;
2150 else if( *sidesVal == SIDES_Top )
2152 sides = Lang::DocumentDestination::TOP;
2154 else if( *sidesVal == SIDES_Left )
2156 sides = Lang::DocumentDestination::LEFT;
2158 else if( *sidesVal == SIDES_Rectangle )
2160 sides = Lang::DocumentDestination::RECTANGLE;
2162 else
2164 std::ostringstream oss;
2165 oss << "Valid sides modes are the symbols { "
2166 << SIDES_TopLeft.name( ).getPtr( ) << ", "
2167 << SIDES_Page.name( ).getPtr( ) << ", "
2168 << SIDES_Top.name( ).getPtr( ) << ", "
2169 << SIDES_Left.name( ).getPtr( ) << ", "
2170 << SIDES_Rectangle.name( ).getPtr( )
2171 << " }." ;
2172 throw Exceptions::CoreOutOfRange( title_, args, sidesMode_i, strrefdup( oss ) );
2176 ++argsi;
2177 typedef const Lang::Boolean FitToType;
2178 RefCountPtr< FitToType > fittobboxVal = Helpers::down_cast_CoreArgument< FitToType >( title_, args, argsi, callLoc, true );
2179 bool fittobbox = false;
2180 if( fittobboxVal != NullPtr< FitToType >( ) )
2182 if( remote || sides == Lang::DocumentDestination::TOPLEFT || sides == Lang::DocumentDestination::RECTANGLE )
2184 throw Exceptions::CoreOutOfRange( title_, args, argsi, "The fit-to-bbox flag cannot be specified in this mode." );
2186 fittobbox = fittobboxVal->val_;
2189 ++argsi;
2190 typedef const Lang::Float ZoomType;
2191 RefCountPtr< ZoomType > zoomVal = Helpers::down_cast_CoreArgument< ZoomType >( title_, args, argsi, callLoc, true );
2192 double zoom = 0; // This will remain zero only if the zoom argument is not specified.
2193 if( zoomVal != NullPtr< ZoomType >( ) )
2195 if( remote || sides != Lang::DocumentDestination::TOPLEFT )
2197 throw Exceptions::CoreOutOfRange( title_, args, argsi, "The zoom can only be specified when using the top-left sides." );
2199 zoom = zoomVal->val_;
2200 if( zoom <= 0 )
2202 throw Exceptions::CoreOutOfRange( title_, args, argsi, "The zoom value must be positive." );
2206 ++argsi;
2207 typedef const Lang::Boolean DoTransformType;
2208 bool doTransform = Helpers::down_cast_CoreArgument< DoTransformType >( title_, args, argsi, callLoc )->val_;
2210 Kernel::ContRef cont = evalState->cont_;
2211 if( remote )
2213 RefCountPtr< const Lang::DocumentDestination >
2214 taggedObj( new Lang::DocumentDestination( remote, name, outlineLevel,
2215 outlineText, outlineOpen, outlineBold, outlineItalic, outlineColor ) );
2216 cont->takeValue( RefCountPtr< const Lang::Value >
2217 ( new Lang::TaggedValue2D( Kernel::THE_NAVIGATION_SYMBOL, taggedObj ) ),
2218 evalState );
2220 else
2222 RefCountPtr< const Lang::DocumentDestination >
2223 taggedObj( new Lang::DocumentDestination( name, outlineLevel,
2224 outlineText, outlineOpen, outlineBold, outlineItalic, outlineColor,
2225 sides, target, fittobbox, zoom ) );
2226 if( doTransform )
2228 cont->takeValue( RefCountPtr< const Lang::Value >
2229 ( new Lang::TaggedGeometric2D( Kernel::THE_NAVIGATION_SYMBOL, taggedObj ) ),
2230 evalState );
2232 else
2234 cont->takeValue( RefCountPtr< const Lang::Value >
2235 ( new Lang::TaggedValue2D( Kernel::THE_NAVIGATION_SYMBOL, taggedObj ) ),
2236 evalState );
2242 class Core_importFont : public Lang::CoreFunction
2244 public:
2245 struct CacheKey
2247 bool outline_;
2248 RefCountPtr< const char > filename_;
2249 CacheKey( bool outline, const RefCountPtr< const char > & filename )
2250 : outline_( outline ), filename_( filename )
2252 ~CacheKey( )
2254 bool operator < ( const CacheKey & other ) const
2256 if( ! outline_ && other.outline_ )
2258 return true;
2260 if( outline_ && ! other.outline_ )
2262 return false;
2264 return strcmp( filename_.getPtr( ), other.filename_.getPtr( ) ) < 0;
2267 private:
2268 static std::map< CacheKey, RefCountPtr< const Lang::Value > > cache;
2269 public:
2270 Core_importFont( const char * title )
2271 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
2273 formals_->appendEvaluatedCoreFormal( "family", Kernel::THE_SLOT_VARIABLE );
2274 formals_->appendEvaluatedCoreFormal( "style", Kernel::THE_VOID_VARIABLE );
2275 formals_->appendEvaluatedCoreFormal( "outline", Kernel::THE_FALSE_VARIABLE );
2277 virtual void
2278 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2280 #ifndef HAVE_FT2
2281 throw Exceptions::BuildRequirement( Interaction::BUILD_REQ_FREETYPE, title_, callLoc );
2282 #else
2283 args.applyDefaults( );
2285 size_t argsi = 0;
2286 std::string full_filename;
2287 #ifndef HAVE_FONTCONFIG
2288 /* Here, it would be possible to allow the user to point out the font file directly instead of using FontConfig,
2289 * but currently there is no such option.
2291 throw Exceptions::BuildRequirement( Interaction::BUILD_REQ_FONTCONFIG, title_, callLoc );
2292 #else
2293 FcPattern * pat = FcPatternCreate( );
2294 Helpers::AutoDestroyFcPattern destroy_pat( pat );
2296 FcValue fc_fontformat;
2297 fc_fontformat.type = FcTypeString;
2298 fc_fontformat.u.s = reinterpret_cast< const FcChar8 * >( "TrueType" );
2299 FcPatternAdd( pat, "fontformat", fc_fontformat, FcFalse );
2301 size_t argsi_family = argsi;
2302 typedef const Lang::String ArgType;
2303 RefCountPtr< ArgType > family = Helpers::down_cast_CoreArgument< ArgType >( title_, args, argsi_family, callLoc );
2304 FcValue fc_family;
2305 fc_family.type = FcTypeString;
2306 fc_family.u.s = reinterpret_cast< const FcChar8 * >( family->val_.getPtr( ) );
2307 FcPatternAdd( pat, "family", fc_family, FcFalse );
2309 ++argsi;
2310 size_t argsi_style = argsi;
2311 RefCountPtr< ArgType > style = Helpers::down_cast_CoreArgument< ArgType >( title_, args, argsi_style, callLoc, true );
2312 FcValue fc_style;
2313 if( style != NullPtr< ArgType >( ) )
2315 fc_style.type = FcTypeString;
2316 fc_style.u.s = reinterpret_cast< const FcChar8 * >( style->val_.getPtr( ) );
2317 FcPatternAdd( pat, "style", fc_family, FcFalse );
2320 FcFontSet * sysFonts = FcConfigGetFonts( NULL, FcSetSystem );
2322 FcResult fc_res;
2324 FcDefaultSubstitute( pat );
2325 FcConfigSubstitute( NULL, pat, FcMatchPattern ); /* Not sure if FcMatchPattern is the correct value to pass here. There are two more possible values, and no documentation. See fontconfig/fontconfig.h. */
2326 FcPattern * match_res = FcFontSetMatch( NULL, & sysFonts, 1, pat, & fc_res );
2327 if( match_res == 0 )
2329 throw Exceptions::ExternalError( "FontConfig' FcFontSetMatch returned with failure." );
2331 Helpers::AutoDestroyFcPattern destroy_match_res( match_res );
2333 switch( fc_res )
2335 case FcResultMatch:
2336 // OK, just continue;
2337 break;
2338 case FcResultNoMatch:
2339 throw Exceptions::OutOfRange( callLoc, "FontConfig returned no matching font." );
2340 case FcResultOutOfMemory:
2341 throw Exceptions::ExternalError( "FontConfig got out of memory." );
2342 case FcResultTypeMismatch:
2343 // {
2344 // std::ostringstream msg;
2345 // msg << "Unexpected FcResult from FcFontSetMatch: " << "FcResultTypeMismatch" << " (ignored)." ;
2346 // WARN_OR_THROW( Exceptions::InternalError( strrefdup( msg ), true ) );
2347 // }
2348 break;
2349 case FcResultNoId:
2350 // {
2351 // std::ostringstream msg;
2352 // msg << "Unexpected FcResult from FcFontSetMatch: " << "FcResultNoId" << " (ignored)." ;
2353 // WARN_OR_THROW( Exceptions::InternalError( strrefdup( msg ), true ) );
2354 // }
2355 break;
2356 default:
2357 // {
2358 // std::ostringstream msg;
2359 // msg << "Unexpected FcResult from FcFontSetMatch: " << fc_res << " (ignored)." ;
2360 // WARN_OR_THROW( Exceptions::InternalError( strrefdup( msg ), true ) );
2361 // }
2362 // throw Exceptions::InternalError( "Unexpected FcResult from FcFontSetMatch." );
2363 break;
2365 // FcPatternPrint( match_res );
2367 FcChar8 * fc_tmp_string;
2368 switch( FcPatternGetString( match_res, "fontformat", 0, & fc_tmp_string ) )
2370 case FcResultMatch:
2371 // OK, just continue;
2372 break;
2373 case FcResultNoMatch:
2374 throw Exceptions::ExternalError( "FontConfig says that the font does not have a 'fontformat'." );
2375 case FcResultTypeMismatch:
2376 throw Exceptions::ExternalError( "FontConfig says 'fontformat' has the wrong type." );
2377 case FcResultNoId:
2378 throw Exceptions::ExternalError( "FontConfig says 'fontformat' is missing something." );
2379 case FcResultOutOfMemory:
2380 throw Exceptions::ExternalError( "FontConfig got out of memory." );
2382 if( strcmp( reinterpret_cast< const char * >( fc_tmp_string ), "TrueType" ) != 0 ) // This is OK, since "TrueType" is in the ASCII range.
2384 throw Exceptions::OutOfRange( callLoc, "Font file format not supported by Shapes, only TrueType is supported at the moment." );
2387 switch( FcPatternGetString( match_res, "file", 0, & fc_tmp_string ) )
2389 case FcResultMatch:
2390 // OK, just continue;
2391 break;
2392 case FcResultNoMatch:
2393 throw Exceptions::ExternalError( "FontConfig says that the font does not have a 'file' (filename)." );
2394 case FcResultTypeMismatch:
2395 throw Exceptions::ExternalError( "FontConfig says 'file' has the wrong type." );
2396 case FcResultNoId:
2397 throw Exceptions::ExternalError( "FontConfig says 'file' is missing something." );
2398 case FcResultOutOfMemory:
2399 throw Exceptions::ExternalError( "FontConfig got out of memory." );
2401 full_filename = reinterpret_cast< const char * >( fc_tmp_string ); /* Let us hope that this string is in the ASCII range! */
2402 #endif
2404 ++argsi;
2405 size_t argsi_outline = argsi;
2406 bool outline = Helpers::down_cast_CoreArgument< const Lang::Boolean >( title_, args, argsi_outline, callLoc )->val_;
2407 CacheKey cacheKey( outline, strrefdup( full_filename.c_str( ) ) );
2409 typedef typeof cache MapType;
2410 MapType::const_iterator i = cache.find( cacheKey );
2411 if( i != cache.end( ) )
2413 Kernel::ContRef cont = evalState->cont_;
2414 cont->takeValue( i->second,
2415 evalState );
2420 FT_Face face;
2422 FT_Error error = FT_New_Face( Kernel::theFreeType,
2423 full_filename.c_str( ),
2425 & face );
2426 if( error == FT_Err_Unknown_File_Format )
2428 throw Exceptions::ExternalError( "Font file format not supported by FreeType." );
2430 else if( error != 0 )
2432 std::ostringstream msg;
2433 msg << "FreeType failed to open " << full_filename << ", reason: " << Kernel::FreeTypeErrorMessage( error ) ;
2434 throw Exceptions::ExternalError( strrefdup( msg ) );
2437 const char * PostScriptName = FT_Get_Postscript_Name( face ); /* See comment on the next line! */
2438 std::ostringstream baseFontName; /* The PostScriptName pointer shall only be used as long as this object is in scope. */
2439 if( PostScriptName == 0 )
2441 for( const char * src = full_filename.c_str( ); *src != '\0'; ++src )
2443 if( *src == '.' )
2445 break;
2447 if( *src != ' ' )
2449 baseFontName << *src ;
2452 PostScriptName = baseFontName.str( ).c_str( );
2455 if( ! FT_IS_SFNT( face ) )
2457 throw Exceptions::OutOfRange( callLoc, "Font file format not supported by Shapes, only TrueType is supported at the moment." );
2459 if( ! outline )
2461 #ifdef HAVE_FT2_10
2462 FT_UShort fsType = FT_Get_FSType_Flags( face );
2463 if( ( fsType & ( FT_FSTYPE_INSTALLABLE_EMBEDDING |
2464 FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING |
2465 FT_FSTYPE_EDITABLE_EMBEDDING ) )
2466 == 0 )
2468 std::ostringstream msg;
2469 msg << "The font " << PostScriptName << " does not permit embedding, and cannot be used with Shapes. Flags: " << std::hex << static_cast< int >( fsType ) << "." ;
2470 throw Exceptions::MiscellaneousRequirement( strrefdup( msg ) );
2472 #else
2473 throw Exceptions::MiscellaneousRequirement( strrefdup( "Shapes does not permit embedding of fonts, since your FreeType library is too old to provide licensing information about your fonts." ) );
2474 #endif
2477 FontMetrics::FreeType2_Metric * newMetrics = new FontMetrics::FreeType2_Metric( face );
2478 RefCountPtr< const FontMetrics::FontMetric > metrics = RefCountPtr< const FontMetrics::FontMetric >( newMetrics );
2480 RefCountPtr< SimplePDF::PDF_Dictionary > dic;
2481 RefCountPtr< SimplePDF::PDF_Object > resource = SimplePDF::indirect( dic, & Kernel::theIndirectObjectCount );
2482 (*dic)[ "Type" ] = SimplePDF::newName( "Font" );
2483 (*dic)[ "Subtype" ] = SimplePDF::newName( "Type0" );
2485 RefCountPtr< SimplePDF::PDF_Dictionary > descendant;
2486 RefCountPtr< SimplePDF::PDF_Vector > descendants;
2487 descendants->vec.push_back( descendant );
2488 (*dic)[ "DescendantFonts" ] = descendants;
2490 RefCountPtr< SimplePDF::PDF_ToUnicode::CharSet > usedChars;
2492 (*descendant)[ "Type" ] = SimplePDF::newName( "Font" );
2493 (*descendant)[ "Subtype" ] = SimplePDF::newName( "CIDFontType2" );
2495 RefCountPtr< SimplePDF::PDF_Name > fontName = RefCountPtr< SimplePDF::PDF_Name >( new SimplePDF::PDF_Name( PostScriptName ) );
2496 (*dic)[ "BaseFont" ] = fontName;
2497 (*descendant)[ "BaseFont" ] = fontName;
2498 (*dic)[ "Encoding" ] = SimplePDF::newName( "Identity-H" );
2499 (*descendant)[ "BaseFont" ] = fontName;
2501 RefCountPtr< SimplePDF::PDF_Dictionary > CIDSystemInfo;
2502 (*CIDSystemInfo)[ "Registry" ] = SimplePDF::newString( "Adobe" );
2503 (*CIDSystemInfo)[ "Ordering" ] = SimplePDF::newString( "Identity" );
2504 (*CIDSystemInfo)[ "Supplement" ] = SimplePDF::newString( "0" );
2505 (*descendant)[ "CIDSystemInfo" ] = CIDSystemInfo;
2506 (*descendant)[ "CIDToGIDMap" ] = SimplePDF::newName( "Identity" );
2508 (*descendant)[ "DW" ] = SimplePDF::newFloat( 0.7 * 1000 ); /* Default width. */
2510 RefCountPtr< SimplePDF::PDF_Dictionary > fontDescriptor;
2511 (*fontDescriptor)[ "Type" ] = SimplePDF::newName( "FontDescriptor" );
2512 (*fontDescriptor)[ "FontName" ] = fontName;
2513 (*fontDescriptor)[ "Flags" ] = SimplePDF::newInt( (size_t)(1) << ( 6 - 1 ) ); // This is the "Nonsymbolic" flag, although we don't know if it really is a non-symbolic font...
2514 (*fontDescriptor)[ "FontBBox" ] =
2515 RefCountPtr< SimplePDF::PDF_Vector >( new SimplePDF::PDF_Vector( newMetrics->fontBBoxXMin_ * 1000, newMetrics->fontBBoxYMin_ * 1000,
2516 newMetrics->fontBBoxXMax_ * 1000, newMetrics->fontBBoxYMax_ * 1000 ) );
2517 (*fontDescriptor)[ "ItalicAngle" ] = SimplePDF::newFloat( 0 );
2518 (*fontDescriptor)[ "Ascent" ] = SimplePDF::newFloat( 1 * 1000 );
2519 (*fontDescriptor)[ "Descent" ] = SimplePDF::newFloat( -0.5 * 1000 );
2521 RefCountPtr< SimplePDF::PDF_Stream_out > fontFile = RefCountPtr< SimplePDF::PDF_Stream_out >( new SimplePDF::PDF_Stream_out( ) );
2522 (*fontFile)[ "Filter" ] = SimplePDF::newName( "FlateDecode" );
2523 std::ifstream iFile( full_filename.c_str( ) );
2524 if( ! iFile.is_open( ) )
2526 throw Exceptions::FileReadOpenError( callLoc, strrefdup( full_filename ), 0, 0 );
2529 iFile.seekg( 0, std::ios::end );
2530 std::streamoff tmp = iFile.tellg( );
2531 std::streamsize size = tmp - static_cast< std::streamoff >( 0 );
2532 (*fontFile)[ "Length1" ] = SimplePDF::newInt( size );
2533 char * buf = new char[ size ];
2534 iFile.seekg( 0, std::ios::beg );
2535 iFile.read( buf, size );
2536 fontFile->data.write( buf, size );
2537 delete buf;
2539 (*fontDescriptor)[ "FontFile2" ] = SimplePDF::indirect( fontFile, & Kernel::theIndirectObjectCount );
2541 (*descendant)[ "FontDescriptor" ] = fontDescriptor;
2543 RefCountPtr< const Lang::Font > res = RefCountPtr< const Lang::Font >( new Lang::FreeTypeFont( face,
2544 newMetrics->fontName_,
2545 outline,
2546 resource,
2547 metrics,
2548 usedChars ) );
2549 RefCountPtr< SimplePDF::PDF_ToUnicode > toUnicode( new SimplePDF::PDF_ToUnicode( usedChars, res ) );
2550 (*dic)[ "ToUnicode" ] = SimplePDF::indirect( toUnicode, & Kernel::theIndirectObjectCount );
2551 RefCountPtr< SimplePDF::PDF_Widths > widths( new SimplePDF::PDF_Widths( usedChars, res ) );
2552 (*descendant)[ "W" ] = SimplePDF::indirect( widths, & Kernel::theIndirectObjectCount );
2555 typedef typeof cache MapType;
2556 cache.insert( MapType::value_type( cacheKey, res ) );
2558 Kernel::ContRef cont = evalState->cont_;
2559 cont->takeValue( res,
2560 evalState );
2561 #endif
2565 std::map< Core_importFont::CacheKey, RefCountPtr< const Lang::Value > > Core_importFont::cache;
2567 class Core_Unicode : public Lang::CoreFunction
2569 public:
2570 Core_Unicode( const char * title )
2571 : CoreFunction( title )
2573 virtual void
2574 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2576 const size_t ARITY = 1;
2577 CHECK_ARITY( args, ARITY, title_ );
2579 size_t argsi = 0;
2580 typedef const Lang::Integer ArgType;
2581 ArgType::ValueType arg = Helpers::down_cast_CoreArgument< ArgType >( title_, args, argsi, callLoc )->val_;
2582 if( arg < 0 )
2584 throw Exceptions::CoreOutOfRange( title_, args, argsi, "Unicode code points cannot be negative." );
2587 Kernel::ContRef cont = evalState->cont_;
2588 cont->takeValue( Kernel::ValueRef( new Lang::Character( arg ) ),
2589 evalState );
2593 class Core_AdobeGlyphList : public Lang::CoreFunction
2595 public:
2596 Core_AdobeGlyphList( const char * title )
2597 : CoreFunction( title )
2599 virtual void
2600 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2602 const size_t ARITY = 1;
2603 CHECK_ARITY( args, ARITY, title_ );
2605 size_t argsi = 0;
2606 typedef const Lang::Symbol ArgType;
2607 RefCountPtr< ArgType > arg = Helpers::down_cast_CoreArgument< ArgType >( title_, args, argsi, callLoc );
2608 if( arg->isUnique( ) )
2610 throw Exceptions::CoreOutOfRange( title_, args, argsi, "Unique symbols do not correspond to any glyphs." );
2612 FontMetrics::GlyphList::UnicodeType res;
2613 const FontMetrics::GlyphList & glyphList = Helpers::requireGlyphList( );
2614 if( ! glyphList.name_to_UCS4( arg->name( ).getPtr( ), & res ) )
2616 std::ostringstream msg;
2617 msg << "Unrecognized glyph name: " ;
2618 arg->show( msg );
2619 throw Exceptions::CoreOutOfRange( title_, args, argsi, strrefdup( msg ) );
2621 Kernel::ContRef cont = evalState->cont_;
2622 cont->takeValue( Kernel::ValueRef( new Lang::Character( res ) ),
2623 evalState );
2631 Lang::Core_range::Core_range( const char * title )
2632 : CoreFunction( title, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title ), true ) )
2634 formals_->appendEvaluatedCoreFormal( "begin", Kernel::THE_VOID_VARIABLE );
2635 formals_->appendEvaluatedCoreFormal( "end", Kernel::THE_VOID_VARIABLE );
2636 formals_->appendEvaluatedCoreFormal( "step", Kernel::THE_VOID_VARIABLE );
2637 formals_->appendEvaluatedCoreFormal( "count", Kernel::THE_VOID_VARIABLE );
2640 void
2641 Lang::Core_range::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2643 makeRange( title_, evalState, args, callLoc );
2646 void
2647 Lang::Core_range::makeRange( const char * title, Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc, bool isSpan, RefCountPtr< const Lang::Value > lastPtr )
2649 const size_t argsi_begin = 0;
2650 const size_t argsi_end = 1;
2651 const size_t argsi_step = 2;
2652 const size_t argsi_count = 3;
2654 typedef const Lang::Integer CountType;
2656 args.applyDefaults( );
2660 typedef const Lang::Integer ArgType;
2662 RefCountPtr< ArgType > beginPtr = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi_begin ), true );
2663 RefCountPtr< ArgType > endPtr = Helpers::down_cast_CoreArgument< ArgType >( title, args, argsi_end, callLoc, true );
2664 if( beginPtr == NullPtr< ArgType >( ) && endPtr == NullPtr< ArgType >( ) )
2666 throw Exceptions::CoreRequirement( "At least one of the arguments <begin> and <end> must be provided.", title, callLoc );
2668 RefCountPtr< ArgType > stepPtr = Helpers::down_cast_CoreArgument< ArgType >( title, args, argsi_step, callLoc, true );
2669 RefCountPtr< CountType > countPtr = Helpers::down_cast_CoreArgument< CountType >( title, args, argsi_count, callLoc, true );
2671 if( beginPtr != NullPtr< ArgType >( ) && endPtr != NullPtr< ArgType >( ) &&
2672 stepPtr != NullPtr< ArgType >( ) && countPtr != NullPtr< CountType >( ) )
2674 throw Exceptions::CoreRequirement( "At least one of the arguments must be omitted.", title, callLoc );
2677 ArgType::ValueType begin = 0;
2678 ArgType::ValueType step = 1;
2679 ArgType::ValueType last = isSpan ? lastPtr.down_cast< ArgType >( )->val_ : 0;
2680 size_t count = 0;
2682 if( stepPtr != NullPtr< ArgType >( ) )
2684 step = stepPtr->val_;
2686 if( countPtr != NullPtr< CountType >( ) )
2688 if( countPtr->val_ < 0 )
2690 throw Exceptions::CoreOutOfRange( title, args, argsi_count, "The <count> must not be negative." );
2692 count = countPtr->val_;
2695 if( beginPtr == NullPtr< ArgType >( ) )
2697 if( countPtr == NullPtr< CountType >( ) )
2699 if( isSpan )
2701 if( endPtr->val_ < 0 )
2703 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a span of integers and <begin> is omitted while <end> is negative.", title, callLoc );
2705 count = 1 + endPtr->val_ / step;
2707 else
2709 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of integers and <begin> is omitted.", title, callLoc );
2712 begin = endPtr->val_ - ( count - 1 ) * step;
2714 else if( endPtr == NullPtr< ArgType >( ) )
2716 begin = beginPtr->val_;
2717 if( countPtr == NullPtr< CountType >( ) )
2719 if( isSpan )
2721 if( last < begin )
2723 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of integers and <end> is omitted while <begin> exceeds %last.", title, callLoc );
2725 count = ( last - begin ) / step + 1;
2727 else
2729 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of integers and <end> is omitted.", title, callLoc );
2733 else
2735 if( countPtr != NullPtr< CountType >( ) )
2737 throw Exceptions::CoreRequirement( "It is an error to provide the <count> argument when constructing a range of integers from <begin> to <end>.", title, args.getLoc( argsi_count ) );
2740 begin = beginPtr->val_;
2741 if( ( endPtr->val_ >= begin && step <= 0 )
2743 ( endPtr->val_ <= begin && step >= 0 ) )
2745 throw Exceptions::CoreOutOfRange( title, args, argsi_step, "When <count> is omitted, the sign of <step> must agree with the order of <begin> and <end>." );
2747 count = 1 + ( endPtr->val_ - begin ) / step;
2750 Kernel::ContRef cont = evalState->cont_;
2751 if( count == 0 )
2753 cont->takeValue( Lang::THE_CONS_NULL,
2754 evalState );
2756 else
2758 cont->takeValue( RefCountPtr< const Lang::SingleList >( new Lang::SingleListRange< ArgType >( begin, step, count ) ),
2759 evalState );
2761 return;
2763 catch( const NonLocalExit::NotThisType & ball )
2765 // Never mind, see below
2770 typedef const Lang::Float ArgType;
2772 RefCountPtr< ArgType > beginPtr = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi_begin ), true );
2773 RefCountPtr< ArgType > endPtr = Helpers::down_cast_CoreArgument< ArgType >( title, args, argsi_end, callLoc, true );
2774 if( beginPtr == NullPtr< ArgType >( ) && endPtr == NullPtr< ArgType >( ) )
2776 throw Exceptions::CoreRequirement( "At least one of the arguments <begin> and <end> must be provided.", title, callLoc );
2778 RefCountPtr< ArgType > stepPtr = Helpers::down_cast_CoreArgument< ArgType >( title, args, argsi_step, callLoc, true );
2779 RefCountPtr< CountType > countPtr = Helpers::down_cast_CoreArgument< CountType >( title, args, argsi_count, callLoc, true );
2781 if( beginPtr != NullPtr< ArgType >( ) && endPtr != NullPtr< ArgType >( ) &&
2782 stepPtr != NullPtr< ArgType >( ) && countPtr != NullPtr< CountType >( ) )
2784 throw Exceptions::CoreRequirement( "At least one of the arguments must be omitted.", title, callLoc );
2787 ArgType::ValueType begin = 0;
2788 ArgType::ValueType step = 1;
2789 ArgType::ValueType last = isSpan ? lastPtr.down_cast< ArgType >( )->val_ : 0;
2790 size_t count = 0;
2792 if( stepPtr != NullPtr< ArgType >( ) )
2794 step = stepPtr->val_;
2796 if( countPtr != NullPtr< CountType >( ) )
2798 if( countPtr->val_ < 0 )
2800 throw Exceptions::CoreOutOfRange( title, args, argsi_count, "The <count> must not be negative." );
2802 count = countPtr->val_;
2805 if( beginPtr == NullPtr< ArgType >( ) )
2807 if( countPtr == NullPtr< CountType >( ) )
2809 if( isSpan )
2811 if( endPtr->val_ < 0 )
2813 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a span of floats and <begin> is omitted while <end> is negative.", title, callLoc );
2815 count = 1 + static_cast< size_t >( endPtr->val_ / step );
2817 else
2819 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of floats and <begin> is omitted.", title, callLoc );
2822 begin = endPtr->val_ - ( count - 1 ) * step;
2824 else if( endPtr == NullPtr< ArgType >( ) )
2826 begin = beginPtr->val_;
2827 if( countPtr == NullPtr< CountType >( ) )
2829 if( isSpan )
2831 if( last < begin )
2833 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of floats and <end> is omitted while <begin> exceeds %last.", title, callLoc );
2835 count = 1 + static_cast< size_t >( ( last - begin ) / step );
2837 else
2839 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of floats and <end> is omitted.", title, callLoc );
2843 else
2845 begin = beginPtr->val_;
2846 // When we reach here, we know that at most one of <step> and <count> is provided.
2847 if( countPtr != NullPtr< CountType >( ) )
2849 if( count < 2 )
2851 throw Exceptions::CoreOutOfRange( title, args, argsi_count, "When <step> is omitted, the <count> be at least 2." );
2853 step = ( endPtr->val_ - begin ) / ( count - 1 );
2855 else
2857 /* If <step> is not provided, it defaults to 1, see above. */
2858 if( step == 0 )
2860 throw Exceptions::CoreOutOfRange( title, args, argsi_step, "When <count> is omitted, <step> must not be zero." );
2862 ArgType::ValueType tmpCount = 1 + ( endPtr->val_ - begin ) / step;
2863 if( tmpCount < 1 )
2865 count = 0;
2867 else
2869 if( tmpCount > std::numeric_limits< size_t >::max( ) )
2871 throw Exceptions::CoreOutOfRange( title, args, argsi_step, "When <count> is omitted, too small <step> values cause overflow in the number of elements." );
2873 count = static_cast< size_t >( tmpCount );
2878 Kernel::ContRef cont = evalState->cont_;
2879 if( count == 0 )
2881 cont->takeValue( Lang::THE_CONS_NULL,
2882 evalState );
2884 else
2886 cont->takeValue( RefCountPtr< const Lang::SingleList >( new Lang::SingleListRange< ArgType >( begin, step, count ) ),
2887 evalState );
2889 return;
2891 catch( const NonLocalExit::NotThisType & ball )
2893 // Never mind, see below
2898 typedef const Lang::Length ArgType;
2900 RefCountPtr< ArgType > beginPtr = Helpers::try_cast_CoreArgument< ArgType >( args.getValue( argsi_begin ), true );
2901 RefCountPtr< ArgType > endPtr = Helpers::down_cast_CoreArgument< ArgType >( title, args, argsi_end, callLoc, true );
2902 if( beginPtr == NullPtr< ArgType >( ) && endPtr == NullPtr< ArgType >( ) )
2904 throw Exceptions::CoreRequirement( "At least one of the arguments <begin> and <end> must be provided.", title, callLoc );
2906 RefCountPtr< ArgType > stepPtr = Helpers::down_cast_CoreArgument< ArgType >( title, args, argsi_step, callLoc, true );
2907 RefCountPtr< CountType > countPtr = Helpers::down_cast_CoreArgument< CountType >( title, args, argsi_count, callLoc, true );
2909 if( beginPtr != NullPtr< ArgType >( ) && endPtr != NullPtr< ArgType >( ) &&
2910 stepPtr != NullPtr< ArgType >( ) && countPtr != NullPtr< CountType >( ) )
2912 throw Exceptions::CoreRequirement( "At least one of the arguments must be omitted.", title, callLoc );
2915 ArgType::ValueType begin = ArgType::ValueType( 0 );
2916 ArgType::ValueType step = ArgType::ValueType( 1 ); /* This is a "default" value that one is not allowed to use! */
2917 ArgType::ValueType last = isSpan ? lastPtr.down_cast< ArgType >( )->get( ) : Concrete::ZERO_LENGTH;
2918 size_t count = 0;
2920 if( stepPtr != NullPtr< ArgType >( ) )
2922 step = stepPtr->get( );
2924 if( countPtr != NullPtr< CountType >( ) )
2926 if( countPtr->val_ < 0 )
2928 throw Exceptions::CoreOutOfRange( title, args, argsi_count, "The <count> must not be negative." );
2930 count = countPtr->val_;
2933 if( beginPtr == NullPtr< ArgType >( ) )
2935 if( stepPtr == NullPtr< ArgType >( ) )
2937 throw Exceptions::CoreRequirement( "The <step> must be provided when constructing a range of lengths when <begin> is omitted.", title, callLoc );
2939 if( countPtr == NullPtr< CountType >( ) )
2941 if( isSpan )
2943 if( endPtr->get( ) < Concrete::ZERO_LENGTH )
2945 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a span of lengths and <begin> is omitted while <end> is negative.", title, callLoc );
2947 count = 1 + static_cast< size_t >( endPtr->get( ) / step );
2949 else
2951 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of lengths and <begin> is omitted.", title, callLoc );
2954 begin = endPtr->get( ) - ( count - 1 ) * step;
2956 else if( endPtr == NullPtr< ArgType >( ) )
2958 begin = beginPtr->get( );
2959 if( stepPtr == NullPtr< ArgType >( ) )
2961 throw Exceptions::CoreRequirement( "The <step> must be provided when constructing a range of lengths when <end> is omitted.", title, callLoc );
2963 if( countPtr == NullPtr< CountType >( ) )
2965 if( isSpan )
2967 if( last < begin )
2969 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of lengths and <end> is omitted while <begin> exceeds %last.", title, callLoc );
2971 count = static_cast< size_t >( ( last - begin ) / step ) + 1;
2973 else
2975 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of lengths and <end> is omitted.", title, callLoc );
2979 else
2981 begin = beginPtr->get( );
2982 if( stepPtr == NullPtr< ArgType >( ) && countPtr == NullPtr< CountType >( ) )
2984 throw Exceptions::CoreRequirement( "Either of the <step> and <count> arguments must be provided when constructing a range of lengths from <begin> to <end>.", title, callLoc );
2986 // When we reach here, we know that exactly one of <step> and <count> is provided.
2987 if( stepPtr != NullPtr< ArgType >( ) )
2989 if( step == 0 )
2991 throw Exceptions::CoreOutOfRange( title, args, argsi_step, "When <count> is omitted, <step> must not be zero." );
2993 double tmpCount = 1 + ( endPtr->get( ) - begin ) / step;
2994 if( tmpCount < 1 )
2996 count = 0;
2998 else
3000 if( tmpCount > std::numeric_limits< size_t >::max( ) )
3002 throw Exceptions::CoreOutOfRange( title, args, argsi_step, "When <count> is omitted, too small <step> values cause overflow in the number of elements." );
3004 count = static_cast< size_t >( tmpCount );
3007 else
3009 if( count < 2 )
3011 throw Exceptions::CoreOutOfRange( title, args, argsi_count, "When <step> is omitted, the <count> be at least 2." );
3013 step = ( endPtr->get( ) - begin ) / ( count - 1 );
3017 Kernel::ContRef cont = evalState->cont_;
3018 if( count == 0 )
3020 cont->takeValue( Lang::THE_CONS_NULL,
3021 evalState );
3023 else
3025 cont->takeValue( RefCountPtr< const Lang::SingleList >( new Lang::SingleListRange< ArgType >( begin, step, count ) ),
3026 evalState );
3028 return;
3030 catch( const NonLocalExit::NotThisType & ball )
3032 // Never mind, see below
3035 throw Exceptions::CoreTypeMismatch( callLoc, title, args, 0, Helpers::typeSetString( Lang::Integer::staticTypeName( ), Lang::Float::staticTypeName( ), Lang::Length::staticTypeName( ) ) );
3040 * To avoid problems with initialization order (Kernel::THE_VOID_VARIABLE has to be initialized first), we first
3041 * initialize with an ugly null value, and then set the correct value when the real function is registered below.
3043 RefCountPtr< const Lang::CoreFunction > Lang::THE_FUNCTION_RANGE = RefCountPtr< const Lang::CoreFunction >( NullPtr< const Lang::CoreFunction >( ) );
3045 void
3046 Kernel::registerCore_construct( Kernel::Environment * env )
3048 Lang::THE_FUNCTION_RANGE = RefCountPtr< const Lang::CoreFunction >( new Lang::Core_range( "range" ) );
3050 env->initDefineCoreFunction( new Lang::Core_cons( "cons" ) );
3051 env->initDefineCoreFunction( new Lang::Core_list( "list" ) );
3052 env->initDefineCoreFunction( new Lang::Core_unlist( "unlist" ) );
3053 env->initDefineCoreFunction( new Lang::Core_isnull( "null?" ) );
3054 env->initDefineCoreFunction( Lang::THE_FUNCTION_RANGE );
3055 env->initDefineCoreFunction( new Lang::Core_span( "span" ) );
3056 env->initDefineCoreFunction( new Lang::Core_affinetransform( "affinetransform" ) );
3057 env->initDefineCoreFunction( new Lang::Core_shift( "shift" ) );
3058 env->initDefineCoreFunction( new Lang::Core_rotate( "rotate" ) );
3059 env->initDefineCoreFunction( new Lang::Core_rotate3d( "rotate3D" ) );
3060 env->initDefineCoreFunction( new Lang::Core_scale( "scale" ) );
3061 env->initDefineCoreFunction( new Lang::Core_scale3d( "scale3D" ) );
3062 env->initDefineCoreFunction( new Lang::Core_affinetransform3D( "affinetransform3D" ) );
3063 env->initDefineCoreFunction( new Lang::Core_inverse( "inverse" ) );
3065 env->initDefineCoreFunction( new Lang::Core_formxo( "formxo" ) );
3066 env->initDefineCoreFunction( new Lang::Core_importRasterImage( "import_raster" ) );
3067 env->initDefineCoreFunction( new Lang::Core_transparencygroup( "tgroup" ) );
3069 env->initDefineCoreFunction( new Lang::Core_tag( "tag" ) );
3070 env->initDefineCoreFunction( new Lang::Core_find( "find" ) );
3071 env->initDefineCoreFunction( new Lang::Core_findall( "findall" ) );
3073 env->initDefineCoreFunction( new Lang::Core_ambient_light( "ambient_light" ) );
3074 env->initDefineCoreFunction( new Lang::Core_specular_light( "specular_light" ) );
3075 env->initDefineCoreFunction( new Lang::Core_distant_light( "distant_light" ) );
3076 env->initDefineCoreFunction( new Lang::Core_phong( "phong" ) );
3078 env->initDefineCoreFunction( new Lang::Core_vector( "vector" ) );
3079 env->initDefineCoreFunction( new Lang::Core_importPDFpages( "import" ) );
3081 env->initDefineCoreFunction( new Lang::Core_svg_path( "svg_path" ) );
3083 env->initDefineCoreFunction( new Lang::Core_sprintf( "sprintf" ) );
3084 env->initDefineCoreFunction( new Lang::Core_strftime( "strftime" ) );
3086 env->initDefineCoreFunction( new Lang::Core_newrandom( "newRandom" ) );
3087 env->initDefineCoreFunction( new Lang::Core_devrandom( "devRandom" ) );
3089 env->initDefineCoreFunction( new Lang::Core_destination( "destination" ) );
3091 env->initDefineCoreFunction( new Lang::Core_textrenderingmode( "textmode" ) );
3092 env->initDefineCoreFunction( new Lang::Core_manualkern( "kerning" ) );
3093 env->initDefineCoreFunction( new Lang::Core_automatickern( "kern" ) );
3095 env->initDefineCoreFunction( new Lang::Core_importFont( "font" ) );
3097 env->initDefineCoreFunction( new Lang::Core_Unicode( "Unicode" ) );
3098 env->initDefineCoreFunction( new Lang::Core_AdobeGlyphList( "AdobeGlyphList" ) );