2006-09-11 10:44:17 +00:00
/*
Copyright ( C ) 2006 Brad Hards < bradh @ frogmouth . net >
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
2006-10-21 22:10:09 +00:00
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
2006-09-11 10:44:17 +00:00
02110 - 1301 , USA .
*/
# include <qdatetime.h>
# include <qfile.h>
2006-09-21 11:41:46 +00:00
# include <qfontdatabase.h>
2006-09-11 10:44:17 +00:00
# include <qimage.h>
# include <qlist.h>
2006-09-21 11:41:46 +00:00
# include <qpainter.h>
2006-09-11 10:44:17 +00:00
# include <qpixmap.h>
# include <qthread.h>
# include <kglobal.h>
# include <kimageeffect.h>
# include <klocale.h>
2007-02-06 07:07:23 +00:00
# include <QFileInfo>
2006-09-11 10:44:17 +00:00
2007-01-03 14:30:48 +00:00
# include <okular/core/document.h>
# include <okular/core/page.h>
2006-09-11 10:44:17 +00:00
# include "generator_xps.h"
2006-09-19 09:09:30 +00:00
OKULAR_EXPORT_PLUGIN ( XpsGenerator )
2006-09-11 10:44:17 +00:00
2006-09-21 11:41:46 +00:00
// From Qt4
static int hex2int ( char hex )
{
QChar hexchar = QLatin1Char ( hex ) ;
int v ;
if ( hexchar . isDigit ( ) )
v = hexchar . digitValue ( ) ;
else if ( hexchar > = QLatin1Char ( ' A ' ) & & hexchar < = QLatin1Char ( ' F ' ) )
v = hexchar . cell ( ) - ' A ' + 10 ;
else if ( hexchar > = QLatin1Char ( ' a ' ) & & hexchar < = QLatin1Char ( ' f ' ) )
v = hexchar . cell ( ) - ' a ' + 10 ;
else
v = - 1 ;
return v ;
}
// Modified from Qt4
static QColor hexToRgba ( const char * name )
{
if ( name [ 0 ] ! = ' # ' )
return QColor ( ) ;
name + + ; // eat the leading '#'
int len = qstrlen ( name ) ;
int r , g , b ;
int a = 255 ;
if ( len = = 6 ) {
r = ( hex2int ( name [ 0 ] ) < < 4 ) + hex2int ( name [ 1 ] ) ;
g = ( hex2int ( name [ 2 ] ) < < 4 ) + hex2int ( name [ 3 ] ) ;
b = ( hex2int ( name [ 4 ] ) < < 4 ) + hex2int ( name [ 5 ] ) ;
} else if ( len = = 8 ) {
a = ( hex2int ( name [ 0 ] ) < < 4 ) + hex2int ( name [ 1 ] ) ;
r = ( hex2int ( name [ 2 ] ) < < 4 ) + hex2int ( name [ 3 ] ) ;
g = ( hex2int ( name [ 4 ] ) < < 4 ) + hex2int ( name [ 5 ] ) ;
b = ( hex2int ( name [ 6 ] ) < < 4 ) + hex2int ( name [ 7 ] ) ;
} else {
r = g = b = - 1 ;
}
if ( ( uint ) r > 255 | | ( uint ) g > 255 | | ( uint ) b > 255 ) {
return QColor ( ) ;
}
return QColor ( r , g , b , a ) ;
}
static QRectF stringToRectF ( const QString & data )
{
QStringList numbers = data . split ( ' , ' ) ;
QPointF origin ( numbers . at ( 0 ) . toDouble ( ) , numbers . at ( 1 ) . toDouble ( ) ) ;
QSizeF size ( numbers . at ( 2 ) . toDouble ( ) , numbers . at ( 3 ) . toDouble ( ) ) ;
return QRectF ( origin , size ) ;
}
2007-02-06 07:07:23 +00:00
static bool parseGUID ( const QString guidString , unsigned short guid [ 16 ] ) {
if ( guidString . length ( ) < = 35 ) {
return false ;
}
// Maps bytes to positions in guidString
const static int indexes [ ] = { 6 , 4 , 2 , 0 , 11 , 9 , 16 , 14 , 19 , 21 , 24 , 26 , 28 , 30 , 32 , 34 } ;
for ( int i = 0 ; i < 16 ; i + + ) {
int hex1 = hex2int ( guidString [ indexes [ i ] ] . cell ( ) ) ;
2007-02-08 16:41:53 +00:00
int hex2 = hex2int ( guidString [ indexes [ i ] + 1 ] . cell ( ) ) ;
2007-02-06 07:07:23 +00:00
2007-02-08 16:41:53 +00:00
if ( ( hex1 < 0 ) | | ( hex2 < 0 ) )
{
return false ;
}
2007-02-06 07:07:23 +00:00
guid [ i ] = hex1 * 16 + hex2 ;
}
return true ;
}
2007-02-08 15:07:54 +00:00
// Read next token of abbreviated path data
static bool nextAbbPathToken ( AbbPathToken * token )
{
int * curPos = & token - > curPos ;
QString data = token - > data ;
while ( ( * curPos < data . length ( ) ) & & ( data . at ( * curPos ) . isSpace ( ) ) )
{
( * curPos ) + + ;
}
if ( * curPos = = data . length ( ) )
{
token - > type = abtEOF ;
return true ;
}
QChar ch = data . at ( * curPos ) ;
if ( ch . isNumber ( ) | | ( ch = = ' + ' ) | | ( ch = = ' - ' ) )
{
int start = * curPos ;
while ( ( * curPos < data . length ( ) ) & & ( ! data . at ( * curPos ) . isSpace ( ) ) & & ( data . at ( * curPos ) ! = ' , ' ) & & ! data . at ( * curPos ) . isLetter ( ) )
2007-02-08 16:41:53 +00:00
{
( * curPos ) + + ;
}
token - > number = data . mid ( start , * curPos - start ) . toDouble ( ) ;
token - > type = abtNumber ;
2007-02-08 15:07:54 +00:00
} else if ( ch = = ' , ' )
{
token - > type = abtComma ;
2007-02-08 16:41:53 +00:00
( * curPos ) + + ;
2007-02-08 15:07:54 +00:00
} else if ( ch . isLetter ( ) )
{
token - > type = abtCommand ;
2007-02-08 16:41:53 +00:00
token - > command = data . at ( * curPos ) . cell ( ) ;
( * curPos ) + + ;
2007-02-08 15:07:54 +00:00
} else
{
return false ;
}
return true ;
}
2007-02-10 17:31:25 +00:00
/**
Read point ( two reals delimited by comma ) from abbreviated path data
*/
static QPointF getPointFromString ( AbbPathToken * token , bool relative , const QPointF currentPosition ) {
2007-02-08 15:07:54 +00:00
//TODO Check grammar
QPointF result ;
result . rx ( ) = token - > number ;
nextAbbPathToken ( token ) ;
nextAbbPathToken ( token ) ; // ,
result . ry ( ) = token - > number ;
nextAbbPathToken ( token ) ;
if ( relative )
{
2007-02-10 17:31:25 +00:00
result + = currentPosition ;
2007-02-08 15:07:54 +00:00
}
return result ;
}
2007-02-06 07:07:23 +00:00
2007-02-10 17:31:25 +00:00
/**
Parse an abbreviated path " Data " description
\ param data the string containing the whitespace separated values
\ see XPS specification 4.2 .3 and Appendix G
*/
static QPainterPath parseAbbreviatedPathData ( const QString & data )
2006-09-21 11:41:46 +00:00
{
2007-02-10 17:31:25 +00:00
QPainterPath path = QPainterPath ( ) ;
2007-02-08 15:07:54 +00:00
2007-02-10 17:31:25 +00:00
AbbPathToken token ;
2007-02-08 15:07:54 +00:00
token . data = data ;
token . curPos = 0 ;
nextAbbPathToken ( & token ) ;
2007-02-08 16:41:53 +00:00
// Used by Smooth cubic curve (command s)
2007-02-08 15:07:54 +00:00
char lastCommand = ' ' ;
2007-02-08 16:41:53 +00:00
QPointF lastSecondControlPoint ;
2007-02-08 15:07:54 +00:00
while ( true )
{
if ( token . type ! = abtCommand )
{
if ( token . type ! = abtEOF )
{
kDebug ( ) < < " Error in parsing abbreviated path data " < < endl ;
2006-09-21 11:41:46 +00:00
}
2007-02-10 17:31:25 +00:00
return path ;
2007-02-08 15:07:54 +00:00
}
char command = QChar ( token . command ) . toLower ( ) . cell ( ) ;
bool isRelative = QChar ( token . command ) . isLower ( ) ;
2007-02-10 17:31:25 +00:00
QPointF currPos = path . currentPosition ( ) ;
2007-02-08 15:07:54 +00:00
nextAbbPathToken ( & token ) ;
switch ( command ) {
case ' f ' :
int rule ;
rule = ( int ) token . number ;
if ( rule = = 0 )
{
2007-02-10 17:31:25 +00:00
path . setFillRule ( Qt : : OddEvenFill ) ;
2007-02-08 15:07:54 +00:00
}
else if ( rule = = 1 )
{
// In xps specs rule 1 means NonZero fill. I think it's equivalent to WindingFill but I'm not sure
2007-02-10 17:31:25 +00:00
path . setFillRule ( Qt : : WindingFill ) ;
2007-02-08 15:07:54 +00:00
}
nextAbbPathToken ( & token ) ;
break ;
case ' m ' : // Move
while ( token . type = = abtNumber )
{
2007-02-10 17:31:25 +00:00
QPointF point = getPointFromString ( & token , isRelative , currPos ) ;
path . moveTo ( point ) ;
2007-02-08 15:07:54 +00:00
}
break ;
case ' l ' : // Line
while ( token . type = = abtNumber )
{
2007-02-10 17:31:25 +00:00
QPointF point = getPointFromString ( & token , isRelative , currPos ) ;
path . lineTo ( point ) ;
2007-02-08 15:07:54 +00:00
}
break ;
case ' h ' : // Horizontal line
while ( token . type = = abtNumber )
{
2007-02-10 17:31:25 +00:00
double x = token . number + isRelative ? path . currentPosition ( ) . x ( ) : 0 ;
path . lineTo ( x , path . currentPosition ( ) . y ( ) ) ;
2007-02-08 15:07:54 +00:00
nextAbbPathToken ( & token ) ;
}
break ;
case ' v ' : // Vertical line
while ( token . type = = abtNumber )
{
2007-02-10 17:31:25 +00:00
double y = token . number + isRelative ? path . currentPosition ( ) . y ( ) : 0 ;
path . lineTo ( path . currentPosition ( ) . x ( ) , y ) ;
2007-02-08 15:07:54 +00:00
nextAbbPathToken ( & token ) ;
}
break ;
case ' c ' : // Cubic bezier curve
while ( token . type = = abtNumber )
{
2007-02-10 17:31:25 +00:00
QPointF firstControl = getPointFromString ( & token , isRelative , currPos ) ;
QPointF secondControl = getPointFromString ( & token , isRelative , currPos ) ;
QPointF endPoint = getPointFromString ( & token , isRelative , currPos ) ;
path . cubicTo ( firstControl , secondControl , endPoint ) ;
2007-02-08 15:07:54 +00:00
2007-02-08 16:41:53 +00:00
lastSecondControlPoint = secondControl ;
2007-02-08 15:07:54 +00:00
}
break ;
case ' q ' : // Quadratic bezier curve
while ( token . type = = abtNumber )
{
2007-02-10 17:31:25 +00:00
QPointF point1 = getPointFromString ( & token , isRelative , currPos ) ;
QPointF point2 = getPointFromString ( & token , isRelative , currPos ) ;
path . quadTo ( point2 , point2 ) ;
2007-02-08 15:07:54 +00:00
}
break ;
case ' s ' : // Smooth cubic bezier curve
while ( token . type = = abtNumber )
{
2007-02-08 16:41:53 +00:00
QPointF firstControl ;
if ( ( lastCommand = = ' s ' ) | | ( lastCommand = = ' c ' ) )
{
2007-02-10 17:31:25 +00:00
firstControl = lastSecondControlPoint + ( lastSecondControlPoint + path . currentPosition ( ) ) ;
2007-02-08 16:41:53 +00:00
}
else
{
2007-02-10 17:31:25 +00:00
firstControl = path . currentPosition ( ) ;
2007-02-08 16:41:53 +00:00
}
2007-02-10 17:31:25 +00:00
QPointF secondControl = getPointFromString ( & token , isRelative , currPos ) ;
QPointF endPoint = getPointFromString ( & token , isRelative , currPos ) ;
path . cubicTo ( firstControl , secondControl , endPoint ) ;
2007-02-08 15:07:54 +00:00
}
break ;
case ' a ' : // Arc
//TODO Implement Arc drawing
while ( token . type = = abtNumber )
{
2007-02-10 17:31:25 +00:00
/*QPointF rp =*/ getPointFromString ( & token , isRelative , currPos ) ;
2007-02-08 15:07:54 +00:00
/*double r = token.number;*/
nextAbbPathToken ( & token ) ;
2007-02-08 16:20:55 +00:00
/*double fArc = token.number; */
2007-02-08 15:07:54 +00:00
nextAbbPathToken ( & token ) ;
/*double fSweep = token.number; */
nextAbbPathToken ( & token ) ;
2007-02-10 17:31:25 +00:00
/*QPointF point = */ getPointFromString ( & token , isRelative , currPos ) ;
2007-02-08 15:07:54 +00:00
}
break ;
case ' z ' : // Close path
2007-02-10 17:31:25 +00:00
path . closeSubpath ( ) ;
2007-02-08 15:07:54 +00:00
break ;
2006-09-21 11:41:46 +00:00
}
2007-02-08 15:07:54 +00:00
2007-02-08 16:41:53 +00:00
lastCommand = command ;
2006-09-21 11:41:46 +00:00
}
2007-02-10 17:31:25 +00:00
return path ;
2006-09-26 11:53:27 +00:00
}
2007-02-08 15:07:54 +00:00
2006-09-26 11:53:27 +00:00
QMatrix XpsHandler : : attsToMatrix ( const QString & csv )
{
QStringList values = csv . split ( ' , ' ) ;
if ( values . count ( ) ! = 6 ) {
return QMatrix ( ) ; // that is an identity matrix - no effect
2007-02-06 07:07:23 +00:00
}
2006-09-26 11:53:27 +00:00
return QMatrix ( values . at ( 0 ) . toDouble ( ) , values . at ( 1 ) . toDouble ( ) ,
values . at ( 2 ) . toDouble ( ) , values . at ( 3 ) . toDouble ( ) ,
2007-02-09 08:11:47 +00:00
values . at ( 4 ) . toDouble ( ) , values . at ( 5 ) . toDouble ( ) ) ;
2006-09-21 11:41:46 +00:00
}
2006-09-11 10:44:17 +00:00
2007-02-10 17:31:25 +00:00
QBrush XpsHandler : : parseRscRefColor ( const QString & data )
{
if ( data [ 0 ] = = ' { ' ) {
//TODO
kDebug ( ) < < " Reference " < < data < < endl ;
return QBrush ( ) ;
} else {
return QBrush ( hexToRgba ( data . toLatin1 ( ) ) ) ;
}
}
QMatrix XpsHandler : : parseRscRefMatrix ( const QString & data )
{
if ( data [ 0 ] = = ' { ' ) {
//TODO
kDebug ( ) < < " Reference " < < data < < endl ;
return QMatrix ( ) ;
} else {
return attsToMatrix ( data ) ;
}
}
2006-09-26 11:53:27 +00:00
XpsHandler : : XpsHandler ( XpsPage * page ) : m_page ( page )
2006-09-21 11:41:46 +00:00
{
2007-02-08 15:07:54 +00:00
m_painter = new QPainter ( m_page - > m_pageImage ) ;
2006-09-21 11:41:46 +00:00
}
XpsHandler : : ~ XpsHandler ( )
2007-02-09 08:11:47 +00:00
{
delete m_painter ;
}
2006-09-21 11:41:46 +00:00
bool XpsHandler : : startDocument ( )
{
2007-02-10 17:31:25 +00:00
kDebug ( ) < < " start document " < < m_page - > m_fileName < < endl ;
2007-02-06 07:07:23 +00:00
m_page - > m_pageImage - > fill ( QColor ( " White " ) . rgba ( ) ) ;
2007-02-10 17:31:25 +00:00
XpsRenderNode node ;
node . name = " document " ;
m_nodes . push ( node ) ;
2006-09-21 11:41:46 +00:00
return true ;
}
bool XpsHandler : : startElement ( const QString & nameSpace ,
const QString & localName ,
const QString & qname ,
const QXmlAttributes & atts )
{
2007-02-10 17:31:25 +00:00
Q_UNUSED ( nameSpace )
Q_UNUSED ( qname )
XpsRenderNode node ;
node . name = localName ;
node . attributes = atts ;
2007-02-12 13:31:16 +00:00
node . data = NULL ;
2007-02-10 17:31:25 +00:00
processStartElement ( node ) ;
m_nodes . push ( node ) ;
2006-09-21 11:41:46 +00:00
return true ;
}
bool XpsHandler : : endElement ( const QString & nameSpace ,
const QString & localName ,
const QString & qname )
{
2007-02-10 17:31:25 +00:00
Q_UNUSED ( nameSpace )
Q_UNUSED ( qname )
XpsRenderNode node = m_nodes . pop ( ) ;
if ( node . name ! = localName ) {
kDebug ( ) < < " Name doesn't match " < < endl ;
}
processEndElement ( node ) ;
node . children . clear ( ) ;
m_nodes . top ( ) . children . append ( node ) ;
return true ;
}
2006-09-21 11:41:46 +00:00
2007-02-10 17:31:25 +00:00
void XpsHandler : : processGlyph ( XpsRenderNode & node )
{
//TODO Currently ignored attributes: BidiLevel, CaretStops, DeviceFontName, IsSideways, Indices, StyleSimulation, Clip, Opacity, OpacityMask, Name, FixedPage.NavigateURI, xml:lang, x:key
//TODO Currently ignored child elements: Clip, OpacityMask
//Handled separately: RenderTransform
QString att ;
m_painter - > save ( ) ;
// Get font (doesn't work well because qt doesn't allow to load font from file)
int fontId = m_page - > getFontByName ( node . attributes . value ( " FontUri " ) ) ;
// kDebug() << "Font families: (" << fontId << ") " << QFontDatabase::applicationFontFamilies( fontId ).at(0) << endl;
QString fontFamily = m_page - > m_fontDatabase . applicationFontFamilies ( fontId ) . at ( 0 ) ;
// kDebug() << "Styles: " << m_page->m_fontDatabase.styles( fontFamily ) << endl;
QString fontStyle = m_page - > m_fontDatabase . styles ( fontFamily ) . at ( 0 ) ;
2007-02-10 17:41:11 +00:00
// This works despite the fact that font size isn't specified in points as required by qt. It's because I set point size to be equal to drawing unit.
2007-02-10 17:31:25 +00:00
QFont font = m_page - > m_fontDatabase . font ( fontFamily , fontStyle , qRound ( node . attributes . value ( " FontRenderingEmSize " ) . toFloat ( ) ) ) ;
m_painter - > setFont ( font ) ;
//Origin
QPointF origin ( node . attributes . value ( " OriginX " ) . toDouble ( ) , node . attributes . value ( " OriginY " ) . toDouble ( ) ) ;
//Fill
QBrush brush ;
att = node . attributes . value ( " Fill " ) ;
if ( att . isEmpty ( ) ) {
2007-02-12 13:31:16 +00:00
void * data = node . getChildData ( " Glyphs.Fill " ) ;
if ( data ! = NULL ) {
brush = * ( XpsFill * ) data ;
2007-02-10 17:31:25 +00:00
} else {
brush = QBrush ( ) ;
2006-09-21 11:41:46 +00:00
}
2007-02-10 17:31:25 +00:00
} else {
brush = parseRscRefColor ( att ) ;
}
m_painter - > setBrush ( brush ) ;
m_painter - > setPen ( QPen ( brush , 0 ) ) ;
2006-09-21 11:41:46 +00:00
2007-02-10 17:31:25 +00:00
//RenderTransform
att = node . attributes . value ( " RenderTransform " ) ;
if ( ! att . isEmpty ( ) ) {
m_painter - > setWorldMatrix ( parseRscRefMatrix ( att ) , true ) ;
}
m_painter - > drawText ( origin , node . attributes . value ( " UnicodeString " ) ) ;
// kDebug() << "Glyphs: " << atts.value("Fill") << ", " << atts.value("FontUri") << endl;
// kDebug() << " Origin: " << atts.value("OriginX") << "," << atts.value("OriginY") << endl;
// kDebug() << " Unicode: " << atts.value("UnicodeString") << endl;
m_painter - > restore ( ) ;
}
void XpsHandler : : processFill ( XpsRenderNode & node )
{
2007-02-12 13:31:16 +00:00
//TODO Ignored child elements: LinearGradientBrush, RadialGradientBrush, VirtualBrush
2007-02-10 17:31:25 +00:00
2007-02-12 13:31:16 +00:00
XpsFill * brush ;
2007-02-10 17:31:25 +00:00
XpsRenderNode * child ;
2007-02-12 13:31:16 +00:00
2007-02-10 17:31:25 +00:00
child = node . findChild ( " SolidColorBrush " ) ;
if ( child ! = NULL ) {
2007-02-12 13:31:16 +00:00
brush = new QBrush ( * ( QColor * ) child - > data ) ;
2007-02-10 17:31:25 +00:00
}
child = node . findChild ( " ImageBrush " ) ;
if ( child ! = NULL ) {
2007-02-12 13:31:16 +00:00
brush = ( XpsImageBrush * ) child - > data ;
2007-02-10 17:31:25 +00:00
}
2007-02-12 13:31:16 +00:00
node . data = brush ;
2007-02-10 17:31:25 +00:00
}
void XpsHandler : : processImageBrush ( XpsRenderNode & node )
{
2007-02-12 13:31:16 +00:00
//TODO Ignored attributes: Opacity, x:key, TileMode, ViewBoxUnits, ViewPortUnits
//TODO Check whether transformation works for non standard situations (viewbox different that whole image, Transform different that simple move & scale, Viewport different than [0, 0, 1, 1]
QString att ;
QBrush brush ;
QRectF viewport = stringToRectF ( node . attributes . value ( " Viewport " ) ) ;
QRectF viewbox = stringToRectF ( node . attributes . value ( " Viewbox " ) ) ;
QImage image = m_page - > loadImageFromFile ( node . attributes . value ( " ImageSource " ) ) ;
// Matrix which can transform [0, 0, 1, 1] rectangle to given viewbox
QMatrix viewboxMatrix = QMatrix ( viewbox . width ( ) * image . physicalDpiX ( ) / 96 , 0 , 0 , viewbox . height ( ) * image . physicalDpiY ( ) / 96 , viewbox . x ( ) , viewbox . y ( ) ) ;
// Matrix which can transform [0, 0, 1, 1] rectangle to given viewport
//TODO Take ViewPort into account
QMatrix viewportMatrix ;
att = node . attributes . value ( " Transform " ) ;
if ( att . isEmpty ( ) ) {
void * data = node . getChildData ( " ImageBrush.Transform " ) ;
if ( data ! = NULL ) {
viewportMatrix = * ( XpsMatrixTransform * ) data ;
} else {
viewportMatrix = QMatrix ( ) ;
}
} else {
viewportMatrix = parseRscRefMatrix ( att ) ;
}
viewportMatrix = viewportMatrix * QMatrix ( viewport . width ( ) , 0 , 0 , viewport . height ( ) , viewport . x ( ) , viewbox . y ( ) ) ;
// TODO Brush should work also for QImage, not only QPixmap. But for some images it doesn't work
brush = QBrush ( QPixmap : : fromImage ( image ) ) ;
brush . setMatrix ( viewboxMatrix . inverted ( ) * viewportMatrix ) ;
node . data = new QBrush ( brush ) ;
2007-02-10 17:31:25 +00:00
}
void XpsHandler : : processPath ( XpsRenderNode & node )
{
//TODO Ignored attributes: Clip, Opacity, OpacityMask, Stroke, StrokeDashArray, StrokeDashCap, StrokeDashOffset, StrokeEndLineCap, StorkeStartLineCap, StrokeLineJoin, StrokeMitterLimit, StrokeThickness, Name, FixedPage.NavigateURI, xml:lang, x:key, AutomationProperties.Name, AutomationProperties.HelpText, SnapsToDevicePixels
//TODO Ignored child elements: RenderTransform, Clip, OpacityMask, Stroke, Data
// Handled separately: RenderTransform
m_painter - > save ( ) ;
QString att ;
QPainterPath path ;
// Get path
att = node . attributes . value ( " Data " ) ;
if ( ! att . isEmpty ( ) ) {
path = parseAbbreviatedPathData ( att ) ;
} else {
path = QPainterPath ( ) ; //TODO
}
// Set Fill
att = node . attributes . value ( " Fill " ) ;
QBrush brush ;
if ( ! att . isEmpty ( ) ) {
brush = parseRscRefColor ( att ) ;
} else {
2007-02-12 13:31:16 +00:00
void * data = node . getChildData ( " Path.Fill " ) ;
if ( data ! = NULL ) {
brush = * ( XpsFill * ) data ;
2007-02-10 17:31:25 +00:00
} else {
brush = QBrush ( ) ;
}
}
m_painter - > setBrush ( brush ) ;
2007-02-12 13:31:16 +00:00
m_painter - > setPen ( QPen ( Qt : : NoPen ) ) ;
2007-02-10 17:31:25 +00:00
// RenderTransform
att = node . attributes . value ( " RenderTransform " ) ;
if ( ! att . isEmpty ( ) ) {
m_painter - > setWorldMatrix ( parseRscRefMatrix ( att ) , true ) ;
}
m_painter - > drawPath ( path ) ;
m_painter - > restore ( ) ;
}
void XpsHandler : : processStartElement ( XpsRenderNode & node )
{
if ( node . name = = " Canvas " ) {
m_painter - > save ( ) ;
}
}
void XpsHandler : : processEndElement ( XpsRenderNode & node )
{
if ( node . name = = " Glyphs " ) {
processGlyph ( node ) ;
} else if ( node . name = = " Path " ) {
processPath ( node ) ;
} else if ( node . name = = " MatrixTransform " ) {
//TODO Ignoring x:key
node . data = new QMatrix ( attsToMatrix ( node . attributes . value ( " Matrix " ) ) ) ;
} else if ( ( node . name = = " Canvas.RenderTransform " ) | | ( node . name = = " Glyphs.RenderTransform " ) | | ( node . name = = " Path.RenderTransform " ) ) {
2007-02-12 13:31:16 +00:00
void * data = node . getRequiredChildData ( " MatrixTransform " ) ;
if ( data ! = NULL ) {
m_painter - > setWorldMatrix ( * ( XpsMatrixTransform * ) data , true ) ;
2007-02-10 17:31:25 +00:00
}
} else if ( node . name = = " Canvas " ) {
2006-09-21 11:41:46 +00:00
m_painter - > restore ( ) ;
2007-02-10 17:31:25 +00:00
} else if ( ( node . name = = " Path.Fill " ) | | ( node . name = = " Glyphs.Fill " ) ) {
processFill ( node ) ;
} else if ( node . name = = " SolidColorBrush " ) {
//TODO Ignoring opacity, x:key
node . data = new QColor ( hexToRgba ( node . attributes . value ( " Color " ) . toLatin1 ( ) ) ) ;
} else if ( node . name = = " ImageBrush " ) {
processImageBrush ( node ) ;
2007-02-12 13:31:16 +00:00
} else if ( node . name = = " ImageBrush.Transform " ) {
node . data = node . getRequiredChildData ( " MatrixTransform " ) ;
2007-02-10 17:31:25 +00:00
} else {
//kDebug() << "Unknown element: " << node->name << endl;
2006-09-21 11:41:46 +00:00
}
}
2007-02-08 16:20:55 +00:00
bool XpsPageSizeHandler : : startElement ( const QString & nameSpace , const QString & localName , const QString & qname , const QXmlAttributes & atts )
{
2007-02-08 16:41:53 +00:00
Q_UNUSED ( nameSpace ) ;
Q_UNUSED ( qname ) ;
if ( localName = = " FixedPage " )
{
m_width = atts . value ( " Width " ) . toInt ( ) ;
m_height = atts . value ( " Height " ) . toInt ( ) ;
m_parsed_successfully = true ;
} else {
m_parsed_successfully = false ;
}
// No need to parse any more
return false ;
2007-02-08 16:20:55 +00:00
}
2006-09-21 11:41:46 +00:00
XpsPage : : XpsPage ( KZip * archive , const QString & fileName ) : m_archive ( archive ) ,
m_fileName ( fileName ) , m_pageIsRendered ( false )
2006-09-11 10:44:17 +00:00
{
2007-02-08 18:09:15 +00:00
m_pageImage = NULL ;
2006-09-11 10:44:17 +00:00
kDebug ( ) < < " page file name: " < < fileName < < endl ;
2006-12-27 17:30:38 +00:00
const KZipFileEntry * pageFile = static_cast < const KZipFileEntry * > ( archive - > directory ( ) - > entry ( fileName ) ) ;
2006-09-11 10:44:17 +00:00
2007-02-08 16:20:55 +00:00
QIODevice * pageDevice = pageFile - > createDevice ( ) ;
2006-09-11 10:44:17 +00:00
2007-02-08 16:41:53 +00:00
XpsPageSizeHandler * handler = new XpsPageSizeHandler ( ) ;
QXmlSimpleReader * parser = new QXmlSimpleReader ( ) ;
parser - > setContentHandler ( handler ) ;
parser - > setErrorHandler ( handler ) ;
QXmlInputSource * source = new QXmlInputSource ( pageDevice ) ;
parser - > parse ( source ) ;
if ( handler - > m_parsed_successfully )
{
m_pageSize . setWidth ( handler - > m_width ) ;
m_pageSize . setHeight ( handler - > m_height ) ;
}
else
{
kDebug ( ) < < " Could not parse XPS page " < < endl ;
}
delete parser ;
delete handler ;
delete source ;
2007-02-09 08:11:47 +00:00
delete pageDevice ;
}
XpsPage : : ~ XpsPage ( )
{
m_fontCache . clear ( ) ;
delete m_pageImage ;
2006-09-11 10:44:17 +00:00
}
2006-09-26 11:53:27 +00:00
bool XpsPage : : renderToImage ( QImage * p )
2006-09-21 11:41:46 +00:00
{
2007-02-08 18:09:15 +00:00
if ( ( m_pageImage = = NULL ) | | ( m_pageImage - > size ( ) ! = p - > size ( ) ) ) {
delete m_pageImage ;
2007-02-10 17:31:25 +00:00
m_pageImage = new QImage ( p - > size ( ) , QImage : : Format_ARGB32 ) ;
2007-02-10 17:41:11 +00:00
// Set one point = one drawing unit. Useful for fonts, because xps specify font size using drawing units, not points as usuall
m_pageImage - > setDotsPerMeterX ( 2835 ) ;
m_pageImage - > setDotsPerMeterY ( 2835 ) ;
2007-02-08 18:09:15 +00:00
m_pageIsRendered = false ;
}
2006-09-21 11:41:46 +00:00
if ( ! m_pageIsRendered ) {
2006-09-26 11:53:27 +00:00
XpsHandler * handler = new XpsHandler ( this ) ;
2007-02-08 18:09:15 +00:00
handler - > m_painter - > setWorldMatrix ( QMatrix ( ) . scale ( ( qreal ) p - > size ( ) . width ( ) / size ( ) . width ( ) , ( qreal ) p - > size ( ) . height ( ) / size ( ) . height ( ) ) ) ;
2006-09-21 11:41:46 +00:00
QXmlSimpleReader * parser = new QXmlSimpleReader ( ) ;
parser - > setContentHandler ( handler ) ;
parser - > setErrorHandler ( handler ) ;
2007-02-08 16:41:53 +00:00
const KZipFileEntry * pageFile = static_cast < const KZipFileEntry * > ( m_archive - > directory ( ) - > entry ( m_fileName ) ) ;
QIODevice * pageDevice = pageFile - > createDevice ( ) ;
2007-02-08 16:20:55 +00:00
QXmlInputSource * source = new QXmlInputSource ( pageDevice ) ;
2006-09-21 11:41:46 +00:00
bool ok = parser - > parse ( source ) ;
kDebug ( ) < < " Parse result: " < < ok < < endl ;
delete source ;
delete parser ;
delete handler ;
2007-02-09 08:11:47 +00:00
delete pageDevice ;
2006-09-21 11:41:46 +00:00
m_pageIsRendered = true ;
}
2007-02-08 18:09:15 +00:00
* p = * m_pageImage ;
2006-09-21 11:41:46 +00:00
return true ;
}
2006-09-11 10:44:17 +00:00
QSize XpsPage : : size ( ) const
{
return m_pageSize ;
}
2007-02-06 07:07:23 +00:00
int XpsPage : : getFontByName ( const QString & fileName )
{
int index = m_fontCache . value ( fileName , - 1 ) ;
2007-02-08 15:07:54 +00:00
if ( index = = - 1 )
2007-02-06 07:07:23 +00:00
{
index = loadFontByName ( fileName ) ;
m_fontCache [ fileName ] = index ;
}
return index ;
}
2006-09-21 11:41:46 +00:00
int XpsPage : : loadFontByName ( const QString & fileName )
{
2006-09-23 00:42:42 +00:00
// kDebug() << "font file name: " << fileName << endl;
2006-09-21 11:41:46 +00:00
2006-12-27 17:30:38 +00:00
const KZipFileEntry * fontFile = static_cast < const KZipFileEntry * > ( m_archive - > directory ( ) - > entry ( fileName ) ) ;
2006-09-21 11:41:46 +00:00
QByteArray fontData = fontFile - > data ( ) ; // once per file, according to the docs
2006-09-23 00:42:42 +00:00
int result = m_fontDatabase . addApplicationFontFromData ( fontData ) ;
2006-09-21 11:41:46 +00:00
if ( - 1 = = result ) {
2007-02-08 15:07:54 +00:00
// Try to deobfuscate font
2007-02-08 16:41:53 +00:00
// TODO Use deobfuscation depending on font content type, don't do it always when standard loading fails
QFileInfo * fileInfo = new QFileInfo ( fileName ) ;
QString baseName = fileInfo - > baseName ( ) ;
delete fileInfo ;
2007-02-06 07:07:23 +00:00
unsigned short guid [ 16 ] ;
if ( ! parseGUID ( baseName , guid ) )
{
2007-02-08 16:41:53 +00:00
kDebug ( ) < < " File to load font - file name isn't a GUID " < < endl ;
2007-02-06 07:07:23 +00:00
}
else
{
2007-02-08 16:41:53 +00:00
if ( fontData . length ( ) < 32 )
2007-02-06 07:07:23 +00:00
{
2007-02-08 16:41:53 +00:00
kDebug ( ) < < " Font file is too small " < < endl ;
2007-02-06 07:07:23 +00:00
} else {
// Obfuscation - xor bytes in font binary with bytes from guid (font's filename)
const static int mapping [ ] = { 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 6 , 7 , 4 , 5 , 0 , 1 , 2 , 3 } ;
for ( int i = 0 ; i < 16 ; i + + ) {
fontData [ i ] = fontData [ i ] ^ guid [ mapping [ i ] ] ;
fontData [ i + 16 ] = fontData [ i + 16 ] ^ guid [ mapping [ i ] ] ;
}
result = m_fontDatabase . addApplicationFontFromData ( fontData ) ;
}
}
2006-09-21 11:41:46 +00:00
}
2007-02-06 07:07:23 +00:00
2006-09-23 00:42:42 +00:00
// kDebug() << "Loaded font: " << m_fontDatabase.applicationFontFamilies( result ) << endl;
2007-02-06 07:07:23 +00:00
2006-09-21 11:41:46 +00:00
return result ; // a font ID
}
2007-02-12 13:31:16 +00:00
QImage XpsPage : : loadImageFromFile ( const QString & fileName )
2006-09-21 11:41:46 +00:00
{
2007-02-10 17:31:25 +00:00
//kDebug() << "image file name: " << fileName << endl;
2006-09-21 11:41:46 +00:00
2006-12-27 17:30:38 +00:00
const KZipFileEntry * imageFile = static_cast < const KZipFileEntry * > ( m_archive - > directory ( ) - > entry ( fileName ) ) ;
2006-09-21 11:41:46 +00:00
QByteArray imageData = imageFile - > data ( ) ; // once per file, according to the docs
2007-02-12 13:31:16 +00:00
QImage image ;
2007-02-10 17:31:25 +00:00
image . loadFromData ( imageData ) ;
//kDebug() << "Image load result: " << result << ", " << image.size() << endl;
2006-09-21 11:41:46 +00:00
return image ;
}
2006-09-11 10:44:17 +00:00
XpsDocument : : XpsDocument ( KZip * archive , const QString & fileName )
{
2006-09-12 10:31:09 +00:00
kDebug ( ) < < " document file name: " < < fileName < < endl ;
2006-12-27 17:30:38 +00:00
const KZipFileEntry * documentFile = static_cast < const KZipFileEntry * > ( archive - > directory ( ) - > entry ( fileName ) ) ;
2006-09-11 10:44:17 +00:00
2007-01-23 01:02:17 +00:00
QIODevice * documentDevice = documentFile - > createDevice ( ) ;
2006-09-11 10:44:17 +00:00
QDomDocument documentDom ;
QString errMsg ;
int errLine , errCol ;
if ( documentDom . setContent ( documentDevice , true , & errMsg , & errLine , & errCol ) = = false ) {
// parse error
kDebug ( ) < < " Could not parse XPS document: " < < errMsg < < " : "
< < errLine < < " : " < < errCol < < endl ;
}
QDomNode node = documentDom . documentElement ( ) . firstChild ( ) ;
while ( ! node . isNull ( ) ) {
QDomElement element = node . toElement ( ) ;
if ( ! element . isNull ( ) ) {
if ( element . tagName ( ) = = " PageContent " ) {
2006-09-12 10:31:09 +00:00
QString pagePath = element . attribute ( " Source " ) ;
if ( pagePath . startsWith ( ' / ' ) = = false ) {
int offset = fileName . lastIndexOf ( ' / ' ) ;
QString thisDir = fileName . mid ( 0 , offset ) + ' / ' ;
pagePath . prepend ( thisDir ) ;
}
XpsPage * page = new XpsPage ( archive , pagePath ) ;
2006-09-11 10:44:17 +00:00
m_pages . append ( page ) ;
} else {
kDebug ( ) < < " Unhandled entry in FixedDocument " < < element . tagName ( ) < < endl ;
}
}
node = node . nextSibling ( ) ;
}
delete documentDevice ;
}
2007-02-09 08:11:47 +00:00
XpsDocument : : ~ XpsDocument ( )
{
for ( int i = 0 ; i < m_pages . size ( ) ; i + + ) {
delete m_pages . at ( i ) ;
}
m_pages . clear ( ) ;
}
2006-09-11 10:44:17 +00:00
int XpsDocument : : numPages ( ) const
{
return m_pages . size ( ) ;
}
XpsPage * XpsDocument : : page ( int pageNum ) const
{
return m_pages . at ( pageNum ) ;
}
2006-09-11 11:05:40 +00:00
XpsFile : : XpsFile ( ) : m_docInfo ( 0 )
2006-09-11 10:44:17 +00:00
{
2006-09-19 09:09:30 +00:00
}
2006-09-11 10:44:17 +00:00
XpsFile : : ~ XpsFile ( )
{
2006-09-19 09:09:30 +00:00
}
2006-09-11 10:44:17 +00:00
bool XpsFile : : loadDocument ( const QString & filename )
{
xpsArchive = new KZip ( filename ) ;
2006-09-12 09:27:21 +00:00
if ( xpsArchive - > open ( QIODevice : : ReadOnly ) = = true ) {
2006-09-11 10:44:17 +00:00
kDebug ( ) < < " Successful open of " < < xpsArchive - > fileName ( ) < < endl ;
} else {
kDebug ( ) < < " Could not open XPS archive: " < < xpsArchive - > fileName ( ) < < endl ;
delete xpsArchive ;
return false ;
}
// The only fixed entry in XPS is _rels/.rels
2006-12-27 17:30:38 +00:00
const KZipFileEntry * relFile = static_cast < const KZipFileEntry * > ( xpsArchive - > directory ( ) - > entry ( " _rels/.rels " ) ) ;
2006-09-11 10:44:17 +00:00
if ( ! relFile ) {
// this might occur if we can't read the zip directory, or it doesn't have the relationships entry
return false ;
}
2007-01-23 01:02:17 +00:00
QIODevice * relDevice = relFile - > createDevice ( ) ;
2006-09-11 10:44:17 +00:00
QDomDocument relDom ;
QString errMsg ;
int errLine , errCol ;
if ( relDom . setContent ( relDevice , true , & errMsg , & errLine , & errCol ) = = false ) {
// parse error
kDebug ( ) < < " Could not parse relationship document: " < < errMsg < < " : "
< < errLine < < " : " < < errCol < < endl ;
return false ;
}
QString fixedRepresentationFileName ;
// We work through the relationships document and pull out each element.
QDomNode n = relDom . documentElement ( ) . firstChild ( ) ;
while ( ! n . isNull ( ) ) {
QDomElement e = n . toElement ( ) ;
if ( ! e . isNull ( ) ) {
if ( " http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail " = = e . attribute ( " Type " ) ) {
m_thumbnailFileName = e . attribute ( " Target " ) ;
} else if ( " http://schemas.microsoft.com/xps/2005/06/fixedrepresentation " = = e . attribute ( " Type " ) ) {
fixedRepresentationFileName = e . attribute ( " Target " ) ;
} else if ( " http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties " = = e . attribute ( " Type " ) ) {
m_corePropertiesFileName = e . attribute ( " Target " ) ;
} else {
kDebug ( ) < < " Unknown relationships element: " < < e . attribute ( " Type " ) < < " : " < < e . attribute ( " Target " ) < < endl ;
}
}
n = n . nextSibling ( ) ;
}
if ( fixedRepresentationFileName . isEmpty ( ) ) {
// FixedRepresentation is a required part of the XPS document
return false ;
}
delete relDevice ;
2006-12-27 17:30:38 +00:00
const KZipFileEntry * fixedRepFile = static_cast < const KZipFileEntry * > ( xpsArchive - > directory ( ) - > entry ( fixedRepresentationFileName ) ) ;
2006-09-11 10:44:17 +00:00
2007-01-23 01:02:17 +00:00
QIODevice * fixedRepDevice = fixedRepFile - > createDevice ( ) ;
2006-09-11 10:44:17 +00:00
QDomDocument fixedRepDom ;
if ( fixedRepDom . setContent ( fixedRepDevice , true , & errMsg , & errLine , & errCol ) = = false ) {
// parse error
kDebug ( ) < < " Could not parse Fixed Representation document: " < < errMsg < < " : "
< < errLine < < " : " < < errCol < < endl ;
return false ;
}
n = fixedRepDom . documentElement ( ) . firstChild ( ) ;
while ( ! n . isNull ( ) ) {
QDomElement e = n . toElement ( ) ;
if ( ! e . isNull ( ) ) {
if ( e . tagName ( ) = = " DocumentReference " ) {
XpsDocument * doc = new XpsDocument ( xpsArchive , e . attribute ( " Source " ) ) ;
2006-09-21 11:41:46 +00:00
for ( int lv = 0 ; lv < doc - > numPages ( ) ; + + lv ) {
// our own copy of the pages list
m_pages . append ( doc - > page ( lv ) ) ;
}
2006-09-11 10:44:17 +00:00
m_documents . append ( doc ) ;
} else {
kDebug ( ) < < " Unhandled entry in FixedDocumentSequence " < < e . tagName ( ) < < endl ;
}
}
n = n . nextSibling ( ) ;
}
delete fixedRepDevice ;
return true ;
}
2006-09-21 08:45:36 +00:00
const Okular : : DocumentInfo * XpsFile : : generateDocumentInfo ( )
2006-09-11 10:44:17 +00:00
{
if ( m_docInfo )
return m_docInfo ;
2006-09-21 08:45:36 +00:00
m_docInfo = new Okular : : DocumentInfo ( ) ;
2006-09-11 10:44:17 +00:00
m_docInfo - > set ( " mimeType " , " application/vnd.ms-xpsdocument " ) ;
if ( ! m_corePropertiesFileName . isEmpty ( ) ) {
2006-12-27 17:30:38 +00:00
const KZipFileEntry * corepropsFile = static_cast < const KZipFileEntry * > ( xpsArchive - > directory ( ) - > entry ( m_corePropertiesFileName ) ) ;
2006-09-11 10:44:17 +00:00
QDomDocument corePropertiesDocumentDom ;
QString errMsg ;
int errLine , errCol ;
2007-01-23 01:02:17 +00:00
QIODevice * corepropsDevice = corepropsFile - > createDevice ( ) ;
2006-09-11 10:44:17 +00:00
if ( corePropertiesDocumentDom . setContent ( corepropsDevice , true , & errMsg , & errLine , & errCol ) = = false ) {
// parse error
kDebug ( ) < < " Could not parse core properties (metadata) document: " < < errMsg < < " : "
< < errLine < < " : " < < errCol < < endl ;
// return whatever we have
return m_docInfo ;
}
QDomNode n = corePropertiesDocumentDom . documentElement ( ) . firstChild ( ) ; // the <coreProperties> level
while ( ! n . isNull ( ) ) {
QDomElement e = n . toElement ( ) ;
if ( ! e . isNull ( ) ) {
if ( e . tagName ( ) = = " title " ) {
m_docInfo - > set ( " title " , e . text ( ) , i18n ( " Title " ) ) ;
} else if ( e . tagName ( ) = = " subject " ) {
m_docInfo - > set ( " subject " , e . text ( ) , i18n ( " Subject " ) ) ;
} else if ( e . tagName ( ) = = " description " ) {
m_docInfo - > set ( " description " , e . text ( ) , i18n ( " Description " ) ) ;
} else if ( e . tagName ( ) = = " creator " ) {
m_docInfo - > set ( " creator " , e . text ( ) , i18n ( " Author " ) ) ;
} else if ( e . tagName ( ) = = " created " ) {
QDateTime createdDate = QDateTime : : fromString ( e . text ( ) , " yyyy-MM-ddThh:mm:ssZ " ) ;
m_docInfo - > set ( " creationDate " , KGlobal : : locale ( ) - > formatDateTime ( createdDate , false , true ) , i18n ( " Created " ) ) ;
} else if ( e . tagName ( ) = = " modified " ) {
QDateTime modifiedDate = QDateTime : : fromString ( e . text ( ) , " yyyy-MM-ddThh:mm:ssZ " ) ;
m_docInfo - > set ( " modifiedDate " , KGlobal : : locale ( ) - > formatDateTime ( modifiedDate , false , true ) , i18n ( " Modified " ) ) ;
} else if ( e . tagName ( ) = = " keywords " ) {
m_docInfo - > set ( " keywords " , e . text ( ) , i18n ( " Keywords " ) ) ;
} else {
kDebug ( ) < < " unhandled metadata tag: " < < e . tagName ( ) < < " : " < < e . text ( ) < < endl ;
}
}
n = n . nextSibling ( ) ;
}
delete corepropsDevice ;
} else {
kDebug ( ) < < " No core properties filename " < < endl ;
}
m_docInfo - > set ( " pages " , QString : : number ( numPages ( ) ) , i18n ( " Pages " ) ) ;
return m_docInfo ;
}
bool XpsFile : : closeDocument ( )
{
if ( m_docInfo )
delete m_docInfo ;
m_docInfo = 0 ;
2007-02-09 08:11:47 +00:00
for ( int i = 0 ; i < m_documents . size ( ) ; i + + ) {
delete m_documents . at ( i ) ;
}
2006-09-11 10:44:17 +00:00
m_documents . clear ( ) ;
delete xpsArchive ;
return true ;
}
int XpsFile : : numPages ( ) const
{
2006-09-21 11:41:46 +00:00
return m_pages . size ( ) ;
2006-09-11 10:44:17 +00:00
}
int XpsFile : : numDocuments ( ) const
{
return m_documents . size ( ) ;
}
XpsDocument * XpsFile : : document ( int documentNum ) const
{
2006-09-21 11:41:46 +00:00
return m_documents . at ( documentNum ) ;
}
XpsPage * XpsFile : : page ( int pageNum ) const
{
return m_pages . at ( pageNum ) ;
2006-09-11 10:44:17 +00:00
}
2006-10-22 11:25:08 +00:00
XpsGenerator : : XpsGenerator ( )
2007-02-10 17:47:44 +00:00
: Okular : : Generator ( ) , m_xpsFile ( 0 )
2006-09-11 10:44:17 +00:00
{
}
XpsGenerator : : ~ XpsGenerator ( )
{
}
2006-09-21 08:45:36 +00:00
bool XpsGenerator : : loadDocument ( const QString & fileName , QVector < Okular : : Page * > & pagesVector )
2006-09-11 10:44:17 +00:00
{
2007-02-06 07:07:23 +00:00
m_xpsFile = new XpsFile ( ) ;
2006-09-11 10:44:17 +00:00
m_xpsFile - > loadDocument ( fileName ) ;
pagesVector . resize ( m_xpsFile - > numPages ( ) ) ;
int pagesVectorOffset = 0 ;
for ( int docNum = 0 ; docNum < m_xpsFile - > numDocuments ( ) ; + + docNum )
{
XpsDocument * doc = m_xpsFile - > document ( docNum ) ;
for ( int pageNum = 0 ; pageNum < doc - > numPages ( ) ; + + pageNum )
{
QSize pageSize = doc - > page ( pageNum ) - > size ( ) ;
2007-01-05 17:09:47 +00:00
pagesVector [ pagesVectorOffset ] = new Okular : : Page ( pagesVectorOffset , pageSize . width ( ) , pageSize . height ( ) , Okular : : Rotation0 ) ;
2006-09-11 10:44:17 +00:00
+ + pagesVectorOffset ;
}
}
return true ;
}
bool XpsGenerator : : closeDocument ( )
{
m_xpsFile - > closeDocument ( ) ;
2007-02-10 17:47:44 +00:00
delete m_xpsFile ;
m_xpsFile = 0 ;
2006-09-11 10:44:17 +00:00
return true ;
}
2007-01-31 18:31:19 +00:00
QImage XpsGenerator : : image ( Okular : : PixmapRequest * request )
2006-09-11 10:44:17 +00:00
{
2007-02-08 18:09:15 +00:00
QSize size ( ( int ) request - > width ( ) , ( int ) request - > height ( ) ) ;
2006-09-26 11:53:27 +00:00
QImage image ( size , QImage : : Format_RGB32 ) ;
2006-10-25 15:35:53 +00:00
XpsPage * pageToRender = m_xpsFile - > page ( request - > page ( ) - > number ( ) ) ;
2006-09-26 11:53:27 +00:00
pageToRender - > renderToImage ( & image ) ;
2007-01-31 18:31:19 +00:00
return image ;
2006-09-11 10:44:17 +00:00
}
2006-09-21 08:45:36 +00:00
const Okular : : DocumentInfo * XpsGenerator : : generateDocumentInfo ( )
2006-09-11 10:44:17 +00:00
{
kDebug ( ) < < " generating document metadata " < < endl ;
return m_xpsFile - > generateDocumentInfo ( ) ;
}
2007-02-10 17:31:25 +00:00
XpsRenderNode * XpsRenderNode : : findChild ( const QString & name )
{
for ( int i = 0 ; i < children . size ( ) ; i + + ) {
if ( children [ i ] . name = = name ) {
return & children [ i ] ;
}
}
return NULL ;
}
2007-02-12 13:31:16 +00:00
void * XpsRenderNode : : getRequiredChildData ( const QString & name )
{
XpsRenderNode * child = findChild ( name ) ;
if ( child = = NULL ) {
kDebug ( ) < < " Required element " < < name < < " is missing in " < < this - > name < < endl ;
return NULL ;
}
return child - > data ;
}
void * XpsRenderNode : : getChildData ( const QString & name )
{
XpsRenderNode * child = findChild ( name ) ;
if ( child = = NULL ) {
return NULL ;
} else {
return child - > data ;
}
}
2006-09-11 10:44:17 +00:00
# include "generator_xps.moc"