1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008, 2009, 2010 Henrik Tidefelt
21 #include "Shapes_Helpers_decls.h"
23 #include "singlelistrange.h"
25 #include "shapescore.h"
27 #include "shapesexceptions.h"
29 #include "simplepdfi.h"
30 #include "simplepdfo.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"
45 #include FT_FREETYPE_H
55 using namespace Shapes
;
62 RasterLoader_PNG theRasterLoader_PNG
;
63 RasterLoader_JPEG theRasterLoader_JPEG
;
69 class Core_tag
: public Lang::CoreFunction
72 Core_tag( const char * title
)
73 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
75 formals_
->appendEvaluatedCoreFormal( "key", Kernel::THE_SLOT_VARIABLE
);
76 formals_
->appendEvaluatedCoreFormal( "obj", Kernel::THE_SLOT_VARIABLE
);
77 formals_
->appendEvaluatedCoreFormal( "transform", Kernel::THE_TRUE_VARIABLE
); // this argument means "transform if applicable"
78 formals_
->appendEvaluatedCoreFormal( "draw", Kernel::THE_TRUE_VARIABLE
); // this argument means "draw if applicable"
82 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
84 args
.applyDefaults( );
86 typedef const Lang::Symbol KeyType
;
87 RefCountPtr
< KeyType
> key
= Helpers::down_cast_CoreArgument
< KeyType
>( title_
, args
, 0, callLoc
);
88 bool tryTransform
= Helpers::down_cast_CoreArgument
< const Lang::Boolean
>( title_
, args
, 2, callLoc
)->val_
;
89 bool tryDraw
= Helpers::down_cast_CoreArgument
< const Lang::Boolean
>( title_
, args
, 3, callLoc
)->val_
;
91 if( tryDraw
&& ! tryTransform
)
93 throw Exceptions::CoreOutOfRange( title_
, args
, 3, "A tagged object which does not transform cannot be drawn." );
102 typedef const Lang::Drawable2D ArgType
;
104 RefCountPtr
< ArgType
> obj
= Helpers::try_cast_CoreArgument
< ArgType
>( args
.getValue( argsi
) );
106 Kernel::ContRef cont
= evalState
->cont_
;
107 cont
->takeValue( RefCountPtr
< const Lang::Value
>( new Lang::TaggedDrawable2D( key
, obj
) ),
111 catch( const NonLocalExit::NotThisType
& ball
)
113 // Never mind, see below
118 typedef const Lang::Drawable3D ArgType
;
120 RefCountPtr
< ArgType
> obj
= Helpers::try_cast_CoreArgument
< ArgType
>( args
.getValue( argsi
) );
122 Kernel::ContRef cont
= evalState
->cont_
;
123 cont
->takeValue( RefCountPtr
< const Lang::Value
>( new Lang::TaggedDrawable3D( key
, obj
) ),
127 catch( const NonLocalExit::NotThisType
& ball
)
129 // Never mind, see below
137 typedef const Lang::Geometric2D ArgType
;
139 RefCountPtr
< ArgType
> obj
= Helpers::try_cast_CoreArgument
< ArgType
>( args
.getValue( argsi
) );
141 Kernel::ContRef cont
= evalState
->cont_
;
142 cont
->takeValue( RefCountPtr
< const Lang::Value
>( new Lang::TaggedGeometric2D( key
, obj
) ),
146 catch( const NonLocalExit::NotThisType
& ball
)
148 // Never mind, see below
153 typedef const Lang::Geometric3D ArgType
;
155 RefCountPtr
< ArgType
> obj
= Helpers::try_cast_CoreArgument
< ArgType
>( args
.getValue( argsi
) );
157 Kernel::ContRef cont
= evalState
->cont_
;
158 cont
->takeValue( RefCountPtr
< const Lang::Value
>( new Lang::TaggedGeometric3D( key
, obj
) ),
162 catch( const NonLocalExit::NotThisType
& ball
)
164 // Never mind, see below
169 // As a last resort, we tag any value.
170 // We return a Drawable2D. Use immerse to make it 3D.
171 Kernel::ContRef cont
= evalState
->cont_
;
172 cont
->takeValue( RefCountPtr
< const Lang::Value
>( new Lang::TaggedValue2D( key
, args
.getValue( argsi
) ) ),
178 // This function is in this file just because it i so related to Core_tag.
179 class Core_find
: public Lang::CoreFunction
182 Core_find( const char * title
)
183 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
185 formals_
->appendEvaluatedCoreFormal( "container", Kernel::THE_SLOT_VARIABLE
);
186 formals_
->appendEvaluatedCoreFormal( "key", Kernel::THE_SLOT_VARIABLE
);
190 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
192 args
.applyDefaults( );
194 typedef const Lang::Symbol KeyType
;
195 RefCountPtr
< KeyType
> key
= Helpers::down_cast_CoreArgument
< KeyType
>( title_
, args
, 1, callLoc
);
201 typedef const Lang::Drawable2D ContainerType
;
203 RefCountPtr
< ContainerType
> container
= Helpers::try_cast_CoreArgument
< ContainerType
>( args
.getValue( argsi
) );
205 if( ! container
->findOneTag( evalState
, key
->getKey( ), Lang::THE_2D_IDENTITY
) )
207 throw Exceptions::CoreOutOfRange( title_
, args
, 1, "Key not found." );
211 catch( const NonLocalExit::NotThisType
& ball
)
213 // Never mind, see below
218 typedef const Lang::Drawable3D ContainerType
;
220 RefCountPtr
< ContainerType
> container
= Helpers::try_cast_CoreArgument
< ContainerType
>( args
.getValue( argsi
) );
222 if( ! container
->findOneTag( evalState
, key
->getKey( ), Lang::THE_3D_IDENTITY
) )
224 throw Exceptions::CoreOutOfRange( title_
, args
, 1, "Key not found." );
228 catch( const NonLocalExit::NotThisType
& ball
)
230 // Never mind, see below
233 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, argsi
, Helpers::typeSetString( Lang::Drawable2D::staticTypeName( ), Lang::Drawable3D::staticTypeName( ) ) );
237 // This function is in this file just because it i so related to Core_tag.
238 class Core_findall
: public Lang::CoreFunction
241 Core_findall( const char * title
)
242 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
244 formals_
->appendEvaluatedCoreFormal( "container", Kernel::THE_SLOT_VARIABLE
);
245 formals_
->appendEvaluatedCoreFormal( "key", Kernel::THE_SLOT_VARIABLE
);
249 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
251 args
.applyDefaults( );
253 typedef const Lang::Symbol KeyType
;
254 RefCountPtr
< KeyType
> key
= Helpers::down_cast_CoreArgument
< KeyType
>( title_
, args
, 1, callLoc
);
260 typedef const Lang::Drawable2D ContainerType
;
262 RefCountPtr
< ContainerType
> container
= Helpers::try_cast_CoreArgument
< ContainerType
>( args
.getValue( argsi
) );
264 std::vector
< Kernel::ValueRef
> * dst
= new std::vector
< Kernel::ValueRef
>;
265 container
->findTags( dst
, evalState
->dyn_
, key
->getKey( ), Lang::THE_2D_IDENTITY
);
267 Kernel::ContRef cont
= evalState
->cont_
;
268 cont
->takeValue( RefCountPtr
< const Lang::Value
>( new Lang::VectorFunction( dst
) ),
272 catch( const NonLocalExit::NotThisType
& ball
)
274 // Never mind, see below
279 typedef const Lang::Drawable3D ContainerType
;
281 RefCountPtr
< ContainerType
> container
= Helpers::try_cast_CoreArgument
< ContainerType
>( args
.getValue( argsi
) );
283 std::vector
< Kernel::ValueRef
> * dst
= new std::vector
< Kernel::ValueRef
>;
284 container
->findTags( dst
, evalState
->dyn_
, key
->getKey( ), Lang::THE_3D_IDENTITY
);
286 Kernel::ContRef cont
= evalState
->cont_
;
287 cont
->takeValue( RefCountPtr
< const Lang::Value
>( new Lang::VectorFunction( dst
) ),
291 catch( const NonLocalExit::NotThisType
& ball
)
293 // Never mind, see below
296 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, argsi
, Helpers::typeSetString( Lang::Drawable2D::staticTypeName( ), Lang::Drawable3D::staticTypeName( ) ) );
300 class Core_phong
: public Lang::CoreFunction
303 Core_phong( const char * title
) : CoreFunction( title
) { }
305 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
307 const size_t ARITY
= 1;
308 CHECK_ARITY( args
, ARITY
, title_
);
310 typedef const Lang::Float ArgType
;
311 double exponent
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 0, callLoc
)->val_
;
314 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "The Phong exponent should be greater than 0." );
317 Kernel::ContRef cont
= evalState
->cont_
;
318 cont
->takeValue( Kernel::ValueRef( new Lang::SpecularReflectionTerm( 1., exponent
) ),
323 class Core_cons
: public Lang::CoreFunction
326 Core_cons( const char * title
)
327 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), false ) )
329 formals_
->appendEvaluatedCoreFormal( "car", Kernel::THE_SLOT_VARIABLE
);
330 formals_
->appendEvaluatedCoreFormal( "cdr", Kernel::THE_SLOT_VARIABLE
);
333 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
335 const size_t ARITY
= 2;
336 CHECK_ARITY( args
, ARITY
, title_
);
338 Kernel::ContRef cont
= evalState
->cont_
;
339 cont
->takeValue( Kernel::ValueRef( new Lang::ConsPair( args
.getHandle( 0 ),
340 args
.getHandle( 1 ) ) ),
345 class Core_list
: public Lang::CoreFunction
348 Core_list( const char * title
) : CoreFunction( title
) { }
350 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
352 RefCountPtr
< const Lang::SingleList
> res
= Lang::THE_CONS_NULL
;
353 if( ! args
.empty( ) )
355 for( size_t i
= args
.size( ) - 1; ; --i
)
357 res
= RefCountPtr
< const Lang::SingleList
>( new Lang::SingleListPair( args
.getHandle( i
), res
) );
365 Kernel::ContRef cont
= evalState
->cont_
;
366 cont
->takeValue( res
,
371 class Core_unlist
: public Lang::CoreFunction
373 Kernel::UnnamedStructureFactory argListFactory_
;
375 Core_unlist( const char * title
) : CoreFunction( title
) { }
377 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
379 const size_t ARITY
= 1;
380 CHECK_ARITY( args
, ARITY
, title_
);
382 typedef const Lang::SingleList ArgType
;
384 Kernel::ContRef cont
= evalState
->cont_
;
385 cont
->takeValue( argListFactory_
.build( Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 0, callLoc
) ),
390 class Core_isnull
: public Lang::CoreFunction
393 Core_isnull( const char * title
) : CoreFunction( title
) { }
395 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
397 const size_t ARITY
= 1;
398 CHECK_ARITY( args
, ARITY
, title_
);
400 RefCountPtr
< const Lang::Value
> aUntyped
= args
.getValue( 0 );
402 Kernel::ContRef cont
= evalState
->cont_
;
403 cont
->takeValue( RefCountPtr
< const Lang::Value
>( new Lang::Boolean( dynamic_cast< const Lang::SingleListNull
* >( args
.getValue( 0 ).getPtr( ) ) != 0 ) ),
408 class Core_span
: public Lang::CoreFunction
411 Core_span( const char * title
)
412 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), false ) )
414 formals_
->appendEvaluatedCoreFormal( "begin", Kernel::THE_VOID_VARIABLE
);
415 formals_
->appendEvaluatedCoreFormal( "end", Kernel::THE_VOID_VARIABLE
);
416 formals_
->appendEvaluatedCoreFormal( "step", Kernel::THE_VOID_VARIABLE
);
417 formals_
->appendEvaluatedCoreFormal( "count", Kernel::THE_VOID_VARIABLE
);
420 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
422 args
.applyDefaults( );
424 Kernel::ContRef cont
= evalState
->cont_
;
425 cont
->takeValue( Kernel::ValueRef( new Lang::Span( args
.getHandle( 0 ), args
.getHandle( 1 ), args
.getHandle( 2 ), args
.getHandle( 3 ) ) ),
430 class Core_affinetransform
: public Lang::CoreFunction
433 Core_affinetransform( const char * title
) : CoreFunction( title
) { }
435 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
437 const size_t ARITY
= 3;
438 CHECK_ARITY( args
, ARITY
, title_
);
440 typedef const Lang::FloatPair ArgType0
;
441 typedef const Lang::FloatPair ArgType1
;
442 typedef const Lang::Coords2D ArgType2
;
444 RefCountPtr
< ArgType0
> argx
= Helpers::down_cast_CoreArgument
< ArgType0
>( title_
, args
, 0, callLoc
);
445 RefCountPtr
< ArgType1
> argy
= Helpers::down_cast_CoreArgument
< ArgType1
>( title_
, args
, 1, callLoc
);
446 RefCountPtr
< ArgType2
> arg1
= Helpers::down_cast_CoreArgument
< ArgType2
>( title_
, args
, 2, callLoc
);
448 Kernel::ContRef cont
= evalState
->cont_
;
449 cont
->takeValue( Kernel::ValueRef( new Lang::Transform2D( argx
->x_
, argx
->y_
, argy
->x_
, argy
->y_
, arg1
->x_
.get( ), arg1
->y_
.get( ) ) ),
454 class Core_affinetransform3D
: public Lang::CoreFunction
457 Core_affinetransform3D( const char * title
) : CoreFunction( title
) { }
459 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
461 const size_t ARITY
= 4;
462 CHECK_ARITY( args
, ARITY
, title_
);
464 typedef const Lang::FloatTriple ArgType0
;
465 typedef const Lang::FloatTriple ArgType1
;
466 typedef const Lang::FloatTriple ArgType2
;
467 typedef const Lang::Coords3D ArgType3
;
469 RefCountPtr
< ArgType0
> argx
= Helpers::down_cast_CoreArgument
< ArgType0
>( title_
, args
, 0, callLoc
);
470 RefCountPtr
< ArgType1
> argy
= Helpers::down_cast_CoreArgument
< ArgType1
>( title_
, args
, 1, callLoc
);
471 RefCountPtr
< ArgType2
> argz
= Helpers::down_cast_CoreArgument
< ArgType2
>( title_
, args
, 2, callLoc
);
472 RefCountPtr
< ArgType3
> arg1
= Helpers::down_cast_CoreArgument
< ArgType3
>( title_
, args
, 3, callLoc
);
474 Kernel::ContRef cont
= evalState
->cont_
;
475 cont
->takeValue( Kernel::ValueRef( new Lang::Transform3D( argx
->x_
, argx
->y_
, argx
->z_
,
476 argy
->x_
, argy
->y_
, argy
->z_
,
477 argz
->x_
, argz
->y_
, argz
->z_
,
478 arg1
->x_
.get( ), arg1
->y_
.get( ), arg1
->z_
.get( ) ) ),
483 class Core_shift
: public Lang::CoreFunction
486 Core_shift( const char * title
) : CoreFunction( title
) { }
488 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
490 const size_t ARITY
= 1;
491 CHECK_ARITY( args
, ARITY
, title_
);
493 Kernel::ContRef cont
= evalState
->cont_
;
498 typedef const Lang::Coords2D ArgType1
;
499 RefCountPtr
< ArgType1
> arg1
= Helpers::try_cast_CoreArgument
< ArgType1
>( args
.getValue( i
) );
500 cont
->takeValue( Kernel::ValueRef( new Lang::Transform2D( 1, 0, 0, 1, arg1
->x_
.get( ), arg1
->y_
.get( ) ) ),
504 catch( const NonLocalExit::NotThisType
& ball
)
506 // Never mind, see below
511 typedef const Lang::Coords3D ArgType1
;
512 RefCountPtr
< ArgType1
> arg1
= Helpers::try_cast_CoreArgument
< ArgType1
>( args
.getValue( i
) );
513 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( ) ) ),
517 catch( const NonLocalExit::NotThisType
& ball
)
519 // Never mind, see below
522 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, i
, Helpers::typeSetString( Lang::Coords2D::staticTypeName( ), Lang::Coords3D::staticTypeName( ) ) );
526 class Core_rotate
: public Lang::CoreFunction
529 Core_rotate( const char * title
)
530 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
532 formals_
->appendEvaluatedCoreFormal( "angle", Kernel::THE_SLOT_VARIABLE
);
535 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
537 args
.applyDefaults( );
541 typedef const Lang::Float ArgType1
;
542 RefCountPtr
< ArgType1
> arg1
= Helpers::down_cast_CoreArgument
< ArgType1
>( title_
, args
, i
, callLoc
);
544 double c
= cos( arg1
->val_
);
545 double s
= sin( arg1
->val_
);
546 Kernel::ContRef cont
= evalState
->cont_
;
547 cont
->takeValue( Kernel::ValueRef( new Lang::Transform2D( c
, s
, -s
, c
, 0, 0 ) ),
552 class Core_rotate3d
: public Lang::CoreFunction
555 Core_rotate3d( const char * title
)
556 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
558 formals_
->appendEvaluatedCoreFormal( "dir", Kernel::THE_SLOT_VARIABLE
);
559 formals_
->appendEvaluatedCoreFormal( "angle", Kernel::THE_SLOT_VARIABLE
);
562 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
564 args
.applyDefaults( );
568 typedef const Lang::FloatTriple ArgType1
;
569 RefCountPtr
< ArgType1
> dir
= Helpers::down_cast_CoreArgument
< ArgType1
>( title_
, args
, i
, callLoc
);
570 if( dir
->x_
== 0 && dir
->y_
== 0 && dir
->z_
== 0 )
572 throw Exceptions::CoreOutOfRange( title_
, args
, i
, "The rotation direction is degenerate, that is (0,0,0)." );
577 typedef const Lang::Float ArgType2
;
578 RefCountPtr
< ArgType2
> angle
= Helpers::down_cast_CoreArgument
< ArgType2
>( title_
, args
, i
, callLoc
);
580 double r
= sqrt( dir
->x_
* dir
->x_
+ dir
->y_
* dir
->y_
+ dir
->z_
* dir
->z_
);
581 double x
= dir
->x_
/ r
;
582 double y
= dir
->y_
/ r
;
583 double z
= dir
->z_
/ r
;
587 double c
= cos( angle
->val_
);
588 double s
= sin( angle
->val_
);
589 Kernel::ContRef cont
= evalState
->cont_
;
590 cont
->takeValue( Kernel::ValueRef( new Lang::Transform3D( x2
+(y2
+z2
)*c
, x
*y
*(1-c
)+z
*s
, x
*z
*(1-c
)-y
*s
,
591 x
*y
*(1-c
)-z
*s
, y2
+(x2
+z2
)*c
, y
*z
*(1-c
)+x
*s
,
592 x
*z
*(1-c
)+y
*s
, y
*z
*(1-c
)-x
*s
, z2
+(x2
+y2
)*c
,
598 class Core_scale
: public Lang::CoreFunction
601 Core_scale( const char * title
)
602 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
604 Kernel::VariableHandle
one( new Kernel::Variable( RefCountPtr
< const Lang::Value
>( new Lang::Float( 1 ) ) ) );
606 formals_
->appendEvaluatedCoreFormal( "r", one
);
607 formals_
->appendEvaluatedCoreFormal( "x", one
);
608 formals_
->appendEvaluatedCoreFormal( "y", one
);
611 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
613 args
.applyDefaults( );
615 typedef const Lang::Float ArgType
;
616 RefCountPtr
< ArgType
> argr
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 0, callLoc
);
617 RefCountPtr
< ArgType
> argx
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 1, callLoc
);
618 RefCountPtr
< ArgType
> argy
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 2, callLoc
);
620 Kernel::ContRef cont
= evalState
->cont_
;
621 cont
->takeValue( Kernel::ValueRef( new Lang::Transform2D( argr
->val_
* argx
->val_
, 0,
622 0, argr
->val_
* argy
->val_
,
628 class Core_scale3d
: public Lang::CoreFunction
631 Core_scale3d( const char * title
)
632 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
634 Kernel::VariableHandle
one( new Kernel::Variable( RefCountPtr
< const Lang::Value
>( new Lang::Float( 1 ) ) ) );
636 formals_
->appendEvaluatedCoreFormal( "r", one
);
637 formals_
->appendEvaluatedCoreFormal( "x", one
);
638 formals_
->appendEvaluatedCoreFormal( "y", one
);
639 formals_
->appendEvaluatedCoreFormal( "z", one
);
642 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
644 args
.applyDefaults( );
646 typedef const Lang::Float ArgType
;
647 RefCountPtr
< ArgType
> argr
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 0, callLoc
);
648 RefCountPtr
< ArgType
> argx
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 1, callLoc
);
649 RefCountPtr
< ArgType
> argy
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 2, callLoc
);
650 RefCountPtr
< ArgType
> argz
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 3, callLoc
);
652 Kernel::ContRef cont
= evalState
->cont_
;
653 cont
->takeValue( Kernel::ValueRef( new Lang::Transform3D( argr
->val_
* argx
->val_
, 0, 0,
654 0, argr
->val_
* argy
->val_
, 0,
655 0, 0, argr
->val_
* argz
->val_
,
661 class Core_inverse
: public Lang::CoreFunction
664 Core_inverse( const char * title
) : CoreFunction( title
) { }
666 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
668 const size_t ARITY
= 1;
669 CHECK_ARITY( args
, ARITY
, title_
);
672 typedef const Lang::Transform2D ArgType
;
673 ArgType
* tf
= dynamic_cast< ArgType
* >( args
.getValue( 0 ).getPtr( ) );
676 double det
= tf
->xx_
* tf
->yy_
- tf
->xy_
* tf
->yx_
;
677 if( fabs( det
) < Computation::SINGULAR_TRANSFORM_LIMIT
)
679 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "Singular transforms cannot be inverted." );
681 double idet
= 1 / det
;
682 double ixx
= idet
* tf
->yy_
;
683 double ixy
= - idet
* tf
->xy_
;
684 double iyx
= - idet
* tf
->yx_
;
685 double iyy
= idet
* tf
->xx_
;
686 Kernel::ContRef cont
= evalState
->cont_
;
687 cont
->takeValue( Kernel::ValueRef( new Lang::Transform2D( ixx
, iyx
,
689 -( ixx
* tf
->xt_
+ ixy
* tf
->yt_
), -( iyx
* tf
->xt_
+ iyy
* tf
->yt_
) ) ),
696 typedef const Lang::Transform3D ArgType
;
697 ArgType
* tf
= dynamic_cast< ArgType
* >( args
.getValue( 0 ).getPtr( ) );
701 tf
->xx_
* ( tf
->yy_
* tf
->zz_
- tf
->yz_
* tf
->zy_
)
702 - tf
->xy_
* ( tf
->yx_
* tf
->zz_
- tf
->yz_
* tf
->zx_
)
703 + tf
->xz_
* ( tf
->yx_
* tf
->zy_
- tf
->yy_
* tf
->zx_
);
704 if( fabs( det
) < Computation::SINGULAR_TRANSFORM_LIMIT
)
706 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "Singular transforms cannot be inverted." );
708 double idet
= 1 / det
;
709 double ixx
= idet
* ( tf
->yy_
* tf
->zz_
- tf
->yz_
* tf
->zy_
);
710 double ixy
= - idet
* ( tf
->xy_
* tf
->zz_
- tf
->xz_
* tf
->zy_
);
711 double ixz
= idet
* ( tf
->xy_
* tf
->yz_
- tf
->xz_
* tf
->yy_
);
712 double iyx
= - idet
* ( tf
->yx_
* tf
->zz_
- tf
->yz_
* tf
->zx_
);
713 double iyy
= idet
* ( tf
->xx_
* tf
->zz_
- tf
->xz_
* tf
->zx_
);
714 double iyz
= - idet
* ( tf
->xx_
* tf
->yz_
- tf
->xz_
* tf
->yx_
);
715 double izx
= idet
* ( tf
->yx_
* tf
->zy_
- tf
->yy_
* tf
->zx_
);
716 double izy
= - idet
* ( tf
->xx_
* tf
->zy_
- tf
->xy_
* tf
->zx_
);
717 double izz
= idet
* ( tf
->xx_
* tf
->yy_
- tf
->xy_
* tf
->yx_
);
718 Kernel::ContRef cont
= evalState
->cont_
;
719 cont
->takeValue( Kernel::ValueRef( new Lang::Transform3D( ixx
, iyx
, izx
,
722 -( ixx
* tf
->xt_
+ ixy
* tf
->yt_
+ ixz
* tf
->zt_
),
723 -( iyx
* tf
->xt_
+ iyy
* tf
->yt_
+ iyz
* tf
->zt_
),
724 -( izx
* tf
->xt_
+ izy
* tf
->yt_
+ izz
* tf
->zt_
) ) ),
730 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, 0, Helpers::typeSetString( Lang::Transform2D::staticTypeName( ), Lang::Transform3D::staticTypeName( ) ) );
734 class Core_formxo
: public Lang::CoreFunction
737 Core_formxo( const char * title
) : CoreFunction( title
) { }
739 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
741 const size_t ARITY
= 1;
742 CHECK_ARITY( args
, ARITY
, title_
);
744 typedef const Lang::Drawable2D ArgType
;
745 RefCountPtr
< ArgType
> arg
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 0, callLoc
);
747 RefCountPtr
< const Lang::ElementaryPath2D
> theBBox
= arg
->bbox( Lang::Drawable2D::BOUNDING
);
748 Concrete::Coords2D
llcorner( 0, 0 );
749 Concrete::Coords2D
urcorner( 0, 0 );
750 if( ! theBBox
->boundingRectangle( & llcorner
, & urcorner
) )
752 std::string
strTitle( title_
);
753 throw Exceptions::InternalError( strrefdup( strTitle
+ ": The object has no bounding box!" ) );
757 RefCountPtr
< SimplePDF::PDF_Stream_out
> form
;
758 RefCountPtr
< SimplePDF::PDF_Object
> indirection
= SimplePDF::indirect( form
, & Kernel::theIndirectObjectCount
);
760 RefCountPtr
< SimplePDF::PDF_Resources
> resources
;
761 (*form
)[ "Resources" ] = SimplePDF::indirect( resources
, & Kernel::theIndirectObjectCount
);
763 (*form
)[ "Subtype" ] = SimplePDF::newName( "Form" );
764 (*form
)[ "FormType" ] = SimplePDF::newInt( 1 );
765 (*form
)[ "BBox" ] = RefCountPtr
< SimplePDF::PDF_Vector
>( new SimplePDF::PDF_Vector( llcorner
.x_
.offtype
< 1, 0 >( ), llcorner
.y_
.offtype
< 1, 0 >( ),
766 urcorner
.x_
.offtype
< 1, 0 >( ), urcorner
.y_
.offtype
< 1, 0 >( ) ) );
768 /* There's a possibility of adding a transformation matrix entry in the dictionary here, but it is not used, not even
769 * for transformed drawables.
771 // (*markForm)[ "Matrix" ] = RefCountPtr<PDF_Object>( new PDF_Vector( 1, 0, 0, 1, -30, -30 ) );
773 Kernel::PageContentStates
pdfState( resources
);
774 arg
->shipout( form
->data
, & pdfState
, Lang::Transform2D( 1, 0, 0, 1, 0, 0 ) );
777 Lang::XObject
* res
= new Lang::XObject( indirection
,
779 res
->setDebugStr( "user form" );
780 Kernel::ContRef cont
= evalState
->cont_
;
781 cont
->takeValue( Kernel::ValueRef( res
),
786 class Core_transparencygroup
: public Lang::CoreFunction
789 Core_transparencygroup( const char * title
)
790 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
792 formals_
->appendEvaluatedCoreFormal( "content", Kernel::THE_SLOT_VARIABLE
);
793 formals_
->appendEvaluatedCoreFormal( "isolated", Kernel::THE_FALSE_VARIABLE
);
794 formals_
->appendEvaluatedCoreFormal( "knockout", Kernel::THE_FALSE_VARIABLE
);
797 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
799 args
.applyDefaults( );
801 typedef const Lang::Group2D ArgType0
;
802 typedef const Lang::Boolean ArgType1
;
803 typedef const Lang::Boolean ArgType2
;
804 RefCountPtr
< ArgType0
> content
= Helpers::down_cast_CoreArgument
< ArgType0
>( title_
, args
, 0, callLoc
);
805 RefCountPtr
< ArgType1
> isolated
= Helpers::down_cast_CoreArgument
< ArgType1
>( title_
, args
, 1, callLoc
);
806 RefCountPtr
< ArgType2
> knockout
= Helpers::down_cast_CoreArgument
< ArgType2
>( title_
, args
, 2, callLoc
);
808 RefCountPtr
< const Lang::ColorSpace
> blendSpace
= evalState
->dyn_
->getBlendSpace( );
810 Kernel::ContRef cont
= evalState
->cont_
;
811 cont
->takeValue( Helpers::newTransparencyGroup( content
, isolated
->val_
, knockout
->val_
, blendSpace
),
816 class Core_importRasterImage
: public Lang::CoreFunction
818 std::map
< const char *, const Helpers::RasterLoader
*, charPtrLess
> loaders_
;
820 Core_importRasterImage( const char * title
)
821 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
823 formals_
->appendEvaluatedCoreFormal( "filename", Kernel::THE_SLOT_VARIABLE
);
824 formals_
->appendEvaluatedCoreFormal( "resolution", Helpers::newValHandle( new Lang::Length( Concrete::Length( 1 ) ) ) );
825 formals_
->appendEvaluatedCoreFormal( "override", Kernel::THE_TRUE_VARIABLE
);
826 formals_
->appendEvaluatedCoreFormal( "kind", Kernel::THE_VOID_VARIABLE
);
828 loaders_
[ "png" ] = & Helpers::theRasterLoader_PNG
;
829 loaders_
[ "PNG" ] = & Helpers::theRasterLoader_PNG
;
831 loaders_
[ "jpg" ] = & Helpers::theRasterLoader_JPEG
;
832 loaders_
[ "JPG" ] = & Helpers::theRasterLoader_JPEG
;
833 loaders_
[ "jpeg" ] = & Helpers::theRasterLoader_JPEG
;
834 loaders_
[ "JPEG" ] = & Helpers::theRasterLoader_JPEG
;
836 /* It would seem natural to also support "JIF"-images, but currently the JPEG library we use won't open such files.
840 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
842 args
.applyDefaults( );
846 typedef const Lang::String ArgType
;
847 RefCountPtr
< ArgType
> filename
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi
, callLoc
);
848 size_t argsi_filename
= argsi
;
850 std::string full_filename
;
853 full_filename
= Ast::theShapesScanner
.searchFile( filename
->val_
.getPtr( ), true ); /* true means that errors should be handled in "runtime mode". */
855 catch( RefCountPtr
< const char > & msg
)
857 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_filename
, msg
);
860 RefCountPtr
< std::ifstream
> iFile( new std::ifstream( full_filename
.c_str( ) ) );
861 if( ! iFile
->good( ) )
863 std::ostringstream msg
;
864 msg
<< "Failed to open file for input: " << full_filename
.c_str( ) ;
865 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_filename
, strrefdup( msg
) );
869 typedef const Lang::Length ResolutionType
;
870 Concrete::Length resolution
= Helpers::down_cast_CoreArgument
< ResolutionType
>( title_
, args
, argsi
, callLoc
)->get( );
871 if( resolution
<= Concrete::ZERO_LENGTH
)
873 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, strrefdup( "The resolution must be positive." ) );
877 typedef const Lang::Boolean OverrideType
;
878 bool override
= Helpers::down_cast_CoreArgument
< OverrideType
>( title_
, args
, argsi
, callLoc
)->val_
;
881 typedef const Lang::Symbol KindType
;
882 RefCountPtr
< KindType
> kind
= Helpers::down_cast_CoreArgument
< KindType
>( title_
, args
, argsi
, callLoc
, true );
883 const Helpers::RasterLoader
* loader
= 0;
884 if( kind
== NullPtr
< KindType
>( ) )
886 const char * begin
= filename
->val_
.getPtr( );
887 const char * ext
= filename
->val_
.getPtr( ) + filename
->bytecount_
- 1;
888 for( ; ext
> begin
; --ext
)
892 typedef typeof loaders_ MapType
;
893 MapType::const_iterator i
= loaders_
.find( ext
+ 1 );
894 if( i
== loaders_
.end( ) )
896 std::ostringstream msg
;
897 msg
<< "Filename extension '" << ext
<< "' has no associated raster loader." ;
898 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_filename
, strrefdup( msg
) );
906 std::ostringstream msg
;
907 msg
<< "Filename without extension must be combined with explicit file kind: " << filename
->val_
.getPtr( ) ;
908 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_filename
, strrefdup( msg
) );
913 static Lang::Symbol
PNG( "PNG" );
914 static Lang::Symbol
JPEG( "JPEG" );
917 loader
= & Helpers::theRasterLoader_PNG
;
919 else if( *kind
== JPEG
)
921 loader
= & Helpers::theRasterLoader_JPEG
;
925 std::ostringstream msg
;
926 msg
<< "The only allowed file kind symbols are { " ;
931 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, strrefdup( msg
) );
935 Kernel::ContRef cont
= evalState
->cont_
;
936 cont
->takeValue( loader
->load( iFile
, full_filename
, resolution
, override
, title_
, callLoc
),
941 class Core_vector
: public Lang::CoreFunction
944 Core_vector( const char * title
) : CoreFunction( title
) { }
946 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
948 std::vector
< RefCountPtr
< const Lang::Value
> > * res
= new std::vector
< RefCountPtr
< const Lang::Value
> >;
949 res
->reserve( args
.size( ) );
951 for( size_t i
= 0; i
!= args
.size( ); ++i
)
953 res
->push_back( args
.getValue( i
) );
956 Kernel::ContRef cont
= evalState
->cont_
;
957 cont
->takeValue( Kernel::ValueRef( new Lang::VectorFunction( res
) ),
962 class Core_interpolate
: public Lang::CoreFunction
965 Core_interpolate( const char * title
)
966 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
968 formals_
->appendEvaluatedCoreFormal( "function", Kernel::THE_SLOT_VARIABLE
);
969 formals_
->appendEvaluatedCoreFormal( "domain", Kernel::THE_SLOT_VARIABLE
);
970 formals_
->appendEvaluatedCoreFormal( "size", Kernel::THE_SLOT_VARIABLE
);
971 formals_
->appendEvaluatedCoreFormal( "range", Kernel::THE_SLOT_VARIABLE
);
972 formals_
->appendEvaluatedCoreFormal( "encode", Kernel::THE_VOID_VARIABLE
);
973 formals_
->appendEvaluatedCoreFormal( "decode", Kernel::THE_VOID_VARIABLE
);
976 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
978 args
.applyDefaults( );
980 throw Exceptions::NotImplemented( "Core_interpolate::call" );
984 class Core_importPDFpages
: public Lang::CoreFunction
987 Core_importPDFpages( const char * title
) : CoreFunction( title
) { }
989 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
991 const size_t ARITY
= 1;
992 CHECK_ARITY( args
, ARITY
, title_
);
994 typedef const Lang::String ArgType
;
995 RefCountPtr
< ArgType
> arg
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, 0, callLoc
);
997 std::string filename
;
1000 filename
= Ast::theShapesScanner
.searchFile( arg
->val_
.getPtr( ), true ); /* true means that errors should be handled in "runtime mode". */
1002 catch( RefCountPtr
< const char > & msg
)
1004 throw Exceptions::CoreOutOfRange( title_
, args
, 0, msg
);
1007 RefCountPtr
< std::ifstream
> iFile( new std::ifstream( filename
.c_str( ) ) );
1008 if( ! iFile
->good( ) )
1010 std::ostringstream msg
;
1011 msg
<< "Failed to open file for input: " << arg
->val_
.getPtr( ) ;
1012 throw Exceptions::CoreOutOfRange( title_
, args
, 0, strrefdup( msg
) );
1014 RefCountPtr
< SimplePDF::PDF_in
> pdfi( new SimplePDF::PDF_in( iFile
) );
1016 RefCountPtr
< const std::vector
< RefCountPtr
< const Lang::XObject
> > > typedRes
= RefCountPtr
< const std::vector
< RefCountPtr
< const Lang::XObject
> > >( NullPtr
< std::vector
< RefCountPtr
< const Lang::XObject
> > >( ) );
1019 typedRes
= Kernel::thePDFImporter
.addPagesAsXObjects( pdfi
);
1021 catch( const char * ball
)
1023 throw Exceptions::InternalError( strrefdup( ( std::string( "An error occurred while importing " ) + arg
->val_
.getPtr( ) + ": " + ball
).c_str( ) ) );
1026 std::vector
< RefCountPtr
< const Lang::Value
> > * untypedRes
= new std::vector
< RefCountPtr
< const Lang::Value
> >;
1027 untypedRes
->reserve( typedRes
->size( ) );
1028 typedef typeof *typedRes ListType
;
1029 for( ListType::const_iterator i
= typedRes
->begin( ); i
!= typedRes
->end( ); ++i
)
1031 untypedRes
->push_back( *i
);
1034 Kernel::ContRef cont
= evalState
->cont_
;
1035 cont
->takeValue( Kernel::ValueRef( new Lang::VectorFunction( untypedRes
) ),
1040 namespace Implementation
1043 svg_path_strtod( const char ** src
)
1045 const char * start
= *src
;
1047 double res
= strtod( start
, & endp
);
1051 for( ; *start
== ' '; ++start
)
1053 throw std::string( start
, strchr( start
, ' ' ) - start
);
1058 class Core_svg_path
: public Lang::CoreFunction
1061 Core_svg_path( const char * title
)
1062 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1064 formals_
->appendEvaluatedCoreFormal( "d", Kernel::THE_SLOT_VARIABLE
);
1065 formals_
->appendEvaluatedCoreFormal( "xunit", Helpers::newValHandle( new Lang::Length( Concrete::Length( 1 ) ) ) );
1066 formals_
->appendEvaluatedCoreFormal( "yunit", Helpers::newValHandle( new Lang::Length( Concrete::Length( 1 ) ) ) );
1067 formals_
->appendEvaluatedCoreFormal( "multi", Kernel::THE_VOID_VARIABLE
);
1068 formals_
->appendEvaluatedCoreFormal( "singletons", Kernel::THE_TRUE_VARIABLE
);
1071 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1073 args
.applyDefaults( );
1076 typedef const Lang::String StrType
;
1077 RefCountPtr
< StrType
> arg
= Helpers::down_cast_CoreArgument
< StrType
>( title_
, args
, argsi
, callLoc
);
1079 typedef const Lang::Length ScaleType
;
1081 Concrete::Length dx
= Helpers::down_cast_CoreArgument
< ScaleType
>( title_
, args
, argsi
, callLoc
)->get( );
1083 Concrete::Length dy
= Helpers::down_cast_CoreArgument
< ScaleType
>( title_
, args
, argsi
, callLoc
)->get( );
1085 typedef const Lang::Boolean FlagType
;
1087 RefCountPtr
< FlagType
> multi
= Helpers::down_cast_CoreArgument
< FlagType
>( title_
, args
, argsi
, callLoc
, true );
1089 bool singletons
= Helpers::down_cast_CoreArgument
< FlagType
>( title_
, args
, argsi
, callLoc
)->val_
;
1091 RefCountPtr
< char > buf
= RefCountPtr
< char >( new char[ 2 * strlen( arg
->val_
.getPtr( ) + 1 ) ] );
1093 /* Get rid of any whitespace that isn't a plain space, and make sure every number is terminated by whitespace.
1095 char * dst
= buf
.getPtr( );
1096 for( const char * src
= arg
->val_
.getPtr( ); *src
!= '\0'; ++src
, ++dst
)
1106 if( ( 'A' <= *src
&& *src
<= 'Z' ) || ( 'a' <= *src
&& *src
<= 'z' ) )
1108 /* Insert whitespace before command to ensure command is not immediately following number.
1120 RefCountPtr
< Lang::MultiPath2D
> multiPath
= RefCountPtr
< Lang::MultiPath2D
>( new Lang::MultiPath2D
);
1121 RefCountPtr
< Lang::ElementaryPath2D
> elemPath
= RefCountPtr
< Lang::ElementaryPath2D
>( NullPtr
< Lang::ElementaryPath2D
>( ) );
1126 Concrete::PathPoint2D
originPathPoint( new Concrete::Coords2D( 0, 0 ) );
1127 Concrete::PathPoint2D
* first
= & originPathPoint
;
1128 Concrete::PathPoint2D
* last
= & originPathPoint
;
1129 const char * srcEnd
= buf
.getPtr( ) + strlen( buf
.getPtr( ) );
1130 for( const char * src
= buf
.getPtr( ); src
< srcEnd
; ++src
)
1132 for( ; *src
== ' '; ++src
)
1166 throw Exceptions::CoreOutOfRange( title_
, args
, 0, strrefdup( std::string( "SVG path command not compatible with cubic splines: " ) + *src
) );
1173 if( elemPath
!= NullPtr
< Lang::ElementaryPath2D
>( ) && ( singletons
|| elemPath
->duration( ) >= 1 ) )
1175 multiPath
->push_back( elemPath
);
1177 Concrete::Length x
= dx
* Implementation::svg_path_strtod( & src
);
1178 Concrete::Length y
= - dy
* Implementation::svg_path_strtod( & src
);
1179 first
= new Concrete::PathPoint2D( new Concrete::Coords2D( x
, y
) );
1181 elemPath
= RefCountPtr
< Lang::ElementaryPath2D
>( new Lang::ElementaryPath2D
);
1182 elemPath
->push_back( last
);
1188 if( elemPath
!= NullPtr
< Lang::ElementaryPath2D
>( ) && ( singletons
|| elemPath
->duration( ) >= 1 ) )
1190 multiPath
->push_back( elemPath
);
1192 Concrete::Length x
= last
->mid_
->x_
+ dx
* Implementation::svg_path_strtod( & src
);
1193 Concrete::Length y
= last
->mid_
->y_
- dy
* Implementation::svg_path_strtod( & src
);
1194 first
= new Concrete::PathPoint2D( new Concrete::Coords2D( x
, y
) );
1196 elemPath
= RefCountPtr
< Lang::ElementaryPath2D
>( new Lang::ElementaryPath2D
);
1197 elemPath
->push_back( last
);
1215 Concrete::Length x
= dx
* Implementation::svg_path_strtod( & src
);
1216 Concrete::Length y
= - dy
* Implementation::svg_path_strtod( & src
);
1217 last
= new Concrete::PathPoint2D( new Concrete::Coords2D( x
, y
) );
1218 elemPath
->push_back( last
);
1223 Concrete::Length x
= last
->mid_
->x_
+ dx
* Implementation::svg_path_strtod( & src
);
1224 Concrete::Length y
= last
->mid_
->y_
- dy
* Implementation::svg_path_strtod( & src
);
1225 last
= new Concrete::PathPoint2D( new Concrete::Coords2D( x
, y
) );
1226 elemPath
->push_back( last
);
1231 Concrete::Length x
= dx
* Implementation::svg_path_strtod( & src
);
1232 last
= new Concrete::PathPoint2D( new Concrete::Coords2D( x
, last
->mid_
->y_
) );
1233 elemPath
->push_back( last
);
1238 Concrete::Length x
= last
->mid_
->x_
+ dx
* Implementation::svg_path_strtod( & src
);
1239 last
= new Concrete::PathPoint2D( new Concrete::Coords2D( x
, last
->mid_
->y_
) );
1240 elemPath
->push_back( last
);
1245 Concrete::Length y
= - dy
* Implementation::svg_path_strtod( & src
);
1246 last
= new Concrete::PathPoint2D( new Concrete::Coords2D( last
->mid_
->x_
, y
) );
1247 elemPath
->push_back( last
);
1252 Concrete::Length y
= last
->mid_
->y_
- dy
* Implementation::svg_path_strtod( & src
);
1253 last
= new Concrete::PathPoint2D( new Concrete::Coords2D( last
->mid_
->x_
, y
) );
1254 elemPath
->push_back( last
);
1259 Concrete::Length x1
= dx
* Implementation::svg_path_strtod( & src
);
1260 Concrete::Length y1
= - dy
* Implementation::svg_path_strtod( & src
);
1261 Concrete::Length x2
= dx
* Implementation::svg_path_strtod( & src
);
1262 Concrete::Length y2
= - dy
* Implementation::svg_path_strtod( & src
);
1263 Concrete::Length x3
= dx
* Implementation::svg_path_strtod( & src
);
1264 Concrete::Length y3
= - dy
* Implementation::svg_path_strtod( & src
);
1265 last
->front_
= new Concrete::Coords2D( x1
, y1
);
1266 last
= new Concrete::PathPoint2D( new Concrete::Coords2D( x3
, y3
) );
1267 last
->rear_
= new Concrete::Coords2D( x2
, y2
);
1268 elemPath
->push_back( last
);
1273 Concrete::Length x1
= last
->mid_
->x_
+ dx
* Implementation::svg_path_strtod( & src
);
1274 Concrete::Length y1
= last
->mid_
->y_
- dy
* Implementation::svg_path_strtod( & src
);
1275 Concrete::Length x2
= last
->mid_
->x_
+ dx
* Implementation::svg_path_strtod( & src
);
1276 Concrete::Length y2
= last
->mid_
->y_
- dy
* Implementation::svg_path_strtod( & src
);
1277 Concrete::Length x3
= last
->mid_
->x_
+ dx
* Implementation::svg_path_strtod( & src
);
1278 Concrete::Length y3
= last
->mid_
->y_
- dy
* Implementation::svg_path_strtod( & src
);
1279 last
->front_
= new Concrete::Coords2D( x1
, y1
);
1280 last
= new Concrete::PathPoint2D( new Concrete::Coords2D( x3
, y3
) );
1281 last
->rear_
= new Concrete::Coords2D( x2
, y2
);
1282 elemPath
->push_back( last
);
1287 Concrete::Length x2
= dx
* Implementation::svg_path_strtod( & src
);
1288 Concrete::Length y2
= - dy
* Implementation::svg_path_strtod( & src
);
1289 Concrete::Length x3
= dx
* Implementation::svg_path_strtod( & src
);
1290 Concrete::Length y3
= - dy
* Implementation::svg_path_strtod( & src
);
1291 last
->front_
= new Concrete::Coords2D( 2 * *(last
->mid_
) - *(last
->rear_
) );
1292 last
= new Concrete::PathPoint2D( new Concrete::Coords2D( x3
, y3
) );
1293 last
->rear_
= new Concrete::Coords2D( x2
, y2
);
1294 elemPath
->push_back( last
);
1299 Concrete::Length x2
= last
->mid_
->x_
+ dx
* Implementation::svg_path_strtod( & src
);
1300 Concrete::Length y2
= last
->mid_
->y_
- dy
* Implementation::svg_path_strtod( & src
);
1301 Concrete::Length x3
= last
->mid_
->x_
+ dx
* Implementation::svg_path_strtod( & src
);
1302 Concrete::Length y3
= last
->mid_
->y_
- dy
* Implementation::svg_path_strtod( & src
);
1303 last
->front_
= new Concrete::Coords2D( 2 * *(last
->mid_
) - *(last
->rear_
) );
1304 last
= new Concrete::PathPoint2D( new Concrete::Coords2D( x3
, y3
) );
1305 last
->rear_
= new Concrete::Coords2D( x2
, y2
);
1306 elemPath
->push_back( last
);
1310 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "Malformed SVG path string (failed to initialize command character)." );
1313 throw Exceptions::InternalError( "While reading SVG path string: Command character out of range." );
1318 catch( const std::string
& badNumber
)
1320 throw Exceptions::CoreOutOfRange( title_
, args
, 0, strrefdup( std::string( "Ill-formed number: " ) + badNumber
) );
1323 if( elemPath
!= NullPtr
< Lang::ElementaryPath2D
>( ) && ( singletons
|| elemPath
->duration( ) >= 1 ) )
1325 multiPath
->push_back( RefCountPtr
< const Lang::Path2D
>( elemPath
) );
1328 if( multiPath
->size( ) == 0 )
1330 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "No path was produced." );
1332 if( multiPath
->size( ) == 1 )
1334 Kernel::ContRef cont
= evalState
->cont_
;
1335 if( multi
!= NullPtr
< FlagType
>( ) && multi
->val_
)
1337 cont
->takeValue( Kernel::ValueRef( multiPath
),
1342 cont
->takeValue( Kernel::ValueRef( multiPath
->front( ) ),
1348 if( multi
!= NullPtr
< FlagType
>( ) && ! multi
->val_
)
1350 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "More than one sub-path conflicts with false for <multi>." );
1352 Kernel::ContRef cont
= evalState
->cont_
;
1353 cont
->takeValue( Kernel::ValueRef( multiPath
),
1359 class Core_sprintf
: public Lang::CoreFunction
1362 Core_sprintf( const char * title
) : CoreFunction( title
) { }
1364 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1368 throw Exceptions::CoreArityMismatch( title_
, 1, args
.size( ) );
1370 typedef typeof args ArgListType
;
1372 typedef const Lang::String Arg1Type
;
1373 RefCountPtr
< Arg1Type
> arg1
= Helpers::down_cast_CoreArgument
< Arg1Type
>( title_
, args
, i
, callLoc
);
1375 /* snprintf( 0, 0, ... ) does not seem to work properly on some systems.
1376 * Therefore, I resort to the use of a dummy string, and "n = 1".
1381 switch( args
.size( ) )
1385 size_t sz
= snprintf( dummy
, 1, arg1
->val_
.getPtr( ), 0 ); /* The final 0 is just a dummy argument that makes the compiler relax. */
1386 res
= new char[ sz
+ 1 ];
1387 status
= sprintf( res
, arg1
->val_
.getPtr( ), 0 ); /* The final 0 is just a dummy argument that makes the compiler relax. */
1394 typedef const Lang::String Arg2Type
;
1395 Arg2Type
* arg2
= dynamic_cast< Arg2Type
* >( args
.getValue( i
).getPtr( ) );
1398 size_t sz
= snprintf( dummy
, 1, arg1
->val_
.getPtr( ), arg2
->val_
.getPtr( ) );
1399 res
= new char[ sz
+ 1 ];
1400 status
= sprintf( res
, arg1
->val_
.getPtr( ), arg2
->val_
.getPtr( ) );
1405 typedef const Lang::Float Arg2Type
;
1406 Arg2Type
* arg2
= dynamic_cast< Arg2Type
* >( args
.getValue( i
).getPtr( ) );
1409 size_t sz
= snprintf( dummy
, 1, arg1
->val_
.getPtr( ), arg2
->val_
);
1410 res
= new char[ sz
+ 1 ];
1411 status
= sprintf( res
, arg1
->val_
.getPtr( ), arg2
->val_
);
1416 typedef const Lang::Integer Arg2Type
;
1417 Arg2Type
* arg2
= dynamic_cast< Arg2Type
* >( args
.getValue( i
).getPtr( ) );
1420 size_t sz
= snprintf( dummy
, 1, arg1
->val_
.getPtr( ), arg2
->val_
);
1421 res
= new char[ sz
+ 1 ];
1422 status
= sprintf( res
, arg1
->val_
.getPtr( ), arg2
->val_
);
1427 typedef const Lang::ChronologicalTime Arg2Type
;
1428 Arg2Type
* arg2
= dynamic_cast< Arg2Type
* >( args
.getValue( i
).getPtr( ) );
1431 const char * fmt
= arg1
->val_
.getPtr( );
1432 const struct tm
* tmp
= arg2
->temporary_localtime( );
1433 size_t sz
= strlen( fmt
) * 2;
1434 res
= new char[ sz
];
1435 while( strftime( res
, sz
, fmt
, tmp
) == 0 )
1439 res
= new char[ sz
];
1441 status
= 0; // Here, I'd like to check some error condition instead...
1445 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, i
, Interaction::SEVERAL_TYPES
);
1449 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "The number of arguments is out of the implemented range." );
1454 throw Exceptions::InternalError( "Failed to assign to res in sprintf." );
1459 std::ostringstream oss
;
1460 oss
<< "Call to library routine returned negative value indicating an error: " << status
<< ".";
1461 throw Exceptions::CoreOutOfRange( title_
, args
, 0, strrefdup( oss
) );
1464 Kernel::ContRef cont
= evalState
->cont_
;
1465 cont
->takeValue( Kernel::ValueRef( new Lang::String( res
, false ) ),
1470 class Core_strftime
: public Lang::CoreFunction
1473 Core_strftime( const char * title
) : CoreFunction( title
) { }
1475 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1477 const size_t ARITY
= 0;
1478 CHECK_ARITY( args
, ARITY
, title_
);
1483 timeInfo
= localtime( & t
);
1484 std::ostringstream res
;
1485 res
<< timeInfo
->tm_hour
<< ":" << timeInfo
->tm_min
<< ":" << timeInfo
->tm_sec
;
1487 Kernel::ContRef cont
= evalState
->cont_
;
1488 cont
->takeValue( Kernel::ValueRef( new Lang::String( strrefdup( res
) ) ),
1493 class Core_ambient_light
: public Lang::CoreFunction
1496 Core_ambient_light( const char * title
)
1497 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1499 formals_
->appendEvaluatedCoreFormal( "color", Kernel::THE_SLOT_VARIABLE
);
1502 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1504 args
.applyDefaults( );
1507 typedef const Lang::Gray ArgType
;
1508 ArgType
* col
= dynamic_cast< ArgType
* >( args
.getValue( 0 ).getPtr( ) );
1511 Kernel::ContRef cont
= evalState
->cont_
;
1512 cont
->takeValue( Kernel::ValueRef( new Lang::AmbientLightGray( col
->components( ) ) ),
1519 typedef const Lang::RGB ArgType
;
1520 ArgType
* col
= dynamic_cast< ArgType
* >( args
.getValue( 0 ).getPtr( ) );
1523 Kernel::ContRef cont
= evalState
->cont_
;
1524 cont
->takeValue( Kernel::ValueRef( new Lang::AmbientLightRGB( col
->components( ) ) ),
1530 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, 0, Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
1534 class Core_specular_light
: public Lang::CoreFunction
1537 Core_specular_light( const char * title
)
1538 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1540 formals_
->appendEvaluatedCoreFormal( "color", Kernel::THE_SLOT_VARIABLE
);
1541 formals_
->appendEvaluatedCoreFormal( "radius", Helpers::newValHandle( new Lang::Length( HUGE_VAL
) ) );
1542 formals_
->appendEvaluatedCoreFormal( "shadows", Kernel::THE_FALSE_VARIABLE
);
1545 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1547 args
.applyDefaults( );
1549 typedef const Lang::Length RadiusType
;
1550 RefCountPtr
< RadiusType
> radius
= Helpers::down_cast_CoreArgument
< RadiusType
>( title_
, args
, 1, callLoc
);
1551 typedef const Lang::Boolean ShadowsType
;
1552 RefCountPtr
< ShadowsType
> shadows
= Helpers::down_cast_CoreArgument
< ShadowsType
>( title_
, args
, 2, callLoc
);
1555 typedef const Lang::Gray ArgType
;
1556 ArgType
* col
= dynamic_cast< ArgType
* >( args
.getValue( 0 ).getPtr( ) );
1559 Kernel::ContRef cont
= evalState
->cont_
;
1560 cont
->takeValue( Kernel::ValueRef( new Lang::SpecularLightGray( Concrete::Coords3D( 0, 0, 0 ),
1570 typedef const Lang::RGB ArgType
;
1571 ArgType
* col
= dynamic_cast< ArgType
* >( args
.getValue( 0 ).getPtr( ) );
1574 Kernel::ContRef cont
= evalState
->cont_
;
1575 cont
->takeValue( Kernel::ValueRef( new Lang::SpecularLightRGB( Concrete::Coords3D( 0, 0, 0 ),
1584 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, 0, Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
1588 class Core_distant_light
: public Lang::CoreFunction
1591 Core_distant_light( const char * title
)
1592 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1594 formals_
->appendEvaluatedCoreFormal( "color", Kernel::THE_SLOT_VARIABLE
);
1595 formals_
->appendEvaluatedCoreFormal( "shadows", Kernel::THE_FALSE_VARIABLE
);
1598 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1600 args
.applyDefaults( );
1602 typedef const Lang::Boolean ShadowsType
;
1603 RefCountPtr
< ShadowsType
> shadows
= Helpers::down_cast_CoreArgument
< ShadowsType
>( title_
, args
, 1, callLoc
);
1606 typedef const Lang::Gray ArgType
;
1607 ArgType
* col
= dynamic_cast< ArgType
* >( args
.getValue( 0 ).getPtr( ) );
1610 Kernel::ContRef cont
= evalState
->cont_
;
1611 cont
->takeValue( Kernel::ValueRef( new Lang::DistantLightGray( Concrete::UnitFloatTriple( 0., 0., -1. ),
1620 typedef const Lang::RGB ArgType
;
1621 ArgType
* col
= dynamic_cast< ArgType
* >( args
.getValue( 0 ).getPtr( ) );
1624 Kernel::ContRef cont
= evalState
->cont_
;
1625 cont
->takeValue( Kernel::ValueRef( new Lang::DistantLightRGB( Concrete::UnitFloatTriple( 0., 0., -1. ),
1633 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, 0, Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
1637 class Core_textrenderingmode
: public Lang::CoreFunction
1640 Core_textrenderingmode( const char * title
)
1641 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1643 formals_
->appendEvaluatedCoreFormal( "fill", Kernel::THE_FALSE_VARIABLE
);
1644 formals_
->appendEvaluatedCoreFormal( "stroke", Kernel::THE_FALSE_VARIABLE
);
1647 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1649 args
.applyDefaults( );
1651 typedef const Lang::Boolean FlagType
;
1652 RefCountPtr
< FlagType
> fill
= Helpers::down_cast_CoreArgument
< FlagType
>( title_
, args
, 0, callLoc
);
1653 RefCountPtr
< FlagType
> stroke
= Helpers::down_cast_CoreArgument
< FlagType
>( title_
, args
, 1, callLoc
);
1655 Kernel::ContRef cont
= evalState
->cont_
;
1656 cont
->takeValue( Kernel::ValueRef( new Lang::TextRenderingMode( fill
->val_
, stroke
->val_
, false ) ),
1661 class Core_manualkern
: public Lang::CoreFunction
1664 Core_manualkern( const char * title
) : CoreFunction( title
) { }
1666 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1668 // 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
1669 // the result is not used.
1670 RefCountPtr
< Lang::KernedText
> res( new Lang::KernedText( evalState
->dyn_
->getTextState( ), evalState
->dyn_
->getGraphicsState( ) ) );
1672 for( size_t i
= 0; i
!= args
.size( ); ++i
)
1676 typedef const Lang::String ArgType
;
1677 res
->pushString( Helpers::try_cast_CoreArgument
< ArgType
>( args
.getValue( i
) ) );
1680 catch( const NonLocalExit::NotThisType
& ball
)
1682 // Never mind, see below
1687 typedef const Lang::Float ArgType
;
1688 res
->pushKerning( Helpers::try_cast_CoreArgument
< ArgType
>( args
.getValue( i
) )->val_
);
1691 catch( const NonLocalExit::NotThisType
& ball
)
1693 // Never mind, see below
1698 typedef const Lang::KernedText ArgType
;
1699 Helpers::try_cast_CoreArgument
< ArgType
>( args
.getValue( i
) )->push( res
.getPtr( ) );
1702 catch( const NonLocalExit::NotThisType
& ball
)
1704 // Never mind, see below
1707 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, i
, Helpers::typeSetString( Lang::String::staticTypeName( ), Lang::Float::staticTypeName( ), Lang::KernedText::staticTypeName( ) ) );
1710 Kernel::ContRef cont
= evalState
->cont_
;
1711 cont
->takeValue( res
,
1716 class Core_automatickern
: public Lang::CoreFunction
1719 Core_automatickern( const char * title
) : CoreFunction( title
) { }
1721 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1723 iconv_t converter
= Helpers::requireUTF8ToUCS4Converter( );
1724 iconv_t backconverter
= Helpers::requireUCS4ToUTF8Converter( );
1726 RefCountPtr
< const FontMetrics::FontMetric
> metrics
= evalState
->dyn_
->getTextState( )->font_
->metrics( );
1727 if( metrics
->horizontalMetrics_
== NullPtr
< FontMetrics::WritingDirectionMetrics
>( ) )
1729 throw Exceptions::FontMetricsError( evalState
->dyn_
->getTextState( )->font_
->fontName( ), strrefdup( "No horizontal metrics defined." ) );
1732 // 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
1733 // the result is not used.
1734 RefCountPtr
< Lang::KernedText
> res( new Lang::KernedText( evalState
->dyn_
->getTextState( ), evalState
->dyn_
->getGraphicsState( ) ) );
1736 std::ostringstream pendingChars
;
1737 Kernel::UnicodeCodePoint
prevChar( 0 );
1738 double pendingKerning
= 0;
1740 const size_t backbufSize
= 5;
1741 char backbuf
[ backbufSize
];
1743 for( size_t i
= 0; i
!= args
.size( ); ++i
)
1747 typedef const Lang::String ArgType
;
1748 RefCountPtr
< ArgType
> str
= Helpers::try_cast_CoreArgument
< ArgType
>( args
.getValue( i
) );
1750 const char * inbuf
= str
->val_
.getPtr( );
1751 size_t inbytesleft
= strlen( inbuf
);
1753 size_t bufSize
= 4 * inbytesleft
;
1754 char * buf
= new char[ bufSize
];
1755 DeleteOnExit
< char > bufDeleter( buf
);
1757 char * outbuf
= buf
;
1758 size_t outbytesleft
= bufSize
;
1759 // The ICONV_CAST macro is defined in config.h.
1760 size_t count
= iconv( converter
,
1761 ICONV_CAST( & inbuf
), & inbytesleft
,
1762 & outbuf
, & outbytesleft
);
1763 if( count
== (size_t)(-1) )
1765 if( errno
== EILSEQ
)
1767 throw Exceptions::MiscellaneousRequirement( "It is suspected that one of the UFT-8 characters used in showed text has no UCS-4 representation." );
1769 else if( errno
== EINVAL
)
1771 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
1773 else if( errno
== E2BIG
)
1775 throw Exceptions::InternalError( "Core_automatickern: The buffer allocated for UTF-8 to UCS-4 conversion was too small." );
1779 std::ostringstream msg
;
1780 msg
<< "iconv failed with an unrecognized error code: " << errno
;
1781 throw Exceptions::InternalError( strrefdup( msg
) );
1784 for( const char * src
= buf
; src
!= outbuf
; src
+= 4 )
1786 Kernel::UnicodeCodePoint currentChar
;
1787 currentChar
.decode_UCS4( src
);
1788 double currentKerning
= pendingKerning
- metrics
->getHorizontalKernPairXByCode( prevChar
, currentChar
);
1789 prevChar
= currentChar
;
1791 if( currentKerning
!= 0 )
1793 if( ! pendingChars
.str( ).empty( ) )
1795 res
->pushString( RefCountPtr
< const Lang::String
>( new Lang::String( strrefdup( pendingChars
) ) ) );
1796 pendingChars
.str( "" );
1798 res
->pushKerning( currentKerning
);
1801 // Copy the current (multibyte) character to the character queue
1803 const char * inbuf
= src
;
1804 char * outbuf
= backbuf
;
1805 size_t inbytesleft
= 4;
1806 size_t outbytesleft
= backbufSize
;
1807 // The ICONV_CAST macro is defined in config.h.
1808 size_t count
= iconv( backconverter
,
1809 ICONV_CAST( & inbuf
), & inbytesleft
,
1810 & outbuf
, & outbytesleft
);
1811 if( count
== (size_t)(-1) )
1813 if( errno
== EILSEQ
)
1815 throw Exceptions::ExternalError( "A character converted from UTF-8 could not be converted back to UFT-8." );
1817 else if( errno
== EINVAL
)
1819 throw Exceptions::ExternalError( "A character converted from UTF-8 was deemed incomplete." );
1821 else if( errno
== E2BIG
)
1823 throw Exceptions::InternalError( "The buffer allocated for conversion of a single character back to UTF-8 was too small." );
1827 std::ostringstream msg
;
1828 msg
<< "iconv failed with an unrecognized error code: " << errno
;
1829 throw Exceptions::InternalError( strrefdup( msg
) );
1833 pendingChars
<< backbuf
;
1838 catch( const NonLocalExit::NotThisType
& ball
)
1840 // Never mind, see below
1845 typedef const Lang::Float ArgType
;
1846 pendingKerning
+= Helpers::try_cast_CoreArgument
< ArgType
>( args
.getValue( i
) )->val_
;
1849 catch( const NonLocalExit::NotThisType
& ball
)
1851 // Never mind, see below
1854 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, i
, Helpers::typeSetString( Lang::String::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
1857 if( ! pendingChars
.str( ).empty( ) )
1859 res
->pushString( RefCountPtr
< const Lang::String
>( new Lang::String( strrefdup( pendingChars
) ) ) );
1860 pendingChars
.str( "" );
1863 Kernel::ContRef cont
= evalState
->cont_
;
1864 cont
->takeValue( res
,
1869 class Core_newrandom
: public Lang::CoreFunction
1872 Core_newrandom( const char * title
)
1873 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1875 formals_
->appendEvaluatedCoreFormal( "seed", Kernel::THE_SLOT_VARIABLE
);
1876 formals_
->appendEvaluatedCoreFormal( "size", Helpers::newValHandle( new Lang::Integer( 32 ) ) );
1879 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1881 args
.applyDefaults( );
1883 typedef const Lang::Integer SizeType
;
1884 Lang::Integer::ValueType sz
= Helpers::down_cast_CoreArgument
< SizeType
>( title_
, args
, 1, callLoc
)->val_
;
1887 throw Exceptions::CoreOutOfRange( title_
, args
, 1, "The size must be at least 8." );
1891 throw Exceptions::CoreOutOfRange( title_
, args
, 1, "The size must at most 256." );
1898 typedef const Lang::ChronologicalTime SeedType
;
1900 RefCountPtr
< SeedType
> seed
= Helpers::try_cast_CoreArgument
< SeedType
>( args
.getValue( argsi
) );
1902 Kernel::ContRef cont
= evalState
->cont_
;
1903 cont
->takeValue( RefCountPtr
< const Lang::Value
>( new Lang::HotRandomSeed( sz
, seed
->val( ) ) ),
1907 catch( const NonLocalExit::NotThisType
& ball
)
1909 // Never mind, see below
1914 typedef const Lang::Integer SeedType
;
1916 RefCountPtr
< SeedType
> seed
= Helpers::try_cast_CoreArgument
< SeedType
>( args
.getValue( argsi
) );
1918 Kernel::ContRef cont
= evalState
->cont_
;
1919 cont
->takeValue( RefCountPtr
< const Lang::Value
>( new Lang::HotRandomSeed( sz
, seed
->val_
) ),
1923 catch( const NonLocalExit::NotThisType
& ball
)
1925 // Never mind, see below
1928 throw Exceptions::CoreTypeMismatch( callLoc
, title_
, args
, argsi
, Helpers::typeSetString( Lang::Integer::staticTypeName( ), Lang::ChronologicalTime::staticTypeName( ) ) );
1932 class Core_devrandom
: public Lang::CoreFunction
1935 Core_devrandom( const char * title
)
1936 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1938 formals_
->appendCoreStateFormal( "device" );
1939 formals_
->appendEvaluatedCoreFormal( "size", Helpers::newValHandle( new Lang::Integer( 32 ) ) );
1942 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1944 args
.applyDefaults( );
1946 typedef const Lang::Integer SizeType
;
1947 Lang::Integer::ValueType sz
= Helpers::down_cast_CoreArgument
< SizeType
>( title_
, args
, 0, callLoc
)->val_
;
1950 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "The size must be at least 8." );
1954 throw Exceptions::CoreOutOfRange( title_
, args
, 0, "The size must at most 256." );
1957 typedef Kernel::WarmRandomDevice GeneratorType
;
1958 GeneratorType
* gen
= Helpers::down_cast_CoreState
< GeneratorType
>( title_
, args
, 0, callLoc
);
1960 Kernel::ContRef cont
= evalState
->cont_
;
1961 cont
->takeValue( RefCountPtr
< const Lang::Value
>( new Lang::HotRandomSeed( static_cast< size_t >( sz
), gen
) ),
1966 class Core_destination
: public Lang::CoreFunction
1969 Core_destination( const char * title
)
1970 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
1972 formals_
->appendEvaluatedCoreFormal( "remote", Kernel::THE_FALSE_VARIABLE
);
1973 formals_
->appendEvaluatedCoreFormal( "name", Kernel::THE_VOID_VARIABLE
);
1974 formals_
->appendEvaluatedCoreFormal( "level", Kernel::THE_VOID_VARIABLE
);
1975 formals_
->appendEvaluatedCoreFormal( "text", Kernel::THE_VOID_VARIABLE
);
1976 formals_
->appendEvaluatedCoreFormal( "open", Kernel::THE_FALSE_VARIABLE
);
1977 formals_
->appendEvaluatedCoreFormal( "bold", Kernel::THE_FALSE_VARIABLE
);
1978 formals_
->appendEvaluatedCoreFormal( "italic", Kernel::THE_FALSE_VARIABLE
);
1979 formals_
->appendEvaluatedCoreFormal( "color", Helpers::newValHandle( new Lang::RGB( Concrete::RGB( 0, 0, 0 ) ) ) );
1980 formals_
->appendEvaluatedCoreFormal( "sides", Kernel::THE_VOID_VARIABLE
);
1981 formals_
->appendEvaluatedCoreFormal( "target", Kernel::THE_VOID_VARIABLE
);
1982 formals_
->appendEvaluatedCoreFormal( "fittobbox", Kernel::THE_VOID_VARIABLE
);
1983 formals_
->appendEvaluatedCoreFormal( "zoom", Kernel::THE_VOID_VARIABLE
);
1984 formals_
->appendEvaluatedCoreFormal( "transform", Kernel::THE_TRUE_VARIABLE
);
1987 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
1989 args
.applyDefaults( );
1992 const size_t remove_i
= argsi
;
1993 typedef const Lang::Boolean RemoteType
;
1994 bool remote
= Helpers::down_cast_CoreArgument
< RemoteType
>( title_
, args
, argsi
, callLoc
)->val_
;
1997 typedef const Lang::String NameType
;
1998 RefCountPtr
< NameType
> nameVal
= Helpers::down_cast_CoreArgument
< NameType
>( title_
, args
, argsi
, callLoc
, true );
1999 RefCountPtr
< const char > name
= RefCountPtr
< const char >( NullPtr
< const char >( ) );
2000 if( nameVal
!= NullPtr
< NameType
>( ) )
2002 const SimplePDF::PDF_Version::Version STRINGDESTS_VERSION
= SimplePDF::PDF_Version::PDF_1_2
;
2003 if( Kernel::the_PDF_version
.greaterOrEqual( STRINGDESTS_VERSION
) )
2005 name
= nameVal
->val_
;
2009 Kernel::the_PDF_version
.message( STRINGDESTS_VERSION
, "The naming of a destination was ignored." );
2010 // Note that this will leave name being null, and hence generate further errors if remote_.
2013 if( nameVal
== NullPtr
< NameType
>( ) ) // Note why this is not an else clause!
2017 throw Exceptions::CoreOutOfRange( title_
, args
, remove_i
, "The destination cannot be remote if no name is given." );
2022 const size_t outlineLevel_i
= argsi
;
2023 typedef const Lang::Integer OutlineLevelType
;
2024 RefCountPtr
< OutlineLevelType
> levelVal
= Helpers::down_cast_CoreArgument
< OutlineLevelType
>( title_
, args
, argsi
, callLoc
, true );
2025 int outlineLevel
= -1; // This will remain negative only if the level is not present.
2026 if( levelVal
!= NullPtr
< OutlineLevelType
>( ) )
2028 outlineLevel
= levelVal
->val_
;
2029 if( outlineLevel
< 0 )
2031 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The outline level must be non-negative." );
2036 typedef const Lang::String OutlineTextType
;
2037 RefCountPtr
< OutlineTextType
> textVal
= Helpers::down_cast_CoreArgument
< OutlineTextType
>( title_
, args
, argsi
, callLoc
, true );
2038 RefCountPtr
< const char > outlineText
= RefCountPtr
< const char >( NullPtr
< const char >( ) );
2039 if( textVal
!= NullPtr
< OutlineTextType
>( ) )
2041 outlineText
= textVal
->val_
;
2045 if( outlineLevel
>= 0 )
2047 throw Exceptions::CoreOutOfRange( title_
, args
, outlineLevel_i
, "Without an outline text, it is not allowed to make an outline item." );
2052 typedef const Lang::Boolean OutlineOpenType
;
2053 bool outlineOpen
= Helpers::down_cast_CoreArgument
< OutlineOpenType
>( title_
, args
, argsi
, callLoc
)->val_
;
2056 typedef const Lang::Boolean OutlineBoldType
;
2057 bool outlineBold
= Helpers::down_cast_CoreArgument
< OutlineBoldType
>( title_
, args
, argsi
, callLoc
)->val_
;
2060 typedef const Lang::Boolean OutlineItalicType
;
2061 bool outlineItalic
= Helpers::down_cast_CoreArgument
< OutlineItalicType
>( title_
, args
, argsi
, callLoc
)->val_
;
2064 typedef const Lang::RGB OutlineColorType
;
2065 Concrete::RGB outlineColor
= Helpers::down_cast_CoreArgument
< OutlineColorType
>( title_
, args
, argsi
, callLoc
)->components( );
2068 const size_t sidesMode_i
= argsi
;
2069 typedef const Lang::Symbol SidesModeType
;
2070 RefCountPtr
< SidesModeType
> sidesVal
= Helpers::down_cast_CoreArgument
< SidesModeType
>( title_
, args
, argsi
, callLoc
, true );
2073 const size_t target_i
= argsi
;
2074 typedef const Lang::Drawable2D TargetType
;
2075 RefCountPtr
< TargetType
> target
= Helpers::down_cast_CoreArgument
< TargetType
>( title_
, args
, argsi
, callLoc
, true );
2077 Lang::DocumentDestination::Sides sides
= Lang::DocumentDestination::PAGE
; // Defaults to false, unless a target is given.
2078 if( target
!= NullPtr
< TargetType
>( ) )
2080 sides
= Lang::DocumentDestination::TOPLEFT
;
2083 throw Exceptions::CoreOutOfRange( title_
, args
, target_i
, "The target can not be specified for remote destinations." );
2086 static Lang::Symbol
SIDES_TopLeft( "topleft" );
2087 static Lang::Symbol
SIDES_Page( "page" );
2088 static Lang::Symbol
SIDES_Top( "top" );
2089 static Lang::Symbol
SIDES_Left( "left" );
2090 static Lang::Symbol
SIDES_Rectangle( "rectangle" );
2091 if( sidesVal
!= NullPtr
< SidesModeType
>( ) )
2093 if( *sidesVal
== SIDES_TopLeft
)
2095 sides
= Lang::DocumentDestination::TOPLEFT
;
2097 else if( *sidesVal
== SIDES_Page
)
2099 if( target
!= NullPtr
< TargetType
>( ) )
2101 throw Exceptions::CoreOutOfRange( title_
, args
, sidesMode_i
, "The sides mode cannot be page when a target object is present." );
2103 sides
= Lang::DocumentDestination::PAGE
;
2105 else if( *sidesVal
== SIDES_Top
)
2107 sides
= Lang::DocumentDestination::TOP
;
2109 else if( *sidesVal
== SIDES_Left
)
2111 sides
= Lang::DocumentDestination::LEFT
;
2113 else if( *sidesVal
== SIDES_Rectangle
)
2115 sides
= Lang::DocumentDestination::RECTANGLE
;
2119 std::ostringstream oss
;
2120 oss
<< "Valid sides modes are the symbols { "
2121 << SIDES_TopLeft
.name( ).getPtr( ) << ", "
2122 << SIDES_Page
.name( ).getPtr( ) << ", "
2123 << SIDES_Top
.name( ).getPtr( ) << ", "
2124 << SIDES_Left
.name( ).getPtr( ) << ", "
2125 << SIDES_Rectangle
.name( ).getPtr( )
2127 throw Exceptions::CoreOutOfRange( title_
, args
, sidesMode_i
, strrefdup( oss
) );
2132 typedef const Lang::Boolean FitToType
;
2133 RefCountPtr
< FitToType
> fittobboxVal
= Helpers::down_cast_CoreArgument
< FitToType
>( title_
, args
, argsi
, callLoc
, true );
2134 bool fittobbox
= false;
2135 if( fittobboxVal
!= NullPtr
< FitToType
>( ) )
2137 if( remote
|| sides
== Lang::DocumentDestination::TOPLEFT
|| sides
== Lang::DocumentDestination::RECTANGLE
)
2139 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The fit-to-bbox flag cannot be specified in this mode." );
2141 fittobbox
= fittobboxVal
->val_
;
2145 typedef const Lang::Float ZoomType
;
2146 RefCountPtr
< ZoomType
> zoomVal
= Helpers::down_cast_CoreArgument
< ZoomType
>( title_
, args
, argsi
, callLoc
, true );
2147 double zoom
= 0; // This will remain zero only if the zoom argument is not specified.
2148 if( zoomVal
!= NullPtr
< ZoomType
>( ) )
2150 if( remote
|| sides
!= Lang::DocumentDestination::TOPLEFT
)
2152 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The zoom can only be specified when using the top-left sides." );
2154 zoom
= zoomVal
->val_
;
2157 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "The zoom value must be positive." );
2162 typedef const Lang::Boolean DoTransformType
;
2163 bool doTransform
= Helpers::down_cast_CoreArgument
< DoTransformType
>( title_
, args
, argsi
, callLoc
)->val_
;
2165 Kernel::ContRef cont
= evalState
->cont_
;
2168 RefCountPtr
< const Lang::DocumentDestination
>
2169 taggedObj( new Lang::DocumentDestination( remote
, name
, outlineLevel
,
2170 outlineText
, outlineOpen
, outlineBold
, outlineItalic
, outlineColor
) );
2171 cont
->takeValue( RefCountPtr
< const Lang::Value
>
2172 ( new Lang::TaggedValue2D( Kernel::THE_NAVIGATION_SYMBOL
, taggedObj
) ),
2177 RefCountPtr
< const Lang::DocumentDestination
>
2178 taggedObj( new Lang::DocumentDestination( name
, outlineLevel
,
2179 outlineText
, outlineOpen
, outlineBold
, outlineItalic
, outlineColor
,
2180 sides
, target
, fittobbox
, zoom
) );
2183 cont
->takeValue( RefCountPtr
< const Lang::Value
>
2184 ( new Lang::TaggedGeometric2D( Kernel::THE_NAVIGATION_SYMBOL
, taggedObj
) ),
2189 cont
->takeValue( RefCountPtr
< const Lang::Value
>
2190 ( new Lang::TaggedValue2D( Kernel::THE_NAVIGATION_SYMBOL
, taggedObj
) ),
2197 class Core_importFont
: public Lang::CoreFunction
2199 static std::map
< RefCountPtr
< const char >, RefCountPtr
< const Lang::Value
>, charRefPtrLess
> cache
;
2201 Core_importFont( const char * title
)
2202 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
2204 formals_
->appendEvaluatedCoreFormal( "filename", Kernel::THE_SLOT_VARIABLE
);
2205 formals_
->appendEvaluatedCoreFormal( "type", Kernel::THE_VOID_VARIABLE
);
2208 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
2211 throw Exceptions::BuildRequirement( "FreeType 2", title_
, callLoc
);
2213 args
.applyDefaults( );
2217 static std::list
< std::string
> fontSearchPath
;
2218 if( fontSearchPath
.empty( ) )
2220 fontSearchPath
.push_back( "/System/Library/Fonts" );
2221 fontSearchPath
.push_back( "/Library/Fonts" );
2222 char * home
= getenv( "HOME" );
2225 fontSearchPath
.push_back( std::string( home
) + "/Library/Fonts" );
2229 size_t argsi_filename
= argsi
;
2230 typedef const Lang::String ArgType
;
2231 RefCountPtr
< ArgType
> filename
= Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi_filename
, callLoc
);
2233 typedef typeof cache MapType
;
2234 MapType::const_iterator match
= cache
.find( filename
->val_
);
2235 if( match
!= cache
.end( ) )
2237 Kernel::ContRef cont
= evalState
->cont_
;
2238 cont
->takeValue( match
->second
,
2244 std::string full_filename
;
2245 if( *(filename
->val_
.getPtr( )) == '/' )
2247 full_filename
= filename
->val_
.getPtr( );
2248 struct stat theStatDummy
;
2249 if( stat( full_filename
.c_str( ), & theStatDummy
) != 0 )
2251 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_filename
, "File not found." );
2257 typedef typeof fontSearchPath ListType
;
2258 for( ListType::const_iterator i
= fontSearchPath
.begin( ); i
!= fontSearchPath
.end( ); ++i
)
2260 full_filename
= *i
+ "/" + filename
->val_
.getPtr( );
2261 struct stat theStatDummy
;
2262 if( stat( full_filename
.c_str( ), & theStatDummy
) == 0 )
2270 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_filename
, "File not found." );
2276 FT_Error error
= FT_New_Face( Kernel::theFreeType
,
2277 full_filename
.c_str( ),
2280 if( error
== FT_Err_Unknown_File_Format
)
2282 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_filename
, "Font file format not supported by FreeType 2." );
2284 else if( error
!= 0 )
2286 std::ostringstream msg
;
2287 msg
<< "FreeType 2 failed to open " << full_filename
<< ", reason: " << Kernel::FreeTypeErrorMessage( error
) ;
2288 throw Exceptions::ExternalError( strrefdup( msg
) );
2291 const char * PostScriptName
= FT_Get_Postscript_Name( face
); /* See comment on the next line! */
2292 std::ostringstream baseFontName
; /* The PostScriptName pointer shall only be used as long as this object is in scope. */
2293 if( PostScriptName
== 0 )
2295 for( const char * src
= filename
->val_
.getPtr( ); *src
!= '\0'; ++src
)
2303 baseFontName
<< *src
;
2306 PostScriptName
= baseFontName
.str( ).c_str( );
2309 if( ! FT_IS_SFNT( face
) )
2311 throw Exceptions::CoreOutOfRange( title_
, args
, argsi_filename
, "Font file format not supported by Shapes, only TrueType is supported at the moment." );
2314 FT_UShort fsType
= FT_Get_FSType_Flags( face
);
2315 if( ( fsType
& ( FT_FSTYPE_INSTALLABLE_EMBEDDING
|
2316 FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING
|
2317 FT_FSTYPE_EDITABLE_EMBEDDING
) )
2320 std::ostringstream msg
;
2321 msg
<< "The font " << PostScriptName
<< " does not permit embedding, and cannot be used with Shapes. Flags: " << std::hex
<< static_cast< int >( fsType
) << "." ;
2322 throw Exceptions::MiscellaneousRequirement( strrefdup( msg
) );
2326 FontMetrics::FreeType2_Metric
* newMetrics
= new FontMetrics::FreeType2_Metric( face
);
2327 RefCountPtr
< const FontMetrics::FontMetric
> metrics
= RefCountPtr
< const FontMetrics::FontMetric
>( newMetrics
);
2329 RefCountPtr
< SimplePDF::PDF_Dictionary
> dic
;
2330 RefCountPtr
< SimplePDF::PDF_Object
> resource
= SimplePDF::indirect( dic
, & Kernel::theIndirectObjectCount
);
2331 (*dic
)[ "Type" ] = SimplePDF::newName( "Font" );
2332 (*dic
)[ "Subtype" ] = SimplePDF::newName( "Type0" );
2334 RefCountPtr
< SimplePDF::PDF_Dictionary
> descendant
;
2335 RefCountPtr
< SimplePDF::PDF_Vector
> descendants
;
2336 descendants
->vec
.push_back( descendant
);
2337 (*dic
)[ "DescendantFonts" ] = descendants
;
2339 RefCountPtr
< SimplePDF::PDF_ToUnicode::CharSet
> usedChars
;
2341 (*descendant
)[ "Type" ] = SimplePDF::newName( "Font" );
2342 (*descendant
)[ "Subtype" ] = SimplePDF::newName( "CIDFontType2" );
2344 RefCountPtr
< SimplePDF::PDF_Name
> fontName
= RefCountPtr
< SimplePDF::PDF_Name
>( new SimplePDF::PDF_Name( PostScriptName
) );
2345 (*dic
)[ "BaseFont" ] = fontName
;
2346 (*descendant
)[ "BaseFont" ] = fontName
;
2347 (*dic
)[ "Encoding" ] = SimplePDF::newName( "Identity-H" );
2348 (*descendant
)[ "BaseFont" ] = fontName
;
2350 RefCountPtr
< SimplePDF::PDF_Dictionary
> CIDSystemInfo
;
2351 (*CIDSystemInfo
)[ "Registry" ] = SimplePDF::newString( "Adobe" );
2352 (*CIDSystemInfo
)[ "Ordering" ] = SimplePDF::newString( "Identity" );
2353 (*CIDSystemInfo
)[ "Supplement" ] = SimplePDF::newString( "0" );
2354 (*descendant
)[ "CIDSystemInfo" ] = CIDSystemInfo
;
2355 (*descendant
)[ "CIDToGIDMap" ] = SimplePDF::newName( "Identity" );
2357 (*descendant
)[ "DW" ] = SimplePDF::newFloat( 0.7 * 1000 ); /* Default width. */
2359 RefCountPtr
< SimplePDF::PDF_Dictionary
> fontDescriptor
;
2360 (*fontDescriptor
)[ "Type" ] = SimplePDF::newName( "FontDescriptor" );
2361 (*fontDescriptor
)[ "FontName" ] = fontName
;
2362 (*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...
2363 (*fontDescriptor
)[ "FontBBox" ] =
2364 RefCountPtr
< SimplePDF::PDF_Vector
>( new SimplePDF::PDF_Vector( newMetrics
->fontBBoxXMin_
* 1000, newMetrics
->fontBBoxYMin_
* 1000,
2365 newMetrics
->fontBBoxXMax_
* 1000, newMetrics
->fontBBoxYMax_
* 1000 ) );
2366 (*fontDescriptor
)[ "ItalicAngle" ] = SimplePDF::newFloat( 0 );
2367 (*fontDescriptor
)[ "Ascent" ] = SimplePDF::newFloat( 1 * 1000 );
2368 (*fontDescriptor
)[ "Descent" ] = SimplePDF::newFloat( -0.5 * 1000 );
2370 RefCountPtr
< SimplePDF::PDF_Stream_out
> fontFile
= RefCountPtr
< SimplePDF::PDF_Stream_out
>( new SimplePDF::PDF_Stream_out( ) );
2371 (*fontFile
)[ "Filter" ] = SimplePDF::newName( "FlateDecode" );
2372 std::ifstream
iFile( full_filename
.c_str( ) );
2373 if( ! iFile
.is_open( ) )
2375 throw Exceptions::FileReadOpenError( callLoc
, strrefdup( full_filename
), 0, 0 );
2378 iFile
.seekg( 0, std::ios::end
);
2379 std::streamoff tmp
= iFile
.tellg( );
2380 std::streamsize size
= tmp
- static_cast< std::streamoff
>( 0 );
2381 (*fontFile
)[ "Length1" ] = SimplePDF::newInt( size
);
2382 char * buf
= new char[ size
];
2383 iFile
.seekg( 0, std::ios::beg
);
2384 iFile
.read( buf
, size
);
2385 fontFile
->data
.write( buf
, size
);
2388 (*fontDescriptor
)[ "FontFile2" ] = SimplePDF::indirect( fontFile
, & Kernel::theIndirectObjectCount
);
2390 (*descendant
)[ "FontDescriptor" ] = fontDescriptor
;
2392 RefCountPtr
< const Lang::Font
> res
= RefCountPtr
< const Lang::Font
>( new Lang::FreeTypeFont( face
,
2393 newMetrics
->fontName_
,
2397 RefCountPtr
< SimplePDF::PDF_ToUnicode
> toUnicode( new SimplePDF::PDF_ToUnicode( usedChars
, res
) );
2398 (*dic
)[ "ToUnicode" ] = SimplePDF::indirect( toUnicode
, & Kernel::theIndirectObjectCount
);
2399 RefCountPtr
< SimplePDF::PDF_Widths
> widths( new SimplePDF::PDF_Widths( usedChars
, res
) );
2400 (*descendant
)[ "W" ] = SimplePDF::indirect( widths
, & Kernel::theIndirectObjectCount
);
2403 typedef typeof cache MapType
;
2404 cache
.insert( MapType::value_type( filename
->val_
, res
) );
2406 Kernel::ContRef cont
= evalState
->cont_
;
2407 cont
->takeValue( res
,
2413 std::map
< RefCountPtr
< const char >, RefCountPtr
< const Lang::Value
>, charRefPtrLess
> Core_importFont::cache
;
2419 Lang::Core_range::Core_range( const char * title
)
2420 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
2422 formals_
->appendEvaluatedCoreFormal( "begin", Kernel::THE_VOID_VARIABLE
);
2423 formals_
->appendEvaluatedCoreFormal( "end", Kernel::THE_VOID_VARIABLE
);
2424 formals_
->appendEvaluatedCoreFormal( "step", Kernel::THE_VOID_VARIABLE
);
2425 formals_
->appendEvaluatedCoreFormal( "count", Kernel::THE_VOID_VARIABLE
);
2429 Lang::Core_range::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
2431 makeRange( title_
, evalState
, args
, callLoc
);
2435 Lang::Core_range::makeRange( const char * title
, Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
, bool isSpan
, RefCountPtr
< const Lang::Value
> lastPtr
)
2437 const size_t argsi_begin
= 0;
2438 const size_t argsi_end
= 1;
2439 const size_t argsi_step
= 2;
2440 const size_t argsi_count
= 3;
2442 typedef const Lang::Integer CountType
;
2444 args
.applyDefaults( );
2448 typedef const Lang::Integer ArgType
;
2450 RefCountPtr
< ArgType
> beginPtr
= Helpers::try_cast_CoreArgument
< ArgType
>( args
.getValue( argsi_begin
), true );
2451 RefCountPtr
< ArgType
> endPtr
= Helpers::down_cast_CoreArgument
< ArgType
>( title
, args
, argsi_end
, callLoc
, true );
2452 if( beginPtr
== NullPtr
< ArgType
>( ) && endPtr
== NullPtr
< ArgType
>( ) )
2454 throw Exceptions::CoreRequirement( "At least one of the arguments <begin> and <end> must be provided.", title
, callLoc
);
2456 RefCountPtr
< ArgType
> stepPtr
= Helpers::down_cast_CoreArgument
< ArgType
>( title
, args
, argsi_step
, callLoc
, true );
2457 RefCountPtr
< CountType
> countPtr
= Helpers::down_cast_CoreArgument
< CountType
>( title
, args
, argsi_count
, callLoc
, true );
2459 if( beginPtr
!= NullPtr
< ArgType
>( ) && endPtr
!= NullPtr
< ArgType
>( ) &&
2460 stepPtr
!= NullPtr
< ArgType
>( ) && countPtr
!= NullPtr
< CountType
>( ) )
2462 throw Exceptions::CoreRequirement( "At least one of the arguments must be omitted.", title
, callLoc
);
2465 ArgType::ValueType begin
= 0;
2466 ArgType::ValueType step
= 1;
2467 ArgType::ValueType last
= isSpan
? lastPtr
.down_cast
< ArgType
>( )->val_
: 0;
2470 if( stepPtr
!= NullPtr
< ArgType
>( ) )
2472 step
= stepPtr
->val_
;
2474 if( countPtr
!= NullPtr
< CountType
>( ) )
2476 if( countPtr
->val_
< 0 )
2478 throw Exceptions::CoreOutOfRange( title
, args
, argsi_count
, "The <count> must not be negative." );
2480 count
= countPtr
->val_
;
2483 if( beginPtr
== NullPtr
< ArgType
>( ) )
2485 if( countPtr
== NullPtr
< CountType
>( ) )
2489 if( endPtr
->val_
< 0 )
2491 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a span of integers and <begin> is omitted while <end> is negative.", title
, callLoc
);
2493 count
= 1 + endPtr
->val_
/ step
;
2497 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of integers and <begin> is omitted.", title
, callLoc
);
2500 begin
= endPtr
->val_
- ( count
- 1 ) * step
;
2502 else if( endPtr
== NullPtr
< ArgType
>( ) )
2504 begin
= beginPtr
->val_
;
2505 if( countPtr
== NullPtr
< CountType
>( ) )
2511 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of integers and <end> is omitted while <begin> exceeds %last.", title
, callLoc
);
2513 count
= ( last
- begin
) / step
+ 1;
2517 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of integers and <end> is omitted.", title
, callLoc
);
2523 if( countPtr
!= NullPtr
< CountType
>( ) )
2525 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
) );
2528 begin
= beginPtr
->val_
;
2529 if( ( endPtr
->val_
>= begin
&& step
<= 0 )
2531 ( endPtr
->val_
<= begin
&& step
>= 0 ) )
2533 throw Exceptions::CoreOutOfRange( title
, args
, argsi_step
, "When <count> is omitted, the sign of <step> must agree with the order of <begin> and <end>." );
2535 count
= 1 + ( endPtr
->val_
- begin
) / step
;
2538 Kernel::ContRef cont
= evalState
->cont_
;
2541 cont
->takeValue( Lang::THE_CONS_NULL
,
2546 cont
->takeValue( RefCountPtr
< const Lang::SingleList
>( new Lang::SingleListRange
< ArgType
>( begin
, step
, count
) ),
2551 catch( const NonLocalExit::NotThisType
& ball
)
2553 // Never mind, see below
2558 typedef const Lang::Float ArgType
;
2560 RefCountPtr
< ArgType
> beginPtr
= Helpers::try_cast_CoreArgument
< ArgType
>( args
.getValue( argsi_begin
), true );
2561 RefCountPtr
< ArgType
> endPtr
= Helpers::down_cast_CoreArgument
< ArgType
>( title
, args
, argsi_end
, callLoc
, true );
2562 if( beginPtr
== NullPtr
< ArgType
>( ) && endPtr
== NullPtr
< ArgType
>( ) )
2564 throw Exceptions::CoreRequirement( "At least one of the arguments <begin> and <end> must be provided.", title
, callLoc
);
2566 RefCountPtr
< ArgType
> stepPtr
= Helpers::down_cast_CoreArgument
< ArgType
>( title
, args
, argsi_step
, callLoc
, true );
2567 RefCountPtr
< CountType
> countPtr
= Helpers::down_cast_CoreArgument
< CountType
>( title
, args
, argsi_count
, callLoc
, true );
2569 if( beginPtr
!= NullPtr
< ArgType
>( ) && endPtr
!= NullPtr
< ArgType
>( ) &&
2570 stepPtr
!= NullPtr
< ArgType
>( ) && countPtr
!= NullPtr
< CountType
>( ) )
2572 throw Exceptions::CoreRequirement( "At least one of the arguments must be omitted.", title
, callLoc
);
2575 ArgType::ValueType begin
= 0;
2576 ArgType::ValueType step
= 1;
2577 ArgType::ValueType last
= isSpan
? lastPtr
.down_cast
< ArgType
>( )->val_
: 0;
2580 if( stepPtr
!= NullPtr
< ArgType
>( ) )
2582 step
= stepPtr
->val_
;
2584 if( countPtr
!= NullPtr
< CountType
>( ) )
2586 if( countPtr
->val_
< 0 )
2588 throw Exceptions::CoreOutOfRange( title
, args
, argsi_count
, "The <count> must not be negative." );
2590 count
= countPtr
->val_
;
2593 if( beginPtr
== NullPtr
< ArgType
>( ) )
2595 if( countPtr
== NullPtr
< CountType
>( ) )
2599 if( endPtr
->val_
< 0 )
2601 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a span of floats and <begin> is omitted while <end> is negative.", title
, callLoc
);
2603 count
= 1 + endPtr
->val_
/ step
;
2607 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of floats and <begin> is omitted.", title
, callLoc
);
2610 begin
= endPtr
->val_
- ( count
- 1 ) * step
;
2612 else if( endPtr
== NullPtr
< ArgType
>( ) )
2614 begin
= beginPtr
->val_
;
2615 if( countPtr
== NullPtr
< CountType
>( ) )
2621 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of floats and <end> is omitted while <begin> exceeds %last.", title
, callLoc
);
2623 count
= ( last
- begin
) / step
+ 1;
2627 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of floats and <end> is omitted.", title
, callLoc
);
2633 begin
= beginPtr
->val_
;
2634 // When we reach here, we know that at most one of <step> and <count> is provided.
2635 if( countPtr
!= NullPtr
< CountType
>( ) )
2639 throw Exceptions::CoreOutOfRange( title
, args
, argsi_count
, "When <step> is omitted, the <count> be at least 2." );
2641 step
= ( endPtr
->val_
- begin
) / ( count
- 1 );
2645 /* If <step> is not provided, it defaults to 1, see above. */
2648 throw Exceptions::CoreOutOfRange( title
, args
, argsi_step
, "When <count> is omitted, <step> must not be zero." );
2650 ArgType::ValueType tmpCount
= 1 + ( endPtr
->val_
- begin
) / step
;
2657 if( tmpCount
> std::numeric_limits
< size_t >::max( ) )
2659 throw Exceptions::CoreOutOfRange( title
, args
, argsi_step
, "When <count> is omitted, too small <step> values cause overflow in the number of elements." );
2661 count
= static_cast< size_t >( tmpCount
);
2666 Kernel::ContRef cont
= evalState
->cont_
;
2669 cont
->takeValue( Lang::THE_CONS_NULL
,
2674 cont
->takeValue( RefCountPtr
< const Lang::SingleList
>( new Lang::SingleListRange
< ArgType
>( begin
, step
, count
) ),
2679 catch( const NonLocalExit::NotThisType
& ball
)
2681 // Never mind, see below
2686 typedef const Lang::Length ArgType
;
2688 RefCountPtr
< ArgType
> beginPtr
= Helpers::try_cast_CoreArgument
< ArgType
>( args
.getValue( argsi_begin
), true );
2689 RefCountPtr
< ArgType
> endPtr
= Helpers::down_cast_CoreArgument
< ArgType
>( title
, args
, argsi_end
, callLoc
, true );
2690 if( beginPtr
== NullPtr
< ArgType
>( ) && endPtr
== NullPtr
< ArgType
>( ) )
2692 throw Exceptions::CoreRequirement( "At least one of the arguments <begin> and <end> must be provided.", title
, callLoc
);
2694 RefCountPtr
< ArgType
> stepPtr
= Helpers::down_cast_CoreArgument
< ArgType
>( title
, args
, argsi_step
, callLoc
, true );
2695 RefCountPtr
< CountType
> countPtr
= Helpers::down_cast_CoreArgument
< CountType
>( title
, args
, argsi_count
, callLoc
, true );
2697 if( beginPtr
!= NullPtr
< ArgType
>( ) && endPtr
!= NullPtr
< ArgType
>( ) &&
2698 stepPtr
!= NullPtr
< ArgType
>( ) && countPtr
!= NullPtr
< CountType
>( ) )
2700 throw Exceptions::CoreRequirement( "At least one of the arguments must be omitted.", title
, callLoc
);
2703 ArgType::ValueType begin
= ArgType::ValueType( 0 );
2704 ArgType::ValueType step
= ArgType::ValueType( 1 ); /* This is a "default" value that one is not allowed to use! */
2705 ArgType::ValueType last
= isSpan
? lastPtr
.down_cast
< ArgType
>( )->get( ) : Concrete::ZERO_LENGTH
;
2708 if( stepPtr
!= NullPtr
< ArgType
>( ) )
2710 step
= stepPtr
->get( );
2712 if( countPtr
!= NullPtr
< CountType
>( ) )
2714 if( countPtr
->val_
< 0 )
2716 throw Exceptions::CoreOutOfRange( title
, args
, argsi_count
, "The <count> must not be negative." );
2718 count
= countPtr
->val_
;
2721 if( beginPtr
== NullPtr
< ArgType
>( ) )
2723 if( stepPtr
== NullPtr
< ArgType
>( ) )
2725 throw Exceptions::CoreRequirement( "The <step> must be provided when constructing a range of lengths when <begin> is omitted.", title
, callLoc
);
2727 if( countPtr
== NullPtr
< CountType
>( ) )
2731 if( endPtr
->get( ) < Concrete::ZERO_LENGTH
)
2733 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a span of lengths and <begin> is omitted while <end> is negative.", title
, callLoc
);
2735 count
= 1 + static_cast< size_t >( endPtr
->get( ) / step
);
2739 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of lengths and <begin> is omitted.", title
, callLoc
);
2742 begin
= endPtr
->get( ) - ( count
- 1 ) * step
;
2744 else if( endPtr
== NullPtr
< ArgType
>( ) )
2746 begin
= beginPtr
->get( );
2747 if( stepPtr
== NullPtr
< ArgType
>( ) )
2749 throw Exceptions::CoreRequirement( "The <step> must be provided when constructing a range of lengths when <end> is omitted.", title
, callLoc
);
2751 if( countPtr
== NullPtr
< CountType
>( ) )
2757 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of lengths and <end> is omitted while <begin> exceeds %last.", title
, callLoc
);
2759 count
= static_cast< size_t >( ( last
- begin
) / step
) + 1;
2763 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of lengths and <end> is omitted.", title
, callLoc
);
2769 begin
= beginPtr
->get( );
2770 if( stepPtr
== NullPtr
< ArgType
>( ) && countPtr
== NullPtr
< CountType
>( ) )
2772 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
);
2774 // When we reach here, we know that exactly one of <step> and <count> is provided.
2775 if( stepPtr
!= NullPtr
< ArgType
>( ) )
2779 throw Exceptions::CoreOutOfRange( title
, args
, argsi_step
, "When <count> is omitted, <step> must not be zero." );
2781 double tmpCount
= 1 + ( endPtr
->get( ) - begin
) / step
;
2788 if( tmpCount
> std::numeric_limits
< size_t >::max( ) )
2790 throw Exceptions::CoreOutOfRange( title
, args
, argsi_step
, "When <count> is omitted, too small <step> values cause overflow in the number of elements." );
2792 count
= static_cast< size_t >( tmpCount
);
2799 throw Exceptions::CoreOutOfRange( title
, args
, argsi_count
, "When <step> is omitted, the <count> be at least 2." );
2801 step
= ( endPtr
->get( ) - begin
) / ( count
- 1 );
2805 Kernel::ContRef cont
= evalState
->cont_
;
2808 cont
->takeValue( Lang::THE_CONS_NULL
,
2813 cont
->takeValue( RefCountPtr
< const Lang::SingleList
>( new Lang::SingleListRange
< ArgType
>( begin
, step
, count
) ),
2818 catch( const NonLocalExit::NotThisType
& ball
)
2820 // Never mind, see below
2823 throw Exceptions::CoreTypeMismatch( callLoc
, title
, args
, 0, Helpers::typeSetString( Lang::Integer::staticTypeName( ), Lang::Float::staticTypeName( ), Lang::Length::staticTypeName( ) ) );
2828 * The following variable must be initalized after Kernel::THE_VOID_VARIABLE has been initialized (in globals.cc).
2830 RefCountPtr
< const Lang::CoreFunction
> Lang::THE_FUNCTION_RANGE( new Lang::Core_range( "range" ) );
2833 Kernel::registerCore_construct( Kernel::Environment
* env
)
2835 env
->initDefineCoreFunction( new Lang::Core_cons( "cons" ) );
2836 env
->initDefineCoreFunction( new Lang::Core_list( "list" ) );
2837 env
->initDefineCoreFunction( new Lang::Core_unlist( "unlist" ) );
2838 env
->initDefineCoreFunction( new Lang::Core_isnull( "null?" ) );
2839 env
->initDefineCoreFunction( Lang::THE_FUNCTION_RANGE
);
2840 env
->initDefineCoreFunction( new Lang::Core_span( "span" ) );
2841 env
->initDefineCoreFunction( new Lang::Core_affinetransform( "affinetransform" ) );
2842 env
->initDefineCoreFunction( new Lang::Core_shift( "shift" ) );
2843 env
->initDefineCoreFunction( new Lang::Core_rotate( "rotate" ) );
2844 env
->initDefineCoreFunction( new Lang::Core_rotate3d( "rotate3D" ) );
2845 env
->initDefineCoreFunction( new Lang::Core_scale( "scale" ) );
2846 env
->initDefineCoreFunction( new Lang::Core_scale3d( "scale3D" ) );
2847 env
->initDefineCoreFunction( new Lang::Core_affinetransform3D( "affinetransform3D" ) );
2848 env
->initDefineCoreFunction( new Lang::Core_inverse( "inverse" ) );
2850 env
->initDefineCoreFunction( new Lang::Core_formxo( "formxo" ) );
2851 env
->initDefineCoreFunction( new Lang::Core_importRasterImage( "import_raster" ) );
2852 env
->initDefineCoreFunction( new Lang::Core_transparencygroup( "tgroup" ) );
2854 env
->initDefineCoreFunction( new Lang::Core_tag( "tag" ) );
2855 env
->initDefineCoreFunction( new Lang::Core_find( "find" ) );
2856 env
->initDefineCoreFunction( new Lang::Core_findall( "findall" ) );
2858 env
->initDefineCoreFunction( new Lang::Core_ambient_light( "ambient_light" ) );
2859 env
->initDefineCoreFunction( new Lang::Core_specular_light( "specular_light" ) );
2860 env
->initDefineCoreFunction( new Lang::Core_distant_light( "distant_light" ) );
2861 env
->initDefineCoreFunction( new Lang::Core_phong( "phong" ) );
2863 env
->initDefineCoreFunction( new Lang::Core_vector( "vector" ) );
2864 env
->initDefineCoreFunction( new Lang::Core_importPDFpages( "import" ) );
2866 env
->initDefineCoreFunction( new Lang::Core_svg_path( "svg_path" ) );
2868 env
->initDefineCoreFunction( new Lang::Core_sprintf( "sprintf" ) );
2869 env
->initDefineCoreFunction( new Lang::Core_strftime( "strftime" ) );
2871 env
->initDefineCoreFunction( new Lang::Core_newrandom( "newRandom" ) );
2872 env
->initDefineCoreFunction( new Lang::Core_devrandom( "devRandom" ) );
2874 env
->initDefineCoreFunction( new Lang::Core_destination( "destination" ) );
2876 env
->initDefineCoreFunction( new Lang::Core_textrenderingmode( "textmode" ) );
2877 env
->initDefineCoreFunction( new Lang::Core_manualkern( "kerning" ) );
2878 env
->initDefineCoreFunction( new Lang::Core_automatickern( "kern" ) );
2880 env
->initDefineCoreFunction( new Lang::Core_importFont( "import_font" ) );