1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008 Henrik Tidefelt
19 #include "Shapes_Helpers_decls.h"
21 #include "multipage.h"
22 #include "annotations.h"
23 #include "pdfstructure.h"
24 #include "classtypes.h"
25 #include "pagecontentstates.h"
26 #include "continuations.h"
28 #include "shapesexceptions.h"
29 #include "shapescore.h"
34 using namespace Shapes
;
36 Lang::DocumentDestination::DocumentDestination( bool remote
, RefCountPtr
< const char > name
, int outlineLevel
,
37 RefCountPtr
< const char > outlineText
, bool outlineOpen
, bool outlineFontBold
, bool outlineFontItalic
, const Concrete::RGB
& outlineColor
)
38 : remote_( remote
), name_( name
), outlineLevel_( outlineLevel
),
39 outlineText_( outlineText
), outlineOpen_( outlineOpen
), outlineFontBold_ ( outlineFontBold
), outlineFontItalic_( outlineFontItalic
), outlineColor_( outlineColor
),
40 target_( NullPtr
< const Lang::Drawable2D
>( ) )
44 throw Exceptions::InternalError( "The constructor of DocumentDestination requires <remote> to be true." );
46 if( name_
== NullPtr
< const char >( ) )
48 throw Exceptions::InternalError( "The constructor remote DocumentDestination requires <name> to be non-null." );
52 Lang::DocumentDestination::DocumentDestination( RefCountPtr
< const char > name
, int outlineLevel
,
53 RefCountPtr
< const char > outlineText
, bool outlineOpen
, bool outlineFontBold
, bool outlineFontItalic
, const Concrete::RGB
& outlineColor
,
54 Sides sidesMode
, RefCountPtr
< const Lang::Drawable2D
> target
, bool fittobbox
, double zoom
)
55 : remote_( false ), name_( name
), outlineLevel_( outlineLevel
),
56 outlineText_( outlineText
), outlineOpen_( outlineOpen
), outlineFontBold_ ( outlineFontBold
), outlineFontItalic_( outlineFontItalic
), outlineColor_( outlineColor
),
57 sidesMode_( sidesMode
), target_( target
), fittobbox_( fittobbox
), zoom_( zoom
)
60 Lang::DocumentDestination::~DocumentDestination( )
64 RefCountPtr
< const Lang::Class
> Lang::DocumentDestination::TypeID( new Lang::SystemFinalClass( strrefdup( "Destination" ) ) );
65 TYPEINFOIMPL( DocumentDestination
);
67 RefCountPtr
< const Lang::Geometric2D
>
68 Lang::DocumentDestination::transformed( const Lang::Transform2D
& transform
, const RefCountPtr
< const Lang::Geometric2D
> & self
) const
75 if( target_
== NullPtr
< const Lang::Drawable2D
>( ) )
81 RefCountPtr
< const Lang::Geometric2D
>
82 ( new Lang::DocumentDestination( name_
, outlineLevel_
,
83 outlineText_
, outlineOpen_
, outlineFontBold_
, outlineFontItalic_
, outlineColor_
,
84 sidesMode_
, target_
->typed_transformed( transform
, target_
), fittobbox_
, zoom_
) );
87 RefCountPtr
< const Lang::Geometric3D
>
88 Lang::DocumentDestination::to3D( const RefCountPtr
< const Lang::Geometric2D
> & self
) const
90 throw Exceptions::NotImplemented( "Destinations in 3D." );
95 Lang::DocumentDestination::gcMark( Kernel::GCMarkedSet
& marked
)
97 if( target_
!= NullPtr
< const Lang::Drawable2D
>( ) )
99 const_cast< Lang::Drawable2D
* >( target_
.getPtr( ) )->gcMark( marked
);
104 Lang::DocumentDestination::definesNamed( ) const
106 return ! remote_
&& name_
!= NullPtr
< const char >( );
109 RefCountPtr
< const char >
110 Lang::DocumentDestination::name( ) const
116 Lang::DocumentDestination::isOutlineEntry( ) const
118 return outlineLevel_
>= 0;
122 Lang::DocumentDestination::outlineLevel( ) const
124 return static_cast< size_t >( outlineLevel_
);
127 RefCountPtr
< SimplePDF::PDF_Vector
>
128 Lang::DocumentDestination::getDirectDestination( const RefCountPtr
< SimplePDF::PDF_Indirect_out
> & i_page
) const
130 RefCountPtr
< SimplePDF::PDF_Vector
> res( new SimplePDF::PDF_Vector
);
131 res
->vec
.push_back( i_page
);
133 Concrete::Coords2D
llcorner( 0, 0 );
134 Concrete::Coords2D
urcorner( 0, 0 );
135 if( target_
!= NullPtr
< const Lang::Drawable2D
>( ) )
137 RefCountPtr
< const Lang::ElementaryPath2D
> theBBox
= target_
->bbox( Lang::Drawable2D::BOUNDING
);
138 if( theBBox
->empty( ) )
140 throw Exceptions::MiscellaneousRequirement( "The destination target produced an empty bounding box." );
142 theBBox
->boundingRectangle( & llcorner
, & urcorner
);
150 res
->vec
.push_back( SimplePDF::newName( "FitB" ) );
154 res
->vec
.push_back( SimplePDF::newName( "Fit" ) );
160 res
->vec
.push_back( SimplePDF::newName( "XYZ" ) );
161 res
->vec
.push_back( SimplePDF::newFloat( llcorner
.x_
.offtype
< 1, 0 >( ) ) );
162 res
->vec
.push_back( SimplePDF::newFloat( urcorner
.y_
.offtype
< 1, 0 >( ) ) );
163 res
->vec
.push_back( SimplePDF::newFloat( zoom_
) );
170 res
->vec
.push_back( SimplePDF::newName( "FitH" ) );
174 res
->vec
.push_back( SimplePDF::newName( "FitBH" ) );
176 res
->vec
.push_back( SimplePDF::newFloat( urcorner
.y_
.offtype
< 1, 0 >( ) ) );
183 res
->vec
.push_back( SimplePDF::newName( "FitV" ) );
187 res
->vec
.push_back( SimplePDF::newName( "FitBV" ) );
189 res
->vec
.push_back( SimplePDF::newFloat( llcorner
.x_
.offtype
< 1, 0 >( ) ) );
194 res
->vec
.push_back( SimplePDF::newName( "FitR" ) );
195 res
->vec
.push_back( SimplePDF::newFloat( llcorner
.x_
.offtype
< 1, 0 >( ) ) );
196 res
->vec
.push_back( SimplePDF::newFloat( llcorner
.y_
.offtype
< 1, 0 >( ) ) );
197 res
->vec
.push_back( SimplePDF::newFloat( urcorner
.x_
.offtype
< 1, 0 >( ) ) );
198 res
->vec
.push_back( SimplePDF::newFloat( urcorner
.y_
.offtype
< 1, 0 >( ) ) );
202 throw Exceptions::InternalError( "Destination's sidesMode_ out of range in getDestination." );
208 RefCountPtr
< SimplePDF::PDF_Object
>
209 Lang::DocumentDestination::getDestination( const RefCountPtr
< SimplePDF::PDF_Indirect_out
> & i_page
) const
213 return SimplePDF::newString( name_
.getPtr( ) );
215 return getDirectDestination( i_page
);
218 RefCountPtr
< SimplePDF::OutlineItem
>
219 Lang::DocumentDestination::getOutlineItem( const RefCountPtr
< SimplePDF::PDF_Indirect_out
> & i_page
, RefCountPtr
< const char > otherText
) const
221 RefCountPtr
< const char > theText
= otherText
;
222 if( theText
== NullPtr
< const char >( ) )
224 theText
= outlineText_
;
227 if( name_
!= NullPtr
< const char >( ) )
229 return RefCountPtr
< SimplePDF::OutlineItem
>
230 ( new SimplePDF::OutlineItem( SimplePDF::newString( name_
.getPtr( ) ), theText
,
231 outlineOpen_
, outlineFontBold_
, outlineFontItalic_
, outlineColor_
) );
233 return RefCountPtr
< SimplePDF::OutlineItem
>
234 ( new SimplePDF::OutlineItem( getDestination( i_page
), theText
,
235 outlineOpen_
, outlineFontBold_
, outlineFontItalic_
, outlineColor_
) );
238 Kernel::WarmCatalog::BoundingRectangle::BoundingRectangle( )
239 : xmin_( Concrete::HUGE_LENGTH
), ymin_( Concrete::HUGE_LENGTH
),
240 xmax_( -Concrete::HUGE_LENGTH
), ymax_( -Concrete::HUGE_LENGTH
),
241 modified_( true ), pdfVec_( RefCountPtr
< SimplePDF::PDF_Vector
>( NullPtr
< SimplePDF::PDF_Vector
>( ) ) )
245 Kernel::WarmCatalog::BoundingRectangle::growToContain( const Concrete::Coords2D
& ll
, const Concrete::Coords2D
& ur
)
247 xmin_
= std::min( xmin_
, ll
.x_
);
248 ymin_
= std::min( ymin_
, ll
.y_
);
249 xmax_
= std::max( xmax_
, ur
.x_
);
250 ymax_
= std::max( ymax_
, ur
.y_
);
254 RefCountPtr
< SimplePDF::PDF_Vector
>
255 Kernel::WarmCatalog::BoundingRectangle::pdfVector( ) const
261 pdfVec_
= RefCountPtr
< SimplePDF::PDF_Vector
>( new SimplePDF::PDF_Vector( xmin_
.offtype
< 1, 0 >( ),
262 ymin_
.offtype
< 1, 0 >( ),
263 xmax_
.offtype
< 1, 0 >( ),
264 ymax_
.offtype
< 1, 0 >( ) ) );
269 Kernel::WarmCatalog::Page::Page( size_t index
, const RefCountPtr
< SimplePDF::PDF_Resources
> & resources
, const RefCountPtr
< SimplePDF::PDF_Stream_out
> & contents
, const RefCountPtr
< Kernel::WarmCatalog::BoundingRectangle
> & mediabox
)
270 : index_( index
), resources_( resources
), contents_( contents
), mediabox_( mediabox
)
273 Kernel::WarmCatalog::Page::~Page( )
277 Kernel::WarmCatalog::PageLabelEntry::PageLabelEntry( size_t pageIndex
, const RefCountPtr
< const char > & prefix
, Style style
, size_t startNumber
)
278 : pageIndex_( pageIndex
), prefix_( prefix
), style_( style
), startNumber_( startNumber
)
281 Kernel::WarmCatalog::PageLabelEntry::~PageLabelEntry( )
290 class Mutator_setbboxgroup
: public Lang::CoreFunction
293 Mutator_setbboxgroup( const char * title
)
294 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
296 formals_
->appendEvaluatedCoreFormal( "key", Kernel::THE_VOID_VARIABLE
);
299 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
301 args
.applyDefaults( );
304 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
305 state
->setBBoxGroup( Helpers::down_cast_CoreArgument
< const Lang::Symbol
>( title_
, args
, 0, callLoc
, true ) );
307 Kernel::ContRef cont
= evalState
->cont_
;
308 cont
->takeValue( Lang::THE_VOID
,
314 class Mutator_setpagelabel
: public Lang::CoreFunction
317 Mutator_setpagelabel( const char * title
)
318 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
320 formals_
->appendEvaluatedCoreFormal( "prefix", Kernel::THE_VOID_VARIABLE
);
321 formals_
->appendEvaluatedCoreFormal( "style", Kernel::THE_VOID_VARIABLE
);
322 formals_
->appendEvaluatedCoreFormal( "number", Kernel::THE_VOID_VARIABLE
);
325 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
327 args
.applyDefaults( );
330 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
333 typedef const Lang::String PrefixValType
;
334 RefCountPtr
< PrefixValType
> prefixVal
= Helpers::down_cast_CoreArgument
< PrefixValType
>( title_
, args
, argsi
, callLoc
, true );
335 RefCountPtr
< const char > prefix
= state
->getNextPagePrefix( );
336 if( prefixVal
!= NullPtr
< PrefixValType
>( ) )
338 prefix
= prefixVal
->val_
;
342 typedef const Lang::Symbol StyleType
;
343 RefCountPtr
< StyleType
> style
= Helpers::down_cast_CoreArgument
< StyleType
>( title_
, args
, argsi
, callLoc
, true );
345 static Lang::Symbol
STYLE_none( "none" );
346 static Lang::Symbol
STYLE_decimal( "decimal" );
347 static Lang::Symbol
STYLE_ROMAN( "ROMAN" );
348 static Lang::Symbol
STYLE_roman( "roman" );
349 static Lang::Symbol
STYLE_ALPHABET( "ALPHABET" );
350 static Lang::Symbol
STYLE_alphabet( "alphabet" );
352 Kernel::WarmCatalog::PageLabelEntry::Style styleVal
;
353 if( style
== NullPtr
< StyleType
>( ) )
355 styleVal
= state
->getNextPageStyle( );
359 if( *style
== STYLE_none
)
361 styleVal
= Kernel::WarmCatalog::PageLabelEntry::NONE
;
363 else if( *style
== STYLE_decimal
)
365 styleVal
= Kernel::WarmCatalog::PageLabelEntry::DECIMAL
;
367 else if( *style
== STYLE_ROMAN
)
369 styleVal
= Kernel::WarmCatalog::PageLabelEntry::ROMAN
;
371 else if( *style
== STYLE_roman
)
373 styleVal
= Kernel::WarmCatalog::PageLabelEntry::rOMAN
;
375 else if( *style
== STYLE_ALPHABET
)
377 styleVal
= Kernel::WarmCatalog::PageLabelEntry::ALPHABET
;
379 else if( *style
== STYLE_alphabet
)
381 styleVal
= Kernel::WarmCatalog::PageLabelEntry::aLPHABET
;
385 std::ostringstream oss
;
386 oss
<< "Valid page label styles are the symbols { "
387 << STYLE_none
.name( ).getPtr( ) << ", "
388 << STYLE_decimal
.name( ).getPtr( ) << ", "
389 << STYLE_ROMAN
.name( ).getPtr( ) << ", "
390 << STYLE_roman
.name( ).getPtr( ) << ", "
391 << STYLE_alphabet
.name( ).getPtr( ) << ", "
392 << STYLE_ALPHABET
.name( ).getPtr( )
394 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, strrefdup( oss
) );
399 typedef const Lang::Integer NumberType
;
400 RefCountPtr
< NumberType
> numberVal
= Helpers::down_cast_CoreArgument
< NumberType
>( title_
, args
, argsi
, callLoc
, true );
402 if( numberVal
!= NullPtr
< NumberType
>( ) )
404 if( numberVal
->val_
< 1 )
406 throw Exceptions::CoreOutOfRange( title_
, args
, argsi
, "PDF only allows strictly positive page numbers." );
408 number
= static_cast< size_t >( numberVal
->val_
);
412 number
= state
->getNextPageNumber( );
415 state
->setLabel( prefix
, styleVal
, number
);
417 Kernel::ContRef cont
= evalState
->cont_
;
418 cont
->takeHandle( Kernel::THE_VOID_VARIABLE
,
424 class Mutator_nextpagelabel
: public Lang::CoreFunction
427 Mutator_nextpagelabel( const char * title
)
428 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
432 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
434 args
.applyDefaults( );
437 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
438 Kernel::ContRef cont
= evalState
->cont_
;
439 cont
->takeValue( Kernel::ValueRef( new Lang::String( state
->getNextPageLabel( ) ) ),
445 class Mutator_nextpagenumber
: public Lang::CoreFunction
448 Mutator_nextpagenumber( const char * title
)
449 : CoreFunction( title
, new Kernel::EvaluatedFormals( Ast::FileID::build_internal( title
), true ) )
453 call( Kernel::EvalState
* evalState
, Kernel::Arguments
& args
, const Ast::SourceLocation
& callLoc
) const
455 args
.applyDefaults( );
458 StateType
* state
= Helpers::mutator_cast_self
< StateType
>( args
.getMutatorSelf( ) );
459 Kernel::ContRef cont
= evalState
->cont_
;
460 cont
->takeValue( Kernel::ValueRef( new Lang::Integer( state
->getNextPageNumber( ) ) ),
467 Kernel::WarmCatalog::WarmCatalog( )
468 : pageLabelsActivated_( false ),
469 bboxGroup_( RefCountPtr
< const Lang::Symbol
>( NullPtr
< const Lang::Symbol
>( ) ) )
471 labelEntries_
.push_back( new Kernel::WarmCatalog::PageLabelEntry( 0, strrefdup( "" ), PageLabelEntry::DECIMAL
, 1 ) );
474 Kernel::WarmCatalog::~WarmCatalog( )
478 WarmCatalog_register_mutators( Lang::SystemFinalClass
* dstClass
)
480 dstClass
->registerMutator( new Kernel::Mutator_setbboxgroup
< Kernel::WarmCatalog
>( "setbboxgroup" ) );
481 dstClass
->registerMutator( new Kernel::Mutator_setpagelabel
< Kernel::WarmCatalog
>( "setpagelabel" ) );
482 dstClass
->registerMutator( new Kernel::Mutator_nextpagelabel
< Kernel::WarmCatalog
>( "nextpagelabel" ) );
483 dstClass
->registerMutator( new Kernel::Mutator_nextpagenumber
< Kernel::WarmCatalog
>( "nextpagenumber" ) );
486 RefCountPtr
< const Lang::Class
> Kernel::WarmCatalog::TypeID( new Lang::SystemFinalClass( strrefdup( "#Catalog" ), WarmCatalog_register_mutators
) );
487 TYPEINFOIMPL_STATE( WarmCatalog
);
490 Kernel::WarmCatalog::tackOnImpl( Kernel::EvalState
* evalState
, const RefCountPtr
< const Lang::Value
> & piece
, const Ast::SourceLocation
& callLoc
)
492 typedef const Lang::Drawable2D ArgType
;
493 RefCountPtr
< const ArgType
> pageContents( Helpers::down_cast
< ArgType
>( piece
, callLoc
) );
495 tackOnPage( evalState
->dyn_
, pageContents
, callLoc
);
497 Kernel::ContRef cont
= evalState
->cont_
;
498 cont
->takeHandle( Kernel::THE_VOID_VARIABLE
,
503 Kernel::WarmCatalog::freezeImpl( Kernel::EvalState
* evalState
, const Ast::SourceLocation
& callLoc
)
505 throw Exceptions::MiscellaneousRequirement( strrefdup( "The catalog state cannot be frozen." ) );
509 Kernel::WarmCatalog::peekImpl( Kernel::EvalState
* evalState
, const Ast::SourceLocation
& callLoc
)
511 throw Exceptions::MiscellaneousRequirement( strrefdup( "The catalog state cannot be peeked." ) );
515 Kernel::WarmCatalog::gcMark( Kernel::GCMarkedSet
& marked
)
519 Kernel::WarmCatalog::setLabel( RefCountPtr
< const char > prefix
, PageLabelEntry::Style style
, size_t start
)
521 const SimplePDF::PDF_Version::Version PAGELABEL_VERSION
= SimplePDF::PDF_Version::PDF_1_3
;
522 if( ! Kernel::the_PDF_version
.greaterOrEqual( PAGELABEL_VERSION
) )
524 Kernel::the_PDF_version
.message( PAGELABEL_VERSION
, "The page label setting was ignored." );
528 pageLabelsActivated_
= true;
530 if( labelEntries_
.back( )->pageIndex_
== pages_
.size( ) )
532 delete labelEntries_
.back( );
533 labelEntries_
.pop_back( );
535 labelEntries_
.push_back( new Kernel::WarmCatalog::PageLabelEntry( pages_
.size( ), prefix
, style
, start
) );
539 Kernel::WarmCatalog::getNextPageNumber( ) const
541 const Kernel::WarmCatalog::PageLabelEntry
* lastEntry
= labelEntries_
.back( );
542 return lastEntry
->startNumber_
+ pages_
.size( ) - lastEntry
->pageIndex_
;
545 Kernel::WarmCatalog::PageLabelEntry::Style
546 Kernel::WarmCatalog::getNextPageStyle( ) const
548 const Kernel::WarmCatalog::PageLabelEntry
* lastEntry
= labelEntries_
.back( );
549 return lastEntry
->style_
;
552 RefCountPtr
< const char >
553 Kernel::WarmCatalog::getNextPagePrefix( ) const
555 const Kernel::WarmCatalog::PageLabelEntry
* lastEntry
= labelEntries_
.back( );
556 return lastEntry
->prefix_
;
559 RefCountPtr
< const char >
560 Kernel::WarmCatalog::getNextPageLabel( ) const
562 return getPageLabel( labelEntries_
.back( ), pages_
.size( ) );
565 RefCountPtr
< const char >
566 Kernel::WarmCatalog::getPageLabel( size_t index
) const
568 typedef typeof labelEntries_ ListType
;
569 ListType::const_iterator i
= labelEntries_
.end( );
571 // Note that labelEntries_.begin( )->pageIndex is 0.
572 while( (*i
)->pageIndex_
> index
)
576 return getPageLabel( *i
, index
);
579 RefCountPtr
< const char >
580 Kernel::WarmCatalog::getPageLabel( const Kernel::WarmCatalog::PageLabelEntry
* entry
, size_t index
) const
582 size_t current
= entry
->startNumber_
+ index
- entry
->pageIndex_
;
583 std::ostringstream oss
;
584 oss
<< entry
->prefix_
.getPtr( ) ;
585 switch( entry
->style_
)
587 case PageLabelEntry::NONE
:
590 case PageLabelEntry::DECIMAL
:
595 case PageLabelEntry::ROMAN
:
597 if( current
>= 5000 )
599 throw Exceptions::NotImplemented( "Conversion to roman numerals of numbers greater or equal 5000." );
603 throw Exceptions::OutOfRange( "Conversion to roman numeral of the page number 0." );
605 while( current
>= 1000 )
625 while( current
>= 100 )
645 while( current
>= 10 )
665 while( current
>= 1 )
672 case PageLabelEntry::rOMAN
:
674 if( current
>= 5000 )
676 throw Exceptions::NotImplemented( "Conversion to roman numerals of numbers greater or equal 5000." );
680 throw Exceptions::OutOfRange( "Conversion to roman numeral of the page number 0." );
682 while( current
>= 1000 )
702 while( current
>= 100 )
722 while( current
>= 10 )
742 while( current
>= 1 )
749 case PageLabelEntry::ALPHABET
:
751 size_t base
= static_cast< size_t >( 'Z' ) - static_cast< size_t >( 'A' ) + 1;
752 size_t baseFactor
= ( current
- 1 ) / base
;
753 char rest
= 'A' + ( current
- baseFactor
* base
) - 1;
754 for( size_t i
= 0; i
< baseFactor
+ 1; ++i
)
760 case PageLabelEntry::aLPHABET
:
762 size_t base
= static_cast< size_t >( 'Z' ) - static_cast< size_t >( 'A' ) + 1;
763 size_t baseFactor
= ( current
- 1 ) / base
;
764 char rest
= 'a' + ( current
- baseFactor
* base
) - 1;
765 for( size_t i
= 0; i
< baseFactor
+ 1; ++i
)
772 throw Exceptions::InternalError( "Page label style out of range." );
774 return strrefdup( oss
);
778 Kernel::WarmCatalog::setBBoxGroup( const RefCountPtr
< const Lang::Symbol
> & group
)
784 Kernel::WarmCatalog::isEmpty( ) const
786 return pages_
.empty( );
790 Kernel::WarmCatalog::tackOnPage( const Kernel::PassedDyn
& dyn
, const RefCountPtr
< const Lang::Drawable2D
> & pageContents
, const Ast::SourceLocation
& callLoc
)
792 RefCountPtr
< SimplePDF::PDF_Resources
> resources( new SimplePDF::PDF_Resources
);
793 RefCountPtr
< SimplePDF::PDF_Stream_out
> contents( new SimplePDF::PDF_Stream_out
);
795 resources
->requireProcedureSet( SimplePDF::PDF_Resources::PROC_SET_PDF
);
797 // Forcing to synch is a bad thing, due to PDF version differences. Instead, refer to the PDF documentation
798 // on the graphics state dictionary (page 180 in the PDF-1.6 reference) to find out the correct default values,
799 // and make sure that these are the initial values of the pdfState.
800 Kernel::PageContentStates
pdfState( resources
, true );
802 pageContents
->shipout( contents
->data
, & pdfState
, Lang::Transform2D( 1, 0, 0, 1, 0, 0 ) );
804 RefCountPtr
< const Lang::ElementaryPath2D
> theBBox
= pageContents
->bbox( Lang::Drawable2D::BLEED
);
805 Concrete::Coords2D
llcorner( 0, 0 );
806 Concrete::Coords2D
urcorner( 0, 0 );
807 if( ! theBBox
->empty( ) )
809 theBBox
->boundingRectangle( & llcorner
, & urcorner
);
811 RefCountPtr
< BoundingRectangle
> mediabox
= RefCountPtr
< BoundingRectangle
>( NullPtr
< BoundingRectangle
>( ) );
812 if( bboxGroup_
== NullPtr
< const Lang::Symbol
>( ) )
814 if( theBBox
->empty( ) )
816 throw Exceptions::InsertingEmptyPage( callLoc
);
818 mediabox
= RefCountPtr
< BoundingRectangle
>( );
822 mediabox
= mediaBoxes_
[ bboxGroup_
->getKey( ) ];
824 if( ! theBBox
->empty( ) )
826 mediabox
->growToContain( llcorner
, urcorner
);
828 Page
* newPage( new Page( pages_
.size( ), resources
, contents
, mediabox
) );
829 pages_
.push_back( newPage
);
832 std::vector
< Kernel::ValueRef
> destinations
;
833 pageContents
->findTags( & destinations
, dyn
, Kernel::THE_NAVIGATION_SYMBOL
->getKey( ), Lang::THE_2D_IDENTITY
);
834 newPage
->destinations_
.reserve( destinations
.size( ) );
835 typedef typeof destinations ListType
;
836 for( ListType::const_iterator i
= destinations
.begin( ); i
!= destinations
.end( ); ++i
)
838 typedef const Lang::DocumentDestination ValType
;
839 RefCountPtr
< ValType
> dest
= i
->down_cast
< ValType
>( );
840 if( dest
== NullPtr
< ValType
>( ) )
842 throw Exceptions::TypeMismatch( callLoc
, "The values tagged for navigations must have a certain type.", (*i
)->getTypeName( ), ValType::staticTypeName( ) );
844 newPage
->destinations_
.push_back( dest
);
849 std::vector
< Kernel::ValueRef
> annotations
;
850 pageContents
->findTags( & annotations
, dyn
, Kernel::THE_ANNOTATION_SYMBOL
->getKey( ), Lang::THE_2D_IDENTITY
);
851 newPage
->annotations_
.reserve( annotations
.size( ) );
852 typedef typeof annotations ListType
;
853 for( ListType::const_iterator i
= annotations
.begin( ); i
!= annotations
.end( ); ++i
)
855 typedef const Lang::AnnotationBase ValType
;
856 RefCountPtr
< ValType
> dest
= i
->down_cast
< ValType
>( );
857 if( dest
== NullPtr
< ValType
>( ) )
859 throw Exceptions::TypeMismatch( callLoc
, "The values tagged for annotation must have a certain type.", (*i
)->getTypeName( ), ValType::staticTypeName( ) );
861 newPage
->annotations_
.push_back( dest
);
867 Kernel::WarmCatalog::shipout( bool split
, ShipoutList
* docs
)
869 RefCountPtr
< SimplePDF::PDF_Indirect_out
> i_info
= Kernel::theDocInfo
.getIndirect( & Kernel::theIndirectObjectCount
);
873 for( size_t pageNo
= 0; pageNo
< pages_
.size( ); ++pageNo
)
875 docs
->push_back( shipoutOne( i_info
, pageNo
) );
880 docs
->push_back( shipoutOne( i_info
, -1 ) );
886 Kernel::WarmCatalog::shipoutOne( RefCountPtr
< SimplePDF::PDF_Indirect_out
> i_info
, int pageNo
)
888 RefCountPtr
< SimplePDF::PDF_Dictionary
> root
= RefCountPtr
< SimplePDF::PDF_Dictionary
>( new SimplePDF::PDF_Dictionary
);
889 RefCountPtr
< SimplePDF::PDF_Indirect_out
> i_root
= SimplePDF::indirect( root
, & Kernel::theIndirectObjectCount
);
890 root
->dic
[ "Type" ] = SimplePDF::newName( "Catalog" );
892 std::map
< RefCountPtr
< const char >, RefCountPtr
< SimplePDF::PDF_Vector
>, charRefPtrLess
> namedDestinations
;
893 std::vector
< RefCountPtr
< SimplePDF::OutlineItem
> > outlineStack
;
894 outlineStack
.reserve( 10 );
895 outlineStack
.push_back
896 ( RefCountPtr
< SimplePDF::OutlineItem
>
897 ( new SimplePDF::OutlineItem( RefCountPtr
< SimplePDF::PDF_Object
>( NullPtr
< SimplePDF::PDF_Object
>( ) ), strrefdup( "Top" ),
898 true, false, false, Concrete::RGB( 0, 0, 0 ) ) ) );
900 RefCountPtr
< SimplePDF::PDF_Dictionary
> pages( new SimplePDF::PDF_Dictionary
);
901 RefCountPtr
< SimplePDF::PDF_Dictionary
> names( new SimplePDF::PDF_Dictionary
);
903 RefCountPtr
< SimplePDF::PDF_Object
> i_pages( SimplePDF::indirect( pages
, & Kernel::theIndirectObjectCount
) );
904 root
->dic
[ "Pages" ] = i_pages
;
906 std::list
< std::pair
< const Page
*, std::pair
< RefCountPtr
< SimplePDF::PDF_Dictionary
>, RefCountPtr
< SimplePDF::PDF_Indirect_out
> > > > annotations
;
908 pages
->dic
[ "Type" ] = SimplePDF::newName( "Pages" );
909 RefCountPtr
< SimplePDF::PDF_Vector
> pagesKids( new SimplePDF::PDF_Vector
);
912 typedef typeof pages_ ListType
;
913 for( ListType::const_iterator i
= pages_
.begin( ); i
!= pages_
.end( ); ++i
, ++currentPage
)
915 if( pageNo
>= 0 && currentPage
!= pageNo
)
919 RefCountPtr
< SimplePDF::PDF_Dictionary
> newPage( new SimplePDF::PDF_Dictionary
);
920 RefCountPtr
< SimplePDF::PDF_Indirect_out
> i_newPage
= SimplePDF::indirect( newPage
, & Kernel::theIndirectObjectCount
);
921 pagesKids
->vec
.push_back( i_newPage
);
922 newPage
->dic
[ "Type" ] = SimplePDF::newName( "Page" );
923 newPage
->dic
[ "Parent" ] = i_pages
;
924 newPage
->dic
[ "MediaBox" ] = (*i
)->mediabox_
->pdfVector( );
925 newPage
->dic
[ "Contents" ] = SimplePDF::indirect( (*i
)->contents_
, & Kernel::theIndirectObjectCount
);
926 newPage
->dic
[ "Resources" ] = SimplePDF::indirect( (*i
)->resources_
, & Kernel::theIndirectObjectCount
);
927 /* The UserUnit entry appears in PDF 1.6, and cannot be relyed on */
928 // newPage->dic[ "UserUnit" ] = RefCountPtr< SimplePDF::PDF_Object >( new SimplePDF::PDF_Float( 72 / 2.52 ) );
930 typedef typeof (*i
)->destinations_ DestListType
;
931 for( DestListType::const_iterator j
= (*i
)->destinations_
.begin( ); j
!= (*i
)->destinations_
.end( ); ++j
)
933 RefCountPtr
< const Lang::DocumentDestination
> dest
= *j
;
934 if( dest
->definesNamed( ) )
936 typedef typeof namedDestinations MapType
;
937 RefCountPtr
< const char > name
= dest
->name( );
938 if( namedDestinations
.find( name
) != namedDestinations
.end( ) )
940 std::ostringstream oss
;
941 oss
<< "The named destination \"" << name
.getPtr( ) << "\" appeared a second time (and possibly also the first time) on the page labeled "
942 << getPageLabel( (*i
)->index_
).getPtr( ) << ", with zero-based physical index " << (*i
)->index_
<< "." ;
943 throw Exceptions::MiscellaneousRequirement( strrefdup( oss
) );
945 namedDestinations
.insert( MapType::value_type( name
, dest
->getDirectDestination( i_newPage
) ) );
948 if( dest
->isOutlineEntry( ) )
950 /* This is the index in the stack at which the item belongs.
951 In other words, this shall be the size of outlineStack just before the new item is pushed.
953 const size_t stackLevel
= dest
->outlineLevel( ) + 1;
955 if( outlineStack
.size( ) < stackLevel
)
957 RefCountPtr
< const char > missingText
= strrefdup( " " );
958 while( outlineStack
.size( ) < stackLevel
)
960 RefCountPtr
< SimplePDF::OutlineItem
> missingItem
= dest
->getOutlineItem( i_newPage
, missingText
);
961 outlineStack
.back( )->addKid( missingItem
);
962 outlineStack
.push_back( missingItem
);
965 while( outlineStack
.size( ) > stackLevel
)
967 outlineStack
.pop_back( );
969 RefCountPtr
< SimplePDF::OutlineItem
> item
= dest
->getOutlineItem( i_newPage
);
970 outlineStack
.back( )->addKid( item
);
971 outlineStack
.push_back( item
);
975 if( ! (*i
)->annotations_
.empty( ) )
977 typedef typeof annotations ListType
;
978 annotations
.push_back( ListType::value_type( *i
, ListType::value_type::second_type( newPage
, i_newPage
) ) );
983 pages
->dic
[ "Kids" ] = pagesKids
;
984 pages
->dic
[ "Count" ] = SimplePDF::newInt( pagesKids
->vec
.size( ) );
987 typedef std::list
< std::pair
< const Page
*, std::pair
< RefCountPtr
< SimplePDF::PDF_Dictionary
>, RefCountPtr
< SimplePDF::PDF_Indirect_out
> > > > ListType
;
988 for( ListType::const_iterator h
= annotations
.begin( ); h
!= annotations
.end( ); ++h
)
990 const Page
* i
= h
->first
;
991 RefCountPtr
< SimplePDF::PDF_Dictionary
> newPage
= h
->second
.first
;
992 RefCountPtr
< SimplePDF::PDF_Indirect_out
> i_newPage
= h
->second
.second
;
993 RefCountPtr
< SimplePDF::PDF_Vector
> annots( new SimplePDF::PDF_Vector
);
994 newPage
->dic
[ "Annots" ] = SimplePDF::indirect( annots
, & Kernel::theIndirectObjectCount
);
995 annots
->vec
.reserve( i
->annotations_
.size( ) );
997 typedef typeof i
->annotations_ AnnotListType
;
998 for( AnnotListType::const_iterator j
= i
->annotations_
.begin( ); j
!= i
->annotations_
.end( ); ++j
)
1000 RefCountPtr
< const Lang::AnnotationBase
> annot
= *j
;
1003 annots
->vec
.push_back( SimplePDF::indirect( annot
->getDictionary( i_newPage
, namedDestinations
), & Kernel::theIndirectObjectCount
) );
1005 catch( Exceptions::UndefinedCrossRef
* ball
)
1009 /* If this is just one page in the document, we expect cross links in the document to be broken, so we just ignore this. */
1014 Kernel::thePostCheckErrorsList
.push_back( ball
);
1022 const SimplePDF::PDF_Version::Version PAGELABELS_VERSION
= SimplePDF::PDF_Version::PDF_1_3
;
1023 if( pageLabelsActivated_
&&
1024 Kernel::the_PDF_version
.greaterOrEqual( PAGELABELS_VERSION
) )
1026 RefCountPtr
< SimplePDF::PDF_Dictionary
> pageLabels( new SimplePDF::PDF_Dictionary
);
1027 root
->dic
[ "PageLabels" ] = SimplePDF::indirect( pageLabels
, & Kernel::theIndirectObjectCount
);
1028 pageLabels
->dic
[ "Type" ] = SimplePDF::newName( "PageLabels" );
1029 RefCountPtr
< SimplePDF::PDF_Vector
> nums( new SimplePDF::PDF_Vector
);
1030 pageLabels
->dic
[ "Nums" ] = nums
;
1031 typedef typeof labelEntries_ ListType
;
1032 for( ListType::const_iterator i
= labelEntries_
.begin( ); i
!= labelEntries_
.end( ); ++i
)
1036 size_t signedPageNo
= static_cast< size_t >( pageNo
);
1037 ListType::const_iterator next
= i
;
1039 if( next
!= labelEntries_
.end( ) && (*next
)->pageIndex_
<= signedPageNo
)
1044 RefCountPtr
< SimplePDF::PDF_Dictionary
> newEntry( new SimplePDF::PDF_Dictionary
);
1045 nums
->vec
.push_back( SimplePDF::newInt( ( pageNo
>= 0 ) ? 0 : (*i
)->pageIndex_
) );
1046 nums
->vec
.push_back( newEntry
);
1048 switch( (*i
)->style_
)
1050 case Kernel::WarmCatalog::PageLabelEntry::NONE
:
1053 case Kernel::WarmCatalog::PageLabelEntry::DECIMAL
:
1055 newEntry
->dic
[ "S" ] = SimplePDF::newName( "D" );
1058 case Kernel::WarmCatalog::PageLabelEntry::ROMAN
:
1060 newEntry
->dic
[ "S" ] = SimplePDF::newName( "R" );
1063 case Kernel::WarmCatalog::PageLabelEntry::rOMAN
:
1065 newEntry
->dic
[ "S" ] = SimplePDF::newName( "r" );
1068 case Kernel::WarmCatalog::PageLabelEntry::ALPHABET
:
1070 newEntry
->dic
[ "S" ] = SimplePDF::newName( "A" );
1073 case Kernel::WarmCatalog::PageLabelEntry::aLPHABET
:
1075 newEntry
->dic
[ "S" ] = SimplePDF::newName( "a" );
1079 throw Exceptions::InternalError( "Page label style out of range during shipout." );
1082 if( strlen( (*i
)->prefix_
.getPtr( ) ) > 0 )
1084 newEntry
->dic
[ "P" ] = SimplePDF::newString( (*i
)->prefix_
.getPtr( ) );
1087 if( (*i
)->startNumber_
!= 1 )
1089 newEntry
->dic
[ "St" ] = SimplePDF::newInt( (*i
)->startNumber_
+ ( ( pageNo
>= 0 ) ? ( pageNo
- (*i
)->pageIndex_
) : 0 ) );
1099 if( outlineStack
.front( )->hasKids( ) &&
1100 pageNo
== -1 ) /* The outline will just be a mess unless we include all pages in the document. */
1102 root
->dic
[ "Outlines" ] = outlineStack
.front( )->getTopIndirectDictionary( Kernel::the_PDF_version
);
1104 if( ! namedDestinations
.empty( ) )
1106 // If there are named destinations, the PDF version is already checked to be high enough.
1107 RefCountPtr
< SimplePDF::PDF_Dictionary
> dests( new SimplePDF::PDF_Dictionary
);
1108 names
->dic
[ "Dests" ] = SimplePDF::indirect( dests
, & Kernel::theIndirectObjectCount
);
1110 RefCountPtr
< SimplePDF::PDF_Vector
> names( new SimplePDF::PDF_Vector
);
1111 typedef typeof namedDestinations Maptype
;
1112 for( Maptype::const_iterator i
= namedDestinations
.begin( ); i
!= namedDestinations
.end( ); ++i
)
1114 RefCountPtr
< SimplePDF::PDF_Dictionary
> newEntry( new SimplePDF::PDF_Dictionary
);
1115 names
->vec
.push_back( SimplePDF::newString( i
->first
.getPtr( ) ) );
1116 names
->vec
.push_back( i
->second
);
1118 dests
->dic
[ "Names" ] = names
;
1122 if( ! names
->dic
.empty( ) )
1124 root
->dic
[ "Names" ] = SimplePDF::indirect( names
, & Kernel::theIndirectObjectCount
);
1127 return SimplePDF::PDF_out( i_root
, i_info
, getPageLabel( std::max( 0, pageNo
) ) );