1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008 Henrik Tidefelt
19 #include "Shapes_Helpers_decls.h"
21 #include "texttypes.h"
22 #include "dynamicenvironment.h"
23 #include "lighttypes.h"
28 #include "autoonoff.h"
29 #include "afmscanner.h"
30 #include "charconverters.h"
31 #include "constructorrepresentation.h"
32 #include "pagecontentstates.h"
36 #include <sys/types.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_
;
46 Lang::Font::push_backFontMetricsPath( const std::string
& path
)
49 path
[ path
.size( ) - 1 ] == '/' )
51 theFontMetricsSearchPath_
.push_back( path
);
55 theFontMetricsSearchPath_
.push_back( path
+ "/" );
60 Lang::Font::searchGlyphList( )
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 )
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." );
83 Lang::Font::searchFontMetrics( RefCountPtr
< const char > fontName
)
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 )
112 throw Exceptions::MissingFontMetrics( fontName
, & theFontMetricsSearchPath_
);
116 Lang::Font::searchCharacterEncoding( const char * encodingName
)
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 )
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
;
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
>( ) )
180 const RefCountPtr
< SimplePDF::PDF_Object
> &
181 Lang::Font::resource( ) const
183 if( resource_
!= NullPtr
< SimplePDF::PDF_Object
>( ) )
188 typedef typeof theFontResourceMap_ MapType
;
191 MapType::const_iterator i
= theFontResourceMap_
.find( fontName_
);
192 if( i
!= theFontResourceMap_
.end( ) )
194 resource_
= i
->second
;
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!
210 RefCountPtr
< const char >
211 Lang::Font::fontName( ) const
216 RefCountPtr
< const FontMetrics::BaseFont
>
217 Lang::Font::metrics( ) const
219 if( metrics_
!= NullPtr
< const FontMetrics::BaseFont
>( ) )
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( );
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
) );
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 )
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( );
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." );
373 std::ostringstream msg
;
374 msg
<< "iconv failed with an unrecognized error code: " << errno
;
375 throw Exceptions::InternalError( strrefdup( msg
) );
379 for( const char * src
= buf
; *src
!= '\0'; ++src
)
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
;
394 throw Exceptions::MiscellaneousRequirement( "Newlines cannot be represented in the pos-character list." );
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
>
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.
416 xpos
+= xSize
* charMetrics
->horizontalCharWidthX_
;
417 xpos
+= characterTrackKern
;
424 if( ki
== kernings_
.end( ) )
426 throw Exceptions::InternalError( "Short of kerning values in KernedText::measure." );
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( ) ) ),
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.
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." );
472 return RefCountPtr
< const Lang::String
>( new Lang::String( strrefdup( buf
) ) );
476 Lang::KernedText::pushString( const RefCountPtr
< const Lang::String
> & str
)
478 strings_
.push_back( str
);
479 maxLength_
= std::max( maxLength_
, strlen( str
->val_
.getPtr( ) ) );
483 Lang::KernedText::pushKerning( double kerning
)
485 strings_
.push_back( NullPtr
< const Lang::String
>( ) );
486 kernings_
.push_back( kerning
);
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( ) << ")" ;
502 if( ki
== kernings_
.end( ) )
504 throw Exceptions::InternalError( "Short of kerning values in KernedText::show." );
510 if( ki
!= kernings_
.end( ) )
512 throw Exceptions::InternalError( "Too many kerning values in KernedText::show." );
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( ) );
529 case Lang::TextRenderingMode::STROKE
:
530 case Lang::TextRenderingMode::STROKECLIP
:
531 pdfState
->graphics_
.synchForStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
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( ) );
538 case Lang::TextRenderingMode::INVISIBLE
:
539 case Lang::TextRenderingMode::CLIP
:
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( ) );
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( );
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( );
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." );
585 std::ostringstream msg
;
586 msg
<< "iconv failed with an unrecognized error code: " << errno
;
587 throw Exceptions::InternalError( strrefdup( msg
) );
592 for( const char * src
= buf
; *src
!= '\0'; ++src
)
606 os
<< ")] TJ T* [(" ;
616 if( ki
== kernings_
.end( ) )
618 throw Exceptions::InternalError( "Short of kerning values in KernedText::writePDFVectorTo." );
620 os
<< 1000 * *ki
<< " " ;
624 if( ki
!= kernings_
.end( ) )
626 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
629 os
<< "] TJ " << std::endl
;
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( );
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." );
690 std::ostringstream msg
;
691 msg
<< "iconv failed with an unrecognized error code: " << errno
;
692 throw Exceptions::InternalError( strrefdup( msg
) );
696 for( const char * src
= buf
; *src
!= '\0'; ++src
)
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
;
712 textMatrix
->prependShift( Concrete::Coords2D( 0, - textState_
->leadingConcrete( ) ) );
713 textLineMatrix
->replaceBy( *textMatrix
);
714 x0
= textLineMatrix
->xt_
;
715 y0
= textLineMatrix
->yt_
+ textState_
->riseConcrete( );
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
;
742 if( ki
== kernings_
.end( ) )
744 throw Exceptions::InternalError( "Short of kerning values in KernedText::measure." );
750 if( ki
!= kernings_
.end( ) )
752 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
755 textLineMatrix
->prependXShift( xpos
);
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( );
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." );
792 std::ostringstream msg
;
793 msg
<< "iconv failed with an unrecognized error code: " << errno
;
794 throw Exceptions::InternalError( strrefdup( msg
) );
798 for( const char * src
= buf
; *src
!= '\0'; ++src
)
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 ;
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 ;
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 ;
864 if( ki
== kernings_
.end( ) )
866 throw Exceptions::InternalError( "Short of kerning values in KernedText::measure." );
868 textLineMatrix
->prependXShift( - xSize
* *ki
);
872 if( ki
!= kernings_
.end( ) )
874 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
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
);
892 dst
->pushKerning( *ki
);
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
)
916 Lang::TextNewline::~TextNewline( )
920 Lang::TextNewline::show( std::ostream
& os
) const
922 os
<< "Newline with offset in bp: " << t_
;
926 Lang::TextNewline::shipout( std::ostream
& os
, Kernel::PageContentStates
* pdfState
, const Lang::Transform2D
& tf
, bool clip
) const
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
);
939 Lang::TextNewline::gcMark( Kernel::GCMarkedSet
& marked
)
942 Lang::TextMoveto::TextMoveto( const RefCountPtr
< const Lang::Transform2D
> & tf
)
946 Lang::TextMoveto::~TextMoveto( )
950 Lang::TextMoveto::show( std::ostream
& os
) const
952 os
<< "Moveto command" ;
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
;
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
);
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
;
980 Lang::TextRenderingMode::TextRenderingMode( const ValueType
& mode
)
984 Lang::TextRenderingMode::TextRenderingMode( bool fill
, bool stroke
, bool clip
)
986 switch( ( fill
? 0x01 : 0x00 ) +
987 ( stroke
? 0x02 : 0x00 ) +
988 ( clip
? 0x04 : 0x00 ) )
1012 mode_
= FILLSTROKECLIP
;
1015 throw Exceptions::InternalError( "Semi-static switch out of range in TextRenderingMode::TextRenderingMode." );
1019 Lang::TextRenderingMode::ValueType
1020 Lang::TextRenderingMode::clipMode( ValueType mode
)
1031 return FILLSTROKECLIP
;
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( )
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( );
1064 newState
->setCharacterSpacing( Concrete::Length::offtype( spacing_
) );
1068 newState
->setCharacterSpacing( spacing_
);
1070 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1074 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
1076 Kernel::TextState
* newState
= new Kernel::TextState( );
1079 newState
->setCharacterSpacing( Concrete::Length::offtype( spacing_
) );
1083 newState
->setCharacterSpacing( spacing_
);
1085 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1089 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
1091 if( newState
->hasCharacterSpacing( ) )
1093 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
1098 newState
->setCharacterSpacing( Concrete::Length::offtype( spacing_
) );
1102 newState
->setCharacterSpacing( spacing_
);
1104 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1108 Lang::CharacterSpacingBinding::show( std::ostream
& os
) const
1110 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
1113 os
<< Concrete::Length::offtype( spacing_
) ;
1117 os
<< spacing_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
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( )
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( );
1146 newState
->setWordSpacing( Concrete::Length::offtype( spacing_
) );
1150 newState
->setWordSpacing( spacing_
);
1152 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1156 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
1158 Kernel::TextState
* newState
= new Kernel::TextState( );
1161 newState
->setWordSpacing( Concrete::Length::offtype( spacing_
) );
1165 newState
->setWordSpacing( spacing_
);
1167 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1171 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
1173 if( newState
->hasWordSpacing( ) )
1175 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
1180 newState
->setWordSpacing( Concrete::Length::offtype( spacing_
) );
1184 newState
->setWordSpacing( spacing_
);
1186 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1190 Lang::WordSpacingBinding::show( std::ostream
& os
) const
1192 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
1195 os
<< Concrete::Length::offtype( spacing_
) ;
1199 os
<< spacing_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
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( )
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
);
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
);
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
);
1247 Lang::HorizontalScalingBinding::show( std::ostream
& os
) const
1249 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":"
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( )
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( );
1278 newState
->setLeading( Concrete::Length::offtype( ty_
) );
1282 newState
->setLeading( ty_
);
1284 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1288 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
1290 Kernel::TextState
* newState
= new Kernel::TextState( );
1293 newState
->setLeading( Concrete::Length::offtype( ty_
) );
1297 newState
->setLeading( ty_
);
1299 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1303 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
1305 if( newState
->hasLeading( ) )
1307 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
1312 newState
->setLeading( Concrete::Length::offtype( ty_
) );
1316 newState
->setLeading( ty_
);
1318 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1322 Lang::LeadingBinding::show( std::ostream
& os
) const
1324 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
1327 os
<< Concrete::Length::offtype( ty_
) ;
1331 os
<< ty_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
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( )
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
);
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
);
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
);
1379 Lang::FontBinding::show( std::ostream
& os
) const
1381 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
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( )
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
);
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
);
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
);
1431 Lang::TextSizeBinding::show( std::ostream
& os
) const
1433 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":"
1434 << size_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
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( )
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
);
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
);
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
);
1481 Lang::TextRenderingModeBinding::show( std::ostream
& os
) const
1483 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":"
1484 << "<internal-enum>" ;
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( )
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( );
1512 newState
->setRise( Concrete::Length::offtype( ty_
) );
1516 newState
->setRise( ty_
);
1518 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1522 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
1524 Kernel::TextState
* newState
= new Kernel::TextState( );
1527 newState
->setRise( Concrete::Length::offtype( ty_
) );
1531 newState
->setRise( ty_
);
1533 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1537 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
1539 if( newState
->hasRise( ) )
1541 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
1546 newState
->setRise( Concrete::Length::offtype( ty_
) );
1550 newState
->setRise( ty_
);
1552 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1556 Lang::TextRiseBinding::show( std::ostream
& os
) const
1558 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
1561 os
<< Concrete::Length::offtype( ty_
) ;
1565 os
<< ty_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
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( )
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
);
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
);
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
);
1613 Lang::TextKnockoutBinding::show( std::ostream
& os
) const
1615 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":"
1616 << ( knockout_
? "true" : "false" ) ;
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( ) ) );
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( ) ) ),
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_
) ),
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( ) ) );
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( ) ) ),
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_
) ),
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_
) ) );
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_
) ),
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( ) ) );
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( ) ) ),
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_
) ),
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_
) );
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( ) ) ) ),
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_
) ) );
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( ) ) ),
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_
) ) );
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_
) ),
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( ) ) );
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( ) ) ),
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_
) ),
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 ) ) );
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_
) ),
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 ),
2042 horizontalScaling_( 1 ),
2045 font_( Lang::THE_FONT_HELVETICA
),
2046 size_( Concrete::Length( 10 ) ),
2047 mode_( Lang::TextRenderingMode::FILL
),
2048 knockout_( 0 ) // this means false
2052 throw Exceptions::InternalError( strrefdup( "setDefaults must be true in TextState::TextState." ) );
2056 Kernel::TextState::~TextState( )
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
;
2075 Kernel::TextState::setLeading( const Concrete::Length leading
)
2077 relativeFlags_
&= ~ RELATIVE_LEADING
;
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_
) );
2099 Kernel::TextState::leadingConcrete( ) const
2101 if( leadingIsRelative( ) )
2103 return Concrete::Length::offtype( leading_
) * size_
;
2109 Kernel::TextState::hasLeading( ) const
2111 return ! IS_NAN( leading_
);
2115 Kernel::TextState::leadingIsRelative( ) const
2117 return ( relativeFlags_
& RELATIVE_LEADING
) != 0;
2122 Kernel::TextState::setRise( const Concrete::Length rise
)
2124 relativeFlags_
&= ~ RELATIVE_RISE
;
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_
) );
2146 Kernel::TextState::riseConcrete( ) const
2148 if( riseIsRelative( ) )
2150 return Concrete::Length::offtype( rise_
) * size_
;
2156 Kernel::TextState::hasRise( ) const
2158 return ! IS_NAN( rise_
);
2162 Kernel::TextState::riseIsRelative( ) const
2164 return ( relativeFlags_
& RELATIVE_RISE
) != 0;
2169 Kernel::TextState::setCharacterSpacing( const Concrete::Length spacing
)
2171 relativeFlags_
&= ~ RELATIVE_CHARACTER_SPACING
;
2172 characterSpacing_
= spacing
;
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_
) );
2193 Kernel::TextState::characterSpacingConcrete( ) const
2195 if( characterSpacingIsRelative( ) )
2197 return Concrete::Length::offtype( characterSpacing_
) * size_
;
2199 return characterSpacing_
;
2203 Kernel::TextState::hasCharacterSpacing( ) const
2205 return ! IS_NAN( characterSpacing_
);
2209 Kernel::TextState::characterSpacingIsRelative( ) const
2211 return ( relativeFlags_
& RELATIVE_CHARACTER_SPACING
) != 0;
2216 Kernel::TextState::setWordSpacing( const Concrete::Length spacing
)
2218 relativeFlags_
&= ~ RELATIVE_WORD_SPACING
;
2219 wordSpacing_
= spacing
;
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_
) );
2240 Kernel::TextState::wordSpacingConcrete( ) const
2242 if( wordSpacingIsRelative( ) )
2244 return Concrete::Length::offtype( wordSpacing_
) * size_
;
2246 return wordSpacing_
;
2250 Kernel::TextState::hasWordSpacing( ) const
2252 return ! IS_NAN( wordSpacing_
);
2256 Kernel::TextState::wordSpacingIsRelative( ) const
2258 return ( relativeFlags_
& RELATIVE_WORD_SPACING
) != 0;
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
);
2270 Kernel::TextState::synchCharacterSpacing( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
2273 characterSpacing_
!= ref
->characterSpacing_
||
2274 characterSpacingIsRelative( ) != ref
->characterSpacingIsRelative( ) )
2276 if( ! ref
->hasCharacterSpacing( ) )
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 " ;
2288 os
<< Concrete::Length::offtype( characterSpacing_
) << " Tc " ;
2296 Kernel::TextState::synchWordSpacing( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
2299 wordSpacing_
!= ref
->wordSpacing_
||
2300 wordSpacingIsRelative( ) != ref
->wordSpacingIsRelative( ) )
2302 if( ! ref
->hasWordSpacing( ) )
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 " ;
2314 os
<< Concrete::Length::offtype( wordSpacing_
) << " Tw " ;
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_
) )
2330 horizontalScaling_
= ref
->horizontalScaling_
;
2331 os
<< 100 * horizontalScaling_
<< " Tz " ;
2338 Kernel::TextState::synchLeading( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
2341 leading_
!= ref
->leading_
||
2342 leadingIsRelative( ) != ref
->leadingIsRelative( ) )
2344 if( ! ref
->hasLeading( ) )
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 " ;
2356 os
<< Concrete::Length::offtype( leading_
) << " TL " ;
2364 Kernel::TextState::synchFontAndSize( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
2367 font_
!= ref
->font_
||
2368 size_
!= ref
->size_
)
2370 if( ref
->font_
== NullPtr
< const Lang::Font
>( ) &&
2371 IS_NAN( ref
->size_
) )
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_
);
2383 os
<< resources
->nameofFont( font_
->resource( ) ) << " " << Concrete::Length::offtype( size_
) << " Tf " ;
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 );
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
)
2419 os
<< mode_
<< " Tr " ;
2426 Kernel::TextState::synchRise( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
2429 rise_
!= ref
->rise_
||
2430 riseIsRelative( ) != ref
->riseIsRelative( ) )
2432 if( ! ref
->hasRise( ) )
2436 relativeFlags_
= ( ref
->riseIsRelative( ) ? ( relativeFlags_
| RELATIVE_RISE
) : ( relativeFlags_
& ~RELATIVE_RISE
) );
2438 if( riseIsRelative( ) )
2440 os
<< Concrete::Length::offtype( rise_
) * Concrete::Length::offtype( ref
->size_
) << " Ts " ;
2444 os
<< Concrete::Length::offtype( rise_
) << " Ts " ;
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 )
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 " ;
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 " ;
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." );
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
;