Updating the changelog in the VERSION file, and version_sync.
[shapes.git] / source / texttypes.cc
blobbce74797b03b33e2715a61df7d8e42c702505ef6
1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * any later version.
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008 Henrik Tidefelt
19 #include "Shapes_Helpers_decls.h"
21 #include "texttypes.h"
22 #include "dynamicenvironment.h"
23 #include "lighttypes.h"
24 #include "ast.h"
25 #include "astvar.h"
26 #include "isnan.h"
27 #include "globals.h"
28 #include "autoonoff.h"
29 #include "afmscanner.h"
30 #include "charconverters.h"
31 #include "constructorrepresentation.h"
32 #include "pagecontentstates.h"
33 #include "config.h"
35 #include <fstream>
36 #include <sys/types.h>
37 #include <sys/stat.h>
39 using namespace Shapes;
41 std::map< RefCountPtr< const char >, RefCountPtr< SimplePDF::PDF_Object >, charRefPtrLess > Lang::Font::theFontResourceMap_;
42 std::map< RefCountPtr< const char >, RefCountPtr< const FontMetrics::BaseFont >, charRefPtrLess > Lang::Font::theFontMetricsMap_;
43 std::list< std::string > Lang::Font::theFontMetricsSearchPath_;
45 void
46 Lang::Font::push_backFontMetricsPath( const std::string & path )
48 if( path.empty( ) ||
49 path[ path.size( ) - 1 ] == '/' )
51 theFontMetricsSearchPath_.push_back( path );
53 else
55 theFontMetricsSearchPath_.push_back( path + "/" );
59 std::string
60 Lang::Font::searchGlyphList( )
62 std::string res;
64 if( theFontMetricsSearchPath_.empty( ) )
66 throw Exceptions::ExternalError( strrefdup( "The font metrics path was not set up (needed for the glyph list). Consider defining the environment variable SHAPESFONTMETRICS." ) );
69 typedef typeof theFontMetricsSearchPath_ ListType;
70 for( ListType::const_iterator i = theFontMetricsSearchPath_.begin( ); i != theFontMetricsSearchPath_.end( ); ++i )
72 res = *i + "glyphlist.txt";
73 struct stat theStatDummy;
74 if( stat( res.c_str( ), & theStatDummy ) == 0 )
76 return res;
79 throw Exceptions::MiscellaneousRequirement( "A font operation required the glyph list, but it was not found. It should be named \"glyphlist.txt\" and reside in a directory on the font metrics path. Please refer to your environment variable SHAPESFONTMETRICS." );
82 std::string
83 Lang::Font::searchFontMetrics( RefCountPtr< const char > fontName )
85 std::string res;
87 if( strlen( fontName.getPtr( ) ) == 0 )
89 throw Exceptions::InternalError( strrefdup( "Lang::Font::searchFontMetrics called with empty argument." ) );
92 if( *fontName.getPtr( ) == '/' )
94 throw Exceptions::InternalError( "The font name cannot begin with \"/\", as if is was an absolute path to something." );
97 if( theFontMetricsSearchPath_.empty( ) )
99 throw Exceptions::ExternalError( strrefdup( "The font metrics path was not set up. Consider defining the environment variable SHAPESFONTMETRICS." ) );
102 typedef typeof theFontMetricsSearchPath_ ListType;
103 for( ListType::const_iterator i = theFontMetricsSearchPath_.begin( ); i != theFontMetricsSearchPath_.end( ); ++i )
105 res = *i + fontName.getPtr( ) + ".afm";
106 struct stat theStatDummy;
107 if( stat( res.c_str( ), & theStatDummy ) == 0 )
109 return res;
112 throw Exceptions::MissingFontMetrics( fontName, & theFontMetricsSearchPath_ );
115 std::string
116 Lang::Font::searchCharacterEncoding( const char * encodingName )
118 std::string res;
120 if( theFontMetricsSearchPath_.empty( ) )
122 throw Exceptions::ExternalError( strrefdup( "The font metrics path was not set up. Consider defining the environment variable SHAPESFONTMETRICS." ) );
125 typedef typeof theFontMetricsSearchPath_ ListType;
126 for( ListType::const_iterator i = theFontMetricsSearchPath_.begin( ); i != theFontMetricsSearchPath_.end( ); ++i )
128 res = *i + encodingName + ".enc";
129 struct stat theStatDummy;
130 if( stat( res.c_str( ), & theStatDummy ) == 0 )
132 return res;
135 std::ostringstream msg;
136 msg << "A font operation required a character encoding file for " << encodingName << ", but it was not found. It should be named \"" << encodingName << ".enc\" and reside in a directory on the font metrics path. Please refer to your environment variable SHAPESFONTMETRICS." ;
137 throw Exceptions::MiscellaneousRequirement( strrefdup( msg ) );
141 Lang::Font::Font( const RefCountPtr< const char > fontName, RefCountPtr< SimplePDF::PDF_Object > & resource, RefCountPtr< const FontMetrics::BaseFont > metrics )
142 : fontName_( fontName ), resource_( resource ), metrics_( metrics )
144 // If this font has been instantiated before, it is reused.
146 typedef typeof theFontResourceMap_ MapType;
147 MapType::const_iterator i = theFontResourceMap_.find( fontName_ );
148 if( i != theFontResourceMap_.end( ) )
150 resource_ = i->second;
152 else
154 theFontResourceMap_.insert( MapType::value_type( fontName_, resource_ ) );
158 typedef typeof theFontMetricsMap_ MapType;
159 MapType::const_iterator i = theFontMetricsMap_.find( fontName_ );
160 if( i != theFontMetricsMap_.end( ) )
162 metrics_ = i->second;
164 else if( metrics_ != NullPtr< const FontMetrics::BaseFont >( ) )
166 theFontMetricsMap_.insert( MapType::value_type( fontName_, metrics_ ) );
171 // Note that we must not initialize name_ with builtinFontMap_[ fontConst ] here, since builtinFontMap_ may not be
172 // initialized when this constructor is invoked from globals.cc.
173 Lang::Font::Font( const RefCountPtr< const char > fontName )
174 : fontName_( fontName ), resource_( NullPtr< SimplePDF::PDF_Object >( ) ), metrics_( NullPtr< const FontMetrics::BaseFont >( ) )
177 Lang::Font::~Font( )
180 const RefCountPtr< SimplePDF::PDF_Object > &
181 Lang::Font::resource( ) const
183 if( resource_ != NullPtr< SimplePDF::PDF_Object >( ) )
185 return resource_;
188 typedef typeof theFontResourceMap_ MapType;
191 MapType::const_iterator i = theFontResourceMap_.find( fontName_ );
192 if( i != theFontResourceMap_.end( ) )
194 resource_ = i->second;
195 return resource_;
200 RefCountPtr< SimplePDF::PDF_Dictionary > dic;
201 resource_ = SimplePDF::indirect( dic, & Kernel::theIndirectObjectCount );
202 (*dic)[ "Type" ] = SimplePDF::newName( "Font" );
203 (*dic)[ "Subtype" ] = SimplePDF::newName( "Type1" );
204 (*dic)[ "Encoding" ] = SimplePDF::newName( "MacRomanEncoding" );
205 (*dic)[ "BaseFont" ] = SimplePDF::newName( fontName_.getPtr( ) ); // Here, it is crucial that this is really a build-in font!
207 return resource_;
210 RefCountPtr< const char >
211 Lang::Font::fontName( ) const
213 return fontName_;
216 RefCountPtr< const FontMetrics::BaseFont >
217 Lang::Font::metrics( ) const
219 if( metrics_ != NullPtr< const FontMetrics::BaseFont >( ) )
221 return metrics_;
224 // Otherwise, we hope that we can find an Adobe Font Metrics file.
225 std::string filename = searchFontMetrics( fontName_ );
226 std::ifstream afmFile( filename.c_str( ) );
227 if( ! afmFile.is_open( ) )
229 std::ostringstream oss;
230 oss << "File has been located but couldn't be opened: " << filename ;
231 throw Exceptions::ExternalError( strrefdup( oss ) );
234 // I fiddle a little with the consts here...
235 FontMetrics::BaseFont * newMetrics = new FontMetrics::BaseFont;
236 metrics_ = RefCountPtr< const FontMetrics::BaseFont >( newMetrics );
238 AfmScanner scanner( newMetrics, & afmFile );
239 scanner.setTellQue( Interaction::fontMetricMessages ); // We want to know about things that are not recognized and this ignored.
240 if( Interaction::fontMetricDebug )
242 scanner.set_debug( 1 );
246 int status = scanner.yylex( );
247 if( status != 0 )
249 std::ostringstream oss;
250 oss << "Font metrics parser returned with non-zero status: " << status ;
251 throw Exceptions::InternalError( strrefdup( oss ) );
254 catch( const char * ball )
256 std::ostringstream oss;
257 oss << "Font metrics parser failed with message: " << ball ;
258 throw Exceptions::InternalError( strrefdup( oss ) );
260 catch( const RefCountPtr< const char > ball )
262 std::ostringstream oss;
263 oss << "Font metrics parser failed with message: " << ball ;
264 throw Exceptions::InternalError( strrefdup( oss ) );
267 return metrics_;
270 void
271 Lang::Font::gcMark( Kernel::GCMarkedSet & marked )
274 RefCountPtr< const Lang::Class > Lang::Font::TypeID( new Lang::SystemFinalClass( strrefdup( "Font" ) ) );
275 TYPEINFOIMPL( Font );
277 Lang::TextOperation::TextOperation( )
280 Lang::TextOperation::~TextOperation( )
283 RefCountPtr< const Lang::Class > Lang::TextOperation::TypeID( new Lang::SystemFinalClass( strrefdup( "TextOperation" ) ) );
284 TYPEINFOIMPL( TextOperation );
287 Lang::KernedText::KernedText( const RefCountPtr< const Kernel::TextState > & textState, const RefCountPtr< const Kernel::GraphicsState > & metaState )
288 : textState_( textState ), metaState_( metaState ), maxLength_( 0 )
291 Lang::KernedText::KernedText( const RefCountPtr< const Kernel::TextState > & textState, const RefCountPtr< const Kernel::GraphicsState > & metaState, const RefCountPtr< const Lang::String > & str)
292 : textState_( textState ), metaState_( metaState ), maxLength_( 0 )
294 pushString( str );
297 Lang::KernedText::~KernedText( )
300 Kernel::VariableHandle
301 Lang::KernedText::getField( const char * fieldID, const RefCountPtr< const Lang::Value > & selfRef ) const
303 if( strcmp( fieldID, "list" ) == 0 )
305 return Kernel::VariableHandle( new Kernel::Variable( makeList( ) ) );
307 throw Exceptions::NonExistentMember( getTypeName( ), fieldID );
310 RefCountPtr< const Lang::SingleList >
311 Lang::KernedText::makeList( ) const
313 /* The list is first computed in a bidirectional list, and then we construct the stateless cons list.
316 /* I'm lazy today, so i use a cons pair to group the horizontal step with the glyph. The better solution
317 * would be to use a structure with nicely named fields...
320 std::list< RefCountPtr< const Lang::Value > > revlist;
322 iconv_t converter = Helpers::requireUTF8ToMacRomanConverter( );
324 RefCountPtr< FontMetrics::WritingDirectionMetrics > horizontalMetrics = textState_->font_->metrics( )->horizontalMetrics_;
325 if( horizontalMetrics == NullPtr< FontMetrics::WritingDirectionMetrics >( ) )
327 throw Exceptions::FontMetricsError( textState_->font_->fontName( ), strrefdup( "No horizontal metrics defined." ) );
329 const FontMetrics::CharacterMetrics * defaultCharMetrics = horizontalMetrics->charData_[ 0 ];
331 Concrete::Length ySize = textState_->size_;
332 Concrete::Length xSize = ySize * textState_->horizontalScaling_;
333 Concrete::Length characterTrackKern = textState_->horizontalScaling_ * textState_->characterSpacing_;
334 Concrete::Length wordTrackKern = textState_->horizontalScaling_ * textState_->wordSpacing_;
336 Concrete::Length xpos = 0;
338 size_t bufSize = maxLength_ + 1; // This will be enough if MacRoman coding is used, since this encoding uses only one byte per character.
339 // The extra one byte will be used to terminate the string.
340 char * buf = new char[ bufSize ];
341 DeleteOnExit< char > bufDeleter( buf );
343 typedef typeof strings_ ListType;
344 std::list< double >::const_iterator ki = kernings_.begin( );
345 for( ListType::const_iterator i = strings_.begin( ); i != strings_.end( ); ++i )
347 if( *i != NullPtr< const Lang::String >( ) )
349 const char * inbuf = (*i)->val_.getPtr( );
350 char * outbuf = buf;
351 size_t inbytesleft = strlen( inbuf );
352 size_t outbytesleft = bufSize - 1;
353 // The ICONV_CAST macro is defined in config.h.
354 size_t count = iconv( converter,
355 ICONV_CAST( & inbuf ), & inbytesleft,
356 & outbuf, & outbytesleft );
357 if( count == (size_t)(-1) )
359 if( errno == EILSEQ )
361 throw Exceptions::MiscellaneousRequirement( "It is suspected that one of the UFT-8 characters used in showed text has no MacRoman representation." );
363 else if( errno == EINVAL )
365 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
367 else if( errno == E2BIG )
369 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to MacRoman conversion was too small." );
371 else
373 std::ostringstream msg;
374 msg << "iconv failed with an unrecognized error code: " << errno ;
375 throw Exceptions::InternalError( strrefdup( msg ) );
378 *outbuf = '\0';
379 for( const char * src = buf; *src != '\0'; ++src )
381 switch( *src )
383 case ' ':
385 // Observe textState_->wordSpacing_
386 const FontMetrics::CharacterMetrics * charMetrics = horizontalMetrics->charByCode( (unsigned char)( 32 ) );
387 xpos += xSize * charMetrics->horizontalCharWidthX_;
388 xpos += characterTrackKern;
389 xpos += wordTrackKern;
391 break;
392 case '\n':
394 throw Exceptions::MiscellaneousRequirement( "Newlines cannot be represented in the pos-character list." );
396 break;
397 default:
399 // Observe textState_->characterSpacing_
400 unsigned char currentChar = *reinterpret_cast< const unsigned char * >( src );
401 const FontMetrics::CharacterMetrics * charMetrics = horizontalMetrics->charByCode( currentChar );
402 if( Computation::fontMetricGuessIsError && charMetrics == defaultCharMetrics )
404 std::ostringstream msg;
405 msg << "Character at offset " << src - buf << " in \"" << buf << "\" was not found in font metrics (and according to your options, guessing is not OK)." ;
406 throw Exceptions::FontMetricsError( textState_->font_->fontName( ), strrefdup( msg ) );
408 revlist.push_back( RefCountPtr< const Lang::Value >
409 ( new Lang::ConsPair
410 ( Helpers::newValHandle( new Lang::Length( xpos ) ),
411 Helpers::newValHandle( new Lang::KernedText( textState_, metaState_, oneMacRomanToUTF8( *src ) ) ) ) ) );
412 /* Although not as efficient, it becomes easier to use the list if the distance is
413 * measured from the start of the text rather than from the previous character.
415 // xpos = 0;
416 xpos += xSize * charMetrics->horizontalCharWidthX_;
417 xpos += characterTrackKern;
422 else
424 if( ki == kernings_.end( ) )
426 throw Exceptions::InternalError( "Short of kerning values in KernedText::measure." );
428 xpos -= xSize * *ki;
429 ++ki;
432 if( ki != kernings_.end( ) )
434 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
437 RefCountPtr< const Lang::SingleList > res = Lang::THE_CONS_NULL;
438 while( ! revlist.empty( ) )
440 res = RefCountPtr< const Lang::SingleList >( new Lang::SingleListPair( Kernel::VariableHandle( new Kernel::Variable( revlist.back( ) ) ),
441 res ) );
442 revlist.pop_back( );
444 return res;
447 RefCountPtr< const Lang::String >
448 Lang::KernedText::oneMacRomanToUTF8( const char c )
450 iconv_t converter = Helpers::requireMacRomanToUTF8Converter( );
452 const size_t BUF_SIZE = 9;
453 char buf[ BUF_SIZE ];
455 static char * charbuf = new char[ 2 ]; // This is a one time leak.
456 charbuf[0] = c;
457 charbuf[1] = '\0';
459 char * outbuf = buf;
460 const char * inbuf = charbuf;
461 size_t inbytesleft = 1;
462 size_t outbytesleft = BUF_SIZE - 1;
463 // The ICONV_CAST macro is defined in config.h.
464 size_t count = iconv( converter,
465 ICONV_CAST( & inbuf ), & inbytesleft,
466 & outbuf, & outbytesleft );
467 if( count == (size_t)(-1) )
469 throw Exceptions::ExternalError( "Conversion of one MacRoman character to UTF-8 failed." );
471 *outbuf = '\0';
472 return RefCountPtr< const Lang::String >( new Lang::String( strrefdup( buf ) ) );
475 void
476 Lang::KernedText::pushString( const RefCountPtr< const Lang::String > & str )
478 strings_.push_back( str );
479 maxLength_ = std::max( maxLength_, strlen( str->val_.getPtr( ) ) );
482 void
483 Lang::KernedText::pushKerning( double kerning )
485 strings_.push_back( NullPtr< const Lang::String >( ) );
486 kernings_.push_back( kerning );
489 void
490 Lang::KernedText::show( std::ostream & os ) const
492 typedef typeof strings_ ListType;
493 std::list< double >::const_iterator ki = kernings_.begin( );
494 for( ListType::const_iterator i = strings_.begin( ); i != strings_.end( ); ++i )
496 if( *i != NullPtr< const Lang::String >( ) )
498 os << "(" << (*i)->val_.getPtr( ) << ")" ;
500 else
502 if( ki == kernings_.end( ) )
504 throw Exceptions::InternalError( "Short of kerning values in KernedText::show." );
506 os << *ki ;
507 ++ki;
510 if( ki != kernings_.end( ) )
512 throw Exceptions::InternalError( "Too many kerning values in KernedText::show." );
517 void
518 Lang::KernedText::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf, bool clip ) const
520 iconv_t converter = Helpers::requireUTF8ToMacRomanConverter( );
522 pdfState->text_.synchAssertKnockout( os, textState_.getPtr( ), pdfState->resources_.getPtr( ), clip );
523 switch( textState_->mode_ )
525 case Lang::TextRenderingMode::FILL:
526 case Lang::TextRenderingMode::FILLCLIP:
527 pdfState->graphics_.synchForNonStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
528 break;
529 case Lang::TextRenderingMode::STROKE:
530 case Lang::TextRenderingMode::STROKECLIP:
531 pdfState->graphics_.synchForStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
532 break;
533 case Lang::TextRenderingMode::FILLSTROKE:
534 case Lang::TextRenderingMode::FILLSTROKECLIP:
535 pdfState->graphics_.synchForStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
536 pdfState->graphics_.synchForNonStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
537 break;
538 case Lang::TextRenderingMode::INVISIBLE:
539 case Lang::TextRenderingMode::CLIP:
540 break;
541 case Lang::TextRenderingMode::UNDEFINED:
542 pdfState->graphics_.synchForStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
543 pdfState->graphics_.synchForNonStroke( os, metaState_.getPtr( ), pdfState->resources_.getPtr( ) );
544 default:
545 throw Exceptions::InternalError( "KernedText::writePDFVectorTo: Text rendering mode out of range." );
549 size_t bufSize = maxLength_ + 1; // This will be enough if MacRoman coding is used, since this encoding uses only one byte per character.
550 // The extra one byte will be used to terminate the string.
551 char * buf = new char[ bufSize ];
552 DeleteOnExit< char > bufDeleter( buf );
554 typedef typeof strings_ ListType;
555 std::list< double >::const_iterator ki = kernings_.begin( );
556 os << "[ " ;
557 for( ListType::const_iterator i = strings_.begin( ); i != strings_.end( ); ++i )
559 if( *i != NullPtr< const Lang::String >( ) )
561 const char * inbuf = (*i)->val_.getPtr( );
562 char * outbuf = buf;
563 size_t inbytesleft = strlen( inbuf );
564 size_t outbytesleft = bufSize - 1;
565 // The ICONV_CAST macro is defined in config.h.
566 size_t count = iconv( converter,
567 ICONV_CAST( & inbuf ), & inbytesleft,
568 & outbuf, & outbytesleft );
569 if( count == (size_t)(-1) )
571 if( errno == EILSEQ )
573 throw Exceptions::MiscellaneousRequirement( "It is suspected that one of the UFT-8 characters used in showed text has no MacRoman representation." );
575 else if( errno == EINVAL )
577 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
579 else if( errno == E2BIG )
581 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to MacRoman conversion was too small." );
583 else
585 std::ostringstream msg;
586 msg << "iconv failed with an unrecognized error code: " << errno ;
587 throw Exceptions::InternalError( strrefdup( msg ) );
590 *outbuf = '\0';
591 os << "(" ;
592 for( const char * src = buf; *src != '\0'; ++src )
594 switch( *src )
596 case '(':
597 os << "\\(" ;
598 break;
599 case ')':
600 os << "\\)" ;
601 break;
602 case '\\':
603 os << "\\\\" ;
604 break;
605 case '\n':
606 os << ")] TJ T* [(" ;
607 break;
608 default:
609 os << *src ;
612 os << ") " ;
614 else
616 if( ki == kernings_.end( ) )
618 throw Exceptions::InternalError( "Short of kerning values in KernedText::writePDFVectorTo." );
620 os << 1000 * *ki << " " ;
621 ++ki;
624 if( ki != kernings_.end( ) )
626 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
629 os << "] TJ " << std::endl ;
632 void
633 Lang::KernedText::measure( Lang::Transform2D * textMatrix, Lang::Transform2D * textLineMatrix, Concrete::Length * xmin, Concrete::Length * ymin, Concrete::Length * xmax, Concrete::Length * ymax ) const
635 iconv_t converter = Helpers::requireUTF8ToMacRomanConverter( );
637 RefCountPtr< FontMetrics::WritingDirectionMetrics > horizontalMetrics = textState_->font_->metrics( )->horizontalMetrics_;
638 if( horizontalMetrics == NullPtr< FontMetrics::WritingDirectionMetrics >( ) )
640 throw Exceptions::FontMetricsError( textState_->font_->fontName( ), strrefdup( "No horizontal metrics defined." ) );
642 const FontMetrics::CharacterMetrics * defaultCharMetrics = horizontalMetrics->charData_[ 0 ];
644 Concrete::Length ySize = textState_->size_;
645 Concrete::Length xSize = ySize * textState_->horizontalScaling_;
646 Concrete::Length characterTrackKern = textState_->horizontalScaling_ * textState_->characterSpacing_;
647 Concrete::Length wordTrackKern = textState_->horizontalScaling_ * textState_->wordSpacing_;
649 size_t bufSize = maxLength_ + 1; // This will be enough if MacRoman coding is used, since this encoding uses only one byte per character.
650 // The extra one byte will be used to terminate the string.
651 char * buf = new char[ bufSize ];
652 DeleteOnExit< char > bufDeleter( buf );
654 if( textLineMatrix->isTranslation( ) )
656 Concrete::Length x0 = textLineMatrix->xt_;
657 Concrete::Length y0 = textLineMatrix->yt_ + textState_->riseConcrete( );
658 Concrete::Length xpos = 0;
660 typedef typeof strings_ ListType;
661 std::list< double >::const_iterator ki = kernings_.begin( );
662 for( ListType::const_iterator i = strings_.begin( ); i != strings_.end( ); ++i )
664 if( *i != NullPtr< const Lang::String >( ) )
666 const char * inbuf = (*i)->val_.getPtr( );
667 char * outbuf = buf;
668 size_t inbytesleft = strlen( inbuf );
669 size_t outbytesleft = bufSize - 1;
670 // The ICONV_CAST macro is defined in config.h.
671 size_t count = iconv( converter,
672 ICONV_CAST( & inbuf ), & inbytesleft,
673 & outbuf, & outbytesleft );
674 if( count == (size_t)(-1) )
676 if( errno == EILSEQ )
678 throw Exceptions::MiscellaneousRequirement( "It is suspected that one of the UFT-8 characters used in showed text has no MacRoman representation." );
680 else if( errno == EINVAL )
682 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
684 else if( errno == E2BIG )
686 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to MacRoman conversion was too small." );
688 else
690 std::ostringstream msg;
691 msg << "iconv failed with an unrecognized error code: " << errno ;
692 throw Exceptions::InternalError( strrefdup( msg ) );
695 *outbuf = '\0';
696 for( const char * src = buf; *src != '\0'; ++src )
698 switch( *src )
700 case ' ':
702 // Observe textState_->wordSpacing_
703 // In addition, it seems reasonable to not let the space character affect the bounding box.
704 const FontMetrics::CharacterMetrics * charMetrics = horizontalMetrics->charByCode( (unsigned char)( 32 ) );
705 xpos += xSize * charMetrics->horizontalCharWidthX_;
706 xpos += characterTrackKern;
707 xpos += wordTrackKern;
709 break;
710 case '\n':
712 textMatrix->prependShift( Concrete::Coords2D( 0, - textState_->leadingConcrete( ) ) );
713 textLineMatrix->replaceBy( *textMatrix );
714 x0 = textLineMatrix->xt_;
715 y0 = textLineMatrix->yt_ + textState_->riseConcrete( );
716 xpos = 0;
718 break;
719 default:
721 // Observe textState_->characterSpacing_
722 unsigned char currentChar = *reinterpret_cast< const unsigned char * >( src );
723 const FontMetrics::CharacterMetrics * charMetrics = horizontalMetrics->charByCode( currentChar );
724 if( Computation::fontMetricGuessIsError && charMetrics == defaultCharMetrics )
726 std::ostringstream msg;
727 msg << "Character at offset " << src - buf << " in \"" << buf << "\" was not found in font metrics (and according to your options, guessing is not OK)." ;
728 throw Exceptions::FontMetricsError( textState_->font_->fontName( ), strrefdup( msg ) );
730 *xmin = std::min( *xmin, x0 + xpos + xSize * charMetrics->xmin_ );
731 *ymin = std::min( *ymin, y0 + ySize * charMetrics->ymin_ );
732 *xmax = std::max( *xmax, x0 + xpos + xSize * charMetrics->xmax_ );
733 *ymax = std::max( *ymax, y0 + ySize * charMetrics->ymax_ );
734 xpos += xSize * charMetrics->horizontalCharWidthX_;
735 xpos += characterTrackKern;
740 else
742 if( ki == kernings_.end( ) )
744 throw Exceptions::InternalError( "Short of kerning values in KernedText::measure." );
746 xpos -= xSize * *ki;
747 ++ki;
750 if( ki != kernings_.end( ) )
752 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
755 textLineMatrix->prependXShift( xpos );
757 else
759 Concrete::Length rise = textState_->riseConcrete( );
760 // std::cerr << "@<< @stroking:RGB_RED | [stroke [shift " << Helpers::shapesFormat( Concrete::Coords2D( 0, 0 ).transformed( *textLineMatrix ) ) << "] [] [circle 2bp]]" << std::endl ;
762 typedef typeof strings_ ListType;
763 std::list< double >::const_iterator ki = kernings_.begin( );
764 for( ListType::const_iterator i = strings_.begin( ); i != strings_.end( ); ++i )
766 if( *i != NullPtr< const Lang::String >( ) )
768 const char * inbuf = (*i)->val_.getPtr( );
769 char * outbuf = buf;
770 size_t inbytesleft = strlen( inbuf );
771 size_t outbytesleft = bufSize - 1;
772 // The ICONV_CAST macro is defined in config.h.
773 size_t count = iconv( converter,
774 ICONV_CAST( & inbuf ), & inbytesleft,
775 & outbuf, & outbytesleft );
776 if( count == (size_t)(-1) )
778 if( errno == EILSEQ )
780 throw Exceptions::MiscellaneousRequirement( "It is suspected that one of the UFT-8 characters used in showed text has no MacRoman representation." );
782 else if( errno == EINVAL )
784 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
786 else if( errno == E2BIG )
788 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to MacRoman conversion was too small." );
790 else
792 std::ostringstream msg;
793 msg << "iconv failed with an unrecognized error code: " << errno ;
794 throw Exceptions::InternalError( strrefdup( msg ) );
797 *outbuf = '\0';
798 for( const char * src = buf; *src != '\0'; ++src )
800 switch( *src )
802 case ' ':
804 // Observe textState_->wordSpacing_
805 // In addition, it seems reasonable to not let the space character affect the bounding box.
806 const FontMetrics::CharacterMetrics * charMetrics = horizontalMetrics->charByCode( (unsigned char)( 32 ) );
807 textLineMatrix->prependXShift( xSize * charMetrics->horizontalCharWidthX_ + characterTrackKern + wordTrackKern );
808 // std::cerr << "@<< @stroking:RGB_BLUE | [stroke [shift " << Helpers::shapesFormat( Concrete::Coords2D( 0, 0 ).transformed( *textLineMatrix ) ) << "] [] [circle 2bp]]" << std::endl ;
810 break;
811 case '\n':
813 textMatrix->prependShift( Concrete::Coords2D( 0, - textState_->leadingConcrete( ) ) );
814 textLineMatrix->replaceBy( *textMatrix );
815 // std::cerr << "@<< @stroking:RGB_RED | [stroke [shift " << Helpers::shapesFormat( Concrete::Coords2D( 0, 0 ).transformed( *textLineMatrix ) ) << "] [] [circle 2bp]]" << std::endl ;
817 break;
818 default:
820 // Observe textState_->characterSpacing_
821 unsigned char currentChar = *reinterpret_cast< const unsigned char * >( src );
822 const FontMetrics::CharacterMetrics * charMetrics = horizontalMetrics->charByCode( currentChar );
823 if( Computation::fontMetricGuessIsError && charMetrics == defaultCharMetrics )
825 std::ostringstream msg;
826 msg << "Character at offset " << src - buf << " in \"" << buf << "\" was not found in the font metrics (and according to your options, guessing is not OK)." ;
827 throw Exceptions::FontMetricsError( textState_->font_->fontName( ), strrefdup( msg ) );
830 Concrete::Coords2D x0y0 = Concrete::Coords2D( xSize * charMetrics->xmin_, ySize * charMetrics->ymin_ + rise ).transformed( *textLineMatrix );
831 Concrete::Coords2D x0y1 = Concrete::Coords2D( xSize * charMetrics->xmin_, ySize * charMetrics->ymax_ + rise ).transformed( *textLineMatrix );
832 Concrete::Coords2D x1y0 = Concrete::Coords2D( xSize * charMetrics->xmax_, ySize * charMetrics->ymin_ + rise ).transformed( *textLineMatrix );
833 Concrete::Coords2D x1y1 = Concrete::Coords2D( xSize * charMetrics->xmax_, ySize * charMetrics->ymax_ + rise ).transformed( *textLineMatrix );
834 // std::cerr << "@<< @width:0.3bp | [stroke "<< Helpers::shapesFormat( x0y0 ) << "--" << Helpers::shapesFormat( x0y1 ) << "--" << Helpers::shapesFormat( x1y1 ) << "--" << Helpers::shapesFormat( x1y0 ) << "--cycle]" << std::endl ;
836 *xmin = std::min( *xmin, x0y0.x_ );
837 *ymin = std::min( *ymin, x0y0.y_ );
838 *xmax = std::max( *xmax, x0y0.x_ );
839 *ymax = std::max( *ymax, x0y0.y_ );
841 *xmin = std::min( *xmin, x0y1.x_ );
842 *ymin = std::min( *ymin, x0y1.y_ );
843 *xmax = std::max( *xmax, x0y1.x_ );
844 *ymax = std::max( *ymax, x0y1.y_ );
846 *xmin = std::min( *xmin, x1y0.x_ );
847 *ymin = std::min( *ymin, x1y0.y_ );
848 *xmax = std::max( *xmax, x1y0.x_ );
849 *ymax = std::max( *ymax, x1y0.y_ );
851 *xmin = std::min( *xmin, x1y1.x_ );
852 *ymin = std::min( *ymin, x1y1.y_ );
853 *xmax = std::max( *xmax, x1y1.x_ );
854 *ymax = std::max( *ymax, x1y1.y_ );
856 textLineMatrix->prependXShift( xSize * charMetrics->horizontalCharWidthX_ + characterTrackKern );
857 // std::cerr << "@<< [stroke [shift " << Helpers::shapesFormat( Concrete::Coords2D( 0, 0 ).transformed( *textLineMatrix ) ) << "] [] [circle 2bp]]" << std::endl ;
862 else
864 if( ki == kernings_.end( ) )
866 throw Exceptions::InternalError( "Short of kerning values in KernedText::measure." );
868 textLineMatrix->prependXShift( - xSize * *ki );
869 ++ki;
872 if( ki != kernings_.end( ) )
874 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
879 void
880 Lang::KernedText::push( Lang::KernedText * dst ) const
882 typedef typeof strings_ ListType;
883 std::list< double >::const_iterator ki = kernings_.begin( );
884 for( ListType::const_iterator i = strings_.begin( ); i != strings_.end( ); ++i )
886 if( *i != NullPtr< const Lang::String >( ) )
888 dst->pushString( *i );
890 else
892 dst->pushKerning( *ki );
893 ++ki;
899 void
900 Lang::KernedText::gcMark( Kernel::GCMarkedSet & marked )
902 typedef typeof strings_ ListType;
903 for( ListType::const_iterator i = strings_.begin( ); i != strings_.end( ); ++i )
905 if( *i != NullPtr< const Lang::String >( ) )
907 const_cast< Lang::String * >( i->getPtr( ) )->gcMark( marked );
912 Lang::TextNewline::TextNewline( const Concrete::Length tx, const Concrete::Length ty )
913 : t_( tx, ty )
916 Lang::TextNewline::~TextNewline( )
919 void
920 Lang::TextNewline::show( std::ostream & os ) const
922 os << "Newline with offset in bp: " << t_ ;
925 void
926 Lang::TextNewline::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf, bool clip ) const
928 os << t_ << " Td " ;
931 void
932 Lang::TextNewline::measure( Lang::Transform2D * textMatrix, Lang::Transform2D * textLineMatrix, Concrete::Length * xmin, Concrete::Length * ymin, Concrete::Length * xmax, Concrete::Length * ymax ) const
934 textMatrix->prependShift( t_ );
935 textLineMatrix->replaceBy( *textMatrix );
938 void
939 Lang::TextNewline::gcMark( Kernel::GCMarkedSet & marked )
942 Lang::TextMoveto::TextMoveto( const RefCountPtr< const Lang::Transform2D > & tf )
943 : tf_( tf )
946 Lang::TextMoveto::~TextMoveto( )
949 void
950 Lang::TextMoveto::show( std::ostream & os ) const
952 os << "Moveto command" ;
955 void
956 Lang::TextMoveto::shipout( std::ostream & os, Kernel::PageContentStates * pdfState, const Lang::Transform2D & tf, bool clip ) const
958 Lang::Transform2D( tf, *tf_ ).shipout( os );
959 os << " Tm" << std::endl ;
962 void
963 Lang::TextMoveto::measure( Lang::Transform2D * textMatrix, Lang::Transform2D * textLineMatrix, Concrete::Length * xmin, Concrete::Length * ymin, Concrete::Length * xmax, Concrete::Length * ymax ) const
965 textMatrix->replaceBy( *tf_ );
966 textLineMatrix->replaceBy( *textMatrix );
969 void
970 Lang::TextMoveto::gcMark( Kernel::GCMarkedSet & marked )
972 const_cast< Lang::Transform2D * >( tf_.getPtr( ) )->gcMark( marked );
977 typedef enum { FILL = 0, STROKE, FILLSTROKE, INVISIBLE, FILLCLIP, STROKECLIP, FILLSTROKECLIP, CLIP, UNDEFINED } ValueType;
978 ValueType mode_;
980 Lang::TextRenderingMode::TextRenderingMode( const ValueType & mode )
981 : mode_( mode )
984 Lang::TextRenderingMode::TextRenderingMode( bool fill, bool stroke, bool clip )
986 switch( ( fill ? 0x01 : 0x00 ) +
987 ( stroke ? 0x02 : 0x00 ) +
988 ( clip ? 0x04 : 0x00 ) )
990 case 0x00:
991 mode_ = INVISIBLE;
992 break;
993 case 0x01:
994 mode_ = FILL;
995 break;
996 case 0x02:
997 mode_ = STROKE;
998 break;
999 case 0x03:
1000 mode_ = FILLSTROKE;
1001 break;
1002 case 0x04:
1003 mode_ = CLIP;
1004 break;
1005 case 0x05:
1006 mode_ = FILLCLIP;
1007 break;
1008 case 0x06:
1009 mode_ = STROKECLIP;
1010 break;
1011 case 0x07:
1012 mode_ = FILLSTROKECLIP;
1013 break;
1014 default:
1015 throw Exceptions::InternalError( "Semi-static switch out of range in TextRenderingMode::TextRenderingMode." );
1019 Lang::TextRenderingMode::ValueType
1020 Lang::TextRenderingMode::clipMode( ValueType mode )
1022 switch( mode )
1024 case INVISIBLE:
1025 return CLIP;
1026 case FILL:
1027 return FILLCLIP;
1028 case STROKE:
1029 return STROKECLIP;
1030 case FILLSTROKE:
1031 return FILLSTROKECLIP;
1032 default:
1033 return UNDEFINED;
1037 Lang::TextRenderingMode::~TextRenderingMode( )
1040 RefCountPtr< const Lang::Class > Lang::TextRenderingMode::TypeID( new Lang::SystemFinalClass( strrefdup( "TextRenderingMode" ) ) );
1041 TYPEINFOIMPL( TextRenderingMode );
1044 Lang::CharacterSpacingBinding::CharacterSpacingBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, const Concrete::Length spacing )
1045 : bindingExpr_( bindingExpr ), spacing_( spacing ), isRelative_( false ), id_( id )
1048 Lang::CharacterSpacingBinding::CharacterSpacingBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, const double r )
1049 : bindingExpr_( bindingExpr ), spacing_( r ), isRelative_( true ), id_( id )
1052 Lang::CharacterSpacingBinding::~CharacterSpacingBinding( )
1055 void
1056 Lang::CharacterSpacingBinding::bind( MapType & bindings, Kernel::SystemDynamicVariables ** sysBindings ) const
1058 if( *sysBindings == 0 )
1060 *sysBindings = new Kernel::SystemDynamicVariables( );
1061 Kernel::TextState * newState = new Kernel::TextState( );
1062 if( isRelative_ )
1064 newState->setCharacterSpacing( Concrete::Length::offtype( spacing_ ) );
1066 else
1068 newState->setCharacterSpacing( spacing_ );
1070 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1071 return;
1074 if( (*sysBindings)->textState_ == NullPtr< const Kernel::TextState >( ) )
1076 Kernel::TextState * newState = new Kernel::TextState( );
1077 if( isRelative_ )
1079 newState->setCharacterSpacing( Concrete::Length::offtype( spacing_ ) );
1081 else
1083 newState->setCharacterSpacing( spacing_ );
1085 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1086 return;
1089 Kernel::TextState * newState = new Kernel::TextState( *((*sysBindings)->textState_) );
1091 if( newState->hasCharacterSpacing( ) )
1093 throw Exceptions::MultipleDynamicBind( id_, bindingExpr_->idLoc( ), Ast::THE_UNKNOWN_LOCATION );
1096 if( isRelative_ )
1098 newState->setCharacterSpacing( Concrete::Length::offtype( spacing_ ) );
1100 else
1102 newState->setCharacterSpacing( spacing_ );
1104 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1107 void
1108 Lang::CharacterSpacingBinding::show( std::ostream & os ) const
1110 os << Interaction::DYNAMIC_VARIABLE_PREFIX << id_ << ":" ;
1111 if( isRelative_ )
1113 os << Concrete::Length::offtype( spacing_ ) ;
1115 else
1117 os << spacing_ / Interaction::displayUnit << Interaction::displayUnitName ;
1121 void
1122 Lang::CharacterSpacingBinding::gcMark( Kernel::GCMarkedSet & marked )
1126 Lang::WordSpacingBinding::WordSpacingBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, const Concrete::Length spacing )
1127 : bindingExpr_( bindingExpr ), spacing_( spacing ), isRelative_( false ), id_( id )
1130 Lang::WordSpacingBinding::WordSpacingBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, const double r )
1131 : bindingExpr_( bindingExpr ), spacing_( r ), isRelative_( true ), id_( id )
1134 Lang::WordSpacingBinding::~WordSpacingBinding( )
1137 void
1138 Lang::WordSpacingBinding::bind( MapType & bindings, Kernel::SystemDynamicVariables ** sysBindings ) const
1140 if( *sysBindings == 0 )
1142 *sysBindings = new Kernel::SystemDynamicVariables( );
1143 Kernel::TextState * newState = new Kernel::TextState( );
1144 if( isRelative_ )
1146 newState->setWordSpacing( Concrete::Length::offtype( spacing_ ) );
1148 else
1150 newState->setWordSpacing( spacing_ );
1152 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1153 return;
1156 if( (*sysBindings)->textState_ == NullPtr< const Kernel::TextState >( ) )
1158 Kernel::TextState * newState = new Kernel::TextState( );
1159 if( isRelative_ )
1161 newState->setWordSpacing( Concrete::Length::offtype( spacing_ ) );
1163 else
1165 newState->setWordSpacing( spacing_ );
1167 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1168 return;
1171 Kernel::TextState * newState = new Kernel::TextState( *((*sysBindings)->textState_) );
1173 if( newState->hasWordSpacing( ) )
1175 throw Exceptions::MultipleDynamicBind( id_, bindingExpr_->idLoc( ), Ast::THE_UNKNOWN_LOCATION );
1178 if( isRelative_ )
1180 newState->setWordSpacing( Concrete::Length::offtype( spacing_ ) );
1182 else
1184 newState->setWordSpacing( spacing_ );
1186 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1189 void
1190 Lang::WordSpacingBinding::show( std::ostream & os ) const
1192 os << Interaction::DYNAMIC_VARIABLE_PREFIX << id_ << ":" ;
1193 if( isRelative_ )
1195 os << Concrete::Length::offtype( spacing_ ) ;
1197 else
1199 os << spacing_ / Interaction::displayUnit << Interaction::displayUnitName ;
1203 void
1204 Lang::WordSpacingBinding::gcMark( Kernel::GCMarkedSet & marked )
1208 Lang::HorizontalScalingBinding::HorizontalScalingBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, double scaling )
1209 : bindingExpr_( bindingExpr ), scaling_( scaling ), id_( id )
1212 Lang::HorizontalScalingBinding::~HorizontalScalingBinding( )
1215 void
1216 Lang::HorizontalScalingBinding::bind( MapType & bindings, Kernel::SystemDynamicVariables ** sysBindings ) const
1218 if( *sysBindings == 0 )
1220 *sysBindings = new Kernel::SystemDynamicVariables( );
1221 Kernel::TextState * newState = new Kernel::TextState( );
1222 newState->horizontalScaling_ = scaling_;
1223 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1224 return;
1227 if( (*sysBindings)->textState_ == NullPtr< const Kernel::TextState >( ) )
1229 Kernel::TextState * newState = new Kernel::TextState( );
1230 newState->horizontalScaling_ = scaling_;
1231 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1232 return;
1235 Kernel::TextState * newState = new Kernel::TextState( *((*sysBindings)->textState_) );
1237 if( ! IS_NAN( newState->horizontalScaling_ ) )
1239 throw Exceptions::MultipleDynamicBind( id_, bindingExpr_->idLoc( ), Ast::THE_UNKNOWN_LOCATION );
1242 newState->horizontalScaling_ = scaling_;
1243 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1246 void
1247 Lang::HorizontalScalingBinding::show( std::ostream & os ) const
1249 os << Interaction::DYNAMIC_VARIABLE_PREFIX << id_ << ":"
1250 << scaling_ ;
1253 void
1254 Lang::HorizontalScalingBinding::gcMark( Kernel::GCMarkedSet & marked )
1258 Lang::LeadingBinding::LeadingBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, const Concrete::Length ty )
1259 : bindingExpr_( bindingExpr ), ty_( ty ), isRelative_( false ), id_( id )
1262 Lang::LeadingBinding::LeadingBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, const double r )
1263 : bindingExpr_( bindingExpr ), ty_( r ), isRelative_( true ), id_( id )
1266 Lang::LeadingBinding::~LeadingBinding( )
1269 void
1270 Lang::LeadingBinding::bind( MapType & bindings, Kernel::SystemDynamicVariables ** sysBindings ) const
1272 if( *sysBindings == 0 )
1274 *sysBindings = new Kernel::SystemDynamicVariables( );
1275 Kernel::TextState * newState = new Kernel::TextState( );
1276 if( isRelative_ )
1278 newState->setLeading( Concrete::Length::offtype( ty_ ) );
1280 else
1282 newState->setLeading( ty_ );
1284 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1285 return;
1288 if( (*sysBindings)->textState_ == NullPtr< const Kernel::TextState >( ) )
1290 Kernel::TextState * newState = new Kernel::TextState( );
1291 if( isRelative_ )
1293 newState->setLeading( Concrete::Length::offtype( ty_ ) );
1295 else
1297 newState->setLeading( ty_ );
1299 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1300 return;
1303 Kernel::TextState * newState = new Kernel::TextState( *((*sysBindings)->textState_) );
1305 if( newState->hasLeading( ) )
1307 throw Exceptions::MultipleDynamicBind( id_, bindingExpr_->idLoc( ), Ast::THE_UNKNOWN_LOCATION );
1310 if( isRelative_ )
1312 newState->setLeading( Concrete::Length::offtype( ty_ ) );
1314 else
1316 newState->setLeading( ty_ );
1318 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1321 void
1322 Lang::LeadingBinding::show( std::ostream & os ) const
1324 os << Interaction::DYNAMIC_VARIABLE_PREFIX << id_ << ":" ;
1325 if( isRelative_ )
1327 os << Concrete::Length::offtype( ty_ ) ;
1329 else
1331 os << ty_ / Interaction::displayUnit << Interaction::displayUnitName ;
1335 void
1336 Lang::LeadingBinding::gcMark( Kernel::GCMarkedSet & marked )
1340 Lang::FontBinding::FontBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, const RefCountPtr< const Lang::Font > & font )
1341 : bindingExpr_( bindingExpr ), font_( font ), id_( id )
1344 Lang::FontBinding::~FontBinding( )
1347 void
1348 Lang::FontBinding::bind( MapType & bindings, Kernel::SystemDynamicVariables ** sysBindings ) const
1350 if( *sysBindings == 0 )
1352 *sysBindings = new Kernel::SystemDynamicVariables( );
1353 Kernel::TextState * newState = new Kernel::TextState( );
1354 newState->font_ = font_;
1355 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1356 return;
1359 if( (*sysBindings)->textState_ == NullPtr< const Kernel::TextState >( ) )
1361 Kernel::TextState * newState = new Kernel::TextState( );
1362 newState->font_ = font_;
1363 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1364 return;
1367 Kernel::TextState * newState = new Kernel::TextState( *((*sysBindings)->textState_) );
1369 if( newState->font_ != NullPtr< const Lang::Font >( ) )
1371 throw Exceptions::MultipleDynamicBind( id_, bindingExpr_->idLoc( ), Ast::THE_UNKNOWN_LOCATION );
1374 newState->font_ = font_;
1375 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1378 void
1379 Lang::FontBinding::show( std::ostream & os ) const
1381 os << Interaction::DYNAMIC_VARIABLE_PREFIX << id_ << ":" ;
1382 font_->show( os );
1385 void
1386 Lang::FontBinding::gcMark( Kernel::GCMarkedSet & marked )
1388 const_cast< Lang::Font * >( font_.getPtr( ) )->gcMark( marked );
1392 Lang::TextSizeBinding::TextSizeBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, const Concrete::Length size )
1393 : bindingExpr_( bindingExpr ), size_( size ), id_( id )
1396 Lang::TextSizeBinding::~TextSizeBinding( )
1399 void
1400 Lang::TextSizeBinding::bind( MapType & bindings, Kernel::SystemDynamicVariables ** sysBindings ) const
1402 if( *sysBindings == 0 )
1404 *sysBindings = new Kernel::SystemDynamicVariables( );
1405 Kernel::TextState * newState = new Kernel::TextState( );
1406 newState->size_ = size_;
1407 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1408 return;
1411 if( (*sysBindings)->textState_ == NullPtr< const Kernel::TextState >( ) )
1413 Kernel::TextState * newState = new Kernel::TextState( );
1414 newState->size_ = size_;
1415 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1416 return;
1419 Kernel::TextState * newState = new Kernel::TextState( *((*sysBindings)->textState_) );
1421 if( ! IS_NAN( newState->size_ ) )
1423 throw Exceptions::MultipleDynamicBind( id_, bindingExpr_->idLoc( ), Ast::THE_UNKNOWN_LOCATION );
1426 newState->size_ = size_;
1427 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1430 void
1431 Lang::TextSizeBinding::show( std::ostream & os ) const
1433 os << Interaction::DYNAMIC_VARIABLE_PREFIX << id_ << ":"
1434 << size_ / Interaction::displayUnit << Interaction::displayUnitName ;
1437 void
1438 Lang::TextSizeBinding::gcMark( Kernel::GCMarkedSet & marked )
1442 Lang::TextRenderingModeBinding::TextRenderingModeBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, const Lang::TextRenderingMode::ValueType mode )
1443 : bindingExpr_( bindingExpr ), mode_( mode ), id_( id )
1446 Lang::TextRenderingModeBinding::~TextRenderingModeBinding( )
1449 void
1450 Lang::TextRenderingModeBinding::bind( MapType & bindings, Kernel::SystemDynamicVariables ** sysBindings ) const
1452 if( *sysBindings == 0 )
1454 *sysBindings = new Kernel::SystemDynamicVariables( );
1455 Kernel::TextState * newState = new Kernel::TextState( );
1456 newState->mode_ = mode_;
1457 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1458 return;
1461 if( (*sysBindings)->textState_ == NullPtr< const Kernel::TextState >( ) )
1463 Kernel::TextState * newState = new Kernel::TextState( );
1464 newState->mode_ = mode_;
1465 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1466 return;
1469 Kernel::TextState * newState = new Kernel::TextState( *((*sysBindings)->textState_) );
1471 if( newState->mode_ != Lang::TextRenderingMode::UNDEFINED )
1473 throw Exceptions::MultipleDynamicBind( id_, bindingExpr_->idLoc( ), Ast::THE_UNKNOWN_LOCATION );
1476 newState->mode_ = mode_;
1477 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1480 void
1481 Lang::TextRenderingModeBinding::show( std::ostream & os ) const
1483 os << Interaction::DYNAMIC_VARIABLE_PREFIX << id_ << ":"
1484 << "<internal-enum>" ;
1487 void
1488 Lang::TextRenderingModeBinding::gcMark( Kernel::GCMarkedSet & marked )
1492 Lang::TextRiseBinding::TextRiseBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, const Concrete::Length ty )
1493 : bindingExpr_( bindingExpr ), ty_( ty ), isRelative_( false ), id_( id )
1496 Lang::TextRiseBinding::TextRiseBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, const double r )
1497 : bindingExpr_( bindingExpr ), ty_( r ), isRelative_( true ), id_( id )
1500 Lang::TextRiseBinding::~TextRiseBinding( )
1503 void
1504 Lang::TextRiseBinding::bind( MapType & bindings, Kernel::SystemDynamicVariables ** sysBindings ) const
1506 if( *sysBindings == 0 )
1508 *sysBindings = new Kernel::SystemDynamicVariables( );
1509 Kernel::TextState * newState = new Kernel::TextState( );
1510 if( isRelative_ )
1512 newState->setRise( Concrete::Length::offtype( ty_ ) );
1514 else
1516 newState->setRise( ty_ );
1518 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1519 return;
1522 if( (*sysBindings)->textState_ == NullPtr< const Kernel::TextState >( ) )
1524 Kernel::TextState * newState = new Kernel::TextState( );
1525 if( isRelative_ )
1527 newState->setRise( Concrete::Length::offtype( ty_ ) );
1529 else
1531 newState->setRise( ty_ );
1533 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1534 return;
1537 Kernel::TextState * newState = new Kernel::TextState( *((*sysBindings)->textState_) );
1539 if( newState->hasRise( ) )
1541 throw Exceptions::MultipleDynamicBind( id_, bindingExpr_->idLoc( ), Ast::THE_UNKNOWN_LOCATION );
1544 if( isRelative_ )
1546 newState->setRise( Concrete::Length::offtype( ty_ ) );
1548 else
1550 newState->setRise( ty_ );
1552 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1555 void
1556 Lang::TextRiseBinding::show( std::ostream & os ) const
1558 os << Interaction::DYNAMIC_VARIABLE_PREFIX << id_ << ":" ;
1559 if( isRelative_ )
1561 os << Concrete::Length::offtype( ty_ ) ;
1563 else
1565 os << ty_ / Interaction::displayUnit << Interaction::displayUnitName ;
1569 void
1570 Lang::TextRiseBinding::gcMark( Kernel::GCMarkedSet & marked )
1574 Lang::TextKnockoutBinding::TextKnockoutBinding( const char * id, const Ast::DynamicBindingExpression * bindingExpr, bool knockout )
1575 : bindingExpr_( bindingExpr ), knockout_( knockout ), id_( id )
1578 Lang::TextKnockoutBinding::~TextKnockoutBinding( )
1581 void
1582 Lang::TextKnockoutBinding::bind( MapType & bindings, Kernel::SystemDynamicVariables ** sysBindings ) const
1584 if( *sysBindings == 0 )
1586 *sysBindings = new Kernel::SystemDynamicVariables( );
1587 Kernel::TextState * newState = new Kernel::TextState( );
1588 newState->knockout_ = knockout_;
1589 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1590 return;
1593 if( (*sysBindings)->textState_ == NullPtr< const Kernel::TextState >( ) )
1595 Kernel::TextState * newState = new Kernel::TextState( );
1596 newState->knockout_ = knockout_;
1597 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1598 return;
1601 Kernel::TextState * newState = new Kernel::TextState( *((*sysBindings)->textState_) );
1603 if( ( newState->knockout_ & Kernel::TextState::KNOCKOUT_UNDEFINED_BIT ) != 0 )
1605 throw Exceptions::MultipleDynamicBind( id_, bindingExpr_->idLoc( ), Ast::THE_UNKNOWN_LOCATION );
1608 newState->knockout_ = ( knockout_ ? Kernel::TextState::KNOCKOUT_FLAG_BIT : 0 );
1609 (*sysBindings)->textState_ = RefCountPtr< const Kernel::TextState >( newState );
1612 void
1613 Lang::TextKnockoutBinding::show( std::ostream & os ) const
1615 os << Interaction::DYNAMIC_VARIABLE_PREFIX << id_ << ":"
1616 << ( knockout_ ? "true" : "false" ) ;
1619 void
1620 Lang::TextKnockoutBinding::gcMark( Kernel::GCMarkedSet & marked )
1624 Kernel::CharacterSpacingDynamicVariableProperties::CharacterSpacingDynamicVariableProperties( const char * name )
1625 : Kernel::DynamicVariableProperties( name )
1628 Kernel::CharacterSpacingDynamicVariableProperties::~CharacterSpacingDynamicVariableProperties( )
1631 Kernel::VariableHandle
1632 Kernel::CharacterSpacingDynamicVariableProperties::fetch( const Kernel::PassedDyn & dyn ) const
1634 RefCountPtr< const Kernel::TextState > textState = dyn->getTextState( );
1635 return Kernel::VariableHandle( new Kernel::Variable( textState->characterSpacing( ) ) );
1638 void
1639 Kernel::CharacterSpacingDynamicVariableProperties::makeBinding( Kernel::VariableHandle val, const Ast::DynamicBindingExpression * bindingExpr, Kernel::EvalState * evalState ) const
1641 RefCountPtr< const Lang::Value > valUntyped = val->getUntyped( );
1643 Kernel::ContRef cont = evalState->cont_;
1647 typedef const Lang::Length ArgType;
1648 RefCountPtr< ArgType > spacing = Helpers::try_cast_CoreArgument< ArgType >( valUntyped );
1649 cont->takeValue( Kernel::ValueRef( new Lang::CharacterSpacingBinding( name_, bindingExpr, spacing->get( ) ) ),
1650 evalState );
1651 return;
1653 catch( const NonLocalExit::NotThisType & ball )
1655 /* Wrong type; never mind!.. but see below!
1661 typedef const Lang::Float ArgType;
1662 RefCountPtr< ArgType > spacing = Helpers::try_cast_CoreArgument< ArgType >( valUntyped );
1663 cont->takeValue( Kernel::ValueRef( new Lang::CharacterSpacingBinding( name_, bindingExpr, spacing->val_ ) ),
1664 evalState );
1665 return;
1667 catch( const NonLocalExit::NotThisType & ball )
1669 /* Wrong type; never mind!.. but see below!
1673 throw Exceptions::TypeMismatch( bindingExpr->exprLoc( ), valUntyped->getTypeName( ), Helpers::typeSetString( Lang::Length::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
1677 Kernel::WordSpacingDynamicVariableProperties::WordSpacingDynamicVariableProperties( const char * name )
1678 : Kernel::DynamicVariableProperties( name )
1681 Kernel::WordSpacingDynamicVariableProperties::~WordSpacingDynamicVariableProperties( )
1684 Kernel::VariableHandle
1685 Kernel::WordSpacingDynamicVariableProperties::fetch( const Kernel::PassedDyn & dyn ) const
1687 RefCountPtr< const Kernel::TextState > textState = dyn->getTextState( );
1688 return Kernel::VariableHandle( new Kernel::Variable( textState->wordSpacing( ) ) );
1691 void
1692 Kernel::WordSpacingDynamicVariableProperties::makeBinding( Kernel::VariableHandle val, const Ast::DynamicBindingExpression * bindingExpr, Kernel::EvalState * evalState ) const
1694 RefCountPtr< const Lang::Value > valUntyped = val->getUntyped( );
1696 Kernel::ContRef cont = evalState->cont_;
1700 typedef const Lang::Length ArgType;
1701 RefCountPtr< ArgType > spacing = Helpers::try_cast_CoreArgument< ArgType >( valUntyped );
1702 cont->takeValue( Kernel::ValueRef( new Lang::WordSpacingBinding( name_, bindingExpr, spacing->get( ) ) ),
1703 evalState );
1704 return;
1706 catch( const NonLocalExit::NotThisType & ball )
1708 /* Wrong type; never mind!.. but see below!
1714 typedef const Lang::Float ArgType;
1715 RefCountPtr< ArgType > spacing = Helpers::try_cast_CoreArgument< ArgType >( valUntyped );
1716 cont->takeValue( Kernel::ValueRef( new Lang::WordSpacingBinding( name_, bindingExpr, spacing->val_ ) ),
1717 evalState );
1718 return;
1720 catch( const NonLocalExit::NotThisType & ball )
1722 /* Wrong type; never mind!.. but see below!
1726 throw Exceptions::TypeMismatch( bindingExpr->exprLoc( ), valUntyped->getTypeName( ), Helpers::typeSetString( Lang::Length::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
1730 Kernel::HorizontalScalingDynamicVariableProperties::HorizontalScalingDynamicVariableProperties( const char * name )
1731 : Kernel::DynamicVariableProperties( name )
1734 Kernel::HorizontalScalingDynamicVariableProperties::~HorizontalScalingDynamicVariableProperties( )
1737 Kernel::VariableHandle
1738 Kernel::HorizontalScalingDynamicVariableProperties::fetch( const Kernel::PassedDyn & dyn ) const
1740 RefCountPtr< const Kernel::TextState > textState = dyn->getTextState( );
1741 return Kernel::VariableHandle( Shapes::Helpers::newValHandle( new Lang::Float( textState->horizontalScaling_ ) ) );
1744 void
1745 Kernel::HorizontalScalingDynamicVariableProperties::makeBinding( Kernel::VariableHandle val, const Ast::DynamicBindingExpression * bindingExpr, Kernel::EvalState * evalState ) const
1747 RefCountPtr< const Lang::Float > scaling = val->getVal< const Lang::Float >( bindingExpr->exprLoc( ) );
1748 Kernel::ContRef cont = evalState->cont_;
1749 cont->takeValue( Kernel::ValueRef( new Lang::HorizontalScalingBinding( name_, bindingExpr, scaling->val_ ) ),
1750 evalState );
1754 Kernel::LeadingDynamicVariableProperties::LeadingDynamicVariableProperties( const char * name )
1755 : Kernel::DynamicVariableProperties( name )
1758 Kernel::LeadingDynamicVariableProperties::~LeadingDynamicVariableProperties( )
1761 Kernel::VariableHandle
1762 Kernel::LeadingDynamicVariableProperties::fetch( const Kernel::PassedDyn & dyn ) const
1764 RefCountPtr< const Kernel::TextState > textState = dyn->getTextState( );
1765 return Kernel::VariableHandle( new Kernel::Variable( textState->leading( ) ) );
1768 void
1769 Kernel::LeadingDynamicVariableProperties::makeBinding( Kernel::VariableHandle val, const Ast::DynamicBindingExpression * bindingExpr, Kernel::EvalState * evalState ) const
1771 RefCountPtr< const Lang::Value > valUntyped = val->getUntyped( );
1773 Kernel::ContRef cont = evalState->cont_;
1777 typedef const Lang::Length ArgType;
1778 RefCountPtr< ArgType > ty = Helpers::try_cast_CoreArgument< ArgType >( valUntyped );
1779 cont->takeValue( Kernel::ValueRef( new Lang::LeadingBinding( name_, bindingExpr, ty->get( ) ) ),
1780 evalState );
1781 return;
1783 catch( const NonLocalExit::NotThisType & ball )
1785 /* Wrong type; never mind!.. but see below!
1791 typedef const Lang::Float ArgType;
1792 RefCountPtr< ArgType > ty = Helpers::try_cast_CoreArgument< ArgType >( valUntyped );
1793 cont->takeValue( Kernel::ValueRef( new Lang::LeadingBinding( name_, bindingExpr, ty->val_ ) ),
1794 evalState );
1795 return;
1797 catch( const NonLocalExit::NotThisType & ball )
1799 /* Wrong type; never mind!.. but see below!
1803 throw Exceptions::TypeMismatch( bindingExpr->exprLoc( ), valUntyped->getTypeName( ), Helpers::typeSetString( Lang::Length::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
1807 Kernel::FontDynamicVariableProperties::FontDynamicVariableProperties( const char * name )
1808 : Kernel::DynamicVariableProperties( name )
1811 Kernel::FontDynamicVariableProperties::~FontDynamicVariableProperties( )
1814 Kernel::VariableHandle
1815 Kernel::FontDynamicVariableProperties::fetch( const Kernel::PassedDyn & dyn ) const
1817 RefCountPtr< const Kernel::TextState > textState = dyn->getTextState( );
1818 return Kernel::VariableHandle( new Kernel::Variable( textState->font_ ) );
1821 void
1822 Kernel::FontDynamicVariableProperties::makeBinding( Kernel::VariableHandle val, const Ast::DynamicBindingExpression * bindingExpr, Kernel::EvalState * evalState ) const
1824 Kernel::ContRef cont = evalState->cont_;
1825 cont->takeValue( Kernel::ValueRef( new Lang::FontBinding( name_, bindingExpr, val->getVal< const Lang::Font >( bindingExpr->exprLoc( ) ) ) ),
1826 evalState );
1830 Kernel::TextSizeDynamicVariableProperties::TextSizeDynamicVariableProperties( const char * name )
1831 : Kernel::DynamicVariableProperties( name )
1834 Kernel::TextSizeDynamicVariableProperties::~TextSizeDynamicVariableProperties( )
1837 Kernel::VariableHandle
1838 Kernel::TextSizeDynamicVariableProperties::fetch( const Kernel::PassedDyn & dyn ) const
1840 RefCountPtr< const Kernel::TextState > textState = dyn->getTextState( );
1841 return Kernel::VariableHandle( Shapes::Helpers::newValHandle( new Lang::Length( textState->size_ ) ) );
1844 void
1845 Kernel::TextSizeDynamicVariableProperties::makeBinding( Kernel::VariableHandle val, const Ast::DynamicBindingExpression * bindingExpr, Kernel::EvalState * evalState ) const
1847 RefCountPtr< const Lang::Length > size = val->getVal< const Lang::Length >( bindingExpr->exprLoc( ) );
1848 Kernel::ContRef cont = evalState->cont_;
1849 cont->takeValue( Kernel::ValueRef( new Lang::TextSizeBinding( name_, bindingExpr, size->get( ) ) ),
1850 evalState );
1854 Kernel::TextRenderingModeDynamicVariableProperties::TextRenderingModeDynamicVariableProperties( const char * name )
1855 : Kernel::DynamicVariableProperties( name )
1858 Kernel::TextRenderingModeDynamicVariableProperties::~TextRenderingModeDynamicVariableProperties( )
1861 Kernel::VariableHandle
1862 Kernel::TextRenderingModeDynamicVariableProperties::fetch( const Kernel::PassedDyn & dyn ) const
1864 RefCountPtr< const Kernel::TextState > textState = dyn->getTextState( );
1865 return Kernel::VariableHandle( Shapes::Helpers::newValHandle( new Lang::TextRenderingMode( textState->mode_ ) ) );
1868 void
1869 Kernel::TextRenderingModeDynamicVariableProperties::makeBinding( Kernel::VariableHandle val, const Ast::DynamicBindingExpression * bindingExpr, Kernel::EvalState * evalState ) const
1871 RefCountPtr< const Lang::TextRenderingMode > mode = val->getVal< const Lang::TextRenderingMode >( bindingExpr->exprLoc( ) );
1872 Kernel::ContRef cont = evalState->cont_;
1873 cont->takeValue( Kernel::ValueRef( new Lang::TextRenderingModeBinding( name_, bindingExpr, mode->mode_ ) ),
1874 evalState );
1878 Kernel::TextRiseDynamicVariableProperties::TextRiseDynamicVariableProperties( const char * name )
1879 : Kernel::DynamicVariableProperties( name )
1882 Kernel::TextRiseDynamicVariableProperties::~TextRiseDynamicVariableProperties( )
1885 Kernel::VariableHandle
1886 Kernel::TextRiseDynamicVariableProperties::fetch( const Kernel::PassedDyn & dyn ) const
1888 RefCountPtr< const Kernel::TextState > textState = dyn->getTextState( );
1889 return Kernel::VariableHandle( new Kernel::Variable( textState->rise( ) ) );
1892 void
1893 Kernel::TextRiseDynamicVariableProperties::makeBinding( Kernel::VariableHandle val, const Ast::DynamicBindingExpression * bindingExpr, Kernel::EvalState * evalState ) const
1895 RefCountPtr< const Lang::Value > valUntyped = val->getUntyped( );
1897 Kernel::ContRef cont = evalState->cont_;
1901 typedef const Lang::Length ArgType;
1902 RefCountPtr< ArgType > ty = Helpers::try_cast_CoreArgument< ArgType >( valUntyped );
1903 cont->takeValue( Kernel::ValueRef( new Lang::TextRiseBinding( name_, bindingExpr, ty->get( ) ) ),
1904 evalState );
1905 return;
1907 catch( const NonLocalExit::NotThisType & ball )
1909 /* Wrong type; never mind!.. but see below!
1915 typedef const Lang::Float ArgType;
1916 RefCountPtr< ArgType > ty = Helpers::try_cast_CoreArgument< ArgType >( valUntyped );
1917 cont->takeValue( Kernel::ValueRef( new Lang::TextRiseBinding( name_, bindingExpr, ty->val_ ) ),
1918 evalState );
1919 return;
1921 catch( const NonLocalExit::NotThisType & ball )
1923 /* Wrong type; never mind!.. but see below!
1927 throw Exceptions::TypeMismatch( bindingExpr->exprLoc( ), valUntyped->getTypeName( ), Helpers::typeSetString( Lang::Length::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
1931 Kernel::TextKnockoutDynamicVariableProperties::TextKnockoutDynamicVariableProperties( const char * name )
1932 : Kernel::DynamicVariableProperties( name )
1935 Kernel::TextKnockoutDynamicVariableProperties::~TextKnockoutDynamicVariableProperties( )
1938 Kernel::VariableHandle
1939 Kernel::TextKnockoutDynamicVariableProperties::fetch( const Kernel::PassedDyn & dyn ) const
1941 RefCountPtr< const Kernel::TextState > textState = dyn->getTextState( );
1942 return Kernel::VariableHandle( Shapes::Helpers::newValHandle( new Lang::Boolean( ( textState->knockout_ & Kernel::TextState::KNOCKOUT_FLAG_BIT ) != 0 ) ) );
1945 void
1946 Kernel::TextKnockoutDynamicVariableProperties::makeBinding( Kernel::VariableHandle val, const Ast::DynamicBindingExpression * bindingExpr, Kernel::EvalState * evalState ) const
1948 RefCountPtr< const Lang::Boolean > mode = val->getVal< const Lang::Boolean >( bindingExpr->exprLoc( ) );
1949 Kernel::ContRef cont = evalState->cont_;
1950 cont->takeValue( Kernel::ValueRef( new Lang::TextKnockoutBinding( name_, bindingExpr, mode->val_ ) ),
1951 evalState );
1956 Kernel::TextState::TextState( )
1957 : relativeFlags_( 0 ),
1958 characterSpacing_( Concrete::Length( std::numeric_limits< double >::signaling_NaN( ) ) ),
1959 wordSpacing_( Concrete::Length( std::numeric_limits< double >::signaling_NaN( ) ) ),
1960 horizontalScaling_( std::numeric_limits< double >::signaling_NaN( ) ),
1961 leading_( Concrete::Length( std::numeric_limits< double >::signaling_NaN( ) ) ),
1962 rise_( Concrete::Length( std::numeric_limits< double >::signaling_NaN( ) ) ),
1963 font_( NullPtr< const Lang::Font >( ) ),
1964 size_( Concrete::Length( std::numeric_limits< double >::signaling_NaN( ) ) ),
1965 mode_( Lang::TextRenderingMode::UNDEFINED ),
1966 knockout_( KNOCKOUT_UNDEFINED_BIT )
1969 Kernel::TextState::TextState( const Kernel::TextState & orig )
1970 : relativeFlags_( orig.relativeFlags_ ),
1971 characterSpacing_( orig.characterSpacing_ ),
1972 wordSpacing_( orig.wordSpacing_ ),
1973 horizontalScaling_( orig.horizontalScaling_ ),
1974 leading_( orig.leading_ ),
1975 rise_( orig.rise_ ),
1976 font_( orig.font_ ),
1977 size_( orig.size_ ),
1978 mode_( orig.mode_ ),
1979 knockout_( orig.knockout_ )
1982 Kernel::TextState::TextState( const Kernel::TextState & newValues, const Kernel::TextState & oldValues )
1983 : relativeFlags_( oldValues.relativeFlags_ ),
1984 characterSpacing_( oldValues.characterSpacing_ ),
1985 wordSpacing_( oldValues.wordSpacing_ ),
1986 horizontalScaling_( oldValues.horizontalScaling_ ),
1987 leading_( oldValues.leading_ ),
1988 rise_( oldValues.rise_ ),
1989 font_( oldValues.font_ ),
1990 size_( oldValues.size_ ),
1991 mode_( oldValues.mode_ ),
1992 knockout_( oldValues.knockout_ )
1994 if( newValues.hasCharacterSpacing( ) )
1996 characterSpacing_ = newValues.characterSpacing_;
1997 relativeFlags_ = ( newValues.characterSpacingIsRelative( ) ? ( relativeFlags_ | RELATIVE_CHARACTER_SPACING ) : ( relativeFlags_ & ~RELATIVE_CHARACTER_SPACING ) );
1999 if( newValues.hasWordSpacing( ) )
2001 wordSpacing_ = newValues.wordSpacing_;
2002 relativeFlags_ = ( newValues.wordSpacingIsRelative( ) ? ( relativeFlags_ | RELATIVE_WORD_SPACING ) : ( relativeFlags_ & ~RELATIVE_WORD_SPACING ) );
2004 if( ! IS_NAN( newValues.horizontalScaling_ ) )
2006 horizontalScaling_ = newValues.horizontalScaling_;
2008 if( newValues.hasLeading( ) )
2010 leading_ = newValues.leading_;
2011 relativeFlags_ = ( newValues.leadingIsRelative( ) ? ( relativeFlags_ | RELATIVE_LEADING ) : ( relativeFlags_ & ~RELATIVE_LEADING ) );
2013 if( newValues.hasRise( ) )
2015 rise_ = newValues.rise_;
2016 relativeFlags_ = ( newValues.riseIsRelative( ) ? ( relativeFlags_ | RELATIVE_RISE ) : ( relativeFlags_ & ~RELATIVE_RISE ) );
2018 if( newValues.font_ != NullPtr< const Lang::Font >( ) )
2020 font_ = newValues.font_;
2022 if( ! IS_NAN( newValues.size_ ) )
2024 size_ = newValues.size_;
2026 if( newValues.mode_ != Lang::TextRenderingMode::UNDEFINED )
2028 mode_ = newValues.mode_;
2030 if( ! ( newValues.knockout_ & KNOCKOUT_UNDEFINED_BIT ) )
2032 knockout_ = newValues.knockout_;
2036 std::map< bool, RefCountPtr< SimplePDF::PDF_Object > > Kernel::TextState::knockoutNameMap_;
2038 Kernel::TextState::TextState( bool setDefaults )
2039 : relativeFlags_( RELATIVE_LEADING ),
2040 characterSpacing_( 0 ),
2041 wordSpacing_( 0 ),
2042 horizontalScaling_( 1 ),
2043 leading_( 1 ),
2044 rise_( 0 ),
2045 font_( Lang::THE_FONT_HELVETICA ),
2046 size_( Concrete::Length( 10 ) ),
2047 mode_( Lang::TextRenderingMode::FILL ),
2048 knockout_( 0 ) // this means false
2050 if( ! setDefaults )
2052 throw Exceptions::InternalError( strrefdup( "setDefaults must be true in TextState::TextState." ) );
2056 Kernel::TextState::~TextState( )
2059 void
2060 Kernel::TextState::print( std::ostream & os, const std::string & indentation ) const
2062 if( font_ != NullPtr< const Lang::Font >( ) )
2064 os << indentation << Interaction::DYNAMIC_VARIABLE_PREFIX << Lang::DYNAMIC_VARIABLE_ID_TEXT_FONT << ": " << font_->fontName( ) << std::endl ;
2066 if( ! IS_NAN( size_ ) )
2068 os << indentation << Interaction::DYNAMIC_VARIABLE_PREFIX << Lang::DYNAMIC_VARIABLE_ID_TEXT_SIZE << ": " << size_ / Interaction::displayUnit << Interaction::displayUnitName << std::endl ;
2070 os << "(and a bunch of other variables...)" << std::endl ;
2074 void
2075 Kernel::TextState::setLeading( const Concrete::Length leading )
2077 relativeFlags_ &= ~ RELATIVE_LEADING;
2078 leading_ = leading;
2081 void
2082 Kernel::TextState::setLeading( const double relativeLeading )
2084 relativeFlags_ |= RELATIVE_LEADING;
2085 leading_ = Concrete::Length( relativeLeading ); // We must keep track of this type trick by always looking at relativeFlags_ & RELATIVE_LEADING.
2088 RefCountPtr< const Lang::Value >
2089 Kernel::TextState::leading( ) const
2091 if( leadingIsRelative( ) )
2093 return RefCountPtr< const Lang::Value >( new Lang::Float( Concrete::Length::offtype( leading_ ) ) );
2095 return RefCountPtr< const Lang::Value >( new Lang::Length( leading_ ) );
2098 Concrete::Length
2099 Kernel::TextState::leadingConcrete( ) const
2101 if( leadingIsRelative( ) )
2103 return Concrete::Length::offtype( leading_ ) * size_;
2105 return leading_;
2108 bool
2109 Kernel::TextState::hasLeading( ) const
2111 return ! IS_NAN( leading_ );
2114 bool
2115 Kernel::TextState::leadingIsRelative( ) const
2117 return ( relativeFlags_ & RELATIVE_LEADING ) != 0;
2121 void
2122 Kernel::TextState::setRise( const Concrete::Length rise )
2124 relativeFlags_ &= ~ RELATIVE_RISE;
2125 rise_ = rise;
2128 void
2129 Kernel::TextState::setRise( const double relativeRise )
2131 relativeFlags_ |= RELATIVE_RISE;
2132 rise_ = Concrete::Length( relativeRise ); // We must keep track of this type trick by always looking at relativeFlags_ & RELATIVE_RISE.
2135 RefCountPtr< const Lang::Value >
2136 Kernel::TextState::rise( ) const
2138 if( riseIsRelative( ) )
2140 return RefCountPtr< const Lang::Value >( new Lang::Float( Concrete::Length::offtype( rise_ ) ) );
2142 return RefCountPtr< const Lang::Value >( new Lang::Length( rise_ ) );
2145 Concrete::Length
2146 Kernel::TextState::riseConcrete( ) const
2148 if( riseIsRelative( ) )
2150 return Concrete::Length::offtype( rise_ ) * size_;
2152 return rise_;
2155 bool
2156 Kernel::TextState::hasRise( ) const
2158 return ! IS_NAN( rise_ );
2161 bool
2162 Kernel::TextState::riseIsRelative( ) const
2164 return ( relativeFlags_ & RELATIVE_RISE ) != 0;
2168 void
2169 Kernel::TextState::setCharacterSpacing( const Concrete::Length spacing )
2171 relativeFlags_ &= ~ RELATIVE_CHARACTER_SPACING;
2172 characterSpacing_ = spacing;
2175 void
2176 Kernel::TextState::setCharacterSpacing( const double relativeSpacing )
2178 relativeFlags_ |= RELATIVE_CHARACTER_SPACING;
2179 characterSpacing_ = Concrete::Length( relativeSpacing ); // We must keep track of this type trick by always looking at the relevant bit in relativeFlags_.
2182 RefCountPtr< const Lang::Value >
2183 Kernel::TextState::characterSpacing( ) const
2185 if( characterSpacingIsRelative( ) )
2187 return RefCountPtr< const Lang::Value >( new Lang::Float( Concrete::Length::offtype( characterSpacing_ ) ) );
2189 return RefCountPtr< const Lang::Value >( new Lang::Length( characterSpacing_ ) );
2192 Concrete::Length
2193 Kernel::TextState::characterSpacingConcrete( ) const
2195 if( characterSpacingIsRelative( ) )
2197 return Concrete::Length::offtype( characterSpacing_ ) * size_;
2199 return characterSpacing_;
2202 bool
2203 Kernel::TextState::hasCharacterSpacing( ) const
2205 return ! IS_NAN( characterSpacing_ );
2208 bool
2209 Kernel::TextState::characterSpacingIsRelative( ) const
2211 return ( relativeFlags_ & RELATIVE_CHARACTER_SPACING ) != 0;
2215 void
2216 Kernel::TextState::setWordSpacing( const Concrete::Length spacing )
2218 relativeFlags_ &= ~ RELATIVE_WORD_SPACING;
2219 wordSpacing_ = spacing;
2222 void
2223 Kernel::TextState::setWordSpacing( const double relativeSpacing )
2225 relativeFlags_ |= RELATIVE_WORD_SPACING;
2226 wordSpacing_ = Concrete::Length( relativeSpacing ); // We must keep track of this type trick by always looking at the relevant bit in relativeFlags_.
2229 RefCountPtr< const Lang::Value >
2230 Kernel::TextState::wordSpacing( ) const
2232 if( wordSpacingIsRelative( ) )
2234 return RefCountPtr< const Lang::Value >( new Lang::Float( Concrete::Length::offtype( wordSpacing_ ) ) );
2236 return RefCountPtr< const Lang::Value >( new Lang::Length( wordSpacing_ ) );
2239 Concrete::Length
2240 Kernel::TextState::wordSpacingConcrete( ) const
2242 if( wordSpacingIsRelative( ) )
2244 return Concrete::Length::offtype( wordSpacing_ ) * size_;
2246 return wordSpacing_;
2249 bool
2250 Kernel::TextState::hasWordSpacing( ) const
2252 return ! IS_NAN( wordSpacing_ );
2255 bool
2256 Kernel::TextState::wordSpacingIsRelative( ) const
2258 return ( relativeFlags_ & RELATIVE_WORD_SPACING ) != 0;
2262 bool
2263 Kernel::TextState::synchAssertKnockout( std::ostream & os, const Kernel::TextState * ref, SimplePDF::PDF_Resources * resources, bool clip, bool force )
2265 assertKnockout( ref );
2266 return synchButKnockout( os, ref, resources, clip, force );
2269 bool
2270 Kernel::TextState::synchCharacterSpacing( std::ostream & os, const Kernel::TextState * ref, SimplePDF::PDF_Resources * resources, bool force )
2272 if( force ||
2273 characterSpacing_ != ref->characterSpacing_ ||
2274 characterSpacingIsRelative( ) != ref->characterSpacingIsRelative( ) )
2276 if( ! ref->hasCharacterSpacing( ) )
2278 return false;
2280 relativeFlags_ = ( ref->characterSpacingIsRelative( ) ? ( relativeFlags_ | RELATIVE_CHARACTER_SPACING ) : ( relativeFlags_ & ~RELATIVE_CHARACTER_SPACING ) );
2281 characterSpacing_ = ref->characterSpacing_;
2282 if( characterSpacingIsRelative( ) )
2284 os << Concrete::Length::offtype( characterSpacing_ ) * Concrete::Length::offtype( ref->size_ ) << " Tc " ;
2286 else
2288 os << Concrete::Length::offtype( characterSpacing_ ) << " Tc " ;
2290 return true;
2292 return false;
2295 bool
2296 Kernel::TextState::synchWordSpacing( std::ostream & os, const Kernel::TextState * ref, SimplePDF::PDF_Resources * resources, bool force )
2298 if( force ||
2299 wordSpacing_ != ref->wordSpacing_ ||
2300 wordSpacingIsRelative( ) != ref->wordSpacingIsRelative( ) )
2302 if( ! ref->hasWordSpacing( ) )
2304 return false;
2306 relativeFlags_ = ( ref->wordSpacingIsRelative( ) ? ( relativeFlags_ | RELATIVE_WORD_SPACING ) : ( relativeFlags_ & ~RELATIVE_WORD_SPACING ) );
2307 wordSpacing_ = ref->wordSpacing_;
2308 if( wordSpacingIsRelative( ) )
2310 os << Concrete::Length::offtype( wordSpacing_ ) * Concrete::Length::offtype( ref->size_ ) << " Tw " ;
2312 else
2314 os << Concrete::Length::offtype( wordSpacing_ ) << " Tw " ;
2316 return true;
2318 return false;
2321 bool
2322 Kernel::TextState::synchHorizontalScaling( std::ostream & os, const Kernel::TextState * ref, SimplePDF::PDF_Resources * resources, bool force )
2324 if( force || horizontalScaling_ != ref->horizontalScaling_ )
2326 if( IS_NAN( ref->horizontalScaling_ ) )
2328 return false;
2330 horizontalScaling_ = ref->horizontalScaling_;
2331 os << 100 * horizontalScaling_ << " Tz " ;
2332 return true;
2334 return false;
2337 bool
2338 Kernel::TextState::synchLeading( std::ostream & os, const Kernel::TextState * ref, SimplePDF::PDF_Resources * resources, bool force )
2340 if( force ||
2341 leading_ != ref->leading_ ||
2342 leadingIsRelative( ) != ref->leadingIsRelative( ) )
2344 if( ! ref->hasLeading( ) )
2346 return false;
2348 relativeFlags_ = ( ref->leadingIsRelative( ) ? ( relativeFlags_ | RELATIVE_LEADING ) : ( relativeFlags_ & ~RELATIVE_LEADING ) );
2349 leading_ = ref->leading_;
2350 if( leadingIsRelative( ) )
2352 os << Concrete::Length::offtype( leading_ ) * Concrete::Length::offtype( ref->size_ ) << " TL " ;
2354 else
2356 os << Concrete::Length::offtype( leading_ ) << " TL " ;
2358 return true;
2360 return false;
2363 bool
2364 Kernel::TextState::synchFontAndSize( std::ostream & os, const Kernel::TextState * ref, SimplePDF::PDF_Resources * resources, bool force )
2366 if( force ||
2367 font_ != ref->font_ ||
2368 size_ != ref->size_ )
2370 if( ref->font_ == NullPtr< const Lang::Font >( ) &&
2371 IS_NAN( ref->size_ ) )
2373 return false;
2375 if( ref->font_ == NullPtr< const Lang::Font >( ) ||
2376 IS_NAN( ref->size_ ) )
2378 throw Exceptions::MiscellaneousRequirement( "It is impossible to leave unspecified only one of font and size." );
2380 bool sizeChanged = ( size_ != ref->size_ );
2381 font_ = ref->font_;
2382 size_ = ref->size_;
2383 os << resources->nameofFont( font_->resource( ) ) << " " << Concrete::Length::offtype( size_ ) << " Tf " ;
2384 if( sizeChanged )
2386 if( ref->hasLeading( ) && ref->leadingIsRelative( ) )
2388 synchLeading( os, ref, resources, true );
2390 if( ref->hasRise( ) && ref->riseIsRelative( ) )
2392 synchRise( os, ref, resources, true );
2394 if( ref->hasCharacterSpacing( ) && ref->characterSpacingIsRelative( ) )
2396 synchCharacterSpacing( os, ref, resources, true );
2398 if( ref->hasWordSpacing( ) && ref->wordSpacingIsRelative( ) )
2400 synchWordSpacing( os, ref, resources, true );
2403 return true;
2405 return false;
2408 bool
2409 Kernel::TextState::synchMode( std::ostream & os, const Kernel::TextState * ref, SimplePDF::PDF_Resources * resources, bool clip, bool force )
2411 Lang::TextRenderingMode::ValueType refMode = clip ? Lang::TextRenderingMode::clipMode( ref->mode_ ) : ref->mode_ ;
2412 if( force || mode_ != refMode )
2414 if( ref->mode_ == Lang::TextRenderingMode::UNDEFINED )
2416 return false;
2418 mode_ = refMode;
2419 os << mode_ << " Tr " ;
2420 return true;
2422 return false;
2425 bool
2426 Kernel::TextState::synchRise( std::ostream & os, const Kernel::TextState * ref, SimplePDF::PDF_Resources * resources, bool force )
2428 if( force ||
2429 rise_ != ref->rise_ ||
2430 riseIsRelative( ) != ref->riseIsRelative( ) )
2432 if( ! ref->hasRise( ) )
2434 return false;
2436 relativeFlags_ = ( ref->riseIsRelative( ) ? ( relativeFlags_ | RELATIVE_RISE ) : ( relativeFlags_ & ~RELATIVE_RISE ) );
2437 rise_ = ref->rise_;
2438 if( riseIsRelative( ) )
2440 os << Concrete::Length::offtype( rise_ ) * Concrete::Length::offtype( ref->size_ ) << " Ts " ;
2442 else
2444 os << Concrete::Length::offtype( rise_ ) << " Ts " ;
2446 return true;
2448 return false;
2451 bool
2452 Kernel::TextState::synchKnockout( std::ostream & os, const Kernel::TextState * ref, SimplePDF::PDF_Resources * resources, bool force )
2454 if( force || knockout_ != ref->knockout_ )
2456 if( ( ref->knockout_ & Kernel::TextState::KNOCKOUT_UNDEFINED_BIT ) != 0 )
2458 return false;
2460 const SimplePDF::PDF_Version::Version KNOCKOUT_VERSION = SimplePDF::PDF_Version::PDF_1_4;
2461 if( ! Kernel::the_PDF_version.greaterOrEqual( KNOCKOUT_VERSION ) )
2463 Kernel::the_PDF_version.message( KNOCKOUT_VERSION, "The text state knockout mode setting was ignored." );
2465 knockout_ = ref->knockout_;
2466 typedef typeof knockoutNameMap_ MapType;
2467 MapType::const_iterator i = knockoutNameMap_.find( knockout_ );
2468 if( i != knockoutNameMap_.end( ) )
2470 os << resources->nameofGraphicsState( i->second ) << " gs " ;
2472 else
2474 RefCountPtr< SimplePDF::PDF_Dictionary > dic;
2475 (*dic)[ "Type" ] = SimplePDF::newName( "ExtGState" );
2476 (*dic)[ "TK" ] = SimplePDF::newBoolean( knockout_ );
2478 RefCountPtr< SimplePDF::PDF_Object > indirection = SimplePDF::indirect( dic, & Kernel::theIndirectObjectCount );
2479 knockoutNameMap_.insert( MapType::value_type( knockout_, indirection ) );
2481 os << resources->nameofGraphicsState( indirection ) << " gs " ;
2483 return true;
2485 return false;
2488 void
2489 Kernel::TextState::assertKnockout( const Kernel::TextState * ref )
2491 if( knockout_ != ref->knockout_ )
2493 throw Exceptions::MiscellaneousRequirement( "PDF does not allow the text knockout mode to change within a text object." );
2497 bool
2498 Kernel::TextState::synchButKnockout( std::ostream & os, const Kernel::TextState * ref, SimplePDF::PDF_Resources * resources, bool clip, bool force )
2500 bool anyChange = false;
2501 anyChange = synchCharacterSpacing( os, ref, resources, force ) || anyChange;
2502 anyChange = synchWordSpacing( os, ref, resources, force ) || anyChange;
2503 anyChange = synchHorizontalScaling( os, ref, resources, force ) || anyChange;
2504 anyChange = synchFontAndSize( os, ref, resources, force ) || anyChange;
2505 anyChange = synchLeading( os, ref, resources, force ) || anyChange; // It is important that this is done after synching the size!
2506 anyChange = synchMode( os, ref, resources, clip, force ) || anyChange;
2507 anyChange = synchRise( os, ref, resources, force ) || anyChange;
2508 if( anyChange )
2510 os << std::endl ;
2512 return anyChange;