Example: Changed glyph-outline.shape for use with FontConfig.
[shapes.git] / source / coreconstruct.cc
blob1cd3f7ebc91c23c248015dd29cdc73f990744cc2
1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * any later version.
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008, 2009, 2010 Henrik Tidefelt
19 #include <cmath>
21 #include "Shapes_Helpers_decls.h"
23 #include "singlelistrange.h"
25 #include "shapescore.h"
26 #include "globals.h"
27 #include "shapesexceptions.h"
28 #include "consts.h"
29 #include "simplepdfi.h"
30 #include "simplepdfo.h"
31 #include "astfun.h"
32 #include "tagtypes.h"
33 #include "multipage.h"
34 #include "charconverters.h"
35 #include "pagecontentstates.h"
36 #include "texlabelmanager.h"
37 #include "autoonoff.h"
38 #include "timetypes.h"
39 #include "shapesscanner.h"
40 #include "rasterloaders.h"
41 #include "config.h"
43 #ifdef HAVE_FT2
44 #include <ft2build.h>
45 #include FT_FREETYPE_H
46 #endif
48 #include <iostream>
49 #include <sstream>
50 #include <fstream>
51 #include <vector>
52 #include <stdio.h>
53 #include <ctime>
55 using namespace Shapes;
58 namespace Shapes
60 namespace Helpers
62 RasterLoader_PNG theRasterLoader_PNG;
63 RasterLoader_JPEG theRasterLoader_JPEG;
66 namespace Lang
69 class Core_tag : public Lang::CoreFunction
71 public:
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"
81 virtual void
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." );
96 size_t argsi = 1;
98 if( tryDraw )
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 ) ),
108 evalState );
109 return;
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 ) ),
124 evalState );
125 return;
127 catch( const NonLocalExit::NotThisType & ball )
129 // Never mind, see below
133 if( tryTransform )
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 ) ),
143 evalState );
144 return;
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 ) ),
159 evalState );
160 return;
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 ) ) ),
173 evalState );
178 // This function is in this file just because it i so related to Core_tag.
179 class Core_find : public Lang::CoreFunction
181 public:
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 );
189 virtual void
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 );
197 size_t argsi = 0;
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." );
209 return;
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." );
226 return;
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
240 public:
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 );
248 virtual void
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 );
256 size_t argsi = 0;
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 ) ),
269 evalState );
270 return;
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 ) ),
288 evalState );
289 return;
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
302 public:
303 Core_phong( const char * title ) : CoreFunction( title ) { }
304 virtual void
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_;
312 if( exponent < 0 )
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 ) ),
319 evalState );
323 class Core_cons : public Lang::CoreFunction
325 public:
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 );
332 virtual void
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 ) ) ),
341 evalState );
345 class Core_list : public Lang::CoreFunction
347 public:
348 Core_list( const char * title ) : CoreFunction( title ) { }
349 virtual void
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 ) );
358 if( i == 0 )
360 break;
365 Kernel::ContRef cont = evalState->cont_;
366 cont->takeValue( res,
367 evalState );
371 class Core_unlist : public Lang::CoreFunction
373 Kernel::UnnamedStructureFactory argListFactory_;
374 public:
375 Core_unlist( const char * title ) : CoreFunction( title ) { }
376 virtual void
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 ) ),
386 evalState );
390 class Core_isnull : public Lang::CoreFunction
392 public:
393 Core_isnull( const char * title ) : CoreFunction( title ) { }
394 virtual void
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 ) ),
404 evalState );
408 class Core_span : public Lang::CoreFunction
410 public:
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 );
419 virtual void
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 ) ) ),
426 evalState );
430 class Core_affinetransform : public Lang::CoreFunction
432 public:
433 Core_affinetransform( const char * title ) : CoreFunction( title ) { }
434 virtual void
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( ) ) ),
450 evalState );
454 class Core_affinetransform3D : public Lang::CoreFunction
456 public:
457 Core_affinetransform3D( const char * title ) : CoreFunction( title ) { }
458 virtual void
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( ) ) ),
479 evalState );
483 class Core_shift : public Lang::CoreFunction
485 public:
486 Core_shift( const char * title ) : CoreFunction( title ) { }
487 virtual void
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_;
495 size_t i = 0;
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( ) ) ),
501 evalState );
502 return;
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( ) ) ),
514 evalState );
515 return;
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
528 public:
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 );
534 virtual void
535 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
537 args.applyDefaults( );
539 size_t i = 0;
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 ) ),
548 evalState );
552 class Core_rotate3d : public Lang::CoreFunction
554 public:
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 );
561 virtual void
562 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
564 args.applyDefaults( );
566 size_t i = 0;
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)." );
575 ++i;
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;
584 double x2 = x * x;
585 double y2 = y * y;
586 double z2 = z * z;
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,
593 0, 0, 0 ) ),
594 evalState );
598 class Core_scale : public Lang::CoreFunction
600 public:
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 );
610 virtual void
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_,
623 0, 0 ) ),
624 evalState );
628 class Core_scale3d : public Lang::CoreFunction
630 public:
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 );
641 virtual void
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_,
656 0, 0, 0 ) ),
657 evalState );
661 class Core_inverse : public Lang::CoreFunction
663 public:
664 Core_inverse( const char * title ) : CoreFunction( title ) { }
665 virtual void
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( ) );
674 if( tf != 0 )
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,
688 ixy, iyy,
689 -( ixx * tf->xt_ + ixy * tf->yt_ ), -( iyx * tf->xt_ + iyy * tf->yt_ ) ) ),
690 evalState );
691 return;
696 typedef const Lang::Transform3D ArgType;
697 ArgType * tf = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
698 if( tf != 0 )
700 double det =
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,
720 ixy, iyy, izy,
721 ixz, iyz, izz,
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_ ) ) ),
725 evalState );
726 return;
730 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, 0, Helpers::typeSetString( Lang::Transform2D::staticTypeName( ), Lang::Transform3D::staticTypeName( ) ) );
734 class Core_formxo : public Lang::CoreFunction
736 public:
737 Core_formxo( const char * title ) : CoreFunction( title ) { }
738 virtual void
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,
778 theBBox );
779 res->setDebugStr( "user form" );
780 Kernel::ContRef cont = evalState->cont_;
781 cont->takeValue( Kernel::ValueRef( res ),
782 evalState );
786 class Core_transparencygroup : public Lang::CoreFunction
788 public:
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 );
796 virtual void
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 ),
812 evalState );
816 class Core_importRasterImage : public Lang::CoreFunction
818 std::map< const char *, const Helpers::RasterLoader *, charPtrLess > loaders_;
819 public:
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.
839 virtual void
840 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
842 args.applyDefaults( );
844 size_t argsi = 0;
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 ) );
868 ++argsi;
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." ) );
876 ++argsi;
877 typedef const Lang::Boolean OverrideType;
878 bool override = Helpers::down_cast_CoreArgument< OverrideType >( title_, args, argsi, callLoc )->val_;
880 ++argsi;
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 )
890 if( *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 ) );
900 loader = i->second;
901 break;
904 if( loader == 0 )
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 ) );
911 else
913 static Lang::Symbol PNG( "PNG" );
914 static Lang::Symbol JPEG( "JPEG" );
915 if( *kind == PNG )
917 loader = & Helpers::theRasterLoader_PNG;
919 else if( *kind == JPEG )
921 loader = & Helpers::theRasterLoader_JPEG;
923 else
925 std::ostringstream msg;
926 msg << "The only allowed file kind symbols are { " ;
927 PNG.show( msg );
928 msg << ", " ;
929 JPEG.show( msg );
930 msg << " }." ;
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 ),
937 evalState );
941 class Core_vector : public Lang::CoreFunction
943 public:
944 Core_vector( const char * title ) : CoreFunction( title ) { }
945 virtual void
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 ) ),
958 evalState );
962 class Core_interpolate : public Lang::CoreFunction
964 public:
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 );
975 virtual void
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
986 public:
987 Core_importPDFpages( const char * title ) : CoreFunction( title ) { }
988 virtual void
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 ) ),
1036 evalState );
1040 namespace Implementation
1042 double
1043 svg_path_strtod( const char ** src )
1045 const char * start = *src;
1046 char * endp;
1047 double res = strtod( start, & endp );
1048 *src = endp;
1049 if( **src != ' ' )
1051 for( ; *start == ' '; ++start )
1053 throw std::string( start, strchr( start, ' ' ) - start );
1055 return res;
1058 class Core_svg_path : public Lang::CoreFunction
1060 public:
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 );
1070 virtual void
1071 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1073 args.applyDefaults( );
1075 size_t argsi = 0;
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;
1080 ++argsi;
1081 Concrete::Length dx = Helpers::down_cast_CoreArgument< ScaleType >( title_, args, argsi, callLoc )->get( );
1082 ++argsi;
1083 Concrete::Length dy = Helpers::down_cast_CoreArgument< ScaleType >( title_, args, argsi, callLoc )->get( );
1085 typedef const Lang::Boolean FlagType;
1086 ++argsi;
1087 RefCountPtr< FlagType > multi = Helpers::down_cast_CoreArgument< FlagType >( title_, args, argsi, callLoc, true );
1088 ++argsi;
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 )
1098 switch( *src )
1100 case '\t':
1101 case '\n':
1102 case ',':
1103 *dst = ' ';
1104 continue;
1106 if( ( 'A' <= *src && *src <= 'Z' ) || ( 'a' <= *src && *src <= 'z' ) )
1108 /* Insert whitespace before command to ensure command is not immediately following number.
1110 *dst = ' ';
1111 ++dst;
1113 *dst = *src;
1115 *dst = ' ';
1116 ++dst;
1117 *dst = '\0';
1120 RefCountPtr< Lang::MultiPath2D > multiPath = RefCountPtr< Lang::MultiPath2D >( new Lang::MultiPath2D );
1121 RefCountPtr< Lang::ElementaryPath2D > elemPath = RefCountPtr< Lang::ElementaryPath2D >( NullPtr< Lang::ElementaryPath2D >( ) );
1125 char cmd = '\0';
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 )
1134 if( *src == '\0' )
1136 break;
1138 switch( *src )
1140 case 'M':
1141 case 'm':
1142 case 'Z':
1143 case 'z':
1144 case 'L':
1145 case 'l':
1146 case 'H':
1147 case 'h':
1148 case 'V':
1149 case 'v':
1150 case 'C':
1151 case 'c':
1152 case 'S':
1153 case 's':
1155 cmd = *src;
1156 ++src;
1157 break;
1159 case 'Q':
1160 case 'q':
1161 case 'T':
1162 case 't':
1163 case 'A':
1164 case 'a':
1166 throw Exceptions::CoreOutOfRange( title_, args, 0, strrefdup( std::string( "SVG path command not compatible with cubic splines: " ) + *src ) );
1169 switch( cmd )
1171 case 'M':
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 ) );
1180 last = first;
1181 elemPath = RefCountPtr< Lang::ElementaryPath2D >( new Lang::ElementaryPath2D );
1182 elemPath->push_back( last );
1183 cmd = 'L';
1184 break;
1186 case 'm':
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 ) );
1195 last = first;
1196 elemPath = RefCountPtr< Lang::ElementaryPath2D >( new Lang::ElementaryPath2D );
1197 elemPath->push_back( last );
1198 cmd = 'l';
1199 break;
1201 case 'Z':
1203 elemPath->close( );
1204 last = first;
1205 break;
1207 case 'z':
1209 elemPath->close( );
1210 last = first;
1211 break;
1213 case 'L':
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 );
1219 break;
1221 case 'l':
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 );
1227 break;
1229 case 'H':
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 );
1234 break;
1236 case 'h':
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 );
1241 break;
1243 case 'V':
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 );
1248 break;
1250 case 'v':
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 );
1255 break;
1257 case 'C':
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 );
1269 break;
1271 case 'c':
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 );
1283 break;
1285 case 'S':
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 );
1295 break;
1297 case 's':
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 );
1307 break;
1309 case '\0':
1310 throw Exceptions::CoreOutOfRange( title_, args, 0, "Malformed SVG path string (failed to initialize command character)." );
1311 default:
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 ),
1338 evalState );
1340 else
1342 cont->takeValue( Kernel::ValueRef( multiPath->front( ) ),
1343 evalState );
1346 else
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 ),
1354 evalState );
1359 class Core_sprintf : public Lang::CoreFunction
1361 public:
1362 Core_sprintf( const char * title ) : CoreFunction( title ) { }
1363 virtual void
1364 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1366 if( args.empty( ) )
1368 throw Exceptions::CoreArityMismatch( title_, 1, args.size( ) );
1370 typedef typeof args ArgListType;
1371 size_t i = 0;
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".
1378 char * res = 0;
1379 int status;
1380 char dummy[1];
1381 switch( args.size( ) )
1383 case 1:
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. */
1389 break;
1390 case 2:
1392 ++i;
1394 typedef const Lang::String Arg2Type;
1395 Arg2Type * arg2 = dynamic_cast< Arg2Type * >( args.getValue( i ).getPtr( ) );
1396 if( arg2 != 0 )
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( ) );
1401 break;
1405 typedef const Lang::Float Arg2Type;
1406 Arg2Type * arg2 = dynamic_cast< Arg2Type * >( args.getValue( i ).getPtr( ) );
1407 if( arg2 != 0 )
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_ );
1412 break;
1416 typedef const Lang::Integer Arg2Type;
1417 Arg2Type * arg2 = dynamic_cast< Arg2Type * >( args.getValue( i ).getPtr( ) );
1418 if( arg2 != 0 )
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_ );
1423 break;
1427 typedef const Lang::ChronologicalTime Arg2Type;
1428 Arg2Type * arg2 = dynamic_cast< Arg2Type * >( args.getValue( i ).getPtr( ) );
1429 if( arg2 != 0 )
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 )
1437 delete res;
1438 sz *= 2;
1439 res = new char[ sz ];
1441 status = 0; // Here, I'd like to check some error condition instead...
1442 break;
1445 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, i, Interaction::SEVERAL_TYPES );
1447 break;
1448 default:
1449 throw Exceptions::CoreOutOfRange( title_, args, 0, "The number of arguments is out of the implemented range." );
1452 if( res == 0 )
1454 throw Exceptions::InternalError( "Failed to assign to res in sprintf." );
1457 if( status < 0 )
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 ) ),
1466 evalState );
1470 class Core_strftime : public Lang::CoreFunction
1472 public:
1473 Core_strftime( const char * title ) : CoreFunction( title ) { }
1474 virtual void
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_ );
1480 time_t t;
1481 tm * timeInfo;
1482 t = time( 0 );
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 ) ) ),
1489 evalState );
1493 class Core_ambient_light : public Lang::CoreFunction
1495 public:
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 );
1501 virtual void
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( ) );
1509 if( col != 0 )
1511 Kernel::ContRef cont = evalState->cont_;
1512 cont->takeValue( Kernel::ValueRef( new Lang::AmbientLightGray( col->components( ) ) ),
1513 evalState );
1514 return;
1519 typedef const Lang::RGB ArgType;
1520 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1521 if( col != 0 )
1523 Kernel::ContRef cont = evalState->cont_;
1524 cont->takeValue( Kernel::ValueRef( new Lang::AmbientLightRGB( col->components( ) ) ),
1525 evalState );
1526 return;
1530 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, 0, Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
1534 class Core_specular_light : public Lang::CoreFunction
1536 public:
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 );
1544 virtual void
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( ) );
1557 if( col != 0 )
1559 Kernel::ContRef cont = evalState->cont_;
1560 cont->takeValue( Kernel::ValueRef( new Lang::SpecularLightGray( Concrete::Coords3D( 0, 0, 0 ),
1561 col->components( ),
1562 radius->get( ),
1563 shadows->val_ ) ),
1564 evalState );
1565 return;
1570 typedef const Lang::RGB ArgType;
1571 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1572 if( col != 0 )
1574 Kernel::ContRef cont = evalState->cont_;
1575 cont->takeValue( Kernel::ValueRef( new Lang::SpecularLightRGB( Concrete::Coords3D( 0, 0, 0 ),
1576 col->components( ),
1577 radius->get( ),
1578 shadows->val_ ) ),
1579 evalState );
1580 return;
1584 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, 0, Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
1588 class Core_distant_light : public Lang::CoreFunction
1590 public:
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 );
1597 virtual void
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( ) );
1608 if( col != 0 )
1610 Kernel::ContRef cont = evalState->cont_;
1611 cont->takeValue( Kernel::ValueRef( new Lang::DistantLightGray( Concrete::UnitFloatTriple( 0., 0., -1. ),
1612 col->components( ),
1613 shadows->val_ ) ),
1614 evalState );
1615 return;
1620 typedef const Lang::RGB ArgType;
1621 ArgType * col = dynamic_cast< ArgType * >( args.getValue( 0 ).getPtr( ) );
1622 if( col != 0 )
1624 Kernel::ContRef cont = evalState->cont_;
1625 cont->takeValue( Kernel::ValueRef( new Lang::DistantLightRGB( Concrete::UnitFloatTriple( 0., 0., -1. ),
1626 col->components( ),
1627 shadows->val_ ) ),
1628 evalState );
1629 return;
1633 throw Exceptions::CoreTypeMismatch( callLoc, title_, args, 0, Helpers::typeSetString( Lang::Gray::staticTypeName( ), Lang::RGB::staticTypeName( ) ) );
1637 class Core_textrenderingmode : public Lang::CoreFunction
1639 public:
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 );
1646 virtual void
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 ) ),
1657 evalState );
1661 class Core_manualkern : public Lang::CoreFunction
1663 public:
1664 Core_manualkern( const char * title ) : CoreFunction( title ) { }
1665 virtual void
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 ) ) );
1678 continue;
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_ );
1689 continue;
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( ) );
1700 continue;
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,
1712 evalState );
1716 class Core_automatickern : public Lang::CoreFunction
1718 public:
1719 Core_automatickern( const char * title ) : CoreFunction( title ) { }
1720 virtual void
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." );
1777 else
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;
1790 pendingKerning = 0;
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." );
1825 else
1827 std::ostringstream msg;
1828 msg << "iconv failed with an unrecognized error code: " << errno ;
1829 throw Exceptions::InternalError( strrefdup( msg ) );
1832 *outbuf = '\0';
1833 pendingChars << backbuf ;
1836 continue;
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_;
1847 continue;
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,
1865 evalState );
1869 class Core_newrandom : public Lang::CoreFunction
1871 public:
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 ) ) );
1878 virtual void
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_;
1885 if( sz < 8 )
1887 throw Exceptions::CoreOutOfRange( title_, args, 1, "The size must be at least 8." );
1889 if( sz > 256 )
1891 throw Exceptions::CoreOutOfRange( title_, args, 1, "The size must at most 256." );
1894 size_t argsi = 0;
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( ) ) ),
1904 evalState );
1905 return;
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_ ) ),
1920 evalState );
1921 return;
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
1934 public:
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 ) ) );
1941 virtual void
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_;
1948 if( sz < 8 )
1950 throw Exceptions::CoreOutOfRange( title_, args, 0, "The size must be at least 8." );
1952 if( sz > 256 )
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 ) ),
1962 evalState );
1966 class Core_destination : public Lang::CoreFunction
1968 public:
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 );
1986 virtual void
1987 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
1989 args.applyDefaults( );
1991 size_t argsi = 0;
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_;
1996 ++argsi;
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_;
2007 else
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!
2015 if( remote )
2017 throw Exceptions::CoreOutOfRange( title_, args, remove_i, "The destination cannot be remote if no name is given." );
2021 ++argsi;
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." );
2035 ++argsi;
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_;
2043 else
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." );
2051 ++argsi;
2052 typedef const Lang::Boolean OutlineOpenType;
2053 bool outlineOpen = Helpers::down_cast_CoreArgument< OutlineOpenType >( title_, args, argsi, callLoc )->val_;
2055 ++argsi;
2056 typedef const Lang::Boolean OutlineBoldType;
2057 bool outlineBold = Helpers::down_cast_CoreArgument< OutlineBoldType >( title_, args, argsi, callLoc )->val_;
2059 ++argsi;
2060 typedef const Lang::Boolean OutlineItalicType;
2061 bool outlineItalic = Helpers::down_cast_CoreArgument< OutlineItalicType >( title_, args, argsi, callLoc )->val_;
2063 ++argsi;
2064 typedef const Lang::RGB OutlineColorType;
2065 Concrete::RGB outlineColor = Helpers::down_cast_CoreArgument< OutlineColorType >( title_, args, argsi, callLoc )->components( );
2067 ++argsi;
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 );
2072 ++argsi;
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;
2081 if( remote )
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;
2117 else
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( )
2126 << " }." ;
2127 throw Exceptions::CoreOutOfRange( title_, args, sidesMode_i, strrefdup( oss ) );
2131 ++argsi;
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_;
2144 ++argsi;
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_;
2155 if( zoom <= 0 )
2157 throw Exceptions::CoreOutOfRange( title_, args, argsi, "The zoom value must be positive." );
2161 ++argsi;
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_;
2166 if( remote )
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 ) ),
2173 evalState );
2175 else
2177 RefCountPtr< const Lang::DocumentDestination >
2178 taggedObj( new Lang::DocumentDestination( name, outlineLevel,
2179 outlineText, outlineOpen, outlineBold, outlineItalic, outlineColor,
2180 sides, target, fittobbox, zoom ) );
2181 if( doTransform )
2183 cont->takeValue( RefCountPtr< const Lang::Value >
2184 ( new Lang::TaggedGeometric2D( Kernel::THE_NAVIGATION_SYMBOL, taggedObj ) ),
2185 evalState );
2187 else
2189 cont->takeValue( RefCountPtr< const Lang::Value >
2190 ( new Lang::TaggedValue2D( Kernel::THE_NAVIGATION_SYMBOL, taggedObj ) ),
2191 evalState );
2197 class Core_importFont : public Lang::CoreFunction
2199 static std::map< RefCountPtr< const char >, RefCountPtr< const Lang::Value >, charRefPtrLess > cache;
2200 public:
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 );
2207 virtual void
2208 call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2210 #ifndef HAVE_FT2
2211 throw Exceptions::BuildRequirement( "FreeType 2", title_, callLoc );
2212 #else
2213 args.applyDefaults( );
2215 size_t argsi = 0;
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" );
2223 if( home != 0 )
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,
2239 evalState );
2240 return;
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." );
2254 else
2256 bool found = false;
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 )
2264 found = true;
2265 break;
2268 if( ! found )
2270 throw Exceptions::CoreOutOfRange( title_, args, argsi_filename, "File not found." );
2274 FT_Face face;
2276 FT_Error error = FT_New_Face( Kernel::theFreeType,
2277 full_filename.c_str( ),
2279 & face );
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 )
2297 if( *src == '.' )
2299 break;
2301 if( *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 ) )
2318 == 0 )
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 );
2386 delete buf;
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_,
2394 resource,
2395 metrics,
2396 usedChars ) );
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,
2408 evalState );
2409 #endif
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 );
2428 void
2429 Lang::Core_range::call( Kernel::EvalState * evalState, Kernel::Arguments & args, const Ast::SourceLocation & callLoc ) const
2431 makeRange( title_, evalState, args, callLoc );
2434 void
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;
2468 size_t count = 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 >( ) )
2487 if( isSpan )
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;
2495 else
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 >( ) )
2507 if( isSpan )
2509 if( last < begin )
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;
2515 else
2517 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of integers and <end> is omitted.", title, callLoc );
2521 else
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_;
2539 if( count == 0 )
2541 cont->takeValue( Lang::THE_CONS_NULL,
2542 evalState );
2544 else
2546 cont->takeValue( RefCountPtr< const Lang::SingleList >( new Lang::SingleListRange< ArgType >( begin, step, count ) ),
2547 evalState );
2549 return;
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;
2578 size_t count = 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 >( ) )
2597 if( isSpan )
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;
2605 else
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 >( ) )
2617 if( isSpan )
2619 if( last < begin )
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;
2625 else
2627 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of floats and <end> is omitted.", title, callLoc );
2631 else
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 >( ) )
2637 if( count < 2 )
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 );
2643 else
2645 /* If <step> is not provided, it defaults to 1, see above. */
2646 if( step == 0 )
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;
2651 if( tmpCount < 1 )
2653 count = 0;
2655 else
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_;
2667 if( count == 0 )
2669 cont->takeValue( Lang::THE_CONS_NULL,
2670 evalState );
2672 else
2674 cont->takeValue( RefCountPtr< const Lang::SingleList >( new Lang::SingleListRange< ArgType >( begin, step, count ) ),
2675 evalState );
2677 return;
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;
2706 size_t count = 0;
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 >( ) )
2729 if( isSpan )
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 );
2737 else
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 >( ) )
2753 if( isSpan )
2755 if( last < begin )
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;
2761 else
2763 throw Exceptions::CoreRequirement( "The <count> must be provided when constructing a range of lengths and <end> is omitted.", title, callLoc );
2767 else
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 >( ) )
2777 if( step == 0 )
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;
2782 if( tmpCount < 1 )
2784 count = 0;
2786 else
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 );
2795 else
2797 if( count < 2 )
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_;
2806 if( count == 0 )
2808 cont->takeValue( Lang::THE_CONS_NULL,
2809 evalState );
2811 else
2813 cont->takeValue( RefCountPtr< const Lang::SingleList >( new Lang::SingleListRange< ArgType >( begin, step, count ) ),
2814 evalState );
2816 return;
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" ) );
2832 void
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" ) );