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"
39 #include <sys/types.h>
49 using namespace Shapes
;
51 std::map
< RefCountPtr
< const char >, RefCountPtr
< SimplePDF::PDF_Object
>, charRefPtrLess
> Lang::Font::theFontResourceMap_
;
52 std::map
< RefCountPtr
< const char >, RefCountPtr
< const FontMetrics::FontMetric
>, charRefPtrLess
> Lang::Font::theFontMetricsMap_
;
53 std::list
< std::string
> Lang::Font::theFontMetricsSearchPath_
;
59 Kernel::StructureFactory
FontMethod_glyph_resultFactory( "odd?", "paths", "advance" );
63 SimplePDF::PDF_ToUnicode::PDF_ToUnicode( RefCountPtr
< CharSet
> charSet
, const RefCountPtr
< const Shapes::Lang::Font
> & font
)
64 : charSet_( charSet
),
67 dic
[ "Filter" ] = SimplePDF::newName( "FlateDecode" );
70 SimplePDF::PDF_ToUnicode::~PDF_ToUnicode( )
74 SimplePDF::PDF_ToUnicode::writeTo( std::ostream
& os
, SimplePDF::PDF_xref
* xref
, const RefCountPtr
< const PDF_Object
> & self
) const
76 std::ostringstream
& wdata
= const_cast< std::ostringstream
& >( data
);
77 wdata
<< std::setfill( '0' );
78 wdata
<< "/CIDInit /ProcSet findresource begin" << std::endl
79 << "12 dict begin" << std::endl
80 << "begincmap" << std::endl
81 << "/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def" << std::endl
82 << "/CMapName /Adobe-Identity-UCS def" << std::endl
83 << "/CMapType 2 def" << std::endl
84 << "1 begincodespacerange" << std::endl
85 << "<0000> <FFFF>" << std::endl
86 << "endcodespacerange" << std::endl
;
87 const size_t bufSize
= 10;
88 unsigned char buf
[ bufSize
];
89 size_t remaining
= charSet_
->size( );
90 size_t room
= std::min( static_cast< size_t >( 100 ), remaining
);
92 wdata
<< room
<< " beginbfchar" << std::endl
;
93 for( CharSet::const_iterator i
= charSet_
->begin( ); i
!= charSet_
->end( ); ++i
, --room
)
97 wdata
<< "endbfchar" << std::endl
;
98 room
= std::min( static_cast< size_t >( 100 ), remaining
);
100 wdata
<< room
<< " beginbfchar" << std::endl
;
102 size_t out_avail
= 2;
103 unsigned char * out_buf
= buf
;
104 font_
->encode( *i
, reinterpret_cast< char ** >( & out_buf
), & out_avail
);
107 throw Exceptions::InternalError( "Expected the encoded character to occupy exactly two bytes." );
109 wdata
<< "<" << std::hex
<< std::setw( 2 ) << static_cast< int >( buf
[0] ) << std::hex
<< std::setw( 2 ) << static_cast< int >( buf
[1] ) << "> " ;
112 i
->encode_UTF16BE( reinterpret_cast< char ** >( & out_buf
), & out_avail
);
114 for( const unsigned char * c
= buf
; c
!= out_buf
; ++c
)
116 wdata
<< std::hex
<< std::setw( 2 ) << static_cast< int >( *c
) ;
118 wdata
<< ">" << std::endl
;
120 wdata
<< "endbfchar" << std::endl
121 << "endcmap" << std::endl
122 << "CMapName currentdict /CMap defineresource pop" << std::endl
123 << "end" << std::endl
124 << "end" ; /* No need to put a newline at the end. */
125 PDF_Stream_out::writeTo( os
, xref
, self
);
128 SimplePDF::PDF_Widths::PDF_Widths( RefCountPtr
< CharSet
> charSet
, const RefCountPtr
< const Shapes::Lang::Font
> & font
)
129 : charSet_( charSet
),
133 SimplePDF::PDF_Widths::~PDF_Widths( )
137 SimplePDF::PDF_Widths::writeTo( std::ostream
& os
, SimplePDF::PDF_xref
* xref
, const RefCountPtr
< const PDF_Object
> & self
) const
139 const FontMetrics::WritingDirectionMetrics
* metrics
= font_
->metrics( )->horizontalMetrics_
.getPtr( );
140 const size_t bufSize
= 2;
141 unsigned char buf
[ bufSize
];
142 VecType
& wvec
= const_cast< VecType
& >( vec
);
143 FontMetrics::CharacterMetrics
m( 0 );
144 for( CharSet::const_iterator i
= charSet_
->begin( ); i
!= charSet_
->end( ); )
146 CharSet::const_iterator j
= i
;
147 CharSet::const_iterator last
= i
;
149 for( ; i
!= charSet_
->end( ) && i
->get_UCS4( ) == last
->get_UCS4( ) + 1; last
= i
, ++i
)
151 size_t out_avail
= bufSize
;
152 unsigned char * out_buf
= buf
;
153 font_
->encode( j
->get_UCS4( ), reinterpret_cast< char ** >( & out_buf
), & out_avail
);
156 throw Exceptions::InternalError( "Expected the encoded character to occupy exactly two bytes." );
158 wvec
.push_back( SimplePDF::newInt( static_cast< SimplePDF::PDF_Int::ValueType
>( buf
[0] ) * 0x100 +
159 static_cast< SimplePDF::PDF_Int::ValueType
>( buf
[1] ) ) );
160 SimplePDF::PDF_Vector
* sub_vec
= new SimplePDF::PDF_Vector
;
161 wvec
.push_back( RefCountPtr
< SimplePDF::PDF_Object
>( sub_vec
) );
164 sub_vec
->vec
.push_back( SimplePDF::newFloat( metrics
->charByCode( j
->get_UCS4( ), & m
)->horizontalCharWidthX_
* 1000 ) );
167 PDF_Vector::writeTo( os
, xref
, self
);
176 class FontMethod_glyph
: public Lang::MethodBase
< Lang::Font
>
179 FontMethod_glyph( RefCountPtr
< const Lang::Font
> _self
, const Ast::FileID
* fullMethodID
);
180 virtual ~FontMethod_glyph( );
181 virtual void call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const;
182 static const char * staticFieldID( ) { return "glyph"; }
189 Font_register_methods( Lang::SystemFinalClass
* dstClass
)
191 dstClass
->registerMethod( new Kernel::MethodFactory
< Lang::Font
, Lang::FontMethod_glyph
>( ) );
195 Lang::Font::push_backFontMetricsPath( const std::string
& path
)
198 path
[ path
.size( ) - 1 ] == '/' )
200 theFontMetricsSearchPath_
.push_back( path
);
204 theFontMetricsSearchPath_
.push_back( path
+ "/" );
209 Lang::Font::searchGlyphList( )
213 if( theFontMetricsSearchPath_
.empty( ) )
215 throw Exceptions::ExternalError( strrefdup( "The font metrics path was not set up (needed for the glyph list). Consider defining the environment variable SHAPESFONTMETRICS." ) );
218 typedef typeof theFontMetricsSearchPath_ ListType
;
219 for( ListType::const_iterator i
= theFontMetricsSearchPath_
.begin( ); i
!= theFontMetricsSearchPath_
.end( ); ++i
)
221 res
= *i
+ "glyphlist.txt";
222 struct stat theStatDummy
;
223 if( stat( res
.c_str( ), & theStatDummy
) == 0 )
228 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." );
232 Lang::Font::searchFontMetrics( RefCountPtr
< const char > fontName
)
236 if( strlen( fontName
.getPtr( ) ) == 0 )
238 throw Exceptions::InternalError( strrefdup( "Lang::Font::searchFontMetrics called with empty argument." ) );
241 if( *fontName
.getPtr( ) == '/' )
243 throw Exceptions::InternalError( "The font name cannot begin with \"/\", as if is was an absolute path to something." );
246 if( theFontMetricsSearchPath_
.empty( ) )
248 throw Exceptions::ExternalError( strrefdup( "The font metrics path was not set up. Consider defining the environment variable SHAPESFONTMETRICS." ) );
251 typedef typeof theFontMetricsSearchPath_ ListType
;
252 for( ListType::const_iterator i
= theFontMetricsSearchPath_
.begin( ); i
!= theFontMetricsSearchPath_
.end( ); ++i
)
254 res
= *i
+ fontName
.getPtr( ) + ".afm";
255 struct stat theStatDummy
;
256 if( stat( res
.c_str( ), & theStatDummy
) == 0 )
261 throw Exceptions::MissingFontMetrics( fontName
, & theFontMetricsSearchPath_
);
265 Lang::Font::searchCharacterEncoding( const char * encodingName
)
269 if( theFontMetricsSearchPath_
.empty( ) )
271 throw Exceptions::ExternalError( strrefdup( "The font metrics path was not set up. Consider defining the environment variable SHAPESFONTMETRICS." ) );
274 typedef typeof theFontMetricsSearchPath_ ListType
;
275 for( ListType::const_iterator i
= theFontMetricsSearchPath_
.begin( ); i
!= theFontMetricsSearchPath_
.end( ); ++i
)
277 res
= *i
+ encodingName
+ ".enc";
278 struct stat theStatDummy
;
279 if( stat( res
.c_str( ), & theStatDummy
) == 0 )
284 std::ostringstream msg
;
285 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." ;
286 throw Exceptions::MiscellaneousRequirement( strrefdup( msg
) );
290 Lang::Font::Font( const RefCountPtr
< const char > fontName
, bool outline
, RefCountPtr
< SimplePDF::PDF_Object
> & resource
, RefCountPtr
< const FontMetrics::FontMetric
> metrics
)
291 : fontName_( fontName
), outline_( outline
), resource_( resource
), metrics_( metrics
)
293 // If this font has been instantiated before, it is reused.
295 typedef typeof theFontResourceMap_ MapType
;
296 MapType::const_iterator i
= theFontResourceMap_
.find( fontName_
);
297 if( i
!= theFontResourceMap_
.end( ) )
299 resource_
= i
->second
;
303 theFontResourceMap_
.insert( MapType::value_type( fontName_
, resource_
) );
307 typedef typeof theFontMetricsMap_ MapType
;
308 MapType::const_iterator i
= theFontMetricsMap_
.find( fontName_
);
309 if( i
!= theFontMetricsMap_
.end( ) )
311 metrics_
= i
->second
;
313 else if( metrics_
!= NullPtr
< const FontMetrics::FontMetric
>( ) )
315 theFontMetricsMap_
.insert( MapType::value_type( fontName_
, metrics_
) );
320 // Note that we must not initialize name_ with builtinFontMap_[ fontConst ] here, since builtinFontMap_ may not be
321 // initialized when this constructor is invoked from globals.cc.
322 Lang::Font::Font( const RefCountPtr
< const char > fontName
)
323 : fontName_( fontName
), outline_( false ), resource_( NullPtr
< SimplePDF::PDF_Object
>( ) ), metrics_( NullPtr
< const FontMetrics::FontMetric
>( ) )
329 Kernel::VariableHandle
330 Lang::Font::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
332 // if( strcmp( fieldID, "CIDFont?" ) == 0 )
334 // return Helpers::newValHandle( new Lang::Boolean( metrics_->isCIDFont_ ) );
336 if( strcmp( fieldID
, "kerning?" ) == 0 )
338 return Helpers::newValHandle( new Lang::Boolean( metrics_
->hasKerning_
) );
340 if( strcmp( fieldID
, "family" ) == 0 )
342 return Kernel::VariableHandle( new Kernel::Variable( this->family_name( ) ) );
344 if( strcmp( fieldID
, "style" ) == 0 )
346 return Kernel::VariableHandle( new Kernel::Variable( this->style_name( ) ) );
348 if( strcmp( fieldID
, "PostScript_name" ) == 0 )
350 return Kernel::VariableHandle( new Kernel::Variable( this->PostScript_name( ) ) );
353 return TypeID
->getMethod( selfRef
, fieldID
); /* This will throw if there is no such method. */
356 RefCountPtr
< const Lang::String
>
357 Lang::Font::family_name( ) const
359 return RefCountPtr
< const Lang::String
>( new Lang::String( fontName_
) );
362 RefCountPtr
< const Lang::String
>
363 Lang::Font::style_name( ) const
365 return RefCountPtr
< const Lang::String
>( new Lang::String( "", true ) );
368 RefCountPtr
< const Lang::Symbol
>
369 Lang::Font::PostScript_name( ) const
371 return RefCountPtr
< const Lang::Symbol
>( new Lang::Symbol( fontName_
.getPtr( ) ) );
374 RefCountPtr
< const Lang::Value
>
375 Lang::Font::getGlyph( Kernel::UnicodeCodePoint c
, Concrete::Length size
) const
377 throw Exceptions::MiscellaneousRequirement( "It is not possible to extract individual glyphs from this font." );
381 const RefCountPtr
< SimplePDF::PDF_Object
> &
382 Lang::Font::resource( ) const
384 if( resource_
!= NullPtr
< SimplePDF::PDF_Object
>( ) )
389 typedef typeof theFontResourceMap_ MapType
;
392 MapType::const_iterator i
= theFontResourceMap_
.find( fontName_
);
393 if( i
!= theFontResourceMap_
.end( ) )
395 resource_
= i
->second
;
401 RefCountPtr
< SimplePDF::PDF_Dictionary
> dic
;
402 resource_
= SimplePDF::indirect( dic
, & Kernel::theIndirectObjectCount
);
403 (*dic
)[ "Type" ] = SimplePDF::newName( "Font" );
404 (*dic
)[ "Subtype" ] = SimplePDF::newName( "Type1" );
405 (*dic
)[ "Encoding" ] = SimplePDF::newName( "MacRomanEncoding" );
406 (*dic
)[ "BaseFont" ] = SimplePDF::newName( fontName_
.getPtr( ) ); // Here, it is crucial that this is really a built-in font!
411 RefCountPtr
< const char >
412 Lang::Font::fontName( ) const
418 Lang::Font::outline( ) const
423 RefCountPtr
< const FontMetrics::FontMetric
>
424 Lang::Font::metrics( ) const
426 if( metrics_
!= NullPtr
< const FontMetrics::FontMetric
>( ) )
431 // Otherwise, we hope that we can find an Adobe Font Metrics file.
432 std::string filename
= searchFontMetrics( fontName_
);
433 std::ifstream
afmFile( filename
.c_str( ) );
434 if( ! afmFile
.is_open( ) )
436 std::ostringstream oss
;
437 oss
<< "File has been located but couldn't be opened: " << filename
;
438 throw Exceptions::ExternalError( strrefdup( oss
) );
441 // I fiddle a little with the consts here...
442 FontMetrics::AFM
* newMetrics
= new FontMetrics::AFM
;
443 metrics_
= RefCountPtr
< const FontMetrics::FontMetric
>( newMetrics
);
445 AfmScanner
scanner( newMetrics
, & afmFile
);
446 scanner
.setTellQue( Interaction::fontMetricMessages
); // We want to know about things that are not recognized and this ignored.
447 if( Interaction::fontMetricDebug
)
449 scanner
.set_debug( 1 );
453 int status
= scanner
.yylex( );
456 std::ostringstream oss
;
457 oss
<< "Font metrics parser returned with non-zero status: " << status
;
458 throw Exceptions::InternalError( strrefdup( oss
) );
461 catch( const char * ball
)
463 std::ostringstream oss
;
464 oss
<< "Font metrics parser failed with message: " << ball
;
465 throw Exceptions::InternalError( strrefdup( oss
) );
467 catch( const RefCountPtr
< const char > ball
)
469 std::ostringstream oss
;
470 oss
<< "Font metrics parser failed with message: " << ball
;
471 throw Exceptions::InternalError( strrefdup( oss
) );
478 Lang::Font::show( std::ostream
& os
) const
480 os
<< "< font: " << fontName_
<< " >" ;
484 Lang::Font::gcMark( Kernel::GCMarkedSet
& marked
)
487 RefCountPtr
< const Lang::Class
> Lang::Font::TypeID( new Lang::SystemFinalClass( strrefdup( "Font" ), Font_register_methods
) );
488 TYPEINFOIMPL( Font
);
491 Lang::PDFStandardFont::PDFStandardFont( const RefCountPtr
< const char > builtInFontName
)
492 : Lang::Font( builtInFontName
)
495 Lang::PDFStandardFont::~PDFStandardFont( )
499 Lang::PDFStandardFont::encode( const char ** text_UTF8
, size_t * in_avail
, char ** dst_PDF
, size_t * out_avail
) const
501 encode_MacRoman( text_UTF8
, in_avail
, dst_PDF
, out_avail
);
505 Lang::PDFStandardFont::encode( Kernel::UnicodeCodePoint c
, char ** dst_PDF
, size_t * out_avail
) const
507 encode_MacRoman( c
, dst_PDF
, out_avail
);
511 Lang::PDFStandardFont::encode_MacRoman( const char ** text_UTF8
, size_t * in_avail
, char ** dst_PDF
, size_t * out_avail
)
513 iconv_t converter
= Helpers::requireUTF8ToMacRomanConverter( );
514 // The ICONV_CAST macro is defined in config.h.
515 size_t count
= iconv( converter
,
516 ICONV_CAST( text_UTF8
), in_avail
,
517 dst_PDF
, out_avail
);
518 if( count
== (size_t)(-1) )
520 if( errno
== EILSEQ
)
522 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)." );
524 else if( errno
== EINVAL
)
526 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
528 else if( errno
== E2BIG
)
530 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to PDF show-text string conversion was too small." );
534 std::ostringstream msg
;
535 msg
<< "iconv failed with an unrecognized error code: " << errno
;
536 throw Exceptions::InternalError( strrefdup( msg
) );
542 Lang::PDFStandardFont::encode_MacRoman( Kernel::UnicodeCodePoint c
, char ** dst_PDF
, size_t * out_avail
)
546 throw Exceptions::InternalError( "The buffer allocated conversion of a single UCS-4 to MacRoman was too small." );
548 **dst_PDF
= c
.get_MacRoman( );
554 Lang::Type3Font::Type3Font( const RefCountPtr
< const char > fontName
, RefCountPtr
< SimplePDF::PDF_Object
> & resource
, RefCountPtr
< const FontMetrics::FontMetric
> metrics
)
555 : Lang::Font( fontName
, false, resource
, metrics
)
558 Lang::Type3Font::~Type3Font( )
562 Lang::Type3Font::encode( const char ** text_UTF8
, size_t * in_avail
, char ** dst_PDF
, size_t * out_avail
) const
564 Lang::PDFStandardFont::encode_MacRoman( text_UTF8
, in_avail
, dst_PDF
, out_avail
);
568 Lang::Type3Font::encode( Kernel::UnicodeCodePoint c
, char ** dst_PDF
, size_t * out_avail
) const
570 Lang::PDFStandardFont::encode_MacRoman( c
, dst_PDF
, out_avail
);
577 Lang::FreeTypeFont::FreeTypeFont( FT_Face face
, const RefCountPtr
< const char > fontName
, bool outline
, RefCountPtr
< SimplePDF::PDF_Object
> & resource
, RefCountPtr
< const FontMetrics::FontMetric
> metrics
, RefCountPtr
< SimplePDF::PDF_ToUnicode::CharSet
> & usedChars
)
578 : Lang::Font( fontName
, outline
, resource
, metrics
),
580 usedChars_( usedChars
)
583 Lang::FreeTypeFont::~FreeTypeFont( )
587 Lang::FreeTypeFont::encode( const char ** text_UTF8
, size_t * in_avail
, char ** dst_PDF
, size_t * out_avail
) const
589 iconv_t converter
= Helpers::requireUTF8ToUCS4Converter( );
591 size_t bufSize
= 4 * *in_avail
;
592 char * buf
= new char[ bufSize
];
594 DeleteOnExit
< char > bufDeleter( buf
);
596 // The ICONV_CAST macro is defined in config.h.
597 size_t count
= iconv( converter
,
598 ICONV_CAST( text_UTF8
), in_avail
,
599 & outbuf
, & bufSize
);
600 if( count
== (size_t)(-1) )
602 if( errno
== EILSEQ
)
604 throw Exceptions::MiscellaneousRequirement( "Failed to convert from UTF-8 to UCS-4 code points." );
606 else if( errno
== EINVAL
)
608 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
610 else if( errno
== E2BIG
)
612 throw Exceptions::InternalError( "The temporary UCS-4 buffer allocated for UTF-8 to PDF show-text string conversion was too small." );
616 std::ostringstream msg
;
617 msg
<< "iconv failed with an unrecognized error code: " << errno
;
618 throw Exceptions::InternalError( strrefdup( msg
) );
621 /* The number of characters equals ( outbuf - buf ) / 4, so the memory needed to store these equals
622 * 2 * ( outbuf - buf ) / 4 = ( outbuf - buf ) / 2
624 if( static_cast< ptrdiff_t >( *out_avail
) < ( outbuf
- buf
) / 2 )
626 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to PDF show-text string conversion was too small." );
628 *out_avail
-= ( outbuf
- buf
) / 2;
629 for( const char * src
= buf
; src
!= outbuf
; src
+= 4)
631 Kernel::UnicodeCodePoint code
;
632 code
.decode_UCS4( src
);
633 usedChars_
->insert( usedChars_
->begin( ), code
);
634 FT_UInt index
= FT_Get_Char_Index( face_
, code
.get_UCS4( ) );
637 std::ostringstream msg
;
638 msg
<< "Missing glyph U+" << std::hex
<< code
.get_UCS4( ) << "." ;
639 WARN_OR_THROW( Exceptions::FontProblem( this->PostScript_name( ), strrefdup( msg
), true ) );
643 throw Exceptions::InternalError( "PDF text encoding: Glyph index is out of the two byte code range." );
645 /* Remember that the endianness is unknown! Hence, don't */
646 // *reinterpret_cast< uint16_t * >( *dst_PDF ) = index;
649 **dst_PDF
= index
/ 0x100;
651 **dst_PDF
= index
% 0x100;
657 Lang::FreeTypeFont::encode( Kernel::UnicodeCodePoint c
, char ** dst_PDF
, size_t * out_avail
) const
661 throw Exceptions::InternalError( "The buffer allocated conversion of one UCS-4 code point to PDF show-text encoding was too small." );
663 FT_UInt index
= FT_Get_Char_Index( face_
, c
.get_UCS4( ) );
666 std::ostringstream msg
;
667 msg
<< "Missing glyph U+" << std::hex
<< c
.get_UCS4( ) << ".";
668 WARN_OR_THROW( Exceptions::FontProblem( this->PostScript_name( ), strrefdup( msg
), true ) );
672 throw Exceptions::InternalError( "PDF text encoding: Glyph index is out of the two byte code range." );
674 /* Remember that the endianness is unknown! Hence, don't */
675 // *reinterpret_cast< uint16_t * >( *dst_PDF ) = index;
678 **dst_PDF
= index
/ 0x100;
680 **dst_PDF
= index
% 0x100;
685 RefCountPtr
< const Lang::String
>
686 Lang::FreeTypeFont::family_name( ) const
688 return RefCountPtr
< const Lang::String
>( new Lang::String( face_
->family_name
, true ) );
691 RefCountPtr
< const Lang::String
>
692 Lang::FreeTypeFont::style_name( ) const
694 return RefCountPtr
< const Lang::String
>( new Lang::String( face_
->style_name
, true ) );
697 RefCountPtr
< const Lang::Symbol
>
698 Lang::FreeTypeFont::PostScript_name( ) const
700 const char * PostScriptName
= FT_Get_Postscript_Name( face_
);
701 if( PostScriptName
== 0 )
703 throw Exceptions::MiscellaneousRequirement( "The FreeType font does not provide a PostScript name." );
705 /* It is assumed that the created symbol is not used after the face_ is destroyed! */
706 return RefCountPtr
< const Lang::Symbol
>( new Lang::Symbol( PostScriptName
) );
716 Lang::MultiPath2D
* paths_
;
717 Lang::ElementaryPath2D
* contour_
;
718 Concrete::PathPoint2D
* last_
;
719 Concrete::Length scaled_font_unit_
;
725 /* We should eliminate the duplicated point where the path begins and ends. */
726 contour_
->pop_back( );
727 if( last_
->rear_
!= last_
->mid_
)
729 contour_
->front( )->rear_
= last_
->rear_
;
730 last_
->rear_
= last_
->mid_
; /* This gives away the ownership of last_->rear_. */
738 int move_to( const FT_Vector
& to
)
741 contour_
= new Lang::ElementaryPath2D( );
742 paths_
->push_back( RefCountPtr
< const Lang::Path2D
>( contour_
) );
743 last_
= new Concrete::PathPoint2D( new Concrete::Coords2D( to
.x
* scaled_font_unit_
, to
.y
* scaled_font_unit_
) );
744 contour_
->push_back( last_
);
747 int line_to( const FT_Vector
& to
)
749 last_
= new Concrete::PathPoint2D( new Concrete::Coords2D( to
.x
* scaled_font_unit_
, to
.y
* scaled_font_unit_
) );
750 contour_
->push_back( last_
);
753 int conic_to( const FT_Vector
& control
, const FT_Vector
& to
)
755 Concrete::Coords2D
c( control
.x
* scaled_font_unit_
, control
.y
* scaled_font_unit_
);
756 last_
->front_
= new Concrete::Coords2D( (2./3) * c
+ (1./3) * *last_
->mid_
);
757 last_
= new Concrete::PathPoint2D( new Concrete::Coords2D( to
.x
* scaled_font_unit_
, to
.y
* scaled_font_unit_
) );
758 last_
->rear_
= new Concrete::Coords2D( (2./3) * c
+ (1./3) * *last_
->mid_
);
759 contour_
->push_back( last_
);
762 int cubic_to( const FT_Vector
& control1
, const FT_Vector
& control2
, const FT_Vector
& to
)
764 last_
->front_
= new Concrete::Coords2D( control1
.x
* scaled_font_unit_
, control1
.y
* scaled_font_unit_
);
765 last_
= new Concrete::PathPoint2D( new Concrete::Coords2D( to
.x
* scaled_font_unit_
, to
.y
* scaled_font_unit_
) );
766 last_
->rear_
= new Concrete::Coords2D( control2
.x
* scaled_font_unit_
, control2
.y
* scaled_font_unit_
);
767 contour_
->push_back( last_
);
771 GetGlyphState( Lang::MultiPath2D
* paths
, Concrete::Length scaled_font_unit
)
775 scaled_font_unit_( scaled_font_unit
)
782 int getGlyph_move_to( const FT_Vector
* to
, void * stateUntyped
)
784 return reinterpret_cast< GetGlyphState
* >( stateUntyped
)->move_to( *to
);
786 int getGlyph_line_to( const FT_Vector
* to
, void * stateUntyped
)
788 return reinterpret_cast< GetGlyphState
* >( stateUntyped
)->line_to( *to
);
790 int getGlyph_conic_to( const FT_Vector
* control
, const FT_Vector
* to
, void * stateUntyped
)
792 return reinterpret_cast< GetGlyphState
* >( stateUntyped
)->conic_to( *control
, *to
);
794 int getGlyph_cubic_to( const FT_Vector
* control1
, const FT_Vector
* control2
, const FT_Vector
* to
, void * stateUntyped
)
796 return reinterpret_cast< GetGlyphState
* >( stateUntyped
)->cubic_to( *control1
, *control2
, *to
);
799 class ShipoutGlyphState
803 Concrete::Coords2D last_
;
805 Concrete::Length scaled_font_unit_
;
806 const Lang::Transform2D
& tf_
;
816 int move_to( const FT_Vector
& to
)
819 last_
= Concrete::Coords2D( to
.x
* scaled_font_unit_
, to
.y
* scaled_font_unit_
).transformed( tf_
);
820 os_
<< last_
<< " m " ;
824 int line_to( const FT_Vector
& to
)
826 last_
= Concrete::Coords2D( to
.x
* scaled_font_unit_
, to
.y
* scaled_font_unit_
).transformed( tf_
);
827 os_
<< last_
<< " l " ;
830 int conic_to( const FT_Vector
& control
, const FT_Vector
& to
)
832 Concrete::Coords2D c
= Concrete::Coords2D( control
.x
* scaled_font_unit_
, control
.y
* scaled_font_unit_
).transformed( tf_
);
833 Concrete::Coords2D control1
= (2./3) * c
+ (1./3) * last_
;
834 last_
= Concrete::Coords2D( to
.x
* scaled_font_unit_
, to
.y
* scaled_font_unit_
).transformed( tf_
);
835 Concrete::Coords2D control2
= (2./3) * c
+ (1./3) * last_
;
836 os_
<< control1
<< " " << control2
<< " " << last_
<< " c " ;
839 int cubic_to( const FT_Vector
& control1
, const FT_Vector
& control2
, const FT_Vector
& to
)
841 last_
= Concrete::Coords2D( to
.x
* scaled_font_unit_
, to
.y
* scaled_font_unit_
).transformed( tf_
);
842 os_
<< Concrete::Coords2D( control1
.x
* scaled_font_unit_
, control1
.y
* scaled_font_unit_
).transformed( tf_
)
843 << " " << Concrete::Coords2D( control2
.x
* scaled_font_unit_
, control2
.y
* scaled_font_unit_
).transformed( tf_
)
849 ShipoutGlyphState( std::ostream
& os
,
850 Concrete::Length scaled_font_unit
,
851 const Lang::Transform2D
& tf
)
855 scaled_font_unit_( scaled_font_unit
),
858 ~ShipoutGlyphState( )
863 int shipoutGlyph_move_to( const FT_Vector
* to
, void * stateUntyped
)
865 return reinterpret_cast< ShipoutGlyphState
* >( stateUntyped
)->move_to( *to
);
867 int shipoutGlyph_line_to( const FT_Vector
* to
, void * stateUntyped
)
869 return reinterpret_cast< ShipoutGlyphState
* >( stateUntyped
)->line_to( *to
);
871 int shipoutGlyph_conic_to( const FT_Vector
* control
, const FT_Vector
* to
, void * stateUntyped
)
873 return reinterpret_cast< ShipoutGlyphState
* >( stateUntyped
)->conic_to( *control
, *to
);
875 int shipoutGlyph_cubic_to( const FT_Vector
* control1
, const FT_Vector
* control2
, const FT_Vector
* to
, void * stateUntyped
)
877 return reinterpret_cast< ShipoutGlyphState
* >( stateUntyped
)->cubic_to( *control1
, *control2
, *to
);
883 Lang::FreeTypeFont::getGlyphOutline( Kernel::UnicodeCodePoint c
) const
885 FT_UInt index
= FT_Get_Char_Index( face_
, c
.get_UCS4( ) );
888 const size_t bufsize
= 10;
891 size_t outavail
= bufsize
- 1;
892 c
.encode_UTF8( & tmp
, & outavail
);
894 std::ostringstream msg
;
895 msg
<< "The font " << fontName_
<< " does not cover the character `" << buf
<< "´ (code point " << c
.get_UCS4( ) << ")." ;
896 throw Exceptions::OutOfRange( strrefdup( msg
) );
898 FT_Error error
= FT_Load_Glyph( face_
, index
, FT_LOAD_NO_SCALE
);
901 std::ostringstream msg
;
902 msg
<< "Unable to load glyph in FreeType, at code point " << c
.get_UCS4( ) ;
903 throw Shapes::Exceptions::OutOfRange( strrefdup( msg
) );
905 if( face_
->glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
907 const size_t bufsize
= 10;
910 size_t outavail
= bufsize
- 1;
911 c
.encode_UTF8( & tmp
, & outavail
);
913 std::ostringstream msg
;
914 msg
<< "Unsupported glyph format in the font " << fontName_
<< ", character `" << buf
<< "´ (code point " << c
.get_UCS4( ) << ")." ;
915 throw Exceptions::MiscellaneousRequirement( strrefdup( msg
) );
918 return face_
->glyph
->outline
;
921 RefCountPtr
< const Lang::Value
>
922 Lang::FreeTypeFont::getGlyph( Kernel::UnicodeCodePoint c
, Concrete::Length size
) const
924 const FT_Outline
& ol
= getGlyphOutline( c
);
926 Helpers::FontMethod_glyph_resultFactory
.set
927 ( "odd?", ( ( ol
.flags
& FT_OUTLINE_REVERSE_FILL
) == 0 ) ? Kernel::THE_FALSE_VARIABLE
: Kernel::THE_TRUE_VARIABLE
);
928 Concrete::Length font_unit_scaled
= size
/ static_cast< double >( face_
->units_per_EM
);
929 Lang::MultiPath2D
* pathsPtr
= new Lang::MultiPath2D( );
930 RefCountPtr
< const Lang::MultiPath2D
> paths( pathsPtr
);
932 FT_Outline_Funcs emitters
;
933 emitters
.move_to
= Helpers::getGlyph_move_to
;
934 emitters
.line_to
= Helpers::getGlyph_line_to
;
935 emitters
.conic_to
= Helpers::getGlyph_conic_to
;
936 emitters
.cubic_to
= Helpers::getGlyph_cubic_to
;
939 Helpers::GetGlyphState
state( pathsPtr
, font_unit_scaled
);
940 FT_Error error
= FT_Outline_Decompose( & face_
->glyph
->outline
, & emitters
, reinterpret_cast< void * >( & state
) );
943 std::ostringstream msg
;
944 msg
<< "FreeType error, FT_Outline_Decompose returned with error: " << Kernel::FreeTypeErrorMessage( error
) ;
945 throw Exceptions::ExternalError( strrefdup( msg
) );
948 Helpers::FontMethod_glyph_resultFactory
.set( "paths", Kernel::VariableHandle( new Kernel::Variable( paths
) ) );
950 Helpers::FontMethod_glyph_resultFactory
.set( "advance", Helpers::newValHandle( new Lang::Length( face_
->glyph
->metrics
.horiAdvance
* font_unit_scaled
) ) );
952 return Helpers::FontMethod_glyph_resultFactory
.build( );
956 Lang::FreeTypeFont::shipout_glyph( Kernel::UnicodeCodePoint c
, Concrete::Length size
, const Lang::Transform2D
& tf
, std::ostream
& os
, bool * dstIsOdd
, Concrete::Length
* dstAdvance
) const
958 const FT_Outline
& ol
= getGlyphOutline( c
);
960 Concrete::Length font_unit_scaled
= size
/ static_cast< double >( face_
->units_per_EM
);
962 *dstIsOdd
= ( ol
.flags
& FT_OUTLINE_REVERSE_FILL
) != 0;
963 *dstAdvance
= Concrete::Length( face_
->glyph
->metrics
.horiAdvance
* font_unit_scaled
); /* Here we use that the correct glyph is in the glyph slot. */
965 FT_Outline_Funcs emitters
;
966 emitters
.move_to
= Helpers::shipoutGlyph_move_to
;
967 emitters
.line_to
= Helpers::shipoutGlyph_line_to
;
968 emitters
.conic_to
= Helpers::shipoutGlyph_conic_to
;
969 emitters
.cubic_to
= Helpers::shipoutGlyph_cubic_to
;
972 Helpers::ShipoutGlyphState
state( os
, font_unit_scaled
, tf
);
973 FT_Error error
= FT_Outline_Decompose( const_cast< FT_Outline
* >( & ol
), & emitters
, reinterpret_cast< void * >( & state
) );
976 std::ostringstream msg
;
977 msg
<< "FreeType error, FT_Outline_Decompose returned with error: " << Kernel::FreeTypeErrorMessage( error
) ;
978 throw Exceptions::ExternalError( strrefdup( msg
) );
982 #endif /* End of #ifdef HAVE_FT2. */
984 Lang::TextOperation::TextOperation( )
987 Lang::TextOperation::~TextOperation( )
990 RefCountPtr
< const Lang::Class
> Lang::TextOperation::TypeID( new Lang::SystemFinalClass( strrefdup( "TextOperation" ) ) );
991 TYPEINFOIMPL( TextOperation
);
994 Lang::KernedText::KernedText( const RefCountPtr
< const Kernel::TextState
> & textState
, const RefCountPtr
< const Kernel::GraphicsState
> & metaState
)
995 : textState_( textState
), metaState_( metaState
), maxLength_( 0 )
998 Lang::KernedText::KernedText( const RefCountPtr
< const Kernel::TextState
> & textState
, const RefCountPtr
< const Kernel::GraphicsState
> & metaState
, const RefCountPtr
< const Lang::String
> & str
)
999 : textState_( textState
), metaState_( metaState
), maxLength_( 0 )
1004 Lang::KernedText::~KernedText( )
1007 Kernel::VariableHandle
1008 Lang::KernedText::getField( const char * fieldID
, const RefCountPtr
< const Lang::Value
> & selfRef
) const
1010 if( strcmp( fieldID
, "list" ) == 0 )
1012 return Kernel::VariableHandle( new Kernel::Variable( makeList( ) ) );
1014 throw Exceptions::NonExistentMember( getTypeName( ), fieldID
);
1017 RefCountPtr
< const Lang::SingleList
>
1018 Lang::KernedText::makeList( ) const
1020 /* The list is first computed in a bidirectional list, and then we construct the stateless cons list.
1023 /* I'm lazy today, so i use a cons pair to group the horizontal step with the glyph. The better solution
1024 * would be to use a structure with nicely named fields...
1027 std::list
< RefCountPtr
< const Lang::Value
> > revlist
;
1029 iconv_t converter
= Helpers::requireUTF8ToUCS4Converter( );
1031 RefCountPtr
< FontMetrics::WritingDirectionMetrics
> horizontalMetrics
= textState_
->font_
->metrics( )->horizontalMetrics_
;
1032 if( horizontalMetrics
== NullPtr
< FontMetrics::WritingDirectionMetrics
>( ) )
1034 throw Exceptions::FontMetricsError( textState_
->font_
->fontName( ), strrefdup( "No horizontal metrics defined." ) );
1036 const FontMetrics::CharacterMetrics
* defaultCharMetrics
= horizontalMetrics
->default_char( );
1038 Concrete::Length ySize
= textState_
->size_
;
1039 Concrete::Length xSize
= ySize
* textState_
->horizontalScaling_
;
1040 Concrete::Length characterTrackKern
= textState_
->horizontalScaling_
* textState_
->characterSpacingConcrete( );
1041 Concrete::Length wordTrackKern
= textState_
->horizontalScaling_
* textState_
->wordSpacingConcrete( );
1043 Concrete::Length xpos
= 0;
1045 size_t bufSize
= 4 * maxLength_
; // This will be enough if UCS4 coding is used, since this encoding uses only one byte per character.
1046 char * buf
= new char[ bufSize
];
1047 DeleteOnExit
< char > bufDeleter( buf
);
1049 FontMetrics::CharacterMetrics
tmpCharMetric( 0 );
1051 typedef typeof strings_ ListType
;
1052 std::list
< double >::const_iterator ki
= kernings_
.begin( );
1053 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1055 if( *i
!= NullPtr
< const Lang::String
>( ) )
1057 const char * inbuf
= (*i
)->val_
.getPtr( );
1058 if( strchr( inbuf
, '\n' ) != 0 )
1060 throw Exceptions::MiscellaneousRequirement( "Newlines cannot be represented in the pos-character list." );
1062 char * outbuf
= buf
;
1063 size_t inbytesleft
= strlen( inbuf
);
1064 size_t outbytesleft
= bufSize
;
1065 // The ICONV_CAST macro is defined in config.h.
1066 size_t count
= iconv( converter
,
1067 ICONV_CAST( & inbuf
), & inbytesleft
,
1068 & outbuf
, & outbytesleft
);
1069 if( count
== (size_t)(-1) )
1071 if( errno
== EILSEQ
)
1073 throw Exceptions::MiscellaneousRequirement( "It is suspected that string data is not proper UFT-8, since conversion to UCS-4 failed." );
1075 else if( errno
== EINVAL
)
1077 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
1079 else if( errno
== E2BIG
)
1081 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to UCS-4 conversion was too small." );
1085 std::ostringstream msg
;
1086 msg
<< "iconv failed with an unrecognized error code: " << errno
;
1087 throw Exceptions::InternalError( strrefdup( msg
) );
1090 for( const char * src
= buf
; src
!= outbuf
; src
+= 4 )
1092 Kernel::UnicodeCodePoint code
;
1093 code
.decode_UCS4( src
);
1094 if( code
== Kernel::UnicodeCodePoint::SPACE
) /* test for space */
1096 // Observe textState_->wordSpacing_
1097 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
1098 xpos
+= xSize
* charMetrics
->horizontalCharWidthX_
;
1099 xpos
+= characterTrackKern
;
1100 xpos
+= wordTrackKern
;
1102 else /* there should not be any newlines in the string, so we expect this to be a non-white character */
1104 // Observe textState_->characterSpacing_
1105 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
1106 if( Computation::fontMetricGuessIsError
&& charMetrics
== defaultCharMetrics
)
1108 std::ostringstream msg
;
1109 msg
<< "Character at offset " << src
- buf
<< " in \"" << buf
<< "\" was not found in font metrics (and according to your options, guessing is not OK)." ;
1110 throw Exceptions::FontMetricsError( textState_
->font_
->fontName( ), strrefdup( msg
) );
1112 revlist
.push_back( RefCountPtr
< const Lang::Value
>
1113 ( new Lang::ConsPair
1114 ( Helpers::newValHandle( new Lang::Length( xpos
) ),
1115 Helpers::newValHandle( new Lang::KernedText( textState_
, metaState_
, oneUCS4ToUTF8( src
) ) ) ) ) );
1116 /* Although not as efficient, it becomes easier to use the list if the distance is
1117 * measured from the start of the text rather than from the previous character.
1120 xpos
+= xSize
* charMetrics
->horizontalCharWidthX_
;
1121 xpos
+= characterTrackKern
;
1127 if( ki
== kernings_
.end( ) )
1129 throw Exceptions::InternalError( "Short of kerning values in KernedText::measure." );
1131 xpos
-= xSize
* *ki
;
1135 if( ki
!= kernings_
.end( ) )
1137 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
1140 RefCountPtr
< const Lang::SingleList
> res
= Lang::THE_CONS_NULL
;
1141 while( ! revlist
.empty( ) )
1143 res
= RefCountPtr
< const Lang::SingleList
>( new Lang::SingleListPair( Kernel::VariableHandle( new Kernel::Variable( revlist
.back( ) ) ),
1145 revlist
.pop_back( );
1150 RefCountPtr
< const Lang::String
>
1151 Lang::KernedText::oneUCS4ToUTF8( const char * c
)
1153 iconv_t converter
= Helpers::requireUCS4ToUTF8Converter( );
1155 const size_t BUF_SIZE
= 9;
1156 char buf
[ BUF_SIZE
];
1168 char * outbuf
= buf
;
1169 const char * inbuf
= charbuf
;
1170 size_t inbytesleft
= 4;
1171 size_t outbytesleft
= BUF_SIZE
- 1;
1172 // The ICONV_CAST macro is defined in config.h.
1173 size_t count
= iconv( converter
,
1174 ICONV_CAST( & inbuf
), & inbytesleft
,
1175 & outbuf
, & outbytesleft
);
1176 if( count
== (size_t)(-1) )
1178 throw Exceptions::ExternalError( "Conversion of one UCS-4 character to UTF-8 failed." );
1181 return RefCountPtr
< const Lang::String
>( new Lang::String( strrefdup( buf
) ) );
1185 Lang::KernedText::pushString( const RefCountPtr
< const Lang::String
> & str
)
1187 strings_
.push_back( str
);
1188 maxLength_
= std::max( maxLength_
, strlen( str
->val_
.getPtr( ) ) );
1192 Lang::KernedText::pushKerning( double kerning
)
1194 strings_
.push_back( NullPtr
< const Lang::String
>( ) );
1195 kernings_
.push_back( kerning
);
1199 Lang::KernedText::show( std::ostream
& os
) const
1201 typedef typeof strings_ ListType
;
1202 std::list
< double >::const_iterator ki
= kernings_
.begin( );
1203 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1205 if( *i
!= NullPtr
< const Lang::String
>( ) )
1207 os
<< "(" << (*i
)->val_
.getPtr( ) << ")" ;
1211 if( ki
== kernings_
.end( ) )
1213 throw Exceptions::InternalError( "Short of kerning values in KernedText::show." );
1219 if( ki
!= kernings_
.end( ) )
1221 throw Exceptions::InternalError( "Too many kerning values in KernedText::show." );
1227 Lang::KernedText::shipout( std::ostream
& os
, Kernel::PageContentStates
* pdfState
, const Lang::Transform2D
& tf
, bool clip
) const
1229 pdfState
->text_
.synchAssertKnockout( os
, textState_
.getPtr( ), pdfState
->resources_
.getPtr( ), clip
);
1230 switch( textState_
->mode_
)
1232 case Lang::TextRenderingMode::FILL
:
1233 case Lang::TextRenderingMode::FILLCLIP
:
1234 pdfState
->graphics_
.synchForNonStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1236 case Lang::TextRenderingMode::STROKE
:
1237 case Lang::TextRenderingMode::STROKECLIP
:
1238 pdfState
->graphics_
.synchForStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1240 case Lang::TextRenderingMode::FILLSTROKE
:
1241 case Lang::TextRenderingMode::FILLSTROKECLIP
:
1242 pdfState
->graphics_
.synchForStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1243 pdfState
->graphics_
.synchForNonStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1245 case Lang::TextRenderingMode::INVISIBLE
:
1246 case Lang::TextRenderingMode::CLIP
:
1248 case Lang::TextRenderingMode::UNDEFINED
:
1249 pdfState
->graphics_
.synchForStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1250 pdfState
->graphics_
.synchForNonStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1252 throw Exceptions::InternalError( "KernedText::writePDFVectorTo: Text rendering mode out of range." );
1256 size_t bufSize
= 4 * maxLength_
; // Even with UTF16BE encoding, no character should use more than 4 bytes.
1257 // The extra one byte will be used to terminate the string.
1258 char * buf
= new char[ bufSize
];
1259 DeleteOnExit
< char > bufDeleter( buf
);
1261 typedef typeof strings_ ListType
;
1262 std::list
< double >::const_iterator ki
= kernings_
.begin( );
1264 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1266 if( *i
!= NullPtr
< const Lang::String
>( ) )
1269 const char * line
= (*i
)->val_
.getPtr( );
1272 const char * nextLine
= strchr( line
, '\n' ); /* Search for line breaks before we convert from UTF8. */
1273 const char * inbuf
= line
;
1274 char * outbuf
= buf
;
1275 size_t inbytesleft
= ( nextLine
!= 0 ) ? ( nextLine
- line
) : strlen( line
);
1276 size_t outbytesleft
= bufSize
;
1277 textState_
->font_
->encode( & inbuf
, & inbytesleft
,
1278 & outbuf
, & outbytesleft
);
1279 const char * end
= buf
+ ( bufSize
- outbytesleft
);
1280 for( const char * src
= buf
; src
!= end
; ++src
)
1301 os
<< ")] TJ T* [(" ;
1303 ++line
; /* Skip the \n character */
1309 if( ki
== kernings_
.end( ) )
1311 throw Exceptions::InternalError( "Short of kerning values in KernedText::writePDFVectorTo." );
1313 os
<< 1000 * *ki
<< " " ;
1317 if( ki
!= kernings_
.end( ) )
1319 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
1322 os
<< "] TJ " << std::endl
;
1326 Lang::KernedText::shipout_outlined( std::ostream
& os
, Kernel::PageContentStates
* pdfState
, const Lang::Transform2D
& tf
, Lang::Transform2D
* textMatrix
, Lang::Transform2D
* lineMatrix
, const SimplePDF::PDF_Name
* clipContent
) const
1329 throw Exceptions::BuildRequirement( Interaction::BUILD_REQ_FREETYPE
, "(outlined fonts)", Ast::THE_UNKNOWN_LOCATION
);
1331 iconv_t converter
= Helpers::requireUTF8ToUCS4Converter( );
1333 RefCountPtr
< const Lang::FreeTypeFont
> font
= textState_
->font_
.down_cast
< const Lang::FreeTypeFont
>( );
1334 if( font
== NullPtr
< typeof *font
>( ) )
1336 throw Exceptions::MiscellaneousRequirement( "Text masking is only supported for fonts accessed through FreeType." );
1339 RefCountPtr
< FontMetrics::WritingDirectionMetrics
> horizontalMetrics
= font
->metrics( )->horizontalMetrics_
;
1340 if( horizontalMetrics
== NullPtr
< FontMetrics::WritingDirectionMetrics
>( ) )
1342 throw Exceptions::FontMetricsError( font
->fontName( ), strrefdup( "No horizontal metrics defined." ) );
1345 Concrete::Length ySize
= textState_
->size_
;
1346 Concrete::Length xSize
= ySize
* textState_
->horizontalScaling_
;
1347 Concrete::Length characterTrackKern
= textState_
->horizontalScaling_
* textState_
->characterSpacingConcrete( );
1348 Concrete::Length wordTrackKern
= textState_
->horizontalScaling_
* textState_
->wordSpacingConcrete( );
1350 size_t bufSize
= 4 * maxLength_
;
1351 char * buf
= new char[ bufSize
];
1352 DeleteOnExit
< char > bufDeleter( buf
);
1354 Concrete::Length rise
= textState_
->riseConcrete( );
1355 FontMetrics::CharacterMetrics
tmpCharMetric( 0 );
1357 if( textState_
->mode_
== Lang::TextRenderingMode::STROKE
||
1358 textState_
->mode_
== Lang::TextRenderingMode::FILLSTROKE
)
1360 pdfState
->graphics_
.synchForStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1362 if( textState_
->mode_
== Lang::TextRenderingMode::FILL
||
1363 textState_
->mode_
== Lang::TextRenderingMode::FILLSTROKE
)
1365 pdfState
->graphics_
.synchForNonStroke( os
, metaState_
.getPtr( ), pdfState
->resources_
.getPtr( ) );
1368 typedef typeof strings_ ListType
;
1369 std::list
< double >::const_iterator ki
= kernings_
.begin( );
1370 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1372 if( *i
!= NullPtr
< const Lang::String
>( ) )
1374 const char * inbuf
= (*i
)->val_
.getPtr( );
1375 char * outbuf
= buf
;
1376 size_t inbytesleft
= strlen( inbuf
);
1377 size_t outbytesleft
= bufSize
;
1378 // The ICONV_CAST macro is defined in config.h.
1379 size_t count
= iconv( converter
,
1380 ICONV_CAST( & inbuf
), & inbytesleft
,
1381 & outbuf
, & outbytesleft
);
1382 if( count
== (size_t)(-1) )
1384 if( errno
== EILSEQ
)
1386 throw Exceptions::MiscellaneousRequirement( "Not proper UFT-8? Failed to convert to UCS-4 code points." );
1388 else if( errno
== EINVAL
)
1390 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
1392 else if( errno
== E2BIG
)
1394 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to UCS-4 conversion was too small." );
1398 std::ostringstream msg
;
1399 msg
<< "iconv failed with an unrecognized error code: " << errno
;
1400 throw Exceptions::InternalError( strrefdup( msg
) );
1403 for( const char * src
= buf
; src
!= outbuf
; src
+= 4 )
1405 Kernel::UnicodeCodePoint code
;
1406 code
.decode_UCS4( src
);
1407 if( code
== Kernel::UnicodeCodePoint::SPACE
)
1409 // Observe textState_->wordSpacing_
1410 // In addition, it seems reasonable to not let the space character affect the bounding box.
1411 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
1412 textMatrix
->prependXShift( xSize
* charMetrics
->horizontalCharWidthX_
+ characterTrackKern
+ wordTrackKern
);
1414 else if( code
== Kernel::UnicodeCodePoint::NEWLINE
)
1416 lineMatrix
->prependShift( Concrete::Coords2D( 0, - textState_
->leadingConcrete( ) ) );
1417 textMatrix
->replaceBy( *lineMatrix
);
1421 // Observe textState_->characterSpacing_
1423 Concrete::Length advance
;
1424 Lang::Transform2D
tmpTf( tf
, *textMatrix
);
1425 tmpTf
.prependYShift( rise
);
1426 tmpTf
.prependXScale( textState_
->horizontalScaling_
);
1427 if( clipContent
== 0 )
1429 /* The graphics state was synched above. */
1430 font
->shipout_glyph( code
, ySize
, tmpTf
, os
, & isOdd
, & advance
);
1431 switch( textState_
->mode_
)
1433 case Lang::TextRenderingMode::FILL
:
1434 os
<< ( isOdd
? "f*" : "f" ) << std::endl
;
1436 case Lang::TextRenderingMode::STROKE
:
1437 os
<< "s" << std::endl
;
1439 case Lang::TextRenderingMode::FILLSTROKE
:
1440 os
<< ( isOdd
? "B*" : "B" ) << std::endl
;
1442 case Lang::TextRenderingMode::INVISIBLE
:
1443 os
<< "n" << std::endl
;
1445 case Lang::TextRenderingMode::FILLCLIP
:
1446 case Lang::TextRenderingMode::STROKECLIP
:
1447 case Lang::TextRenderingMode::FILLSTROKECLIP
:
1448 case Lang::TextRenderingMode::CLIP
:
1449 throw Exceptions::InternalError( "The clipping text rendering modes are not supposed to be used." );
1450 case Lang::TextRenderingMode::UNDEFINED
:
1451 throw Exceptions::InternalError( "Undefined text rendering mode during shipout of outlined text." );
1456 Kernel::Auto_qQ
auto_qQ( & pdfState
->graphics_
, & pdfState
->text_
, os
);
1457 font
->shipout_glyph( code
, ySize
, tmpTf
, os
, & isOdd
, & advance
);
1458 os
<< ( isOdd
? "W* " : "W " ) ;
1459 switch( textState_
->mode_
)
1461 case Lang::TextRenderingMode::FILL
:
1462 os
<< ( isOdd
? "f*" : "f" ) ;
1464 case Lang::TextRenderingMode::STROKE
:
1467 case Lang::TextRenderingMode::FILLSTROKE
:
1468 os
<< ( isOdd
? "B*" : "B" ) ;
1470 case Lang::TextRenderingMode::INVISIBLE
:
1473 case Lang::TextRenderingMode::FILLCLIP
:
1474 case Lang::TextRenderingMode::STROKECLIP
:
1475 case Lang::TextRenderingMode::FILLSTROKECLIP
:
1476 case Lang::TextRenderingMode::CLIP
:
1477 throw Exceptions::InternalError( "The clipping text rendering modes are not supposed to be used." );
1478 case Lang::TextRenderingMode::UNDEFINED
:
1479 throw Exceptions::InternalError( "Undefined text rendering mode during shipout of outlined text." );
1481 os
<< " " << *clipContent
<< " Do" << std::endl
;
1484 textMatrix
->prependXShift( advance
* textState_
->horizontalScaling_
+ characterTrackKern
);
1490 if( ki
== kernings_
.end( ) )
1492 throw Exceptions::InternalError( "Short of kerning values in KernedText::shipout_outlined." );
1494 textMatrix
->prependXShift( - xSize
* *ki
);
1498 if( ki
!= kernings_
.end( ) )
1500 throw Exceptions::InternalError( "Too many kerning values in KernedText::shipout_outlined." );
1502 #endif /* End of #ifndef HAVE_FT2 / #else. */
1506 Lang::KernedText::measure( Lang::Transform2D
* textMatrix
, Lang::Transform2D
* textLineMatrix
, Concrete::Length
* xmin
, Concrete::Length
* ymin
, Concrete::Length
* xmax
, Concrete::Length
* ymax
) const
1508 iconv_t converter
= Helpers::requireUTF8ToUCS4Converter( );
1510 RefCountPtr
< FontMetrics::WritingDirectionMetrics
> horizontalMetrics
= textState_
->font_
->metrics( )->horizontalMetrics_
;
1511 if( horizontalMetrics
== NullPtr
< FontMetrics::WritingDirectionMetrics
>( ) )
1513 throw Exceptions::FontMetricsError( textState_
->font_
->fontName( ), strrefdup( "No horizontal metrics defined." ) );
1515 const FontMetrics::CharacterMetrics
* defaultCharMetrics
= horizontalMetrics
->default_char( );
1517 Concrete::Length ySize
= textState_
->size_
;
1518 Concrete::Length xSize
= ySize
* textState_
->horizontalScaling_
;
1519 Concrete::Length characterTrackKern
= textState_
->horizontalScaling_
* textState_
->characterSpacingConcrete( );
1520 Concrete::Length wordTrackKern
= textState_
->horizontalScaling_
* textState_
->wordSpacingConcrete( );
1522 size_t bufSize
= 4 * maxLength_
;
1523 char * buf
= new char[ bufSize
];
1524 DeleteOnExit
< char > bufDeleter( buf
);
1526 FontMetrics::CharacterMetrics
tmpCharMetric( 0 );
1528 if( textLineMatrix
->isTranslation( ) )
1530 Concrete::Length x0
= textLineMatrix
->xt_
;
1531 Concrete::Length y0
= textLineMatrix
->yt_
+ textState_
->riseConcrete( );
1532 Concrete::Length xpos
= 0;
1534 typedef typeof strings_ ListType
;
1535 std::list
< double >::const_iterator ki
= kernings_
.begin( );
1536 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1538 if( *i
!= NullPtr
< const Lang::String
>( ) )
1540 const char * inbuf
= (*i
)->val_
.getPtr( );
1541 char * outbuf
= buf
;
1542 size_t inbytesleft
= strlen( inbuf
);
1543 size_t outbytesleft
= bufSize
;
1544 // The ICONV_CAST macro is defined in config.h.
1545 size_t count
= iconv( converter
,
1546 ICONV_CAST( & inbuf
), & inbytesleft
,
1547 & outbuf
, & outbytesleft
);
1548 if( count
== (size_t)(-1) )
1550 if( errno
== EILSEQ
)
1552 throw Exceptions::MiscellaneousRequirement( "Not proper UFT-8? Failed to convert to UCS-4 code points." );
1554 else if( errno
== EINVAL
)
1556 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
1558 else if( errno
== E2BIG
)
1560 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to UCS-4 conversion was too small." );
1564 std::ostringstream msg
;
1565 msg
<< "iconv failed with an unrecognized error code: " << errno
;
1566 throw Exceptions::InternalError( strrefdup( msg
) );
1569 for( const char * src
= buf
; src
!= outbuf
; src
+= 4 )
1571 Kernel::UnicodeCodePoint code
;
1572 code
.decode_UCS4( src
);
1573 if( code
== Kernel::UnicodeCodePoint::SPACE
)
1575 // Observe textState_->wordSpacing_
1576 // In addition, it seems reasonable to not let the space character affect the bounding box.
1577 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
1578 xpos
+= xSize
* charMetrics
->horizontalCharWidthX_
;
1579 xpos
+= characterTrackKern
;
1580 xpos
+= wordTrackKern
;
1582 else if( code
== Kernel::UnicodeCodePoint::NEWLINE
)
1584 textMatrix
->prependShift( Concrete::Coords2D( 0, - textState_
->leadingConcrete( ) ) );
1585 textLineMatrix
->replaceBy( *textMatrix
);
1586 x0
= textLineMatrix
->xt_
;
1587 y0
= textLineMatrix
->yt_
+ textState_
->riseConcrete( );
1592 // Observe textState_->characterSpacing_
1593 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
1594 if( Computation::fontMetricGuessIsError
&& charMetrics
== defaultCharMetrics
)
1596 std::ostringstream msg
;
1597 msg
<< "Character at offset " << src
- buf
<< " in \"" << buf
<< "\" was not found in font metrics (and according to your options, guessing is not OK)." ;
1598 throw Exceptions::FontMetricsError( textState_
->font_
->fontName( ), strrefdup( msg
) );
1600 *xmin
= std::min( *xmin
, x0
+ xpos
+ xSize
* charMetrics
->xmin_
);
1601 *ymin
= std::min( *ymin
, y0
+ ySize
* charMetrics
->ymin_
);
1602 *xmax
= std::max( *xmax
, x0
+ xpos
+ xSize
* charMetrics
->xmax_
);
1603 *ymax
= std::max( *ymax
, y0
+ ySize
* charMetrics
->ymax_
);
1604 xpos
+= xSize
* charMetrics
->horizontalCharWidthX_
;
1605 xpos
+= characterTrackKern
;
1611 if( ki
== kernings_
.end( ) )
1613 throw Exceptions::InternalError( "Short of kerning values in KernedText::measure." );
1615 xpos
-= xSize
* *ki
;
1619 if( ki
!= kernings_
.end( ) )
1621 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
1624 textLineMatrix
->prependXShift( xpos
);
1628 Concrete::Length rise
= textState_
->riseConcrete( );
1630 typedef typeof strings_ ListType
;
1631 std::list
< double >::const_iterator ki
= kernings_
.begin( );
1632 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1634 if( *i
!= NullPtr
< const Lang::String
>( ) )
1636 const char * inbuf
= (*i
)->val_
.getPtr( );
1637 char * outbuf
= buf
;
1638 size_t inbytesleft
= strlen( inbuf
);
1639 size_t outbytesleft
= bufSize
;
1640 // The ICONV_CAST macro is defined in config.h.
1641 size_t count
= iconv( converter
,
1642 ICONV_CAST( & inbuf
), & inbytesleft
,
1643 & outbuf
, & outbytesleft
);
1644 if( count
== (size_t)(-1) )
1646 if( errno
== EILSEQ
)
1648 throw Exceptions::MiscellaneousRequirement( "Not proper UFT-8? Failed to convert to UCS-4 code points." );
1650 else if( errno
== EINVAL
)
1652 throw Exceptions::MiscellaneousRequirement( "It is suspected that showed text ended with an incomplete multibyte character." );
1654 else if( errno
== E2BIG
)
1656 throw Exceptions::InternalError( "The buffer allocated for UTF-8 to UCS-4 conversion was too small." );
1660 std::ostringstream msg
;
1661 msg
<< "iconv failed with an unrecognized error code: " << errno
;
1662 throw Exceptions::InternalError( strrefdup( msg
) );
1665 for( const char * src
= buf
; src
!= outbuf
; src
+= 4 )
1667 Kernel::UnicodeCodePoint code
;
1668 code
.decode_UCS4( src
);
1669 if( code
== Kernel::UnicodeCodePoint::SPACE
)
1671 // Observe textState_->wordSpacing_
1672 // In addition, it seems reasonable to not let the space character affect the bounding box.
1673 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
1674 textLineMatrix
->prependXShift( xSize
* charMetrics
->horizontalCharWidthX_
+ characterTrackKern
+ wordTrackKern
);
1676 else if( code
== Kernel::UnicodeCodePoint::NEWLINE
)
1678 textMatrix
->prependShift( Concrete::Coords2D( 0, - textState_
->leadingConcrete( ) ) );
1679 textLineMatrix
->replaceBy( *textMatrix
);
1683 // Observe textState_->characterSpacing_
1684 const FontMetrics::CharacterMetrics
* charMetrics
= horizontalMetrics
->charByCode( code
, & tmpCharMetric
);
1685 if( Computation::fontMetricGuessIsError
&& charMetrics
== defaultCharMetrics
)
1687 std::ostringstream msg
;
1688 msg
<< "Character at offset " << src
- buf
<< " in \"" << buf
<< "\" was not found in the font metrics (and according to your options, guessing is not OK)." ;
1689 throw Exceptions::FontMetricsError( textState_
->font_
->fontName( ), strrefdup( msg
) );
1692 Concrete::Coords2D x0y0
= Concrete::Coords2D( xSize
* charMetrics
->xmin_
, ySize
* charMetrics
->ymin_
+ rise
).transformed( *textLineMatrix
);
1693 Concrete::Coords2D x0y1
= Concrete::Coords2D( xSize
* charMetrics
->xmin_
, ySize
* charMetrics
->ymax_
+ rise
).transformed( *textLineMatrix
);
1694 Concrete::Coords2D x1y0
= Concrete::Coords2D( xSize
* charMetrics
->xmax_
, ySize
* charMetrics
->ymin_
+ rise
).transformed( *textLineMatrix
);
1695 Concrete::Coords2D x1y1
= Concrete::Coords2D( xSize
* charMetrics
->xmax_
, ySize
* charMetrics
->ymax_
+ rise
).transformed( *textLineMatrix
);
1697 *xmin
= std::min( *xmin
, x0y0
.x_
);
1698 *ymin
= std::min( *ymin
, x0y0
.y_
);
1699 *xmax
= std::max( *xmax
, x0y0
.x_
);
1700 *ymax
= std::max( *ymax
, x0y0
.y_
);
1702 *xmin
= std::min( *xmin
, x0y1
.x_
);
1703 *ymin
= std::min( *ymin
, x0y1
.y_
);
1704 *xmax
= std::max( *xmax
, x0y1
.x_
);
1705 *ymax
= std::max( *ymax
, x0y1
.y_
);
1707 *xmin
= std::min( *xmin
, x1y0
.x_
);
1708 *ymin
= std::min( *ymin
, x1y0
.y_
);
1709 *xmax
= std::max( *xmax
, x1y0
.x_
);
1710 *ymax
= std::max( *ymax
, x1y0
.y_
);
1712 *xmin
= std::min( *xmin
, x1y1
.x_
);
1713 *ymin
= std::min( *ymin
, x1y1
.y_
);
1714 *xmax
= std::max( *xmax
, x1y1
.x_
);
1715 *ymax
= std::max( *ymax
, x1y1
.y_
);
1717 textLineMatrix
->prependXShift( xSize
* charMetrics
->horizontalCharWidthX_
+ characterTrackKern
);
1723 if( ki
== kernings_
.end( ) )
1725 throw Exceptions::InternalError( "Short of kerning values in KernedText::measure." );
1727 textLineMatrix
->prependXShift( - xSize
* *ki
);
1731 if( ki
!= kernings_
.end( ) )
1733 throw Exceptions::InternalError( "Too many kerning values in KernedText::writePDFVectorTo." );
1739 Lang::KernedText::push( Lang::KernedText
* dst
) const
1741 typedef typeof strings_ ListType
;
1742 std::list
< double >::const_iterator ki
= kernings_
.begin( );
1743 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1745 if( *i
!= NullPtr
< const Lang::String
>( ) )
1747 dst
->pushString( *i
);
1751 dst
->pushKerning( *ki
);
1759 Lang::KernedText::gcMark( Kernel::GCMarkedSet
& marked
)
1761 typedef typeof strings_ ListType
;
1762 for( ListType::const_iterator i
= strings_
.begin( ); i
!= strings_
.end( ); ++i
)
1764 if( *i
!= NullPtr
< const Lang::String
>( ) )
1766 const_cast< Lang::String
* >( i
->getPtr( ) )->gcMark( marked
);
1771 Lang::TextNewline::TextNewline( const Concrete::Length tx
, const Concrete::Length ty
)
1775 Lang::TextNewline::~TextNewline( )
1779 Lang::TextNewline::show( std::ostream
& os
) const
1781 os
<< "Newline with offset in bp: " << t_
;
1785 Lang::TextNewline::shipout( std::ostream
& os
, Kernel::PageContentStates
* pdfState
, const Lang::Transform2D
& tf
, bool clip
) const
1787 os
<< t_
<< " Td " ;
1791 Lang::TextNewline::shipout_outlined( std::ostream
& os
, Kernel::PageContentStates
* pdfState
, const Lang::Transform2D
& tf
, Lang::Transform2D
* textMatrix
, Lang::Transform2D
* lineMatrix
, const SimplePDF::PDF_Name
* clipContent
) const
1793 lineMatrix
->prependShift( t_
);
1794 textMatrix
->replaceBy( *lineMatrix
);
1799 Lang::TextNewline::measure( Lang::Transform2D
* textMatrix
, Lang::Transform2D
* textLineMatrix
, Concrete::Length
* xmin
, Concrete::Length
* ymin
, Concrete::Length
* xmax
, Concrete::Length
* ymax
) const
1801 textMatrix
->prependShift( t_
);
1802 textLineMatrix
->replaceBy( *textMatrix
);
1806 Lang::TextNewline::gcMark( Kernel::GCMarkedSet
& marked
)
1809 Lang::TextMoveto::TextMoveto( const RefCountPtr
< const Lang::Transform2D
> & tf
)
1813 Lang::TextMoveto::~TextMoveto( )
1817 Lang::TextMoveto::show( std::ostream
& os
) const
1819 os
<< "Moveto command" ;
1823 Lang::TextMoveto::shipout( std::ostream
& os
, Kernel::PageContentStates
* pdfState
, const Lang::Transform2D
& tf
, bool clip
) const
1825 Lang::Transform2D( tf
, *tf_
).shipout( os
);
1826 os
<< " Tm" << std::endl
;
1830 Lang::TextMoveto::shipout_outlined( std::ostream
& os
, Kernel::PageContentStates
* pdfState
, const Lang::Transform2D
& tf
, Lang::Transform2D
* textMatrix
, Lang::Transform2D
* lineMatrix
, const SimplePDF::PDF_Name
* clipContent
) const
1832 lineMatrix
->replaceBy( Lang::Transform2D( tf
, *tf_
) );
1833 textMatrix
->replaceBy( *lineMatrix
);
1837 Lang::TextMoveto::measure( Lang::Transform2D
* textMatrix
, Lang::Transform2D
* textLineMatrix
, Concrete::Length
* xmin
, Concrete::Length
* ymin
, Concrete::Length
* xmax
, Concrete::Length
* ymax
) const
1839 textMatrix
->replaceBy( *tf_
);
1840 textLineMatrix
->replaceBy( *textMatrix
);
1844 Lang::TextMoveto::gcMark( Kernel::GCMarkedSet
& marked
)
1846 const_cast< Lang::Transform2D
* >( tf_
.getPtr( ) )->gcMark( marked
);
1851 typedef enum { FILL
= 0, STROKE
, FILLSTROKE
, INVISIBLE
, FILLCLIP
, STROKECLIP
, FILLSTROKECLIP
, CLIP
, UNDEFINED
} ValueType
;
1854 Lang::TextRenderingMode::TextRenderingMode( const ValueType
& mode
)
1858 Lang::TextRenderingMode::TextRenderingMode( bool fill
, bool stroke
, bool clip
)
1860 switch( ( fill
? 0x01 : 0x00 ) +
1861 ( stroke
? 0x02 : 0x00 ) +
1862 ( clip
? 0x04 : 0x00 ) )
1886 mode_
= FILLSTROKECLIP
;
1889 throw Exceptions::InternalError( "Semi-static switch out of range in TextRenderingMode::TextRenderingMode." );
1893 Lang::TextRenderingMode::ValueType
1894 Lang::TextRenderingMode::clipMode( ValueType mode
)
1905 return FILLSTROKECLIP
;
1911 Lang::TextRenderingMode::~TextRenderingMode( )
1914 RefCountPtr
< const Lang::Class
> Lang::TextRenderingMode::TypeID( new Lang::SystemFinalClass( strrefdup( "TextRenderingMode" ) ) );
1915 TYPEINFOIMPL( TextRenderingMode
);
1918 Lang::CharacterSpacingBinding::CharacterSpacingBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, const Concrete::Length spacing
)
1919 : bindingExpr_( bindingExpr
), spacing_( spacing
), isRelative_( false ), id_( id
)
1922 Lang::CharacterSpacingBinding::CharacterSpacingBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, const double r
)
1923 : bindingExpr_( bindingExpr
), spacing_( r
), isRelative_( true ), id_( id
)
1926 Lang::CharacterSpacingBinding::~CharacterSpacingBinding( )
1930 Lang::CharacterSpacingBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
1932 if( *sysBindings
== 0 )
1934 *sysBindings
= new Kernel::SystemDynamicVariables( );
1935 Kernel::TextState
* newState
= new Kernel::TextState( );
1938 newState
->setCharacterSpacing( Concrete::Length::offtype( spacing_
) );
1942 newState
->setCharacterSpacing( spacing_
);
1944 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1948 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
1950 Kernel::TextState
* newState
= new Kernel::TextState( );
1953 newState
->setCharacterSpacing( Concrete::Length::offtype( spacing_
) );
1957 newState
->setCharacterSpacing( spacing_
);
1959 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1963 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
1965 if( newState
->hasCharacterSpacing( ) )
1967 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
1972 newState
->setCharacterSpacing( Concrete::Length::offtype( spacing_
) );
1976 newState
->setCharacterSpacing( spacing_
);
1978 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
1982 Lang::CharacterSpacingBinding::show( std::ostream
& os
) const
1984 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
1987 os
<< Concrete::Length::offtype( spacing_
) ;
1991 os
<< spacing_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
1996 Lang::CharacterSpacingBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2000 Lang::WordSpacingBinding::WordSpacingBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, const Concrete::Length spacing
)
2001 : bindingExpr_( bindingExpr
), spacing_( spacing
), isRelative_( false ), id_( id
)
2004 Lang::WordSpacingBinding::WordSpacingBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, const double r
)
2005 : bindingExpr_( bindingExpr
), spacing_( r
), isRelative_( true ), id_( id
)
2008 Lang::WordSpacingBinding::~WordSpacingBinding( )
2012 Lang::WordSpacingBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
2014 if( *sysBindings
== 0 )
2016 *sysBindings
= new Kernel::SystemDynamicVariables( );
2017 Kernel::TextState
* newState
= new Kernel::TextState( );
2020 newState
->setWordSpacing( Concrete::Length::offtype( spacing_
) );
2024 newState
->setWordSpacing( spacing_
);
2026 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2030 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
2032 Kernel::TextState
* newState
= new Kernel::TextState( );
2035 newState
->setWordSpacing( Concrete::Length::offtype( spacing_
) );
2039 newState
->setWordSpacing( spacing_
);
2041 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2045 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
2047 if( newState
->hasWordSpacing( ) )
2049 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
2054 newState
->setWordSpacing( Concrete::Length::offtype( spacing_
) );
2058 newState
->setWordSpacing( spacing_
);
2060 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2064 Lang::WordSpacingBinding::show( std::ostream
& os
) const
2066 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
2069 os
<< Concrete::Length::offtype( spacing_
) ;
2073 os
<< spacing_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
2078 Lang::WordSpacingBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2082 Lang::HorizontalScalingBinding::HorizontalScalingBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, double scaling
)
2083 : bindingExpr_( bindingExpr
), scaling_( scaling
), id_( id
)
2086 Lang::HorizontalScalingBinding::~HorizontalScalingBinding( )
2090 Lang::HorizontalScalingBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
2092 if( *sysBindings
== 0 )
2094 *sysBindings
= new Kernel::SystemDynamicVariables( );
2095 Kernel::TextState
* newState
= new Kernel::TextState( );
2096 newState
->horizontalScaling_
= scaling_
;
2097 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2101 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
2103 Kernel::TextState
* newState
= new Kernel::TextState( );
2104 newState
->horizontalScaling_
= scaling_
;
2105 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2109 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
2111 if( ! IS_NAN( newState
->horizontalScaling_
) )
2113 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
2116 newState
->horizontalScaling_
= scaling_
;
2117 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2121 Lang::HorizontalScalingBinding::show( std::ostream
& os
) const
2123 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":"
2128 Lang::HorizontalScalingBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2132 Lang::LeadingBinding::LeadingBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, const Concrete::Length ty
)
2133 : bindingExpr_( bindingExpr
), ty_( ty
), isRelative_( false ), id_( id
)
2136 Lang::LeadingBinding::LeadingBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, const double r
)
2137 : bindingExpr_( bindingExpr
), ty_( r
), isRelative_( true ), id_( id
)
2140 Lang::LeadingBinding::~LeadingBinding( )
2144 Lang::LeadingBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
2146 if( *sysBindings
== 0 )
2148 *sysBindings
= new Kernel::SystemDynamicVariables( );
2149 Kernel::TextState
* newState
= new Kernel::TextState( );
2152 newState
->setLeading( Concrete::Length::offtype( ty_
) );
2156 newState
->setLeading( ty_
);
2158 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2162 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
2164 Kernel::TextState
* newState
= new Kernel::TextState( );
2167 newState
->setLeading( Concrete::Length::offtype( ty_
) );
2171 newState
->setLeading( ty_
);
2173 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2177 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
2179 if( newState
->hasLeading( ) )
2181 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
2186 newState
->setLeading( Concrete::Length::offtype( ty_
) );
2190 newState
->setLeading( ty_
);
2192 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2196 Lang::LeadingBinding::show( std::ostream
& os
) const
2198 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
2201 os
<< Concrete::Length::offtype( ty_
) ;
2205 os
<< ty_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
2210 Lang::LeadingBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2214 Lang::FontBinding::FontBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, const RefCountPtr
< const Lang::Font
> & font
)
2215 : bindingExpr_( bindingExpr
), font_( font
), id_( id
)
2218 Lang::FontBinding::~FontBinding( )
2222 Lang::FontBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
2224 if( *sysBindings
== 0 )
2226 *sysBindings
= new Kernel::SystemDynamicVariables( );
2227 Kernel::TextState
* newState
= new Kernel::TextState( );
2228 newState
->font_
= font_
;
2229 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2233 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
2235 Kernel::TextState
* newState
= new Kernel::TextState( );
2236 newState
->font_
= font_
;
2237 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2241 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
2243 if( newState
->font_
!= NullPtr
< const Lang::Font
>( ) )
2245 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
2248 newState
->font_
= font_
;
2249 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2253 Lang::FontBinding::show( std::ostream
& os
) const
2255 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
2260 Lang::FontBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2262 const_cast< Lang::Font
* >( font_
.getPtr( ) )->gcMark( marked
);
2266 Lang::TextSizeBinding::TextSizeBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, const Concrete::Length size
)
2267 : bindingExpr_( bindingExpr
), size_( size
), id_( id
)
2270 Lang::TextSizeBinding::~TextSizeBinding( )
2274 Lang::TextSizeBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
2276 if( *sysBindings
== 0 )
2278 *sysBindings
= new Kernel::SystemDynamicVariables( );
2279 Kernel::TextState
* newState
= new Kernel::TextState( );
2280 newState
->size_
= size_
;
2281 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2285 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
2287 Kernel::TextState
* newState
= new Kernel::TextState( );
2288 newState
->size_
= size_
;
2289 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2293 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
2295 if( ! IS_NAN( newState
->size_
) )
2297 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
2300 newState
->size_
= size_
;
2301 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2305 Lang::TextSizeBinding::show( std::ostream
& os
) const
2307 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":"
2308 << size_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
2312 Lang::TextSizeBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2316 Lang::TextRenderingModeBinding::TextRenderingModeBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, const Lang::TextRenderingMode::ValueType mode
)
2317 : bindingExpr_( bindingExpr
), mode_( mode
), id_( id
)
2320 Lang::TextRenderingModeBinding::~TextRenderingModeBinding( )
2324 Lang::TextRenderingModeBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
2326 if( *sysBindings
== 0 )
2328 *sysBindings
= new Kernel::SystemDynamicVariables( );
2329 Kernel::TextState
* newState
= new Kernel::TextState( );
2330 newState
->mode_
= mode_
;
2331 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2335 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
2337 Kernel::TextState
* newState
= new Kernel::TextState( );
2338 newState
->mode_
= mode_
;
2339 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2343 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
2345 if( newState
->mode_
!= Lang::TextRenderingMode::UNDEFINED
)
2347 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
2350 newState
->mode_
= mode_
;
2351 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2355 Lang::TextRenderingModeBinding::show( std::ostream
& os
) const
2357 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":"
2358 << "<internal-enum>" ;
2362 Lang::TextRenderingModeBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2366 Lang::TextRiseBinding::TextRiseBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, const Concrete::Length ty
)
2367 : bindingExpr_( bindingExpr
), ty_( ty
), isRelative_( false ), id_( id
)
2370 Lang::TextRiseBinding::TextRiseBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, const double r
)
2371 : bindingExpr_( bindingExpr
), ty_( r
), isRelative_( true ), id_( id
)
2374 Lang::TextRiseBinding::~TextRiseBinding( )
2378 Lang::TextRiseBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
2380 if( *sysBindings
== 0 )
2382 *sysBindings
= new Kernel::SystemDynamicVariables( );
2383 Kernel::TextState
* newState
= new Kernel::TextState( );
2386 newState
->setRise( Concrete::Length::offtype( ty_
) );
2390 newState
->setRise( ty_
);
2392 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2396 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
2398 Kernel::TextState
* newState
= new Kernel::TextState( );
2401 newState
->setRise( Concrete::Length::offtype( ty_
) );
2405 newState
->setRise( ty_
);
2407 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2411 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
2413 if( newState
->hasRise( ) )
2415 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
2420 newState
->setRise( Concrete::Length::offtype( ty_
) );
2424 newState
->setRise( ty_
);
2426 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2430 Lang::TextRiseBinding::show( std::ostream
& os
) const
2432 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":" ;
2435 os
<< Concrete::Length::offtype( ty_
) ;
2439 os
<< ty_
/ Interaction::displayUnit
<< Interaction::displayUnitName
;
2444 Lang::TextRiseBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2448 Lang::TextKnockoutBinding::TextKnockoutBinding( const Ast::PlacedIdentifier
* id
, const Ast::DynamicBindingExpression
* bindingExpr
, bool knockout
)
2449 : bindingExpr_( bindingExpr
), knockout_( knockout
), id_( id
)
2452 Lang::TextKnockoutBinding::~TextKnockoutBinding( )
2456 Lang::TextKnockoutBinding::bind( MapType
& bindings
, Kernel::SystemDynamicVariables
** sysBindings
) const
2458 if( *sysBindings
== 0 )
2460 *sysBindings
= new Kernel::SystemDynamicVariables( );
2461 Kernel::TextState
* newState
= new Kernel::TextState( );
2462 newState
->knockout_
= knockout_
;
2463 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2467 if( (*sysBindings
)->textState_
== NullPtr
< const Kernel::TextState
>( ) )
2469 Kernel::TextState
* newState
= new Kernel::TextState( );
2470 newState
->knockout_
= knockout_
;
2471 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2475 Kernel::TextState
* newState
= new Kernel::TextState( *((*sysBindings
)->textState_
) );
2477 if( ( newState
->knockout_
& Kernel::TextState::KNOCKOUT_UNDEFINED_BIT
) != 0 )
2479 throw Exceptions::MultipleDynamicBind( id_
, bindingExpr_
->idLoc( ), Ast::THE_UNKNOWN_LOCATION
);
2482 newState
->knockout_
= ( knockout_
? Kernel::TextState::KNOCKOUT_FLAG_BIT
: 0 );
2483 (*sysBindings
)->textState_
= RefCountPtr
< const Kernel::TextState
>( newState
);
2487 Lang::TextKnockoutBinding::show( std::ostream
& os
) const
2489 os
<< Interaction::DYNAMIC_VARIABLE_PREFIX
<< id_
<< ":"
2490 << ( knockout_
? "true" : "false" ) ;
2494 Lang::TextKnockoutBinding::gcMark( Kernel::GCMarkedSet
& marked
)
2498 Kernel::CharacterSpacingDynamicVariableProperties::CharacterSpacingDynamicVariableProperties( const Ast::PlacedIdentifier
* id
)
2499 : Kernel::DynamicVariableProperties( id
)
2502 Kernel::CharacterSpacingDynamicVariableProperties::~CharacterSpacingDynamicVariableProperties( )
2505 Kernel::VariableHandle
2506 Kernel::CharacterSpacingDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2508 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2509 return Kernel::VariableHandle( new Kernel::Variable( textState
->characterSpacing( ) ) );
2513 Kernel::CharacterSpacingDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2515 RefCountPtr
< const Lang::Value
> valUntyped
= val
->getUntyped( );
2517 Kernel::ContRef cont
= evalState
->cont_
;
2521 typedef const Lang::Length ArgType
;
2522 RefCountPtr
< ArgType
> spacing
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2523 cont
->takeValue( Kernel::ValueRef( new Lang::CharacterSpacingBinding( id_
, bindingExpr
, spacing
->get( ) ) ),
2527 catch( const NonLocalExit::NotThisType
& ball
)
2529 /* Wrong type; never mind!.. but see below!
2535 typedef const Lang::Float ArgType
;
2536 RefCountPtr
< ArgType
> spacing
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2537 cont
->takeValue( Kernel::ValueRef( new Lang::CharacterSpacingBinding( id_
, bindingExpr
, spacing
->val_
) ),
2541 catch( const NonLocalExit::NotThisType
& ball
)
2543 /* Wrong type; never mind!.. but see below!
2547 throw Exceptions::TypeMismatch( bindingExpr
->exprLoc( ), valUntyped
->getTypeName( ), Helpers::typeSetString( Lang::Length::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
2551 Kernel::WordSpacingDynamicVariableProperties::WordSpacingDynamicVariableProperties( const Ast::PlacedIdentifier
* id
)
2552 : Kernel::DynamicVariableProperties( id
)
2555 Kernel::WordSpacingDynamicVariableProperties::~WordSpacingDynamicVariableProperties( )
2558 Kernel::VariableHandle
2559 Kernel::WordSpacingDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2561 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2562 return Kernel::VariableHandle( new Kernel::Variable( textState
->wordSpacing( ) ) );
2566 Kernel::WordSpacingDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2568 RefCountPtr
< const Lang::Value
> valUntyped
= val
->getUntyped( );
2570 Kernel::ContRef cont
= evalState
->cont_
;
2574 typedef const Lang::Length ArgType
;
2575 RefCountPtr
< ArgType
> spacing
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2576 cont
->takeValue( Kernel::ValueRef( new Lang::WordSpacingBinding( id_
, bindingExpr
, spacing
->get( ) ) ),
2580 catch( const NonLocalExit::NotThisType
& ball
)
2582 /* Wrong type; never mind!.. but see below!
2588 typedef const Lang::Float ArgType
;
2589 RefCountPtr
< ArgType
> spacing
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2590 cont
->takeValue( Kernel::ValueRef( new Lang::WordSpacingBinding( id_
, bindingExpr
, spacing
->val_
) ),
2594 catch( const NonLocalExit::NotThisType
& ball
)
2596 /* Wrong type; never mind!.. but see below!
2600 throw Exceptions::TypeMismatch( bindingExpr
->exprLoc( ), valUntyped
->getTypeName( ), Helpers::typeSetString( Lang::Length::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
2604 Kernel::HorizontalScalingDynamicVariableProperties::HorizontalScalingDynamicVariableProperties( const Ast::PlacedIdentifier
* id
)
2605 : Kernel::DynamicVariableProperties( id
)
2608 Kernel::HorizontalScalingDynamicVariableProperties::~HorizontalScalingDynamicVariableProperties( )
2611 Kernel::VariableHandle
2612 Kernel::HorizontalScalingDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2614 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2615 return Kernel::VariableHandle( Shapes::Helpers::newValHandle( new Lang::Float( textState
->horizontalScaling_
) ) );
2619 Kernel::HorizontalScalingDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2621 RefCountPtr
< const Lang::Float
> scaling
= val
->getVal
< const Lang::Float
>( bindingExpr
->exprLoc( ) );
2622 Kernel::ContRef cont
= evalState
->cont_
;
2623 cont
->takeValue( Kernel::ValueRef( new Lang::HorizontalScalingBinding( id_
, bindingExpr
, scaling
->val_
) ),
2628 Kernel::LeadingDynamicVariableProperties::LeadingDynamicVariableProperties( const Ast::PlacedIdentifier
* id
)
2629 : Kernel::DynamicVariableProperties( id
)
2632 Kernel::LeadingDynamicVariableProperties::~LeadingDynamicVariableProperties( )
2635 Kernel::VariableHandle
2636 Kernel::LeadingDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2638 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2639 return Kernel::VariableHandle( new Kernel::Variable( textState
->leading( ) ) );
2643 Kernel::LeadingDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2645 RefCountPtr
< const Lang::Value
> valUntyped
= val
->getUntyped( );
2647 Kernel::ContRef cont
= evalState
->cont_
;
2651 typedef const Lang::Length ArgType
;
2652 RefCountPtr
< ArgType
> ty
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2653 cont
->takeValue( Kernel::ValueRef( new Lang::LeadingBinding( id_
, bindingExpr
, ty
->get( ) ) ),
2657 catch( const NonLocalExit::NotThisType
& ball
)
2659 /* Wrong type; never mind!.. but see below!
2665 typedef const Lang::Float ArgType
;
2666 RefCountPtr
< ArgType
> ty
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2667 cont
->takeValue( Kernel::ValueRef( new Lang::LeadingBinding( id_
, bindingExpr
, ty
->val_
) ),
2671 catch( const NonLocalExit::NotThisType
& ball
)
2673 /* Wrong type; never mind!.. but see below!
2677 throw Exceptions::TypeMismatch( bindingExpr
->exprLoc( ), valUntyped
->getTypeName( ), Helpers::typeSetString( Lang::Length::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
2681 Kernel::FontDynamicVariableProperties::FontDynamicVariableProperties( const Ast::PlacedIdentifier
* id
)
2682 : Kernel::DynamicVariableProperties( id
)
2685 Kernel::FontDynamicVariableProperties::~FontDynamicVariableProperties( )
2688 Kernel::VariableHandle
2689 Kernel::FontDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2691 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2692 return Kernel::VariableHandle( new Kernel::Variable( textState
->font_
) );
2696 Kernel::FontDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2698 Kernel::ContRef cont
= evalState
->cont_
;
2699 cont
->takeValue( Kernel::ValueRef( new Lang::FontBinding( id_
, bindingExpr
, val
->getVal
< const Lang::Font
>( bindingExpr
->exprLoc( ) ) ) ),
2704 Kernel::TextSizeDynamicVariableProperties::TextSizeDynamicVariableProperties( const Ast::PlacedIdentifier
* id
)
2705 : Kernel::DynamicVariableProperties( id
)
2708 Kernel::TextSizeDynamicVariableProperties::~TextSizeDynamicVariableProperties( )
2711 Kernel::VariableHandle
2712 Kernel::TextSizeDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2714 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2715 return Kernel::VariableHandle( Shapes::Helpers::newValHandle( new Lang::Length( textState
->size_
) ) );
2719 Kernel::TextSizeDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2721 RefCountPtr
< const Lang::Length
> size
= val
->getVal
< const Lang::Length
>( bindingExpr
->exprLoc( ) );
2722 Kernel::ContRef cont
= evalState
->cont_
;
2723 cont
->takeValue( Kernel::ValueRef( new Lang::TextSizeBinding( id_
, bindingExpr
, size
->get( ) ) ),
2728 Kernel::TextRenderingModeDynamicVariableProperties::TextRenderingModeDynamicVariableProperties( const Ast::PlacedIdentifier
* id
)
2729 : Kernel::DynamicVariableProperties( id
)
2732 Kernel::TextRenderingModeDynamicVariableProperties::~TextRenderingModeDynamicVariableProperties( )
2735 Kernel::VariableHandle
2736 Kernel::TextRenderingModeDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2738 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2739 return Kernel::VariableHandle( Shapes::Helpers::newValHandle( new Lang::TextRenderingMode( textState
->mode_
) ) );
2743 Kernel::TextRenderingModeDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2745 RefCountPtr
< const Lang::TextRenderingMode
> mode
= val
->getVal
< const Lang::TextRenderingMode
>( bindingExpr
->exprLoc( ) );
2746 Kernel::ContRef cont
= evalState
->cont_
;
2747 cont
->takeValue( Kernel::ValueRef( new Lang::TextRenderingModeBinding( id_
, bindingExpr
, mode
->mode_
) ),
2752 Kernel::TextRiseDynamicVariableProperties::TextRiseDynamicVariableProperties( const Ast::PlacedIdentifier
* id
)
2753 : Kernel::DynamicVariableProperties( id
)
2756 Kernel::TextRiseDynamicVariableProperties::~TextRiseDynamicVariableProperties( )
2759 Kernel::VariableHandle
2760 Kernel::TextRiseDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2762 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2763 return Kernel::VariableHandle( new Kernel::Variable( textState
->rise( ) ) );
2767 Kernel::TextRiseDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2769 RefCountPtr
< const Lang::Value
> valUntyped
= val
->getUntyped( );
2771 Kernel::ContRef cont
= evalState
->cont_
;
2775 typedef const Lang::Length ArgType
;
2776 RefCountPtr
< ArgType
> ty
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2777 cont
->takeValue( Kernel::ValueRef( new Lang::TextRiseBinding( id_
, bindingExpr
, ty
->get( ) ) ),
2781 catch( const NonLocalExit::NotThisType
& ball
)
2783 /* Wrong type; never mind!.. but see below!
2789 typedef const Lang::Float ArgType
;
2790 RefCountPtr
< ArgType
> ty
= Helpers::try_cast_CoreArgument
< ArgType
>( valUntyped
);
2791 cont
->takeValue( Kernel::ValueRef( new Lang::TextRiseBinding( id_
, bindingExpr
, ty
->val_
) ),
2795 catch( const NonLocalExit::NotThisType
& ball
)
2797 /* Wrong type; never mind!.. but see below!
2801 throw Exceptions::TypeMismatch( bindingExpr
->exprLoc( ), valUntyped
->getTypeName( ), Helpers::typeSetString( Lang::Length::staticTypeName( ), Lang::Float::staticTypeName( ) ) );
2805 Kernel::TextKnockoutDynamicVariableProperties::TextKnockoutDynamicVariableProperties( const Ast::PlacedIdentifier
* id
)
2806 : Kernel::DynamicVariableProperties( id
)
2809 Kernel::TextKnockoutDynamicVariableProperties::~TextKnockoutDynamicVariableProperties( )
2812 Kernel::VariableHandle
2813 Kernel::TextKnockoutDynamicVariableProperties::fetch( const Kernel::PassedDyn
& dyn
) const
2815 RefCountPtr
< const Kernel::TextState
> textState
= dyn
->getTextState( );
2816 return Kernel::VariableHandle( Shapes::Helpers::newValHandle( new Lang::Boolean( ( textState
->knockout_
& Kernel::TextState::KNOCKOUT_FLAG_BIT
) != 0 ) ) );
2820 Kernel::TextKnockoutDynamicVariableProperties::makeBinding( Kernel::VariableHandle val
, const Ast::DynamicBindingExpression
* bindingExpr
, Kernel::EvalState
* evalState
) const
2822 RefCountPtr
< const Lang::Boolean
> mode
= val
->getVal
< const Lang::Boolean
>( bindingExpr
->exprLoc( ) );
2823 Kernel::ContRef cont
= evalState
->cont_
;
2824 cont
->takeValue( Kernel::ValueRef( new Lang::TextKnockoutBinding( id_
, bindingExpr
, mode
->val_
) ),
2830 Kernel::TextState::TextState( )
2831 : relativeFlags_( 0 ),
2832 characterSpacing_( Concrete::Length( std::numeric_limits
< double >::signaling_NaN( ) ) ),
2833 wordSpacing_( Concrete::Length( std::numeric_limits
< double >::signaling_NaN( ) ) ),
2834 horizontalScaling_( std::numeric_limits
< double >::signaling_NaN( ) ),
2835 leading_( Concrete::Length( std::numeric_limits
< double >::signaling_NaN( ) ) ),
2836 rise_( Concrete::Length( std::numeric_limits
< double >::signaling_NaN( ) ) ),
2837 font_( NullPtr
< const Lang::Font
>( ) ),
2838 size_( Concrete::Length( std::numeric_limits
< double >::signaling_NaN( ) ) ),
2839 mode_( Lang::TextRenderingMode::UNDEFINED
),
2840 knockout_( KNOCKOUT_UNDEFINED_BIT
)
2843 Kernel::TextState::TextState( const Kernel::TextState
& orig
)
2844 : relativeFlags_( orig
.relativeFlags_
),
2845 characterSpacing_( orig
.characterSpacing_
),
2846 wordSpacing_( orig
.wordSpacing_
),
2847 horizontalScaling_( orig
.horizontalScaling_
),
2848 leading_( orig
.leading_
),
2849 rise_( orig
.rise_
),
2850 font_( orig
.font_
),
2851 size_( orig
.size_
),
2852 mode_( orig
.mode_
),
2853 knockout_( orig
.knockout_
)
2856 Kernel::TextState::TextState( const Kernel::TextState
& newValues
, const Kernel::TextState
& oldValues
)
2857 : relativeFlags_( oldValues
.relativeFlags_
),
2858 characterSpacing_( oldValues
.characterSpacing_
),
2859 wordSpacing_( oldValues
.wordSpacing_
),
2860 horizontalScaling_( oldValues
.horizontalScaling_
),
2861 leading_( oldValues
.leading_
),
2862 rise_( oldValues
.rise_
),
2863 font_( oldValues
.font_
),
2864 size_( oldValues
.size_
),
2865 mode_( oldValues
.mode_
),
2866 knockout_( oldValues
.knockout_
)
2868 if( newValues
.hasCharacterSpacing( ) )
2870 characterSpacing_
= newValues
.characterSpacing_
;
2871 relativeFlags_
= ( newValues
.characterSpacingIsRelative( ) ? ( relativeFlags_
| RELATIVE_CHARACTER_SPACING
) : ( relativeFlags_
& ~RELATIVE_CHARACTER_SPACING
) );
2873 if( newValues
.hasWordSpacing( ) )
2875 wordSpacing_
= newValues
.wordSpacing_
;
2876 relativeFlags_
= ( newValues
.wordSpacingIsRelative( ) ? ( relativeFlags_
| RELATIVE_WORD_SPACING
) : ( relativeFlags_
& ~RELATIVE_WORD_SPACING
) );
2878 if( ! IS_NAN( newValues
.horizontalScaling_
) )
2880 horizontalScaling_
= newValues
.horizontalScaling_
;
2882 if( newValues
.hasLeading( ) )
2884 leading_
= newValues
.leading_
;
2885 relativeFlags_
= ( newValues
.leadingIsRelative( ) ? ( relativeFlags_
| RELATIVE_LEADING
) : ( relativeFlags_
& ~RELATIVE_LEADING
) );
2887 if( newValues
.hasRise( ) )
2889 rise_
= newValues
.rise_
;
2890 relativeFlags_
= ( newValues
.riseIsRelative( ) ? ( relativeFlags_
| RELATIVE_RISE
) : ( relativeFlags_
& ~RELATIVE_RISE
) );
2892 if( newValues
.font_
!= NullPtr
< const Lang::Font
>( ) )
2894 font_
= newValues
.font_
;
2896 if( ! IS_NAN( newValues
.size_
) )
2898 size_
= newValues
.size_
;
2900 if( newValues
.mode_
!= Lang::TextRenderingMode::UNDEFINED
)
2902 mode_
= newValues
.mode_
;
2904 if( ! ( newValues
.knockout_
& KNOCKOUT_UNDEFINED_BIT
) )
2906 knockout_
= newValues
.knockout_
;
2910 std::map
< bool, RefCountPtr
< SimplePDF::PDF_Object
> > Kernel::TextState::knockoutNameMap_
;
2912 Kernel::TextState::TextState( bool setDefaults
)
2913 : relativeFlags_( RELATIVE_LEADING
),
2914 characterSpacing_( 0 ),
2916 horizontalScaling_( 1 ),
2919 font_( Lang::THE_FONT_HELVETICA
),
2920 size_( Concrete::Length( 10 ) ),
2921 mode_( Lang::TextRenderingMode::FILL
),
2922 knockout_( KNOCKOUT_FLAG_BIT
) // this means true
2926 throw Exceptions::InternalError( strrefdup( "setDefaults must be true in TextState::TextState." ) );
2930 Kernel::TextState::~TextState( )
2934 Kernel::TextState::print( std::ostream
& os
, const std::string
& indentation
) const
2936 if( font_
!= NullPtr
< const Lang::Font
>( ) )
2939 Lang::DYNAMIC_VARIABLE_ID_TEXT_FONT
.show( os
, Ast::Identifier::DYNAMIC_VARIABLE
);
2940 os
<< ": " << font_
->fontName( ) << std::endl
;
2942 if( ! IS_NAN( size_
) )
2945 Lang::DYNAMIC_VARIABLE_ID_TEXT_SIZE
.show( os
, Ast::Identifier::DYNAMIC_VARIABLE
);
2946 os
<< ": " << size_
/ Interaction::displayUnit
<< Interaction::displayUnitName
<< std::endl
;
2948 os
<< "(and a bunch of other variables...)" << std::endl
;
2953 Kernel::TextState::setLeading( const Concrete::Length leading
)
2955 relativeFlags_
&= ~ RELATIVE_LEADING
;
2960 Kernel::TextState::setLeading( const double relativeLeading
)
2962 relativeFlags_
|= RELATIVE_LEADING
;
2963 leading_
= Concrete::Length( relativeLeading
); /* We must keep track of this type trick by always looking at relativeFlags_ & RELATIVE_LEADING. */
2966 RefCountPtr
< const Lang::Value
>
2967 Kernel::TextState::leading( ) const
2969 if( leadingIsRelative( ) )
2971 return RefCountPtr
< const Lang::Value
>( new Lang::Float( Concrete::Length::offtype( leading_
) ) );
2973 return RefCountPtr
< const Lang::Value
>( new Lang::Length( leading_
) );
2977 Kernel::TextState::leadingConcrete( ) const
2979 if( leadingIsRelative( ) )
2981 return Concrete::Length::offtype( leading_
) * size_
;
2987 Kernel::TextState::hasLeading( ) const
2989 return ! IS_NAN( leading_
);
2993 Kernel::TextState::leadingIsRelative( ) const
2995 return ( relativeFlags_
& RELATIVE_LEADING
) != 0;
3000 Kernel::TextState::setRise( const Concrete::Length rise
)
3002 relativeFlags_
&= ~ RELATIVE_RISE
;
3007 Kernel::TextState::setRise( const double relativeRise
)
3009 relativeFlags_
|= RELATIVE_RISE
;
3010 rise_
= Concrete::Length( relativeRise
); // We must keep track of this type trick by always looking at relativeFlags_ & RELATIVE_RISE.
3013 RefCountPtr
< const Lang::Value
>
3014 Kernel::TextState::rise( ) const
3016 if( riseIsRelative( ) )
3018 return RefCountPtr
< const Lang::Value
>( new Lang::Float( Concrete::Length::offtype( rise_
) ) );
3020 return RefCountPtr
< const Lang::Value
>( new Lang::Length( rise_
) );
3024 Kernel::TextState::riseConcrete( ) const
3026 if( riseIsRelative( ) )
3028 return Concrete::Length::offtype( rise_
) * size_
;
3034 Kernel::TextState::hasRise( ) const
3036 return ! IS_NAN( rise_
);
3040 Kernel::TextState::riseIsRelative( ) const
3042 return ( relativeFlags_
& RELATIVE_RISE
) != 0;
3047 Kernel::TextState::setCharacterSpacing( const Concrete::Length spacing
)
3049 relativeFlags_
&= ~ RELATIVE_CHARACTER_SPACING
;
3050 characterSpacing_
= spacing
;
3054 Kernel::TextState::setCharacterSpacing( const double relativeSpacing
)
3056 relativeFlags_
|= RELATIVE_CHARACTER_SPACING
;
3057 characterSpacing_
= Concrete::Length( relativeSpacing
); // We must keep track of this type trick by always looking at the relevant bit in relativeFlags_.
3060 RefCountPtr
< const Lang::Value
>
3061 Kernel::TextState::characterSpacing( ) const
3063 if( characterSpacingIsRelative( ) )
3065 return RefCountPtr
< const Lang::Value
>( new Lang::Float( Concrete::Length::offtype( characterSpacing_
) ) );
3067 return RefCountPtr
< const Lang::Value
>( new Lang::Length( characterSpacing_
) );
3071 Kernel::TextState::characterSpacingConcrete( ) const
3073 if( characterSpacingIsRelative( ) )
3075 return Concrete::Length::offtype( characterSpacing_
) * size_
;
3077 return characterSpacing_
;
3081 Kernel::TextState::hasCharacterSpacing( ) const
3083 return ! IS_NAN( characterSpacing_
);
3087 Kernel::TextState::characterSpacingIsRelative( ) const
3089 return ( relativeFlags_
& RELATIVE_CHARACTER_SPACING
) != 0;
3094 Kernel::TextState::setWordSpacing( const Concrete::Length spacing
)
3096 relativeFlags_
&= ~ RELATIVE_WORD_SPACING
;
3097 wordSpacing_
= spacing
;
3101 Kernel::TextState::setWordSpacing( const double relativeSpacing
)
3103 relativeFlags_
|= RELATIVE_WORD_SPACING
;
3104 wordSpacing_
= Concrete::Length( relativeSpacing
); // We must keep track of this type trick by always looking at the relevant bit in relativeFlags_.
3107 RefCountPtr
< const Lang::Value
>
3108 Kernel::TextState::wordSpacing( ) const
3110 if( wordSpacingIsRelative( ) )
3112 return RefCountPtr
< const Lang::Value
>( new Lang::Float( Concrete::Length::offtype( wordSpacing_
) ) );
3114 return RefCountPtr
< const Lang::Value
>( new Lang::Length( wordSpacing_
) );
3118 Kernel::TextState::wordSpacingConcrete( ) const
3120 if( wordSpacingIsRelative( ) )
3122 return Concrete::Length::offtype( wordSpacing_
) * size_
;
3124 return wordSpacing_
;
3128 Kernel::TextState::hasWordSpacing( ) const
3130 return ! IS_NAN( wordSpacing_
);
3134 Kernel::TextState::wordSpacingIsRelative( ) const
3136 return ( relativeFlags_
& RELATIVE_WORD_SPACING
) != 0;
3141 Kernel::TextState::synchAssertKnockout( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool clip
, bool force
)
3143 assertKnockout( ref
);
3144 return synchButKnockout( os
, ref
, resources
, clip
, force
);
3148 Kernel::TextState::synchCharacterSpacing( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
3151 characterSpacing_
!= ref
->characterSpacing_
||
3152 characterSpacingIsRelative( ) != ref
->characterSpacingIsRelative( ) )
3154 if( ! ref
->hasCharacterSpacing( ) )
3158 relativeFlags_
= ( ref
->characterSpacingIsRelative( ) ? ( relativeFlags_
| RELATIVE_CHARACTER_SPACING
) : ( relativeFlags_
& ~RELATIVE_CHARACTER_SPACING
) );
3159 characterSpacing_
= ref
->characterSpacing_
;
3160 if( characterSpacingIsRelative( ) )
3162 os
<< Concrete::Length::offtype( characterSpacing_
) * Concrete::Length::offtype( ref
->size_
) << " Tc " ;
3166 os
<< Concrete::Length::offtype( characterSpacing_
) << " Tc " ;
3174 Kernel::TextState::synchWordSpacing( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
3177 wordSpacing_
!= ref
->wordSpacing_
||
3178 wordSpacingIsRelative( ) != ref
->wordSpacingIsRelative( ) )
3180 if( ! ref
->hasWordSpacing( ) )
3184 relativeFlags_
= ( ref
->wordSpacingIsRelative( ) ? ( relativeFlags_
| RELATIVE_WORD_SPACING
) : ( relativeFlags_
& ~RELATIVE_WORD_SPACING
) );
3185 wordSpacing_
= ref
->wordSpacing_
;
3186 if( wordSpacingIsRelative( ) )
3188 os
<< Concrete::Length::offtype( wordSpacing_
) * Concrete::Length::offtype( ref
->size_
) << " Tw " ;
3192 os
<< Concrete::Length::offtype( wordSpacing_
) << " Tw " ;
3200 Kernel::TextState::synchHorizontalScaling( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
3202 if( force
|| horizontalScaling_
!= ref
->horizontalScaling_
)
3204 if( IS_NAN( ref
->horizontalScaling_
) )
3208 horizontalScaling_
= ref
->horizontalScaling_
;
3209 os
<< 100 * horizontalScaling_
<< " Tz " ;
3216 Kernel::TextState::synchLeading( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
3219 leading_
!= ref
->leading_
||
3220 leadingIsRelative( ) != ref
->leadingIsRelative( ) )
3222 if( ! ref
->hasLeading( ) )
3226 relativeFlags_
= ( ref
->leadingIsRelative( ) ? ( relativeFlags_
| RELATIVE_LEADING
) : ( relativeFlags_
& ~RELATIVE_LEADING
) );
3227 leading_
= ref
->leading_
;
3228 if( leadingIsRelative( ) )
3230 os
<< Concrete::Length::offtype( leading_
) * Concrete::Length::offtype( ref
->size_
) << " TL " ;
3234 os
<< Concrete::Length::offtype( leading_
) << " TL " ;
3242 Kernel::TextState::synchFontAndSize( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
3245 font_
!= ref
->font_
||
3246 size_
!= ref
->size_
)
3248 if( ref
->font_
== NullPtr
< const Lang::Font
>( ) &&
3249 IS_NAN( ref
->size_
) )
3253 if( ref
->font_
== NullPtr
< const Lang::Font
>( ) ||
3254 IS_NAN( ref
->size_
) )
3256 throw Exceptions::MiscellaneousRequirement( "It is impossible to leave unspecified only one of font and size." );
3258 bool sizeChanged
= ( size_
!= ref
->size_
);
3261 os
<< resources
->nameofFont( font_
->resource( ) ) << " " << Concrete::Length::offtype( size_
) << " Tf " ;
3264 if( ref
->hasLeading( ) && ref
->leadingIsRelative( ) )
3266 synchLeading( os
, ref
, resources
, true );
3268 if( ref
->hasRise( ) && ref
->riseIsRelative( ) )
3270 synchRise( os
, ref
, resources
, true );
3272 if( ref
->hasCharacterSpacing( ) && ref
->characterSpacingIsRelative( ) )
3274 synchCharacterSpacing( os
, ref
, resources
, true );
3276 if( ref
->hasWordSpacing( ) && ref
->wordSpacingIsRelative( ) )
3278 synchWordSpacing( os
, ref
, resources
, true );
3287 Kernel::TextState::synchMode( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool clip
, bool force
)
3289 Lang::TextRenderingMode::ValueType refMode
= clip
? Lang::TextRenderingMode::clipMode( ref
->mode_
) : ref
->mode_
;
3290 if( force
|| mode_
!= refMode
)
3292 if( ref
->mode_
== Lang::TextRenderingMode::UNDEFINED
)
3297 os
<< mode_
<< " Tr " ;
3304 Kernel::TextState::synchRise( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
3307 rise_
!= ref
->rise_
||
3308 riseIsRelative( ) != ref
->riseIsRelative( ) )
3310 if( ! ref
->hasRise( ) )
3314 relativeFlags_
= ( ref
->riseIsRelative( ) ? ( relativeFlags_
| RELATIVE_RISE
) : ( relativeFlags_
& ~RELATIVE_RISE
) );
3316 if( riseIsRelative( ) )
3318 os
<< Concrete::Length::offtype( rise_
) * Concrete::Length::offtype( ref
->size_
) << " Ts " ;
3322 os
<< Concrete::Length::offtype( rise_
) << " Ts " ;
3330 Kernel::TextState::synchKnockout( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool force
)
3332 if( force
|| knockout_
!= ref
->knockout_
)
3334 if( ( ref
->knockout_
& Kernel::TextState::KNOCKOUT_UNDEFINED_BIT
) != 0 )
3338 const SimplePDF::PDF_Version::Version KNOCKOUT_VERSION
= SimplePDF::PDF_Version::PDF_1_4
;
3339 if( ! Kernel::the_PDF_version
.greaterOrEqual( KNOCKOUT_VERSION
) )
3341 Kernel::the_PDF_version
.message( KNOCKOUT_VERSION
, "The text state knockout mode setting was ignored." );
3343 knockout_
= ref
->knockout_
;
3344 typedef typeof knockoutNameMap_ MapType
;
3345 MapType::const_iterator i
= knockoutNameMap_
.find( knockout_
);
3346 if( i
!= knockoutNameMap_
.end( ) )
3348 os
<< resources
->nameofGraphicsState( i
->second
) << " gs " ;
3352 RefCountPtr
< SimplePDF::PDF_Dictionary
> dic
;
3353 (*dic
)[ "Type" ] = SimplePDF::newName( "ExtGState" );
3354 (*dic
)[ "TK" ] = SimplePDF::newBoolean( knockout_
);
3356 RefCountPtr
< SimplePDF::PDF_Object
> indirection
= SimplePDF::indirect( dic
, & Kernel::theIndirectObjectCount
);
3357 knockoutNameMap_
.insert( MapType::value_type( knockout_
, indirection
) );
3359 os
<< resources
->nameofGraphicsState( indirection
) << " gs " ;
3367 Kernel::TextState::assertKnockout( const Kernel::TextState
* ref
)
3369 if( knockout_
!= ref
->knockout_
)
3371 throw Exceptions::MiscellaneousRequirement( "PDF does not allow the text knockout mode to change within a text object." );
3376 Kernel::TextState::synchButKnockout( std::ostream
& os
, const Kernel::TextState
* ref
, SimplePDF::PDF_Resources
* resources
, bool clip
, bool force
)
3378 bool anyChange
= false;
3379 anyChange
= synchCharacterSpacing( os
, ref
, resources
, force
) || anyChange
;
3380 anyChange
= synchWordSpacing( os
, ref
, resources
, force
) || anyChange
;
3381 anyChange
= synchHorizontalScaling( os
, ref
, resources
, force
) || anyChange
;
3382 anyChange
= synchFontAndSize( os
, ref
, resources
, force
) || anyChange
;
3383 anyChange
= synchLeading( os
, ref
, resources
, force
) || anyChange
; // It is important that this is done after synching the size!
3384 anyChange
= synchMode( os
, ref
, resources
, clip
, force
) || anyChange
;
3385 anyChange
= synchRise( os
, ref
, resources
, force
) || anyChange
;
3394 Lang::FontMethod_glyph::FontMethod_glyph( RefCountPtr
< const Lang::Font
> self
, const Ast::FileID
* fullMethodID
)
3395 : Lang::MethodBase
< class_type
>( self
, fullMethodID
, false, true )
3397 formals_
->appendEvaluatedCoreFormal( "char", Kernel::THE_SLOT_VARIABLE
);
3400 Lang::FontMethod_glyph::~FontMethod_glyph( )
3404 Lang::FontMethod_glyph::call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
3406 args
.applyDefaults( callLoc
);
3409 typedef const Lang::Character ArgType
;
3411 Kernel::ContRef cont
= evalState
->cont_
;
3412 cont
->takeValue( self_
->getGlyph( Helpers::down_cast_CoreArgument
< ArgType
>( coreLoc_
, args
, argsi
, callLoc
)->val_
,
3413 evalState
->dyn_
->getTextState( )->size_
),