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, 2010 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"
33 #include "methodbase.h"
34 #include "shapescore.h"
38 #include <sys/types.h>
48 using namespace Shapes
;
50 std::map
< RefCountPtr
< const char >, RefCountPtr
< SimplePDF::PDF_Object
>, charRefPtrLess
> Lang::Font::theFontResourceMap_
;
51 std::map
< RefCountPtr
< const char >, RefCountPtr
< const FontMetrics::FontMetric
>, charRefPtrLess
> Lang::Font::theFontMetricsMap_
;
52 std::list
< std::string
> Lang::Font::theFontMetricsSearchPath_
;
58 Kernel::StructureFactory
FontMethod_glyph_resultFactory( "painter", "paths" );
62 SimplePDF::PDF_ToUnicode::PDF_ToUnicode( RefCountPtr
< CharSet
> charSet
, const RefCountPtr
< const Shapes::Lang::Font
> & font
)
63 : charSet_( charSet
),
66 dic
[ "Filter" ] = SimplePDF::newName( "FlateDecode" );
69 SimplePDF::PDF_ToUnicode::~PDF_ToUnicode( )
73 SimplePDF::PDF_ToUnicode::writeTo( std::ostream
& os
, SimplePDF::PDF_xref
* xref
, const RefCountPtr
< const PDF_Object
> & self
) const
75 std::ostringstream
& wdata
= const_cast< std::ostringstream
& >( data
);
76 wdata
<< std::setfill( '0' );
77 wdata
<< "/CIDInit /ProcSet findresource begin" << std::endl
78 << "12 dict begin" << std::endl
79 << "begincmap" << std::endl
80 << "/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def" << std::endl
81 << "/CMapName /Adobe-Identity-UCS def" << std::endl
82 << "/CMapType 2 def" << std::endl
83 << "1 begincodespacerange" << std::endl
84 << "<0000> <FFFF>" << std::endl
85 << "endcodespacerange" << std::endl
;
86 const size_t bufSize
= 10;
87 unsigned char buf
[ bufSize
];
88 size_t remaining
= charSet_
->size( );
89 size_t room
= std::min( static_cast< size_t >( 100 ), remaining
);
91 wdata
<< room
<< " beginbfchar" << std::endl
;
92 for( CharSet::const_iterator i
= charSet_
->begin( ); i
!= charSet_
->end( ); ++i
, --room
)
96 wdata
<< "endbfchar" << std::endl
;
97 room
= std::min( static_cast< size_t >( 100 ), remaining
);
99 wdata
<< room
<< " beginbfchar" << std::endl
;
101 size_t out_avail
= 2;
102 unsigned char * out_buf
= buf
;
103 font_
->encode( *i
, reinterpret_cast< char ** >( & out_buf
), & out_avail
);
106 throw Exceptions::InternalError( "Expected the encoded character to occupy exactly two bytes." );
108 wdata
<< "<" << std::hex
<< std::setw( 2 ) << static_cast< int >( buf
[0] ) << std::hex
<< std::setw( 2 ) << static_cast< int >( buf
[1] ) << "> " ;
111 i
->encode_UTF16BE( reinterpret_cast< char ** >( & out_buf
), & out_avail
);
113 for( const unsigned char * c
= buf
; c
!= out_buf
; ++c
)
115 wdata
<< std::hex
<< std::setw( 2 ) << static_cast< int >( *c
) ;
117 wdata
<< ">" << std::endl
;
119 wdata
<< "endbfchar" << std::endl
120 << "endcmap" << std::endl
121 << "CMapName currentdict /CMap defineresource pop" << std::endl
122 << "end" << std::endl
123 << "end" ; /* No need to put a newline at the end. */
124 PDF_Stream_out::writeTo( os
, xref
, self
);
127 SimplePDF::PDF_Widths::PDF_Widths( RefCountPtr
< CharSet
> charSet
, const RefCountPtr
< const Shapes::Lang::Font
> & font
)
128 : charSet_( charSet
),
132 SimplePDF::PDF_Widths::~PDF_Widths( )
136 SimplePDF::PDF_Widths::writeTo( std::ostream
& os
, SimplePDF::PDF_xref
* xref
, const RefCountPtr
< const PDF_Object
> & self
) const
138 const FontMetrics::WritingDirectionMetrics
* metrics
= font_
->metrics( )->horizontalMetrics_
.getPtr( );
139 const size_t bufSize
= 2;
140 unsigned char buf
[ bufSize
];
141 VecType
& wvec
= const_cast< VecType
& >( vec
);
142 FontMetrics::CharacterMetrics
m( 0 );
143 for( CharSet::const_iterator i
= charSet_
->begin( ); i
!= charSet_
->end( ); )
145 CharSet::const_iterator j
= i
;
146 CharSet::const_iterator last
= i
;
148 for( ; i
!= charSet_
->end( ) && i
->get_UCS4( ) == last
->get_UCS4( ) + 1; last
= i
, ++i
)
150 size_t out_avail
= bufSize
;
151 unsigned char * out_buf
= buf
;
152 font_
->encode( j
->get_UCS4( ), reinterpret_cast< char ** >( & out_buf
), & out_avail
);
155 throw Exceptions::InternalError( "Expected the encoded character to occupy exactly two bytes." );
157 wvec
.push_back( SimplePDF::newInt( static_cast< SimplePDF::PDF_Int::ValueType
>( buf
[0] ) * 0x100 +
158 static_cast< SimplePDF::PDF_Int::ValueType
>( buf
[1] ) ) );
159 SimplePDF::PDF_Vector
* sub_vec
= new SimplePDF::PDF_Vector
;
160 wvec
.push_back( RefCountPtr
< SimplePDF::PDF_Object
>( sub_vec
) );
163 sub_vec
->vec
.push_back( SimplePDF::newFloat( metrics
->charByCode( j
->get_UCS4( ), & m
)->horizontalCharWidthX_
* 1000 ) );
166 PDF_Vector::writeTo( os
, xref
, self
);
175 class FontMethod_glyph
: public Lang::MethodBase
< Lang::Font
>
178 FontMethod_glyph( RefCountPtr
< const Lang::Font
> _self
, const Ast::FileID
* fullMethodID
);
179 virtual ~FontMethod_glyph( );
180 virtual void call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const;
181 static const char * staticFieldID( ) { return "glyph"; }
188 Font_register_methods( Lang::SystemFinalClass
* dstClass
)
190 dstClass
->registerMethod( new Kernel::MethodFactory
< Lang::Font
, Lang::FontMethod_glyph
>( ) );
194 Lang::Font::push_backFontMetricsPath( const std::string
& path
)
197 path
[ path
.size( ) - 1 ] == '/' )
199 theFontMetricsSearchPath_
.push_back( path
);
203 theFontMetricsSearchPath_
.push_back( path
+ "/" );
208 Lang::Font::searchGlyphList( )
212 if( theFontMetricsSearchPath_
.empty( ) )
214 throw Exceptions::ExternalError( strrefdup( "The font metrics path was not set up (needed for the glyph list). Consider defining the environment variable SHAPESFONTMETRICS." ) );
217 typedef typeof theFontMetricsSearchPath_ ListType
;
218 for( ListType::const_iterator i
= theFontMetricsSearchPath_
.begin( ); i
!= theFontMetricsSearchPath_
.end( ); ++i
)
220 res
= *i
+ "glyphlist.txt";
221 struct stat theStatDummy
;
222 if( stat( res
.c_str( ), & theStatDummy
) == 0 )
227 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." );
231 Lang::Font::searchFontMetrics( RefCountPtr
< const char > fontName
)
235 if( strlen( fontName
.getPtr( ) ) == 0 )
237 throw Exceptions::InternalError( strrefdup( "Lang::Font::searchFontMetrics called with empty argument." ) );
240 if( *fontName
.getPtr( ) == '/' )
242 throw Exceptions::InternalError( "The font name cannot begin with \"/\", as if is was an absolute path to something." );
245 if( theFontMetricsSearchPath_
.empty( ) )
247 throw Exceptions::ExternalError( strrefdup( "The font metrics path was not set up. Consider defining the environment variable SHAPESFONTMETRICS." ) );
250 typedef typeof theFontMetricsSearchPath_ ListType
;
251 for( ListType::const_iterator i
= theFontMetricsSearchPath_
.begin( ); i
!= theFontMetricsSearchPath_
.end( ); ++i
)
253 res
= *i
+ fontName
.getPtr( ) + ".afm";
254 struct stat theStatDummy
;
255 if( stat( res
.c_str( ), & theStatDummy
) == 0 )
260 throw Exceptions::MissingFontMetrics( fontName
, & theFontMetricsSearchPath_
);
264 Lang::Font::searchCharacterEncoding( const char * encodingName
)
268 if( theFontMetricsSearchPath_
.empty( ) )
270 throw Exceptions::ExternalError( strrefdup( "The font metrics path was not set up. Consider defining the environment variable SHAPESFONTMETRICS." ) );
273 typedef typeof theFontMetricsSearchPath_ ListType
;
274 for( ListType::const_iterator i
= theFontMetricsSearchPath_
.begin( ); i
!= theFontMetricsSearchPath_
.end( ); ++i
)
276 res
= *i
+ encodingName
+ ".enc";
277 struct stat theStatDummy
;
278 if( stat( res
.c_str( ), & theStatDummy
) == 0 )
283 std::ostringstream msg
;
284 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." ;
285 throw Exceptions::MiscellaneousRequirement( strrefdup( msg
) );
289 Lang::Font::Font( const RefCountPtr
< const char > fontName
, RefCountPtr
< SimplePDF::PDF_Object
> & resource
, RefCountPtr
< const FontMetrics::FontMetric
> metrics
)
290 : fontName_( fontName
), resource_( resource
), metrics_( metrics
)
292 // If this font has been instantiated before, it is reused.
294 typedef typeof theFontResourceMap_ MapType
;
295 MapType::const_iterator i
= theFontResourceMap_
.find( fontName_
);
296 if( i
!= theFontResourceMap_
.end( ) )
298 resource_
= i
->second
;
302 theFontResourceMap_
.insert( MapType::value_type( fontName_
, resource_
) );
306 typedef typeof theFontMetricsMap_ MapType
;
307 MapType::const_iterator i
= theFontMetricsMap_
.find( fontName_
);
308 if( i
!= theFontMetricsMap_
.end( ) )
310 metrics_
= i
->second
;
312 else if( metrics_
!= NullPtr
< const FontMetrics::FontMetric
>( ) )
314 theFontMetricsMap_
.insert( MapType::value_type( fontName_
, metrics_
) );
319 // Note that we must not initialize name_ with builtinFontMap_[ fontConst ] here, since builtinFontMap_ may not be
320 // initialized when this constructor is invoked from globals.cc.
321 Lang::Font::Font( const RefCountPtr
< const char > fontName
)
322 : fontName_( fontName
), resource_( NullPtr
< SimplePDF::PDF_Object
>( ) ), metrics_( NullPtr
< const FontMetrics::FontMetric
>( ) )
328 Kernel::VariableHandle
329 Lang::Font::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
331 // if( strcmp( fieldID, "CIDFont?" ) == 0 )
333 // return Helpers::newValHandle( new Lang::Boolean( metrics_->isCIDFont_ ) );
335 if( strcmp( fieldID
, "kerning?" ) == 0 )
337 return Helpers::newValHandle( new Lang::Boolean( metrics_
->hasKerning_
) );
339 if( strcmp( fieldID
, "family" ) == 0 )
341 return Kernel::VariableHandle( new Kernel::Variable( this->family_name( ) ) );
343 if( strcmp( fieldID
, "style" ) == 0 )
345 return Kernel::VariableHandle( new Kernel::Variable( this->style_name( ) ) );
347 if( strcmp( fieldID
, "PostScript_name" ) == 0 )
349 return Kernel::VariableHandle( new Kernel::Variable( this->PostScript_name( ) ) );
352 return TypeID
->getMethod( selfRef
, fieldID
); /* This will throw if there is no such method. */
355 RefCountPtr
< const Lang::String
>
356 Lang::Font::family_name( ) const
358 return RefCountPtr
< const Lang::String
>( new Lang::String( fontName_
) );
361 RefCountPtr
< const Lang::String
>
362 Lang::Font::style_name( ) const
364 return RefCountPtr
< const Lang::String
>( new Lang::String( "", true ) );
367 RefCountPtr
< const Lang::Symbol
>
368 Lang::Font::PostScript_name( ) const
370 return RefCountPtr
< const Lang::Symbol
>( new Lang::Symbol( fontName_
.getPtr( ) ) );
373 RefCountPtr
< const Lang::Value
>
374 Lang::Font::getGlyph( Kernel::UnicodeCodePoint c
, Concrete::Length size
) const
376 throw Exceptions::MiscellaneousRequirement( "It is not possible to extract individual glyphs from this font." );
380 const RefCountPtr
< SimplePDF::PDF_Object
> &
381 Lang::Font::resource( ) const
383 if( resource_
!= NullPtr
< SimplePDF::PDF_Object
>( ) )
388 typedef typeof theFontResourceMap_ MapType
;
391 MapType::const_iterator i
= theFontResourceMap_
.find( fontName_
);
392 if( i
!= theFontResourceMap_
.end( ) )
394 resource_
= i
->second
;
400 RefCountPtr
< SimplePDF::PDF_Dictionary
> dic
;
401 resource_
= SimplePDF::indirect( dic
, & Kernel::theIndirectObjectCount
);
402 (*dic
)[ "Type" ] = SimplePDF::newName( "Font" );
403 (*dic
)[ "Subtype" ] = SimplePDF::newName( "Type1" );
404 (*dic
)[ "Encoding" ] = SimplePDF::newName( "MacRomanEncoding" );
405 (*dic
)[ "BaseFont" ] = SimplePDF::newName( fontName_
.getPtr( ) ); // Here, it is crucial that this is really a built-in font!
410 RefCountPtr
< const char >
411 Lang::Font::fontName( ) const
416 RefCountPtr
< const FontMetrics::FontMetric
>
417 Lang::Font::metrics( ) const
419 if( metrics_
!= NullPtr
< const FontMetrics::FontMetric
>( ) )
424 // Otherwise, we hope that we can find an Adobe Font Metrics file.
425 std::string filename
= searchFontMetrics( fontName_
);
426 std::ifstream
afmFile( filename
.c_str( ) );
427 if( ! afmFile
.is_open( ) )
429 std::ostringstream oss
;
430 oss
<< "File has been located but couldn't be opened: " << filename
;
431 throw Exceptions::ExternalError( strrefdup( oss
) );
434 // I fiddle a little with the consts here...
435 FontMetrics::AFM
* newMetrics
= new FontMetrics::AFM
;
436 metrics_
= RefCountPtr
< const FontMetrics::FontMetric
>( newMetrics
);
438 AfmScanner
scanner( newMetrics
, & afmFile
);
439 scanner
.setTellQue( Interaction::fontMetricMessages
); // We want to know about things that are not recognized and this ignored.
440 if( Interaction::fontMetricDebug
)
442 scanner
.set_debug( 1 );
446 int status
= scanner
.yylex( );
449 std::ostringstream oss
;
450 oss
<< "Font metrics parser returned with non-zero status: " << status
;
451 throw Exceptions::InternalError( strrefdup( oss
) );
454 catch( const char * ball
)
456 std::ostringstream oss
;
457 oss
<< "Font metrics parser failed with message: " << ball
;
458 throw Exceptions::InternalError( strrefdup( oss
) );
460 catch( const RefCountPtr
< const char > ball
)
462 std::ostringstream oss
;
463 oss
<< "Font metrics parser failed with message: " << ball
;
464 throw Exceptions::InternalError( strrefdup( oss
) );
471 Lang::Font::show( std::ostream
& os
) const
473 os
<< "< font: " << fontName_
<< " >" ;
477 Lang::Font::gcMark( Kernel::GCMarkedSet
& marked
)
480 RefCountPtr
< const Lang::Class
> Lang::Font::TypeID( new Lang::SystemFinalClass( strrefdup( "Font" ), Font_register_methods
) );
481 TYPEINFOIMPL( Font
);
484 Lang::PDFStandardFont::PDFStandardFont( const RefCountPtr
< const char > builtInFontName
)
485 : Lang::Font( builtInFontName
)
488 Lang::PDFStandardFont::~PDFStandardFont( )
492 Lang::PDFStandardFont::encode( const char ** text_UTF8
, size_t * in_avail
, char ** dst_PDF
, size_t * out_avail
) const
494 encode_MacRoman( text_UTF8
, in_avail
, dst_PDF
, out_avail
);
498 Lang::PDFStandardFont::encode( Kernel::UnicodeCodePoint c
, char ** dst_PDF
, size_t * out_avail
) const
500 encode_MacRoman( c
, dst_PDF
, out_avail
);
504 Lang::PDFStandardFont::encode_MacRoman( const char ** text_UTF8
, size_t * in_avail
, char ** dst_PDF
, size_t * out_avail
)
506 iconv_t converter
= Helpers::requireUTF8ToMacRomanConverter( );
507 // The ICONV_CAST macro is defined in config.h.
508 size_t count
= iconv( converter
,
509 ICONV_CAST( text_UTF8
), in_avail
,
510 dst_PDF
, out_avail
);
511 if( count
== (size_t)(-1) )
513 if( errno
== EILSEQ
)
515 throw Exceptions::MiscellaneousRequirement( "It is suspected that one of the UFT-8 characters used in showed text cannot be represented in the MacRoman encoding (used for the 14 standard fonts of PDF; consider using a normal font instead)." );
517 else if( errno
== EINVAL
)
519 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
521 else if( errno
== E2BIG
)
523 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to PDF show-text string conversion was too small." );
527 std::ostringstream msg
;
528 msg
<< "iconv failed with an unrecognized error code: " << errno
;
529 throw Exceptions::InternalError( strrefdup( msg
) );
535 Lang::PDFStandardFont::encode_MacRoman( Kernel::UnicodeCodePoint c
, char ** dst_PDF
, size_t * out_avail
)
539 throw Exceptions::InternalError( "The buffer allocated conversion of a single UCS-4 to MacRoman was too small." );
541 **dst_PDF
= c
.get_MacRoman( );
547 Lang::Type3Font::Type3Font( const RefCountPtr
< const char > fontName
, RefCountPtr
< SimplePDF::PDF_Object
> & resource
, RefCountPtr
< const FontMetrics::FontMetric
> metrics
)
548 : Lang::Font( fontName
, resource
, metrics
)
551 Lang::Type3Font::~Type3Font( )
555 Lang::Type3Font::encode( const char ** text_UTF8
, size_t * in_avail
, char ** dst_PDF
, size_t * out_avail
) const
557 Lang::PDFStandardFont::encode_MacRoman( text_UTF8
, in_avail
, dst_PDF
, out_avail
);
561 Lang::Type3Font::encode( Kernel::UnicodeCodePoint c
, char ** dst_PDF
, size_t * out_avail
) const
563 Lang::PDFStandardFont::encode_MacRoman( c
, dst_PDF
, out_avail
);
570 Lang::FreeTypeFont::FreeTypeFont( FT_Face face
, const RefCountPtr
< const char > fontName
, RefCountPtr
< SimplePDF::PDF_Object
> & resource
, RefCountPtr
< const FontMetrics::FontMetric
> metrics
, RefCountPtr
< SimplePDF::PDF_ToUnicode::CharSet
> & usedChars
)
571 : Lang::Font( fontName
, resource
, metrics
),
573 usedChars_( usedChars
)
576 Lang::FreeTypeFont::~FreeTypeFont( )
580 Lang::FreeTypeFont::encode( const char ** text_UTF8
, size_t * in_avail
, char ** dst_PDF
, size_t * out_avail
) const
582 iconv_t converter
= Helpers::requireUTF8ToUCS4Converter( );
584 size_t bufSize
= 4 * *in_avail
;
585 char * buf
= new char[ bufSize
];
587 DeleteOnExit
< char > bufDeleter( buf
);
589 // The ICONV_CAST macro is defined in config.h.
590 size_t count
= iconv( converter
,
591 ICONV_CAST( text_UTF8
), in_avail
,
592 & outbuf
, & bufSize
);
593 if( count
== (size_t)(-1) )
595 if( errno
== EILSEQ
)
597 throw Exceptions::MiscellaneousRequirement( "Failed to convert from UTF-8 to UCS-4 code points." );
599 else if( errno
== EINVAL
)
601 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
603 else if( errno
== E2BIG
)
605 throw Exceptions::InternalError( "The temporary UCS-4 buffer allocated for UTF-8 to PDF show-text string conversion was too small." );
609 std::ostringstream msg
;
610 msg
<< "iconv failed with an unrecognized error code: " << errno
;
611 throw Exceptions::InternalError( strrefdup( msg
) );
614 /* The number of characters equals ( outbuf - buf ) / 4, so the memory needed to store these equals
615 * 2 * ( outbuf - buf ) / 4 = ( outbuf - buf ) / 2
617 if( static_cast< ptrdiff_t >( *out_avail
) < ( outbuf
- buf
) / 2 )
619 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to PDF show-text string conversion was too small." );
621 *out_avail
-= ( outbuf
- buf
) / 2;
622 for( const char * src
= buf
; src
!= outbuf
; src
+= 4)
624 Kernel::UnicodeCodePoint code
;
625 code
.decode_UCS4( src
);
626 usedChars_
->insert( usedChars_
->begin( ), code
);
627 FT_UInt index
= FT_Get_Char_Index( face_
, code
.get_UCS4( ) );
630 std::cerr
<< "Warning: Missing glyph: " << code
.get_UCS4( ) << std::endl
;
634 throw Exceptions::InternalError( "PDF text encoding: Glyph index is out of the two byte code range." );
636 /* Remember that the endianness is unknown! Hence, don't */
637 // *reinterpret_cast< uint16_t * >( *dst_PDF ) = index;
640 **dst_PDF
= index
/ 0x100;
642 **dst_PDF
= index
% 0x100;
648 Lang::FreeTypeFont::encode( Kernel::UnicodeCodePoint c
, char ** dst_PDF
, size_t * out_avail
) const
652 throw Exceptions::InternalError( "The buffer allocated conversion of one UCS-4 code point to PDF show-text encoding was too small." );
654 FT_UInt index
= FT_Get_Char_Index( face_
, c
.get_UCS4( ) );
657 std::cerr
<< "Warning: Missing glyph: " << c
.get_UCS4( ) << std::endl
;
661 throw Exceptions::InternalError( "PDF text encoding: Glyph index is out of the two byte code range." );
663 /* Remember that the endianness is unknown! Hence, don't */
664 // *reinterpret_cast< uint16_t * >( *dst_PDF ) = index;
667 **dst_PDF
= index
/ 0x100;
669 **dst_PDF
= index
% 0x100;
674 RefCountPtr
< const Lang::String
>
675 Lang::FreeTypeFont::family_name( ) const
677 return RefCountPtr
< const Lang::String
>( new Lang::String( face_
->family_name
, true ) );
680 RefCountPtr
< const Lang::String
>
681 Lang::FreeTypeFont::style_name( ) const
683 return RefCountPtr
< const Lang::String
>( new Lang::String( face_
->style_name
, true ) );
686 RefCountPtr
< const Lang::Symbol
>
687 Lang::FreeTypeFont::PostScript_name( ) const
689 const char * PostScriptName
= FT_Get_Postscript_Name( face_
);
690 if( PostScriptName
== 0 )
692 throw Exceptions::MiscellaneousRequirement( "The FreeType font does not provide a PostScript name." );
694 /* It is assumed that the created symbol is not used after the face_ is destroyed! */
695 return RefCountPtr
< const Lang::Symbol
>( new Lang::Symbol( PostScriptName
) );
705 Lang::MultiPath2D
* paths_
;
706 Lang::ElementaryPath2D
* contour_
;
707 Concrete::PathPoint2D
* last_
;
708 Concrete::Length scaled_font_unit_
;
714 /* We should eliminate the duplicated point where the path begins and ends. */
715 contour_
->pop_back( );
716 if( last_
->rear_
!= last_
->mid_
)
718 contour_
->front( )->rear_
= last_
->rear_
;
719 last_
->rear_
= last_
->mid_
; /* This gives away the ownership of last_->rear_. */
727 int move_to( const FT_Vector
& to
)
730 contour_
= new Lang::ElementaryPath2D( );
731 paths_
->push_back( RefCountPtr
< const Lang::Path2D
>( contour_
) );
732 last_
= new Concrete::PathPoint2D( new Concrete::Coords2D( to
.x
* scaled_font_unit_
, to
.y
* scaled_font_unit_
) );
733 contour_
->push_back( last_
);
736 int line_to( const FT_Vector
& to
)
738 last_
= new Concrete::PathPoint2D( new Concrete::Coords2D( to
.x
* scaled_font_unit_
, to
.y
* scaled_font_unit_
) );
739 contour_
->push_back( last_
);
742 int conic_to( const FT_Vector
& control
, const FT_Vector
& to
)
744 Concrete::Coords2D
c( control
.x
* scaled_font_unit_
, control
.y
* scaled_font_unit_
);
745 last_
->front_
= new Concrete::Coords2D( (2./3) * c
+ (1./3) * *last_
->mid_
);
746 last_
= new Concrete::PathPoint2D( new Concrete::Coords2D( to
.x
* scaled_font_unit_
, to
.y
* scaled_font_unit_
) );
747 last_
->rear_
= new Concrete::Coords2D( (2./3) * c
+ (1./3) * *last_
->mid_
);
748 contour_
->push_back( last_
);
751 int cubic_to( const FT_Vector
& control1
, const FT_Vector
& control2
, const FT_Vector
& to
)
753 last_
->front_
= new Concrete::Coords2D( control1
.x
* scaled_font_unit_
, control1
.y
* scaled_font_unit_
);
754 last_
= new Concrete::PathPoint2D( new Concrete::Coords2D( to
.x
* scaled_font_unit_
, to
.y
* scaled_font_unit_
) );
755 last_
->rear_
= new Concrete::Coords2D( control2
.x
* scaled_font_unit_
, control2
.y
* scaled_font_unit_
);
756 contour_
->push_back( last_
);
760 GetGlyphState( Lang::MultiPath2D
* paths
, Concrete::Length scaled_font_unit
)
764 scaled_font_unit_( scaled_font_unit
)
771 int getGlyph_move_to( const FT_Vector
* to
, void * stateUntyped
)
773 return reinterpret_cast< GetGlyphState
* >( stateUntyped
)->move_to( *to
);
775 int getGlyph_line_to( const FT_Vector
* to
, void * stateUntyped
)
777 return reinterpret_cast< GetGlyphState
* >( stateUntyped
)->line_to( *to
);
779 int getGlyph_conic_to( const FT_Vector
* control
, const FT_Vector
* to
, void * stateUntyped
)
781 return reinterpret_cast< GetGlyphState
* >( stateUntyped
)->conic_to( *control
, *to
);
783 int getGlyph_cubic_to( const FT_Vector
* control1
, const FT_Vector
* control2
, const FT_Vector
* to
, void * stateUntyped
)
785 return reinterpret_cast< GetGlyphState
* >( stateUntyped
)->cubic_to( *control1
, *control2
, *to
);
790 RefCountPtr
< const Lang::Value
>
791 Lang::FreeTypeFont::getGlyph( Kernel::UnicodeCodePoint c
, Concrete::Length size
) const
793 FT_UInt index
= FT_Get_Char_Index( face_
, c
.get_UCS4( ) );
796 const size_t bufsize
= 10;
799 size_t outavail
= bufsize
- 1;
800 c
.encode_UTF8( & tmp
, & outavail
);
802 std::ostringstream msg
;
803 msg
<< "The font " << fontName_
<< " does not cover the character `" << buf
<< "´ (code point " << c
.get_UCS4( ) << ")." ;
804 throw Exceptions::OutOfRange( strrefdup( msg
) );
806 FT_Error error
= FT_Load_Glyph( face_
, index
, FT_LOAD_NO_SCALE
);
809 std::ostringstream msg
;
810 msg
<< "Unable to load glyph in FreeType 2, at code point " << c
.get_UCS4( ) ;
811 throw Shapes::Exceptions::OutOfRange( strrefdup( msg
) );
813 if( face_
->glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
815 const size_t bufsize
= 10;
818 size_t outavail
= bufsize
- 1;
819 c
.encode_UTF8( & tmp
, & outavail
);
821 std::ostringstream msg
;
822 msg
<< "Unsupported glyph format in the font " << fontName_
<< ", character `" << buf
<< "´ (code point " << c
.get_UCS4( ) << ")." ;
823 throw Exceptions::MiscellaneousRequirement( strrefdup( msg
) );
826 const FT_Outline
& ol
= face_
->glyph
->outline
;
828 Helpers::FontMethod_glyph_resultFactory
.set
830 Kernel::VariableHandle( new Kernel::Variable( ( ( ol
.flags
& FT_OUTLINE_REVERSE_FILL
) == 0 ) ? Lang::THE_FILL
: Lang::THE_FILLODD
) ) );
832 Lang::MultiPath2D
* pathsPtr
= new Lang::MultiPath2D( );
833 RefCountPtr
< const Lang::MultiPath2D
> paths( pathsPtr
);
835 FT_Outline_Funcs emitters
;
836 emitters
.move_to
= Helpers::getGlyph_move_to
;
837 emitters
.line_to
= Helpers::getGlyph_line_to
;
838 emitters
.conic_to
= Helpers::getGlyph_conic_to
;
839 emitters
.cubic_to
= Helpers::getGlyph_cubic_to
;
842 Helpers::GetGlyphState
state( pathsPtr
, size
/ static_cast< double >( face_
->units_per_EM
) );
843 FT_Error error
= FT_Outline_Decompose( & face_
->glyph
->outline
, & emitters
, reinterpret_cast< void * >( & state
) );
846 std::ostringstream msg
;
847 msg
<< "FreeType error, FT_Outline_Decompose returned with error: " << Kernel::FreeTypeErrorMessage( error
) ;
848 throw Exceptions::ExternalError( strrefdup( msg
) );
851 Helpers::FontMethod_glyph_resultFactory
.set( "paths", Kernel::VariableHandle( new Kernel::Variable( paths
) ) );
853 return Helpers::FontMethod_glyph_resultFactory
.build( );
856 #endif /* End of #ifdef HAVE_FT2. */
858 Lang::TextOperation::TextOperation( )
861 Lang::TextOperation::~TextOperation( )
864 RefCountPtr
< const Lang::Class
> Lang::TextOperation::TypeID( new Lang::SystemFinalClass( strrefdup( "TextOperation" ) ) );
865 TYPEINFOIMPL( TextOperation
);
868 Lang::KernedText::KernedText( const RefCountPtr
< const Kernel::TextState
> & textState
, const RefCountPtr
< const Kernel::GraphicsState
> & metaState
)
869 : textState_( textState
), metaState_( metaState
), maxLength_( 0 )
872 Lang::KernedText::KernedText( const RefCountPtr
< const Kernel::TextState
> & textState
, const RefCountPtr
< const Kernel::GraphicsState
> & metaState
, const RefCountPtr
< const Lang::String
> & str
)
873 : textState_( textState
), metaState_( metaState
), maxLength_( 0 )
878 Lang::KernedText::~KernedText( )
881 Kernel::VariableHandle
882 Lang::KernedText::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
884 if( strcmp( fieldID
, "list" ) == 0 )
886 return Kernel::VariableHandle( new Kernel::Variable( makeList( ) ) );
888 throw Exceptions::NonExistentMember( getTypeName( ), fieldID
);
891 RefCountPtr
< const Lang::SingleList
>
892 Lang::KernedText::makeList( ) const
894 /* The list is first computed in a bidirectional list, and then we construct the stateless cons list.
897 /* I'm lazy today, so i use a cons pair to group the horizontal step with the glyph. The better solution
898 * would be to use a structure with nicely named fields...
901 std::list
< RefCountPtr
< const Lang::Value
> > revlist
;
903 iconv_t converter
= Helpers::requireUTF8ToUCS4Converter( );
905 RefCountPtr
< FontMetrics::WritingDirectionMetrics
> horizontalMetrics
= textState_
->font_
->metrics( )->horizontalMetrics_
;
906 if( horizontalMetrics
== NullPtr
< FontMetrics::WritingDirectionMetrics
>( ) )
908 throw Exceptions::FontMetricsError( textState_
->font_
->fontName( ), strrefdup( "No horizontal metrics defined." ) );
910 const FontMetrics::CharacterMetrics
* defaultCharMetrics
= horizontalMetrics
->default_char( );
912 Concrete::Length ySize
= textState_
->size_
;
913 Concrete::Length xSize
= ySize
* textState_
->horizontalScaling_
;
914 Concrete::Length characterTrackKern
= textState_
->horizontalScaling_
* textState_
->characterSpacing_
;
915 Concrete::Length wordTrackKern
= textState_
->horizontalScaling_
* textState_
->wordSpacing_
;
917 Concrete::Length xpos
= 0;
919 size_t bufSize
= 4 * maxLength_
; // This will be enough if UCS4 coding is used, since this encoding uses only one byte per character.
920 char * buf
= new char[ bufSize
];
921 DeleteOnExit
< char > bufDeleter( buf
);
923 FontMetrics::CharacterMetrics
tmpCharMetric( 0 );
925 typedef typeof strings_ ListType
;
926 std::list
< double >::const_iterator ki
= kernings_
.begin( );
927 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
929 if( *i
!= NullPtr
< const Lang::String
>( ) )
931 const char * inbuf
= (*i
)->val_
.getPtr( );
932 if( strchr( inbuf
, '\n' ) != 0 )
934 throw Exceptions::MiscellaneousRequirement( "Newlines cannot be represented in the pos-character list." );
937 size_t inbytesleft
= strlen( inbuf
);
938 size_t outbytesleft
= bufSize
;
939 // The ICONV_CAST macro is defined in config.h.
940 size_t count
= iconv( converter
,
941 ICONV_CAST( & inbuf
), & inbytesleft
,
942 & outbuf
, & outbytesleft
);
943 if( count
== (size_t)(-1) )
945 if( errno
== EILSEQ
)
947 throw Exceptions::MiscellaneousRequirement( "It is suspected that string data is not proper UFT-8, since conversion to UCS-4 failed." );
949 else if( errno
== EINVAL
)
951 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
953 else if( errno
== E2BIG
)
955 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to UCS-4 conversion was too small." );
959 std::ostringstream msg
;
960 msg
<< "iconv failed with an unrecognized error code: " << errno
;
961 throw Exceptions::InternalError( strrefdup( msg
) );
964 for( const char * src
= buf
; src
!= outbuf
; src
+= 4 )
966 Kernel::UnicodeCodePoint code
;
967 code
.decode_UCS4( src
);
968 if( code
== Kernel::UnicodeCodePoint::SPACE
) /* test for space */
970 // Observe textState_->wordSpacing_
971 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
972 xpos
+= xSize
* charMetrics
->horizontalCharWidthX_
;
973 xpos
+= characterTrackKern
;
974 xpos
+= wordTrackKern
;
976 else /* there should not be any newlines in the string, so we expect this to be a non-white character */
978 // Observe textState_->characterSpacing_
979 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
980 if( Computation::fontMetricGuessIsError
&& charMetrics
== defaultCharMetrics
)
982 std::ostringstream msg
;
983 msg
<< "Character at offset " << src
- buf
<< " in \"" << buf
<< "\" was not found in font metrics (and according to your options, guessing is not OK)." ;
984 throw Exceptions::FontMetricsError( textState_
->font_
->fontName( ), strrefdup( msg
) );
986 revlist
.push_back( RefCountPtr
< const Lang::Value
>
988 ( Helpers::newValHandle( new Lang::Length( xpos
) ),
989 Helpers::newValHandle( new Lang::KernedText( textState_
, metaState_
, oneUCS4ToUTF8( src
) ) ) ) ) );
990 /* Although not as efficient, it becomes easier to use the list if the distance is
991 * measured from the start of the text rather than from the previous character.
994 xpos
+= xSize
* charMetrics
->horizontalCharWidthX_
;
995 xpos
+= characterTrackKern
;
1001 if( ki
== kernings_
.end( ) )
1003 throw Exceptions::InternalError( "Short of kerning values in KernedText::measure." );
1005 xpos
-= xSize
* *ki
;
1009 if( ki
!= kernings_
.end( ) )
1011 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
1014 RefCountPtr
< const Lang::SingleList
> res
= Lang::THE_CONS_NULL
;
1015 while( ! revlist
.empty( ) )
1017 res
= RefCountPtr
< const Lang::SingleList
>( new Lang::SingleListPair( Kernel::VariableHandle( new Kernel::Variable( revlist
.back( ) ) ),
1019 revlist
.pop_back( );
1024 RefCountPtr
< const Lang::String
>
1025 Lang::KernedText::oneUCS4ToUTF8( const char * c
)
1027 iconv_t converter
= Helpers::requireUCS4ToUTF8Converter( );
1029 const size_t BUF_SIZE
= 9;
1030 char buf
[ BUF_SIZE
];
1042 char * outbuf
= buf
;
1043 const char * inbuf
= charbuf
;
1044 size_t inbytesleft
= 4;
1045 size_t outbytesleft
= BUF_SIZE
- 1;
1046 // The ICONV_CAST macro is defined in config.h.
1047 size_t count
= iconv( converter
,
1048 ICONV_CAST( & inbuf
), & inbytesleft
,
1049 & outbuf
, & outbytesleft
);
1050 if( count
== (size_t)(-1) )
1052 throw Exceptions::ExternalError( "Conversion of one UCS-4 character to UTF-8 failed." );
1055 return RefCountPtr
< const Lang::String
>( new Lang::String( strrefdup( buf
) ) );
1059 Lang::KernedText::pushString( const RefCountPtr
< const Lang::String
> & str
)
1061 strings_
.push_back( str
);
1062 maxLength_
= std::max( maxLength_
, strlen( str
->val_
.getPtr( ) ) );
1066 Lang::KernedText::pushKerning( double kerning
)
1068 strings_
.push_back( NullPtr
< const Lang::String
>( ) );
1069 kernings_
.push_back( kerning
);
1073 Lang::KernedText::show( std::ostream
& os
) const
1075 typedef typeof strings_ ListType
;
1076 std::list
< double >::const_iterator ki
= kernings_
.begin( );
1077 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1079 if( *i
!= NullPtr
< const Lang::String
>( ) )
1081 os
<< "(" << (*i
)->val_
.getPtr( ) << ")" ;
1085 if( ki
== kernings_
.end( ) )
1087 throw Exceptions::InternalError( "Short of kerning values in KernedText::show." );
1093 if( ki
!= kernings_
.end( ) )
1095 throw Exceptions::InternalError( "Too many kerning values in KernedText::show." );
1101 Lang::KernedText::shipout( std::ostream
& os
, Kernel::PageContentStates
* pdfState
, const Lang::Transform2D
& tf
, bool clip
) const
1103 pdfState
->text_
.synchAssertKnockout( os
, textState_
.getPtr( ), pdfState
->resources_
.getPtr( ), clip
);
1104 switch( textState_
->mode_
)
1106 case Lang::TextRenderingMode::FILL
:
1107 case Lang::TextRenderingMode::FILLCLIP
:
1108 pdfState
->graphics_
.synchForNonStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1110 case Lang::TextRenderingMode::STROKE
:
1111 case Lang::TextRenderingMode::STROKECLIP
:
1112 pdfState
->graphics_
.synchForStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1114 case Lang::TextRenderingMode::FILLSTROKE
:
1115 case Lang::TextRenderingMode::FILLSTROKECLIP
:
1116 pdfState
->graphics_
.synchForStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1117 pdfState
->graphics_
.synchForNonStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1119 case Lang::TextRenderingMode::INVISIBLE
:
1120 case Lang::TextRenderingMode::CLIP
:
1122 case Lang::TextRenderingMode::UNDEFINED
:
1123 pdfState
->graphics_
.synchForStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1124 pdfState
->graphics_
.synchForNonStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1126 throw Exceptions::InternalError( "KernedText::writePDFVectorTo: Text rendering mode out of range." );
1130 size_t bufSize
= 4 * maxLength_
; // Even with UTF16BE encoding, no character should use more than 4 bytes.
1131 // The extra one byte will be used to terminate the string.
1132 char * buf
= new char[ bufSize
];
1133 DeleteOnExit
< char > bufDeleter( buf
);
1135 typedef typeof strings_ ListType
;
1136 std::list
< double >::const_iterator ki
= kernings_
.begin( );
1138 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1140 if( *i
!= NullPtr
< const Lang::String
>( ) )
1143 const char * line
= (*i
)->val_
.getPtr( );
1146 const char * nextLine
= strchr( line
, '\n' ); /* Search for line breaks before we convert from UTF8. */
1147 const char * inbuf
= line
;
1148 char * outbuf
= buf
;
1149 size_t inbytesleft
= ( nextLine
!= 0 ) ? ( nextLine
- line
) : strlen( line
);
1150 size_t outbytesleft
= bufSize
;
1151 textState_
->font_
->encode( & inbuf
, & inbytesleft
,
1152 & outbuf
, & outbytesleft
);
1153 const char * end
= buf
+ ( bufSize
- outbytesleft
);
1154 for( const char * src
= buf
; src
!= end
; ++src
)
1175 os
<< ")] TJ T* [(" ;
1177 ++line
; /* Skip the \n character */
1183 if( ki
== kernings_
.end( ) )
1185 throw Exceptions::InternalError( "Short of kerning values in KernedText::writePDFVectorTo." );
1187 os
<< 1000 * *ki
<< " " ;
1191 if( ki
!= kernings_
.end( ) )
1193 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
1196 os
<< "] TJ " << std::endl
;
1200 Lang::KernedText::measure( Lang::Transform2D
* textMatrix
, Lang::Transform2D
* textLineMatrix
, Concrete::Length
* xmin
, Concrete::Length
* ymin
, Concrete::Length
* xmax
, Concrete::Length
* ymax
) const
1202 iconv_t converter
= Helpers::requireUTF8ToUCS4Converter( );
1204 RefCountPtr
< FontMetrics::WritingDirectionMetrics
> horizontalMetrics
= textState_
->font_
->metrics( )->horizontalMetrics_
;
1205 if( horizontalMetrics
== NullPtr
< FontMetrics::WritingDirectionMetrics
>( ) )
1207 throw Exceptions::FontMetricsError( textState_
->font_
->fontName( ), strrefdup( "No horizontal metrics defined." ) );
1209 const FontMetrics::CharacterMetrics
* defaultCharMetrics
= horizontalMetrics
->default_char( );
1211 Concrete::Length ySize
= textState_
->size_
;
1212 Concrete::Length xSize
= ySize
* textState_
->horizontalScaling_
;
1213 Concrete::Length characterTrackKern
= textState_
->horizontalScaling_
* textState_
->characterSpacing_
;
1214 Concrete::Length wordTrackKern
= textState_
->horizontalScaling_
* textState_
->wordSpacing_
;
1216 size_t bufSize
= 4 * maxLength_
;
1217 char * buf
= new char[ bufSize
];
1218 DeleteOnExit
< char > bufDeleter( buf
);
1220 FontMetrics::CharacterMetrics
tmpCharMetric( 0 );
1222 if( textLineMatrix
->isTranslation( ) )
1224 Concrete::Length x0
= textLineMatrix
->xt_
;
1225 Concrete::Length y0
= textLineMatrix
->yt_
+ textState_
->riseConcrete( );
1226 Concrete::Length xpos
= 0;
1228 typedef typeof strings_ ListType
;
1229 std::list
< double >::const_iterator ki
= kernings_
.begin( );
1230 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1232 if( *i
!= NullPtr
< const Lang::String
>( ) )
1234 const char * inbuf
= (*i
)->val_
.getPtr( );
1235 char * outbuf
= buf
;
1236 size_t inbytesleft
= strlen( inbuf
);
1237 size_t outbytesleft
= bufSize
;
1238 // The ICONV_CAST macro is defined in config.h.
1239 size_t count
= iconv( converter
,
1240 ICONV_CAST( & inbuf
), & inbytesleft
,
1241 & outbuf
, & outbytesleft
);
1242 if( count
== (size_t)(-1) )
1244 if( errno
== EILSEQ
)
1246 throw Exceptions::MiscellaneousRequirement( "Failed to convert from UFT-8 to UCS-4 code points." );
1248 else if( errno
== EINVAL
)
1250 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
1252 else if( errno
== E2BIG
)
1254 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to UCS-4 conversion was too small." );
1258 std::ostringstream msg
;
1259 msg
<< "iconv failed with an unrecognized error code: " << errno
;
1260 throw Exceptions::InternalError( strrefdup( msg
) );
1263 for( const char * src
= buf
; src
!= outbuf
; src
+= 4 )
1265 Kernel::UnicodeCodePoint code
;
1266 code
.decode_UCS4( src
);
1267 if( code
== Kernel::UnicodeCodePoint::SPACE
)
1269 // Observe textState_->wordSpacing_
1270 // In addition, it seems reasonable to not let the space character affect the bounding box.
1271 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
1272 xpos
+= xSize
* charMetrics
->horizontalCharWidthX_
;
1273 xpos
+= characterTrackKern
;
1274 xpos
+= wordTrackKern
;
1276 else if( code
== Kernel::UnicodeCodePoint::NEWLINE
)
1278 textMatrix
->prependShift( Concrete::Coords2D( 0, - textState_
->leadingConcrete( ) ) );
1279 textLineMatrix
->replaceBy( *textMatrix
);
1280 x0
= textLineMatrix
->xt_
;
1281 y0
= textLineMatrix
->yt_
+ textState_
->riseConcrete( );
1286 // Observe textState_->characterSpacing_
1287 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
1288 if( Computation::fontMetricGuessIsError
&& charMetrics
== defaultCharMetrics
)
1290 std::ostringstream msg
;
1291 msg
<< "Character at offset " << src
- buf
<< " in \"" << buf
<< "\" was not found in font metrics (and according to your options, guessing is not OK)." ;
1292 throw Exceptions::FontMetricsError( textState_
->font_
->fontName( ), strrefdup( msg
) );
1294 *xmin
= std::min( *xmin
, x0
+ xpos
+ xSize
* charMetrics
->xmin_
);
1295 *ymin
= std::min( *ymin
, y0
+ ySize
* charMetrics
->ymin_
);
1296 *xmax
= std::max( *xmax
, x0
+ xpos
+ xSize
* charMetrics
->xmax_
);
1297 *ymax
= std::max( *ymax
, y0
+ ySize
* charMetrics
->ymax_
);
1298 xpos
+= xSize
* charMetrics
->horizontalCharWidthX_
;
1299 xpos
+= characterTrackKern
;
1305 if( ki
== kernings_
.end( ) )
1307 throw Exceptions::InternalError( "Short of kerning values in KernedText::measure." );
1309 xpos
-= xSize
* *ki
;
1313 if( ki
!= kernings_
.end( ) )
1315 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
1318 textLineMatrix
->prependXShift( xpos
);
1322 Concrete::Length rise
= textState_
->riseConcrete( );
1323 // std::cerr << "@<< @stroking:RGB_RED | [stroke [shift " << Helpers::shapesFormat( Concrete::Coords2D( 0, 0 ).transformed( *textLineMatrix ) ) << "] [] [circle 2bp]]" << std::endl ;
1325 typedef typeof strings_ ListType
;
1326 std::list
< double >::const_iterator ki
= kernings_
.begin( );
1327 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1329 if( *i
!= NullPtr
< const Lang::String
>( ) )
1331 const char * inbuf
= (*i
)->val_
.getPtr( );
1332 char * outbuf
= buf
;
1333 size_t inbytesleft
= strlen( inbuf
);
1334 size_t outbytesleft
= bufSize
;
1335 // The ICONV_CAST macro is defined in config.h.
1336 size_t count
= iconv( converter
,
1337 ICONV_CAST( & inbuf
), & inbytesleft
,
1338 & outbuf
, & outbytesleft
);
1339 if( count
== (size_t)(-1) )
1341 if( errno
== EILSEQ
)
1343 throw Exceptions::MiscellaneousRequirement( "It is suspected that one of the UFT-8 characters used in showed text has no MacRoman representation." );
1345 else if( errno
== EINVAL
)
1347 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
1349 else if( errno
== E2BIG
)
1351 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to UCS-4 conversion was too small." );
1355 std::ostringstream msg
;
1356 msg
<< "iconv failed with an unrecognized error code: " << errno
;
1357 throw Exceptions::InternalError( strrefdup( msg
) );
1360 for( const char * src
= buf
; src
!= outbuf
; src
+= 4 )
1362 Kernel::UnicodeCodePoint code
;
1363 code
.decode_UCS4( src
);
1364 if( code
== Kernel::UnicodeCodePoint::SPACE
)
1366 // Observe textState_->wordSpacing_
1367 // In addition, it seems reasonable to not let the space character affect the bounding box.
1368 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
1369 textLineMatrix
->prependXShift( xSize
* charMetrics
->horizontalCharWidthX_
+ characterTrackKern
+ wordTrackKern
);
1370 // std::cerr << "@<< @stroking:RGB_BLUE | [stroke [shift " << Helpers::shapesFormat( Concrete::Coords2D( 0, 0 ).transformed( *textLineMatrix ) ) << "] [] [circle 2bp]]" << std::endl ;
1372 else if( code
== Kernel::UnicodeCodePoint::NEWLINE
)
1374 textMatrix
->prependShift( Concrete::Coords2D( 0, - textState_
->leadingConcrete( ) ) );
1375 textLineMatrix
->replaceBy( *textMatrix
);
1376 // std::cerr << "@<< @stroking:RGB_RED | [stroke [shift " << Helpers::shapesFormat( Concrete::Coords2D( 0, 0 ).transformed( *textLineMatrix ) ) << "] [] [circle 2bp]]" << std::endl ;
1380 // Observe textState_->characterSpacing_
1381 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
1382 if( Computation::fontMetricGuessIsError
&& charMetrics
== defaultCharMetrics
)
1384 std::ostringstream msg
;
1385 msg
<< "Character at offset " << src
- buf
<< " in \"" << buf
<< "\" was not found in the font metrics (and according to your options, guessing is not OK)." ;
1386 throw Exceptions::FontMetricsError( textState_
->font_
->fontName( ), strrefdup( msg
) );
1389 Concrete::Coords2D x0y0
= Concrete::Coords2D( xSize
* charMetrics
->xmin_
, ySize
* charMetrics
->ymin_
+ rise
).transformed( *textLineMatrix
);
1390 Concrete::Coords2D x0y1
= Concrete::Coords2D( xSize
* charMetrics
->xmin_
, ySize
* charMetrics
->ymax_
+ rise
).transformed( *textLineMatrix
);
1391 Concrete::Coords2D x1y0
= Concrete::Coords2D( xSize
* charMetrics
->xmax_
, ySize
* charMetrics
->ymin_
+ rise
).transformed( *textLineMatrix
);
1392 Concrete::Coords2D x1y1
= Concrete::Coords2D( xSize
* charMetrics
->xmax_
, ySize
* charMetrics
->ymax_
+ rise
).transformed( *textLineMatrix
);
1393 // std::cerr << "@<< @width:0.3bp | [stroke "<< Helpers::shapesFormat( x0y0 ) << "--" << Helpers::shapesFormat( x0y1 ) << "--" << Helpers::shapesFormat( x1y1 ) << "--" << Helpers::shapesFormat( x1y0 ) << "--cycle]" << std::endl ;
1395 *xmin
= std::min( *xmin
, x0y0
.x_
);
1396 *ymin
= std::min( *ymin
, x0y0
.y_
);
1397 *xmax
= std::max( *xmax
, x0y0
.x_
);
1398 *ymax
= std::max( *ymax
, x0y0
.y_
);
1400 *xmin
= std::min( *xmin
, x0y1
.x_
);
1401 *ymin
= std::min( *ymin
, x0y1
.y_
);
1402 *xmax
= std::max( *xmax
, x0y1
.x_
);
1403 *ymax
= std::max( *ymax
, x0y1
.y_
);
1405 *xmin
= std::min( *xmin
, x1y0
.x_
);
1406 *ymin
= std::min( *ymin
, x1y0
.y_
);
1407 *xmax
= std::max( *xmax
, x1y0
.x_
);
1408 *ymax
= std::max( *ymax
, x1y0
.y_
);
1410 *xmin
= std::min( *xmin
, x1y1
.x_
);
1411 *ymin
= std::min( *ymin
, x1y1
.y_
);
1412 *xmax
= std::max( *xmax
, x1y1
.x_
);
1413 *ymax
= std::max( *ymax
, x1y1
.y_
);
1415 textLineMatrix
->prependXShift( xSize
* charMetrics
->horizontalCharWidthX_
+ characterTrackKern
);
1416 // std::cerr << "@<< [stroke [shift " << Helpers::shapesFormat( Concrete::Coords2D( 0, 0 ).transformed( *textLineMatrix ) ) << "] [] [circle 2bp]]" << std::endl ;
1422 if( ki
== kernings_
.end( ) )
1424 throw Exceptions::InternalError( "Short of kerning values in KernedText::measure." );
1426 textLineMatrix
->prependXShift( - xSize
* *ki
);
1430 if( ki
!= kernings_
.end( ) )
1432 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
1438 Lang::KernedText::push( Lang::KernedText
* dst
) const
1440 typedef typeof strings_ ListType
;
1441 std::list
< double >::const_iterator ki
= kernings_
.begin( );
1442 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1444 if( *i
!= NullPtr
< const Lang::String
>( ) )
1446 dst
->pushString( *i
);
1450 dst
->pushKerning( *ki
);
1458 Lang::KernedText::gcMark( Kernel::GCMarkedSet
& marked
)
1460 typedef typeof strings_ ListType
;
1461 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1463 if( *i
!= NullPtr
< const Lang::String
>( ) )
1465 const_cast< Lang::String
* >( i
->getPtr( ) )->gcMark( marked
);
1470 Lang::TextNewline::TextNewline( const Concrete::Length tx
, const Concrete::Length ty
)
1474 Lang::TextNewline::~TextNewline( )
1478 Lang::TextNewline::show( std::ostream
& os
) const
1480 os
<< "Newline with offset in bp: " << t_
;
1484 Lang::TextNewline::shipout( std::ostream
& os
, Kernel::PageContentStates
* pdfState
, const Lang::Transform2D
& tf
, bool clip
) const
1486 os
<< t_
<< " Td " ;
1490 Lang::TextNewline::measure( Lang::Transform2D
* textMatrix
, Lang::Transform2D
* textLineMatrix
, Concrete::Length
* xmin
, Concrete::Length
* ymin
, Concrete::Length
* xmax
, Concrete::Length
* ymax
) const
1492 textMatrix
->prependShift( t_
);
1493 textLineMatrix
->replaceBy( *textMatrix
);
1497 Lang::TextNewline::gcMark( Kernel::GCMarkedSet
& marked
)
1500 Lang::TextMoveto::TextMoveto( const RefCountPtr
< const Lang::Transform2D
> & tf
)
1504 Lang::TextMoveto::~TextMoveto( )
1508 Lang::TextMoveto::show( std::ostream
& os
) const
1510 os
<< "Moveto command" ;
1514 Lang::TextMoveto::shipout( std::ostream
& os
, Kernel::PageContentStates
* pdfState
, const Lang::Transform2D
& tf
, bool clip
) const
1516 Lang::Transform2D( tf
, *tf_
).shipout( os
);
1517 os
<< " Tm" << std::endl
;
1521 Lang::TextMoveto::measure( Lang::Transform2D
* textMatrix
, Lang::Transform2D
* textLineMatrix
, Concrete::Length
* xmin
, Concrete::Length
* ymin
, Concrete::Length
* xmax
, Concrete::Length
* ymax
) const
1523 textMatrix
->replaceBy( *tf_
);
1524 textLineMatrix
->replaceBy( *textMatrix
);
1528 Lang::TextMoveto::gcMark( Kernel::GCMarkedSet
& marked
)
1530 const_cast< Lang::Transform2D
* >( tf_
.getPtr( ) )->gcMark( marked
);
1535 typedef enum { FILL
= 0, STROKE
, FILLSTROKE
, INVISIBLE
, FILLCLIP
, STROKECLIP
, FILLSTROKECLIP
, CLIP
, UNDEFINED
} ValueType
;
1538 Lang::TextRenderingMode::TextRenderingMode( const ValueType
& mode
)
1542 Lang::TextRenderingMode::TextRenderingMode( bool fill
, bool stroke
, bool clip
)
1544 switch( ( fill
? 0x01 : 0x00 ) +
1545 ( stroke
? 0x02 : 0x00 ) +
1546 ( clip
? 0x04 : 0x00 ) )
1570 mode_
= FILLSTROKECLIP
;
1573 throw Exceptions::InternalError( "Semi-static switch out of range in TextRenderingMode::TextRenderingMode." );
1577 Lang::TextRenderingMode::ValueType
1578 Lang::TextRenderingMode::clipMode( ValueType mode
)
1589 return FILLSTROKECLIP
;
1595 Lang::TextRenderingMode::~TextRenderingMode( )
1598 RefCountPtr
< const Lang::Class
> Lang::TextRenderingMode::TypeID( new Lang::SystemFinalClass( strrefdup( "TextRenderingMode" ) ) );
1599 TYPEINFOIMPL( TextRenderingMode
);
1602 Lang::CharacterSpacingBinding::CharacterSpacingBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, const Concrete::Length spacing
)
1603 : bindingExpr_( bindingExpr
), spacing_( spacing
), isRelative_( false ), id_( id
)
1606 Lang::CharacterSpacingBinding::CharacterSpacingBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, const double r
)
1607 : bindingExpr_( bindingExpr
), spacing_( r
), isRelative_( true ), id_( id
)
1610 Lang::CharacterSpacingBinding::~CharacterSpacingBinding( )
1614 Lang::CharacterSpacingBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
1616 if( *sysBindings
== 0 )
1618 *sysBindings
= new Kernel::SystemDynamicVariables( );
1619 Kernel::TextState
* newState
= new Kernel::TextState( );
1622 newState
->setCharacterSpacing( Concrete::Length::offtype( spacing_
) );
1626 newState
->setCharacterSpacing( spacing_
);
1628 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1632 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
1634 Kernel::TextState
* newState
= new Kernel::TextState( );
1637 newState
->setCharacterSpacing( Concrete::Length::offtype( spacing_
) );
1641 newState
->setCharacterSpacing( spacing_
);
1643 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1647 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
1649 if( newState
->hasCharacterSpacing( ) )
1651 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
1656 newState
->setCharacterSpacing( Concrete::Length::offtype( spacing_
) );
1660 newState
->setCharacterSpacing( spacing_
);
1662 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1666 Lang::CharacterSpacingBinding::show( std::ostream
& os
) const
1668 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
1671 os
<< Concrete::Length::offtype( spacing_
) ;
1675 os
<< spacing_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
1680 Lang::CharacterSpacingBinding::gcMark( Kernel::GCMarkedSet
& marked
)
1684 Lang::WordSpacingBinding::WordSpacingBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, const Concrete::Length spacing
)
1685 : bindingExpr_( bindingExpr
), spacing_( spacing
), isRelative_( false ), id_( id
)
1688 Lang::WordSpacingBinding::WordSpacingBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, const double r
)
1689 : bindingExpr_( bindingExpr
), spacing_( r
), isRelative_( true ), id_( id
)
1692 Lang::WordSpacingBinding::~WordSpacingBinding( )
1696 Lang::WordSpacingBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
1698 if( *sysBindings
== 0 )
1700 *sysBindings
= new Kernel::SystemDynamicVariables( );
1701 Kernel::TextState
* newState
= new Kernel::TextState( );
1704 newState
->setWordSpacing( Concrete::Length::offtype( spacing_
) );
1708 newState
->setWordSpacing( spacing_
);
1710 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1714 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
1716 Kernel::TextState
* newState
= new Kernel::TextState( );
1719 newState
->setWordSpacing( Concrete::Length::offtype( spacing_
) );
1723 newState
->setWordSpacing( spacing_
);
1725 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1729 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
1731 if( newState
->hasWordSpacing( ) )
1733 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
1738 newState
->setWordSpacing( Concrete::Length::offtype( spacing_
) );
1742 newState
->setWordSpacing( spacing_
);
1744 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1748 Lang::WordSpacingBinding::show( std::ostream
& os
) const
1750 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
1753 os
<< Concrete::Length::offtype( spacing_
) ;
1757 os
<< spacing_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
1762 Lang::WordSpacingBinding::gcMark( Kernel::GCMarkedSet
& marked
)
1766 Lang::HorizontalScalingBinding::HorizontalScalingBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, double scaling
)
1767 : bindingExpr_( bindingExpr
), scaling_( scaling
), id_( id
)
1770 Lang::HorizontalScalingBinding::~HorizontalScalingBinding( )
1774 Lang::HorizontalScalingBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
1776 if( *sysBindings
== 0 )
1778 *sysBindings
= new Kernel::SystemDynamicVariables( );
1779 Kernel::TextState
* newState
= new Kernel::TextState( );
1780 newState
->horizontalScaling_
= scaling_
;
1781 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1785 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
1787 Kernel::TextState
* newState
= new Kernel::TextState( );
1788 newState
->horizontalScaling_
= scaling_
;
1789 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1793 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
1795 if( ! IS_NAN( newState
->horizontalScaling_
) )
1797 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
1800 newState
->horizontalScaling_
= scaling_
;
1801 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1805 Lang::HorizontalScalingBinding::show( std::ostream
& os
) const
1807 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":"
1812 Lang::HorizontalScalingBinding::gcMark( Kernel::GCMarkedSet
& marked
)
1816 Lang::LeadingBinding::LeadingBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, const Concrete::Length ty
)
1817 : bindingExpr_( bindingExpr
), ty_( ty
), isRelative_( false ), id_( id
)
1820 Lang::LeadingBinding::LeadingBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, const double r
)
1821 : bindingExpr_( bindingExpr
), ty_( r
), isRelative_( true ), id_( id
)
1824 Lang::LeadingBinding::~LeadingBinding( )
1828 Lang::LeadingBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
1830 if( *sysBindings
== 0 )
1832 *sysBindings
= new Kernel::SystemDynamicVariables( );
1833 Kernel::TextState
* newState
= new Kernel::TextState( );
1836 newState
->setLeading( Concrete::Length::offtype( ty_
) );
1840 newState
->setLeading( ty_
);
1842 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1846 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
1848 Kernel::TextState
* newState
= new Kernel::TextState( );
1851 newState
->setLeading( Concrete::Length::offtype( ty_
) );
1855 newState
->setLeading( ty_
);
1857 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1861 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
1863 if( newState
->hasLeading( ) )
1865 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
1870 newState
->setLeading( Concrete::Length::offtype( ty_
) );
1874 newState
->setLeading( ty_
);
1876 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1880 Lang::LeadingBinding::show( std::ostream
& os
) const
1882 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
1885 os
<< Concrete::Length::offtype( ty_
) ;
1889 os
<< ty_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
1894 Lang::LeadingBinding::gcMark( Kernel::GCMarkedSet
& marked
)
1898 Lang::FontBinding::FontBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, const RefCountPtr
< const Lang::Font
> & font
)
1899 : bindingExpr_( bindingExpr
), font_( font
), id_( id
)
1902 Lang::FontBinding::~FontBinding( )
1906 Lang::FontBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
1908 if( *sysBindings
== 0 )
1910 *sysBindings
= new Kernel::SystemDynamicVariables( );
1911 Kernel::TextState
* newState
= new Kernel::TextState( );
1912 newState
->font_
= font_
;
1913 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1917 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
1919 Kernel::TextState
* newState
= new Kernel::TextState( );
1920 newState
->font_
= font_
;
1921 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1925 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
1927 if( newState
->font_
!= NullPtr
< const Lang::Font
>( ) )
1929 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
1932 newState
->font_
= font_
;
1933 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1937 Lang::FontBinding::show( std::ostream
& os
) const
1939 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
1944 Lang::FontBinding::gcMark( Kernel::GCMarkedSet
& marked
)
1946 const_cast< Lang::Font
* >( font_
.getPtr( ) )->gcMark( marked
);
1950 Lang::TextSizeBinding::TextSizeBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, const Concrete::Length size
)
1951 : bindingExpr_( bindingExpr
), size_( size
), id_( id
)
1954 Lang::TextSizeBinding::~TextSizeBinding( )
1958 Lang::TextSizeBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
1960 if( *sysBindings
== 0 )
1962 *sysBindings
= new Kernel::SystemDynamicVariables( );
1963 Kernel::TextState
* newState
= new Kernel::TextState( );
1964 newState
->size_
= size_
;
1965 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1969 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
1971 Kernel::TextState
* newState
= new Kernel::TextState( );
1972 newState
->size_
= size_
;
1973 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1977 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
1979 if( ! IS_NAN( newState
->size_
) )
1981 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
1984 newState
->size_
= size_
;
1985 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1989 Lang::TextSizeBinding::show( std::ostream
& os
) const
1991 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":"
1992 << size_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
1996 Lang::TextSizeBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2000 Lang::TextRenderingModeBinding::TextRenderingModeBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, const Lang::TextRenderingMode::ValueType mode
)
2001 : bindingExpr_( bindingExpr
), mode_( mode
), id_( id
)
2004 Lang::TextRenderingModeBinding::~TextRenderingModeBinding( )
2008 Lang::TextRenderingModeBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
2010 if( *sysBindings
== 0 )
2012 *sysBindings
= new Kernel::SystemDynamicVariables( );
2013 Kernel::TextState
* newState
= new Kernel::TextState( );
2014 newState
->mode_
= mode_
;
2015 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2019 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
2021 Kernel::TextState
* newState
= new Kernel::TextState( );
2022 newState
->mode_
= mode_
;
2023 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2027 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
2029 if( newState
->mode_
!= Lang::TextRenderingMode::UNDEFINED
)
2031 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
2034 newState
->mode_
= mode_
;
2035 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2039 Lang::TextRenderingModeBinding::show( std::ostream
& os
) const
2041 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":"
2042 << "<internal-enum>" ;
2046 Lang::TextRenderingModeBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2050 Lang::TextRiseBinding::TextRiseBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, const Concrete::Length ty
)
2051 : bindingExpr_( bindingExpr
), ty_( ty
), isRelative_( false ), id_( id
)
2054 Lang::TextRiseBinding::TextRiseBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, const double r
)
2055 : bindingExpr_( bindingExpr
), ty_( r
), isRelative_( true ), id_( id
)
2058 Lang::TextRiseBinding::~TextRiseBinding( )
2062 Lang::TextRiseBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
2064 if( *sysBindings
== 0 )
2066 *sysBindings
= new Kernel::SystemDynamicVariables( );
2067 Kernel::TextState
* newState
= new Kernel::TextState( );
2070 newState
->setRise( Concrete::Length::offtype( ty_
) );
2074 newState
->setRise( ty_
);
2076 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2080 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
2082 Kernel::TextState
* newState
= new Kernel::TextState( );
2085 newState
->setRise( Concrete::Length::offtype( ty_
) );
2089 newState
->setRise( ty_
);
2091 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2095 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
2097 if( newState
->hasRise( ) )
2099 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
2104 newState
->setRise( Concrete::Length::offtype( ty_
) );
2108 newState
->setRise( ty_
);
2110 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2114 Lang::TextRiseBinding::show( std::ostream
& os
) const
2116 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
2119 os
<< Concrete::Length::offtype( ty_
) ;
2123 os
<< ty_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
2128 Lang::TextRiseBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2132 Lang::TextKnockoutBinding::TextKnockoutBinding( const char * id
, const Ast::DynamicBindingExpression
* bindingExpr
, bool knockout
)
2133 : bindingExpr_( bindingExpr
), knockout_( knockout
), id_( id
)
2136 Lang::TextKnockoutBinding::~TextKnockoutBinding( )
2140 Lang::TextKnockoutBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
2142 if( *sysBindings
== 0 )
2144 *sysBindings
= new Kernel::SystemDynamicVariables( );
2145 Kernel::TextState
* newState
= new Kernel::TextState( );
2146 newState
->knockout_
= knockout_
;
2147 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2151 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
2153 Kernel::TextState
* newState
= new Kernel::TextState( );
2154 newState
->knockout_
= knockout_
;
2155 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2159 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
2161 if( ( newState
->knockout_
& Kernel::TextState::KNOCKOUT_UNDEFINED_BIT
) != 0 )
2163 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
2166 newState
->knockout_
= ( knockout_
? Kernel::TextState::KNOCKOUT_FLAG_BIT
: 0 );
2167 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2171 Lang::TextKnockoutBinding::show( std::ostream
& os
) const
2173 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":"
2174 << ( knockout_
? "true" : "false" ) ;
2178 Lang::TextKnockoutBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2182 Kernel::CharacterSpacingDynamicVariableProperties::CharacterSpacingDynamicVariableProperties( const char * name
)
2183 : Kernel::DynamicVariableProperties( name
)
2186 Kernel::CharacterSpacingDynamicVariableProperties::~CharacterSpacingDynamicVariableProperties( )
2189 Kernel::VariableHandle
2190 Kernel::CharacterSpacingDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2192 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2193 return Kernel::VariableHandle( new Kernel::Variable( textState
->characterSpacing( ) ) );
2197 Kernel::CharacterSpacingDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2199 RefCountPtr
< const Lang::Value
> valUntyped
= val
->getUntyped( );
2201 Kernel::ContRef cont
= evalState
->cont_
;
2205 typedef const Lang::Length ArgType
;
2206 RefCountPtr
< ArgType
> spacing
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2207 cont
->takeValue( Kernel::ValueRef( new Lang::CharacterSpacingBinding( name_
, bindingExpr
, spacing
->get( ) ) ),
2211 catch( const NonLocalExit::NotThisType
& ball
)
2213 /* Wrong type; never mind!.. but see below!
2219 typedef const Lang::Float ArgType
;
2220 RefCountPtr
< ArgType
> spacing
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2221 cont
->takeValue( Kernel::ValueRef( new Lang::CharacterSpacingBinding( name_
, bindingExpr
, spacing
->val_
) ),
2225 catch( const NonLocalExit::NotThisType
& ball
)
2227 /* Wrong type; never mind!.. but see below!
2231 throw Exceptions::TypeMismatch( bindingExpr
->exprLoc( ), valUntyped
->getTypeName( ), Helpers::typeSetString( Lang::Length::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
2235 Kernel::WordSpacingDynamicVariableProperties::WordSpacingDynamicVariableProperties( const char * name
)
2236 : Kernel::DynamicVariableProperties( name
)
2239 Kernel::WordSpacingDynamicVariableProperties::~WordSpacingDynamicVariableProperties( )
2242 Kernel::VariableHandle
2243 Kernel::WordSpacingDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2245 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2246 return Kernel::VariableHandle( new Kernel::Variable( textState
->wordSpacing( ) ) );
2250 Kernel::WordSpacingDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2252 RefCountPtr
< const Lang::Value
> valUntyped
= val
->getUntyped( );
2254 Kernel::ContRef cont
= evalState
->cont_
;
2258 typedef const Lang::Length ArgType
;
2259 RefCountPtr
< ArgType
> spacing
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2260 cont
->takeValue( Kernel::ValueRef( new Lang::WordSpacingBinding( name_
, bindingExpr
, spacing
->get( ) ) ),
2264 catch( const NonLocalExit::NotThisType
& ball
)
2266 /* Wrong type; never mind!.. but see below!
2272 typedef const Lang::Float ArgType
;
2273 RefCountPtr
< ArgType
> spacing
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2274 cont
->takeValue( Kernel::ValueRef( new Lang::WordSpacingBinding( name_
, bindingExpr
, spacing
->val_
) ),
2278 catch( const NonLocalExit::NotThisType
& ball
)
2280 /* Wrong type; never mind!.. but see below!
2284 throw Exceptions::TypeMismatch( bindingExpr
->exprLoc( ), valUntyped
->getTypeName( ), Helpers::typeSetString( Lang::Length::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
2288 Kernel::HorizontalScalingDynamicVariableProperties::HorizontalScalingDynamicVariableProperties( const char * name
)
2289 : Kernel::DynamicVariableProperties( name
)
2292 Kernel::HorizontalScalingDynamicVariableProperties::~HorizontalScalingDynamicVariableProperties( )
2295 Kernel::VariableHandle
2296 Kernel::HorizontalScalingDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2298 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2299 return Kernel::VariableHandle( Shapes::Helpers::newValHandle( new Lang::Float( textState
->horizontalScaling_
) ) );
2303 Kernel::HorizontalScalingDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2305 RefCountPtr
< const Lang::Float
> scaling
= val
->getVal
< const Lang::Float
>( bindingExpr
->exprLoc( ) );
2306 Kernel::ContRef cont
= evalState
->cont_
;
2307 cont
->takeValue( Kernel::ValueRef( new Lang::HorizontalScalingBinding( name_
, bindingExpr
, scaling
->val_
) ),
2312 Kernel::LeadingDynamicVariableProperties::LeadingDynamicVariableProperties( const char * name
)
2313 : Kernel::DynamicVariableProperties( name
)
2316 Kernel::LeadingDynamicVariableProperties::~LeadingDynamicVariableProperties( )
2319 Kernel::VariableHandle
2320 Kernel::LeadingDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2322 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2323 return Kernel::VariableHandle( new Kernel::Variable( textState
->leading( ) ) );
2327 Kernel::LeadingDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2329 RefCountPtr
< const Lang::Value
> valUntyped
= val
->getUntyped( );
2331 Kernel::ContRef cont
= evalState
->cont_
;
2335 typedef const Lang::Length ArgType
;
2336 RefCountPtr
< ArgType
> ty
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2337 cont
->takeValue( Kernel::ValueRef( new Lang::LeadingBinding( name_
, bindingExpr
, ty
->get( ) ) ),
2341 catch( const NonLocalExit::NotThisType
& ball
)
2343 /* Wrong type; never mind!.. but see below!
2349 typedef const Lang::Float ArgType
;
2350 RefCountPtr
< ArgType
> ty
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2351 cont
->takeValue( Kernel::ValueRef( new Lang::LeadingBinding( name_
, bindingExpr
, ty
->val_
) ),
2355 catch( const NonLocalExit::NotThisType
& ball
)
2357 /* Wrong type; never mind!.. but see below!
2361 throw Exceptions::TypeMismatch( bindingExpr
->exprLoc( ), valUntyped
->getTypeName( ), Helpers::typeSetString( Lang::Length::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
2365 Kernel::FontDynamicVariableProperties::FontDynamicVariableProperties( const char * name
)
2366 : Kernel::DynamicVariableProperties( name
)
2369 Kernel::FontDynamicVariableProperties::~FontDynamicVariableProperties( )
2372 Kernel::VariableHandle
2373 Kernel::FontDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2375 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2376 return Kernel::VariableHandle( new Kernel::Variable( textState
->font_
) );
2380 Kernel::FontDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2382 Kernel::ContRef cont
= evalState
->cont_
;
2383 cont
->takeValue( Kernel::ValueRef( new Lang::FontBinding( name_
, bindingExpr
, val
->getVal
< const Lang::Font
>( bindingExpr
->exprLoc( ) ) ) ),
2388 Kernel::TextSizeDynamicVariableProperties::TextSizeDynamicVariableProperties( const char * name
)
2389 : Kernel::DynamicVariableProperties( name
)
2392 Kernel::TextSizeDynamicVariableProperties::~TextSizeDynamicVariableProperties( )
2395 Kernel::VariableHandle
2396 Kernel::TextSizeDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2398 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2399 return Kernel::VariableHandle( Shapes::Helpers::newValHandle( new Lang::Length( textState
->size_
) ) );
2403 Kernel::TextSizeDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2405 RefCountPtr
< const Lang::Length
> size
= val
->getVal
< const Lang::Length
>( bindingExpr
->exprLoc( ) );
2406 Kernel::ContRef cont
= evalState
->cont_
;
2407 cont
->takeValue( Kernel::ValueRef( new Lang::TextSizeBinding( name_
, bindingExpr
, size
->get( ) ) ),
2412 Kernel::TextRenderingModeDynamicVariableProperties::TextRenderingModeDynamicVariableProperties( const char * name
)
2413 : Kernel::DynamicVariableProperties( name
)
2416 Kernel::TextRenderingModeDynamicVariableProperties::~TextRenderingModeDynamicVariableProperties( )
2419 Kernel::VariableHandle
2420 Kernel::TextRenderingModeDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2422 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2423 return Kernel::VariableHandle( Shapes::Helpers::newValHandle( new Lang::TextRenderingMode( textState
->mode_
) ) );
2427 Kernel::TextRenderingModeDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2429 RefCountPtr
< const Lang::TextRenderingMode
> mode
= val
->getVal
< const Lang::TextRenderingMode
>( bindingExpr
->exprLoc( ) );
2430 Kernel::ContRef cont
= evalState
->cont_
;
2431 cont
->takeValue( Kernel::ValueRef( new Lang::TextRenderingModeBinding( name_
, bindingExpr
, mode
->mode_
) ),
2436 Kernel::TextRiseDynamicVariableProperties::TextRiseDynamicVariableProperties( const char * name
)
2437 : Kernel::DynamicVariableProperties( name
)
2440 Kernel::TextRiseDynamicVariableProperties::~TextRiseDynamicVariableProperties( )
2443 Kernel::VariableHandle
2444 Kernel::TextRiseDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2446 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2447 return Kernel::VariableHandle( new Kernel::Variable( textState
->rise( ) ) );
2451 Kernel::TextRiseDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2453 RefCountPtr
< const Lang::Value
> valUntyped
= val
->getUntyped( );
2455 Kernel::ContRef cont
= evalState
->cont_
;
2459 typedef const Lang::Length ArgType
;
2460 RefCountPtr
< ArgType
> ty
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2461 cont
->takeValue( Kernel::ValueRef( new Lang::TextRiseBinding( name_
, bindingExpr
, ty
->get( ) ) ),
2465 catch( const NonLocalExit::NotThisType
& ball
)
2467 /* Wrong type; never mind!.. but see below!
2473 typedef const Lang::Float ArgType
;
2474 RefCountPtr
< ArgType
> ty
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2475 cont
->takeValue( Kernel::ValueRef( new Lang::TextRiseBinding( name_
, bindingExpr
, ty
->val_
) ),
2479 catch( const NonLocalExit::NotThisType
& ball
)
2481 /* Wrong type; never mind!.. but see below!
2485 throw Exceptions::TypeMismatch( bindingExpr
->exprLoc( ), valUntyped
->getTypeName( ), Helpers::typeSetString( Lang::Length::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
2489 Kernel::TextKnockoutDynamicVariableProperties::TextKnockoutDynamicVariableProperties( const char * name
)
2490 : Kernel::DynamicVariableProperties( name
)
2493 Kernel::TextKnockoutDynamicVariableProperties::~TextKnockoutDynamicVariableProperties( )
2496 Kernel::VariableHandle
2497 Kernel::TextKnockoutDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2499 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2500 return Kernel::VariableHandle( Shapes::Helpers::newValHandle( new Lang::Boolean( ( textState
->knockout_
& Kernel::TextState::KNOCKOUT_FLAG_BIT
) != 0 ) ) );
2504 Kernel::TextKnockoutDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2506 RefCountPtr
< const Lang::Boolean
> mode
= val
->getVal
< const Lang::Boolean
>( bindingExpr
->exprLoc( ) );
2507 Kernel::ContRef cont
= evalState
->cont_
;
2508 cont
->takeValue( Kernel::ValueRef( new Lang::TextKnockoutBinding( name_
, bindingExpr
, mode
->val_
) ),
2514 Kernel::TextState::TextState( )
2515 : relativeFlags_( 0 ),
2516 characterSpacing_( Concrete::Length( std::numeric_limits
< double >::signaling_NaN( ) ) ),
2517 wordSpacing_( Concrete::Length( std::numeric_limits
< double >::signaling_NaN( ) ) ),
2518 horizontalScaling_( std::numeric_limits
< double >::signaling_NaN( ) ),
2519 leading_( Concrete::Length( std::numeric_limits
< double >::signaling_NaN( ) ) ),
2520 rise_( Concrete::Length( std::numeric_limits
< double >::signaling_NaN( ) ) ),
2521 font_( NullPtr
< const Lang::Font
>( ) ),
2522 size_( Concrete::Length( std::numeric_limits
< double >::signaling_NaN( ) ) ),
2523 mode_( Lang::TextRenderingMode::UNDEFINED
),
2524 knockout_( KNOCKOUT_UNDEFINED_BIT
)
2527 Kernel::TextState::TextState( const Kernel::TextState
& orig
)
2528 : relativeFlags_( orig
.relativeFlags_
),
2529 characterSpacing_( orig
.characterSpacing_
),
2530 wordSpacing_( orig
.wordSpacing_
),
2531 horizontalScaling_( orig
.horizontalScaling_
),
2532 leading_( orig
.leading_
),
2533 rise_( orig
.rise_
),
2534 font_( orig
.font_
),
2535 size_( orig
.size_
),
2536 mode_( orig
.mode_
),
2537 knockout_( orig
.knockout_
)
2540 Kernel::TextState::TextState( const Kernel::TextState
& newValues
, const Kernel::TextState
& oldValues
)
2541 : relativeFlags_( oldValues
.relativeFlags_
),
2542 characterSpacing_( oldValues
.characterSpacing_
),
2543 wordSpacing_( oldValues
.wordSpacing_
),
2544 horizontalScaling_( oldValues
.horizontalScaling_
),
2545 leading_( oldValues
.leading_
),
2546 rise_( oldValues
.rise_
),
2547 font_( oldValues
.font_
),
2548 size_( oldValues
.size_
),
2549 mode_( oldValues
.mode_
),
2550 knockout_( oldValues
.knockout_
)
2552 if( newValues
.hasCharacterSpacing( ) )
2554 characterSpacing_
= newValues
.characterSpacing_
;
2555 relativeFlags_
= ( newValues
.characterSpacingIsRelative( ) ? ( relativeFlags_
| RELATIVE_CHARACTER_SPACING
) : ( relativeFlags_
& ~RELATIVE_CHARACTER_SPACING
) );
2557 if( newValues
.hasWordSpacing( ) )
2559 wordSpacing_
= newValues
.wordSpacing_
;
2560 relativeFlags_
= ( newValues
.wordSpacingIsRelative( ) ? ( relativeFlags_
| RELATIVE_WORD_SPACING
) : ( relativeFlags_
& ~RELATIVE_WORD_SPACING
) );
2562 if( ! IS_NAN( newValues
.horizontalScaling_
) )
2564 horizontalScaling_
= newValues
.horizontalScaling_
;
2566 if( newValues
.hasLeading( ) )
2568 leading_
= newValues
.leading_
;
2569 relativeFlags_
= ( newValues
.leadingIsRelative( ) ? ( relativeFlags_
| RELATIVE_LEADING
) : ( relativeFlags_
& ~RELATIVE_LEADING
) );
2571 if( newValues
.hasRise( ) )
2573 rise_
= newValues
.rise_
;
2574 relativeFlags_
= ( newValues
.riseIsRelative( ) ? ( relativeFlags_
| RELATIVE_RISE
) : ( relativeFlags_
& ~RELATIVE_RISE
) );
2576 if( newValues
.font_
!= NullPtr
< const Lang::Font
>( ) )
2578 font_
= newValues
.font_
;
2580 if( ! IS_NAN( newValues
.size_
) )
2582 size_
= newValues
.size_
;
2584 if( newValues
.mode_
!= Lang::TextRenderingMode::UNDEFINED
)
2586 mode_
= newValues
.mode_
;
2588 if( ! ( newValues
.knockout_
& KNOCKOUT_UNDEFINED_BIT
) )
2590 knockout_
= newValues
.knockout_
;
2594 std::map
< bool, RefCountPtr
< SimplePDF::PDF_Object
> > Kernel::TextState::knockoutNameMap_
;
2596 Kernel::TextState::TextState( bool setDefaults
)
2597 : relativeFlags_( RELATIVE_LEADING
),
2598 characterSpacing_( 0 ),
2600 horizontalScaling_( 1 ),
2603 font_( Lang::THE_FONT_HELVETICA
),
2604 size_( Concrete::Length( 10 ) ),
2605 mode_( Lang::TextRenderingMode::FILL
),
2606 knockout_( 0 ) // this means false
2610 throw Exceptions::InternalError( strrefdup( "setDefaults must be true in TextState::TextState." ) );
2614 Kernel::TextState::~TextState( )
2618 Kernel::TextState::print( std::ostream
& os
, const std::string
& indentation
) const
2620 if( font_
!= NullPtr
< const Lang::Font
>( ) )
2622 os
<< indentation
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< Lang::DYNAMIC_VARIABLE_ID_TEXT_FONT
<< ": " << font_
->fontName( ) << std::endl
;
2624 if( ! IS_NAN( size_
) )
2626 os
<< indentation
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< Lang::DYNAMIC_VARIABLE_ID_TEXT_SIZE
<< ": " << size_
/ Interaction::displayUnit
<< Interaction::displayUnitName
<< std::endl
;
2628 os
<< "(and a bunch of other variables...)" << std::endl
;
2633 Kernel::TextState::setLeading( const Concrete::Length leading
)
2635 relativeFlags_
&= ~ RELATIVE_LEADING
;
2640 Kernel::TextState::setLeading( const double relativeLeading
)
2642 relativeFlags_
|= RELATIVE_LEADING
;
2643 leading_
= Concrete::Length( relativeLeading
); // We must keep track of this type trick by always looking at relativeFlags_ & RELATIVE_LEADING.
2646 RefCountPtr
< const Lang::Value
>
2647 Kernel::TextState::leading( ) const
2649 if( leadingIsRelative( ) )
2651 return RefCountPtr
< const Lang::Value
>( new Lang::Float( Concrete::Length::offtype( leading_
) ) );
2653 return RefCountPtr
< const Lang::Value
>( new Lang::Length( leading_
) );
2657 Kernel::TextState::leadingConcrete( ) const
2659 if( leadingIsRelative( ) )
2661 return Concrete::Length::offtype( leading_
) * size_
;
2667 Kernel::TextState::hasLeading( ) const
2669 return ! IS_NAN( leading_
);
2673 Kernel::TextState::leadingIsRelative( ) const
2675 return ( relativeFlags_
& RELATIVE_LEADING
) != 0;
2680 Kernel::TextState::setRise( const Concrete::Length rise
)
2682 relativeFlags_
&= ~ RELATIVE_RISE
;
2687 Kernel::TextState::setRise( const double relativeRise
)
2689 relativeFlags_
|= RELATIVE_RISE
;
2690 rise_
= Concrete::Length( relativeRise
); // We must keep track of this type trick by always looking at relativeFlags_ & RELATIVE_RISE.
2693 RefCountPtr
< const Lang::Value
>
2694 Kernel::TextState::rise( ) const
2696 if( riseIsRelative( ) )
2698 return RefCountPtr
< const Lang::Value
>( new Lang::Float( Concrete::Length::offtype( rise_
) ) );
2700 return RefCountPtr
< const Lang::Value
>( new Lang::Length( rise_
) );
2704 Kernel::TextState::riseConcrete( ) const
2706 if( riseIsRelative( ) )
2708 return Concrete::Length::offtype( rise_
) * size_
;
2714 Kernel::TextState::hasRise( ) const
2716 return ! IS_NAN( rise_
);
2720 Kernel::TextState::riseIsRelative( ) const
2722 return ( relativeFlags_
& RELATIVE_RISE
) != 0;
2727 Kernel::TextState::setCharacterSpacing( const Concrete::Length spacing
)
2729 relativeFlags_
&= ~ RELATIVE_CHARACTER_SPACING
;
2730 characterSpacing_
= spacing
;
2734 Kernel::TextState::setCharacterSpacing( const double relativeSpacing
)
2736 relativeFlags_
|= RELATIVE_CHARACTER_SPACING
;
2737 characterSpacing_
= Concrete::Length( relativeSpacing
); // We must keep track of this type trick by always looking at the relevant bit in relativeFlags_.
2740 RefCountPtr
< const Lang::Value
>
2741 Kernel::TextState::characterSpacing( ) const
2743 if( characterSpacingIsRelative( ) )
2745 return RefCountPtr
< const Lang::Value
>( new Lang::Float( Concrete::Length::offtype( characterSpacing_
) ) );
2747 return RefCountPtr
< const Lang::Value
>( new Lang::Length( characterSpacing_
) );
2751 Kernel::TextState::characterSpacingConcrete( ) const
2753 if( characterSpacingIsRelative( ) )
2755 return Concrete::Length::offtype( characterSpacing_
) * size_
;
2757 return characterSpacing_
;
2761 Kernel::TextState::hasCharacterSpacing( ) const
2763 return ! IS_NAN( characterSpacing_
);
2767 Kernel::TextState::characterSpacingIsRelative( ) const
2769 return ( relativeFlags_
& RELATIVE_CHARACTER_SPACING
) != 0;
2774 Kernel::TextState::setWordSpacing( const Concrete::Length spacing
)
2776 relativeFlags_
&= ~ RELATIVE_WORD_SPACING
;
2777 wordSpacing_
= spacing
;
2781 Kernel::TextState::setWordSpacing( const double relativeSpacing
)
2783 relativeFlags_
|= RELATIVE_WORD_SPACING
;
2784 wordSpacing_
= Concrete::Length( relativeSpacing
); // We must keep track of this type trick by always looking at the relevant bit in relativeFlags_.
2787 RefCountPtr
< const Lang::Value
>
2788 Kernel::TextState::wordSpacing( ) const
2790 if( wordSpacingIsRelative( ) )
2792 return RefCountPtr
< const Lang::Value
>( new Lang::Float( Concrete::Length::offtype( wordSpacing_
) ) );
2794 return RefCountPtr
< const Lang::Value
>( new Lang::Length( wordSpacing_
) );
2798 Kernel::TextState::wordSpacingConcrete( ) const
2800 if( wordSpacingIsRelative( ) )
2802 return Concrete::Length::offtype( wordSpacing_
) * size_
;
2804 return wordSpacing_
;
2808 Kernel::TextState::hasWordSpacing( ) const
2810 return ! IS_NAN( wordSpacing_
);
2814 Kernel::TextState::wordSpacingIsRelative( ) const
2816 return ( relativeFlags_
& RELATIVE_WORD_SPACING
) != 0;
2821 Kernel::TextState::synchAssertKnockout( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool clip
, bool force
)
2823 assertKnockout( ref
);
2824 return synchButKnockout( os
, ref
, resources
, clip
, force
);
2828 Kernel::TextState::synchCharacterSpacing( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
2831 characterSpacing_
!= ref
->characterSpacing_
||
2832 characterSpacingIsRelative( ) != ref
->characterSpacingIsRelative( ) )
2834 if( ! ref
->hasCharacterSpacing( ) )
2838 relativeFlags_
= ( ref
->characterSpacingIsRelative( ) ? ( relativeFlags_
| RELATIVE_CHARACTER_SPACING
) : ( relativeFlags_
& ~RELATIVE_CHARACTER_SPACING
) );
2839 characterSpacing_
= ref
->characterSpacing_
;
2840 if( characterSpacingIsRelative( ) )
2842 os
<< Concrete::Length::offtype( characterSpacing_
) * Concrete::Length::offtype( ref
->size_
) << " Tc " ;
2846 os
<< Concrete::Length::offtype( characterSpacing_
) << " Tc " ;
2854 Kernel::TextState::synchWordSpacing( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
2857 wordSpacing_
!= ref
->wordSpacing_
||
2858 wordSpacingIsRelative( ) != ref
->wordSpacingIsRelative( ) )
2860 if( ! ref
->hasWordSpacing( ) )
2864 relativeFlags_
= ( ref
->wordSpacingIsRelative( ) ? ( relativeFlags_
| RELATIVE_WORD_SPACING
) : ( relativeFlags_
& ~RELATIVE_WORD_SPACING
) );
2865 wordSpacing_
= ref
->wordSpacing_
;
2866 if( wordSpacingIsRelative( ) )
2868 os
<< Concrete::Length::offtype( wordSpacing_
) * Concrete::Length::offtype( ref
->size_
) << " Tw " ;
2872 os
<< Concrete::Length::offtype( wordSpacing_
) << " Tw " ;
2880 Kernel::TextState::synchHorizontalScaling( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
2882 if( force
|| horizontalScaling_
!= ref
->horizontalScaling_
)
2884 if( IS_NAN( ref
->horizontalScaling_
) )
2888 horizontalScaling_
= ref
->horizontalScaling_
;
2889 os
<< 100 * horizontalScaling_
<< " Tz " ;
2896 Kernel::TextState::synchLeading( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
2899 leading_
!= ref
->leading_
||
2900 leadingIsRelative( ) != ref
->leadingIsRelative( ) )
2902 if( ! ref
->hasLeading( ) )
2906 relativeFlags_
= ( ref
->leadingIsRelative( ) ? ( relativeFlags_
| RELATIVE_LEADING
) : ( relativeFlags_
& ~RELATIVE_LEADING
) );
2907 leading_
= ref
->leading_
;
2908 if( leadingIsRelative( ) )
2910 os
<< Concrete::Length::offtype( leading_
) * Concrete::Length::offtype( ref
->size_
) << " TL " ;
2914 os
<< Concrete::Length::offtype( leading_
) << " TL " ;
2922 Kernel::TextState::synchFontAndSize( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
2925 font_
!= ref
->font_
||
2926 size_
!= ref
->size_
)
2928 if( ref
->font_
== NullPtr
< const Lang::Font
>( ) &&
2929 IS_NAN( ref
->size_
) )
2933 if( ref
->font_
== NullPtr
< const Lang::Font
>( ) ||
2934 IS_NAN( ref
->size_
) )
2936 throw Exceptions::MiscellaneousRequirement( "It is impossible to leave unspecified only one of font and size." );
2938 bool sizeChanged
= ( size_
!= ref
->size_
);
2941 os
<< resources
->nameofFont( font_
->resource( ) ) << " " << Concrete::Length::offtype( size_
) << " Tf " ;
2944 if( ref
->hasLeading( ) && ref
->leadingIsRelative( ) )
2946 synchLeading( os
, ref
, resources
, true );
2948 if( ref
->hasRise( ) && ref
->riseIsRelative( ) )
2950 synchRise( os
, ref
, resources
, true );
2952 if( ref
->hasCharacterSpacing( ) && ref
->characterSpacingIsRelative( ) )
2954 synchCharacterSpacing( os
, ref
, resources
, true );
2956 if( ref
->hasWordSpacing( ) && ref
->wordSpacingIsRelative( ) )
2958 synchWordSpacing( os
, ref
, resources
, true );
2967 Kernel::TextState::synchMode( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool clip
, bool force
)
2969 Lang::TextRenderingMode::ValueType refMode
= clip
? Lang::TextRenderingMode::clipMode( ref
->mode_
) : ref
->mode_
;
2970 if( force
|| mode_
!= refMode
)
2972 if( ref
->mode_
== Lang::TextRenderingMode::UNDEFINED
)
2977 os
<< mode_
<< " Tr " ;
2984 Kernel::TextState::synchRise( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
2987 rise_
!= ref
->rise_
||
2988 riseIsRelative( ) != ref
->riseIsRelative( ) )
2990 if( ! ref
->hasRise( ) )
2994 relativeFlags_
= ( ref
->riseIsRelative( ) ? ( relativeFlags_
| RELATIVE_RISE
) : ( relativeFlags_
& ~RELATIVE_RISE
) );
2996 if( riseIsRelative( ) )
2998 os
<< Concrete::Length::offtype( rise_
) * Concrete::Length::offtype( ref
->size_
) << " Ts " ;
3002 os
<< Concrete::Length::offtype( rise_
) << " Ts " ;
3010 Kernel::TextState::synchKnockout( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
3012 if( force
|| knockout_
!= ref
->knockout_
)
3014 if( ( ref
->knockout_
& Kernel::TextState::KNOCKOUT_UNDEFINED_BIT
) != 0 )
3018 const SimplePDF::PDF_Version::Version KNOCKOUT_VERSION
= SimplePDF::PDF_Version::PDF_1_4
;
3019 if( ! Kernel::the_PDF_version
.greaterOrEqual( KNOCKOUT_VERSION
) )
3021 Kernel::the_PDF_version
.message( KNOCKOUT_VERSION
, "The text state knockout mode setting was ignored." );
3023 knockout_
= ref
->knockout_
;
3024 typedef typeof knockoutNameMap_ MapType
;
3025 MapType::const_iterator i
= knockoutNameMap_
.find( knockout_
);
3026 if( i
!= knockoutNameMap_
.end( ) )
3028 os
<< resources
->nameofGraphicsState( i
->second
) << " gs " ;
3032 RefCountPtr
< SimplePDF::PDF_Dictionary
> dic
;
3033 (*dic
)[ "Type" ] = SimplePDF::newName( "ExtGState" );
3034 (*dic
)[ "TK" ] = SimplePDF::newBoolean( knockout_
);
3036 RefCountPtr
< SimplePDF::PDF_Object
> indirection
= SimplePDF::indirect( dic
, & Kernel::theIndirectObjectCount
);
3037 knockoutNameMap_
.insert( MapType::value_type( knockout_
, indirection
) );
3039 os
<< resources
->nameofGraphicsState( indirection
) << " gs " ;
3047 Kernel::TextState::assertKnockout( const Kernel::TextState
* ref
)
3049 if( knockout_
!= ref
->knockout_
)
3051 throw Exceptions::MiscellaneousRequirement( "PDF does not allow the text knockout mode to change within a text object." );
3056 Kernel::TextState::synchButKnockout( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool clip
, bool force
)
3058 bool anyChange
= false;
3059 anyChange
= synchCharacterSpacing( os
, ref
, resources
, force
) || anyChange
;
3060 anyChange
= synchWordSpacing( os
, ref
, resources
, force
) || anyChange
;
3061 anyChange
= synchHorizontalScaling( os
, ref
, resources
, force
) || anyChange
;
3062 anyChange
= synchFontAndSize( os
, ref
, resources
, force
) || anyChange
;
3063 anyChange
= synchLeading( os
, ref
, resources
, force
) || anyChange
; // It is important that this is done after synching the size!
3064 anyChange
= synchMode( os
, ref
, resources
, clip
, force
) || anyChange
;
3065 anyChange
= synchRise( os
, ref
, resources
, force
) || anyChange
;
3074 Lang::FontMethod_glyph::FontMethod_glyph( RefCountPtr
< const Lang::Font
> self
, const Ast::FileID
* fullMethodID
)
3075 : Lang::MethodBase
< class_type
>( self
, fullMethodID
, false, true )
3077 formals_
->appendEvaluatedCoreFormal( "char", Kernel::THE_SLOT_VARIABLE
);
3080 Lang::FontMethod_glyph::~FontMethod_glyph( )
3084 Lang::FontMethod_glyph::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
3086 args
.applyDefaults( );
3089 typedef const Lang::Character ArgType
;
3091 Kernel::ContRef cont
= evalState
->cont_
;
3092 cont
->takeValue( self_
->getGlyph( Helpers::down_cast_CoreArgument
< ArgType
>( title_
, args
, argsi
, callLoc
)->val_
,
3093 evalState
->dyn_
->getTextState( )->size_
),