From 0edb09e9286413f0f219afc07db62c813eb89658 Mon Sep 17 00:00:00 2001 From: Christophe Devriese Date: Tue, 15 Apr 2003 12:14:00 +0000 Subject: [PATCH] imported code from qpdf, now it works again ! svn path=/trunk/kdegraphics/kpdf/; revision=220285 --- kpdf/Makefile.am | 4 +- kpdf/QOutputDev.cpp | 1040 +++++++++++++++++++++++++++++++++++++++++++ kpdf/QOutputDev.h | 181 ++++++++ kpdf/kpdf_part.cpp | 39 +- kpdf/kpdf_part.h | 7 +- kpdf/kpdf_shell.cpp | 2 +- xpdf/Makefile.am | 3 +- 7 files changed, 1235 insertions(+), 41 deletions(-) create mode 100644 kpdf/QOutputDev.cpp create mode 100644 kpdf/QOutputDev.h diff --git a/kpdf/Makefile.am b/kpdf/Makefile.am index 13b394f6e..13ae9eccd 100644 --- a/kpdf/Makefile.am +++ b/kpdf/Makefile.am @@ -6,7 +6,7 @@ SUBDIRS = . INCLUDES = -I.. -I$(top_srcdir)/kpdf/goo -I$(top_srcdir)/kpdf/xpdf $(all_includes) # these are the headers for your project -noinst_HEADERS = kpdf_shell.h kpdf_part.h kpdf_canvas.h kpdf_pagewidget.h +noinst_HEADERS = kpdf_shell.h kpdf_part.h kpdf_canvas.h kpdf_pagewidget.h QOutputDev.h # let automoc handle all of the meta source files (moc) METASOURCES = AUTO @@ -43,7 +43,7 @@ shellrc_DATA = kpdf_shell.rc kde_module_LTLIBRARIES = libkpdfpart.la # the Part's source, library search path, and link libraries -libkpdfpart_la_SOURCES = kpdf_canvas.cpp kpdf_part.cpp kpdf_pagewidget.cc +libkpdfpart_la_SOURCES = kpdf_canvas.cpp kpdf_part.cpp kpdf_pagewidget.cc QOutputDev.cpp libkpdfpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) libkpdfpart_la_LIBADD = ../xpdf/libxpdf.la $(LIB_KPARTS) $(LIB_KFILE) $(LIB_KDEPRINT) diff --git a/kpdf/QOutputDev.cpp b/kpdf/QOutputDev.cpp new file mode 100644 index 000000000..b118877bf --- /dev/null +++ b/kpdf/QOutputDev.cpp @@ -0,0 +1,1040 @@ +///======================================================================== +// +// QOutputDev.cc +// +// Copyright 1996 Derek B. Noonburg +// CopyRight 2002 Robert Griebl +// +//======================================================================== + +#ifdef __GNUC__ +#pragma implementation +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include + +//#define QPDFDBG(x) x // special debug mode +#define QPDFDBG(x) // normal compilation + + +//------------------------------------------------------------------------ +// Constants and macros +//------------------------------------------------------------------------ + + +static inline QColor q_col ( const GfxRGB &rgb ) +{ + return QColor ( lrint ( rgb. r * 255 ), lrint ( rgb. g * 255 ), lrint ( rgb. b * 255 )); +} + + +//------------------------------------------------------------------------ +// Font substitutions +//------------------------------------------------------------------------ + +struct QOutFontSubst { + char * m_name; + char * m_sname; + bool m_bold; + bool m_italic; + QFont::StyleHint m_hint; +}; + +static QOutFontSubst qStdFonts [] = { + { "Helvetica", "Helvetica", false, false, QFont::Helvetica }, + { "Helvetica-Oblique", "Helvetica", false, true, QFont::Helvetica }, + { "Helvetica-Bold", "Helvetica", true, false, QFont::Helvetica }, + { "Helvetica-BoldOblique", "Helvetica", true, true, QFont::Helvetica }, + { "Times-Roman", "Times", false, false, QFont::Times }, + { "Times-Italic", "Times", false, true, QFont::Times }, + { "Times-Bold", "Times", true, false, QFont::Times }, + { "Times-BoldItalic", "Times", true, true, QFont::Times }, + { "Courier", "Courier", false, false, QFont::Courier }, + { "Courier-Oblique", "Courier", false, true, QFont::Courier }, + { "Courier-Bold", "Courier", true, false, QFont::Courier }, + { "Courier-BoldOblique", "Courier", true, true, QFont::Courier }, + + { "Symbol", 0, false, false, QFont::AnyStyle }, + { "Zapf-Dingbats", 0, false, false, QFont::AnyStyle }, + + { 0, 0, false, false, QFont::AnyStyle } +}; + + + + + + + +QFont QOutputDev::matchFont ( GfxFont *gfxFont, fp_t m11, fp_t m12, fp_t m21, fp_t m22 ) +{ + static QDict stdfonts; + + // build dict for std. fonts on first invocation + if ( stdfonts. isEmpty ( )) { + for ( QOutFontSubst *ptr = qStdFonts; ptr-> m_name; ptr++ ) { + stdfonts. insert ( QString ( ptr-> m_name ), ptr ); + } + } + + // compute size and normalized transform matrix + int size = lrint ( sqrt ( m21 * m21 + m22 * m22 )); + + QPDFDBG( printf ( "SET FONT: Name=%s, Size=%d, Bold=%d, Italic=%d, Mono=%d, Serif=%d, Symbol=%d, CID=%d, EmbFN=%s, M=(%f,%f,%f,%f)\n", + (( gfxFont-> getName ( )) ? gfxFont-> getName ( )-> getCString ( ) : "" ), + size, + gfxFont-> isBold ( ), + gfxFont-> isItalic ( ), + gfxFont-> isFixedWidth ( ), + gfxFont-> isSerif ( ), + gfxFont-> isSymbolic ( ), + gfxFont-> isCIDFont ( ), + ( gfxFont-> getEmbeddedFontName ( ) ? gfxFont-> getEmbeddedFontName ( ) : "" ), + (double) m11, (double) m12, (double) m21, (double) m22 )); + + + QString fname (( gfxFont-> getName ( )) ? gfxFont-> getName ( )-> getCString ( ) : "" ); + + QFont f; + f. setPixelSize ( size > 0 ? size : 8 ); // type3 fonts misbehave sometimes + + // fast lookup for std. fonts + QOutFontSubst *subst = stdfonts [fname]; + + if ( subst ) { + if ( subst-> m_sname ) + f. setFamily ( subst-> m_sname ); + f. setStyleHint ( subst-> m_hint, (QFont::StyleStrategy) ( QFont::PreferOutline | QFont::PreferQuality )); + f. setBold ( subst-> m_bold ); + f. setItalic ( subst-> m_italic ); + } + else { + QFont::StyleHint sty; + + if ( gfxFont-> isSerif ( )) + sty = QFont::Serif; + else if ( gfxFont-> isFixedWidth ( )) + sty = QFont::TypeWriter; + else + sty = QFont::Helvetica; + + f. setStyleHint ( sty, (QFont::StyleStrategy) ( QFont::PreferOutline | QFont::PreferQuality )); + f. setBold ( gfxFont-> isBold ( ) > 0 ); + f. setItalic ( gfxFont-> isItalic ( ) > 0 ); + f. setFixedPitch ( gfxFont-> isFixedWidth ( ) > 0 ); + + // common specifiers in font names + if ( fname. contains ( "Oblique" ) || fname. contains ( "Italic" )) + f. setItalic ( true ); + if ( fname. contains ( "Bold" )) + f. setWeight ( QFont::Bold ); + if ( fname. contains ( "Demi" )) + f. setWeight ( QFont::DemiBold ); + if ( fname. contains ( "Light" )) + f. setWeight ( QFont::Light ); + if ( fname. contains ( "Black" )) + f. setWeight ( QFont::Black ); + } + // Treat x-sheared fonts as italic + if (( m12 > -0.1 ) && ( m12 < 0.1 ) && ((( m21 > -5.0 ) && ( m21 < -0.1 )) || (( m21 > 0.1 ) && ( m21 < 5.0 )))) { + f. setItalic ( true ); + } + return f; +} + + + +//------------------------------------------------------------------------ +// QOutputDev +//------------------------------------------------------------------------ + +QOutputDev::QOutputDev ( QWidget *parent, const char *name, int flags ) : QScrollView ( parent, name, WRepaintNoErase | WResizeNoErase | flags ) +{ + m_pixmap = 0; + m_painter = 0; + + // create text object + m_text = new TextPage ( gFalse ); +} + +QOutputDev::~QOutputDev ( ) +{ + delete m_painter; + delete m_pixmap; + delete m_text; +} + + +void QOutputDev::startPage ( int /*pageNum*/, GfxState *state ) +{ + delete m_pixmap; + delete m_painter; + + m_pixmap = new QPixmap ( lrint ( state-> getPageWidth ( )), lrint ( state-> getPageHeight ( ))); + m_painter = new QPainter ( m_pixmap ); + + QPDFDBG( printf ( "NEW PIXMAP (%ld x %ld)\n", lrint ( state-> getPageWidth ( )), lrint ( state-> getPageHeight ( )))); + + resizeContents ( m_pixmap-> width ( ), m_pixmap-> height ( )); + setContentsPos ( 0, 0 ); + + m_pixmap-> fill ( white ); // clear window + m_text-> clear ( ); // cleat text object + viewport ( )-> repaint ( ); +} + +void QOutputDev::endPage ( ) +{ + m_text-> coalesce ( ); + + delete m_painter; + m_painter = 0; + + updateContents ( 0, 0, contentsWidth ( ), contentsHeight ( )); +} + +void QOutputDev::drawLink ( Link *link, Catalog */*catalog*/ ) +{ + fp_t x1, y1, x2, y2, w; + + link-> getBorder ( &x1, &y1, &x2, &y2, &w ); + + if ( w > 0 ) { + int x, y, dx, dy; + + cvtUserToDev ( x1, y1, &x, &y ); + cvtUserToDev ( x2, y2, &dx, &dy ); + + QPen oldpen = m_painter-> pen ( ); + m_painter-> setPen ( blue ); + m_painter-> drawRect ( x, y, dx, dy ); + m_painter-> setPen ( oldpen ); + } +} + +void QOutputDev::saveState ( GfxState */*state*/ ) +{ + QPDFDBG( printf ( "SAVE (CLIP=%d/%d)\n", m_painter-> hasClipping ( ), !m_painter-> clipRegion ( ). isEmpty ( ))); + + m_painter-> save ( ); +} + +void QOutputDev::restoreState ( GfxState */*state*/ ) +{ + m_painter-> restore ( ); + +// m_painter-> setClipRegion ( QRect ( 0, 0, m_pixmap-> width ( ), m_pixmap-> height ( ))); +// m_painter-> setClipping ( false ); + QPDFDBG ( printf ( "RESTORE (CLIP=%d/%d)\n", m_painter-> hasClipping ( ), !m_painter-> clipRegion ( ). isEmpty ( ))); +} + +void QOutputDev::updateAll ( GfxState *state ) +{ + updateLineAttrs ( state, gTrue ); +// updateFlatness ( state ); +// updateMiterLimit ( state ); + updateFillColor ( state ); + updateStrokeColor ( state ); + updateFont ( state ); +} + +void QOutputDev::updateCTM ( GfxState *state, fp_t /*m11*/, fp_t /*m12*/, fp_t /*m21*/, fp_t /*m22*/, fp_t /*m31*/, fp_t /*m32*/ ) +{ + updateLineAttrs ( state, gTrue ); +} + +void QOutputDev::updateLineDash ( GfxState *state ) +{ + updateLineAttrs ( state, gTrue ); +} + +void QOutputDev::updateFlatness ( GfxState */*state*/ ) +{ + // not supported + QPDFDBG( printf ( "updateFlatness not supported !\n" )); +} + +void QOutputDev::updateLineJoin ( GfxState *state ) +{ + updateLineAttrs ( state, gFalse ); +} + +void QOutputDev::updateLineCap ( GfxState *state ) +{ + updateLineAttrs ( state, gFalse ); +} + +// unimplemented +void QOutputDev::updateMiterLimit ( GfxState */*state*/ ) +{ + QPDFDBG( printf ( "updateMiterLimit not supported !\n" )); +} + +void QOutputDev::updateLineWidth ( GfxState *state ) +{ + updateLineAttrs ( state, gFalse ); +} + +void QOutputDev::updateLineAttrs ( GfxState *state, GBool updateDash ) +{ + fp_t *dashPattern; + int dashLength; + fp_t dashStart; + + Qt::PenCapStyle cap; + Qt::PenJoinStyle join; + int width; + + width = lrint ( state-> getTransformedLineWidth ( )); + + switch ( state-> getLineCap ( )) { + case 0: cap = FlatCap; break; + case 1: cap = RoundCap; break; + case 2: cap = SquareCap; break; + default: + qWarning ( "Bad line cap style (%d)\n", state-> getLineCap ( )); + cap = FlatCap; + break; + } + + switch (state->getLineJoin()) { + case 0: join = MiterJoin; break; + case 1: join = RoundJoin; break; + case 2: join = BevelJoin; break; + default: + qWarning ( "Bad line join style (%d)\n", state->getLineJoin ( )); + join = MiterJoin; + break; + } + + state-> getLineDash ( &dashPattern, &dashLength, &dashStart ); + + QColor oldcol = m_painter-> pen ( ). color ( ); + GfxRGB rgb; + + state-> getStrokeRGB ( &rgb ); + oldcol = q_col ( rgb ); + + m_painter-> setPen ( QPen ( oldcol, width, dashLength > 0 ? DashLine : SolidLine, cap, join )); + + if ( updateDash && ( dashLength > 0 )) { + // Not supported by QT +/* + char dashList[20]; + if (dashLength > 20) + dashLength = 20; + for ( int i = 0; i < dashLength; ++i ) { + dashList[i] = xoutRound(state->transformWidth(dashPattern[i])); + if (dashList[i] == 0) + dashList[i] = 1; + } + XSetDashes(display, strokeGC, xoutRound(dashStart), dashList, dashLength); +*/ + } +} + +void QOutputDev::updateFillColor ( GfxState *state ) +{ + GfxRGB rgb; + state-> getFillRGB ( &rgb ); + + m_painter-> setBrush ( q_col ( rgb )); +} + +void QOutputDev::updateStrokeColor ( GfxState *state ) +{ + GfxRGB rgb; + state-> getStrokeRGB ( &rgb ); + + QPen pen = m_painter-> pen ( ); + pen. setColor ( q_col ( rgb )); + m_painter-> setPen ( pen ); +} + +void QOutputDev::updateFont ( GfxState *state ) +{ + fp_t m11, m12, m21, m22; + GfxFont *gfxFont = state-> getFont ( ); + + if ( !gfxFont ) + return; + + state-> getFontTransMat ( &m11, &m12, &m21, &m22 ); + m11 *= state-> getHorizScaling ( ); + m12 *= state-> getHorizScaling ( ); + + QFont font = matchFont ( gfxFont, m11, m12, m21, m22 ); + + m_painter-> setFont ( font ); + m_text-> updateFont ( state ); +} + +void QOutputDev::stroke ( GfxState *state ) +{ + QPointArray points; + QArray lengths; + + // transform points + int n = convertPath ( state, points, lengths ); + + QPDFDBG( printf ( "DRAWING: %d POLYS\n", n )); + + // draw each subpath + int j = 0; + for ( int i = 0; i < n; i++ ) { + int len = lengths [i]; + + if ( len >= 2 ) { + QPDFDBG( printf ( " - POLY %d: ", i )); + QPDFDBG( for ( int ii = 0; ii < len; ii++ )) + QPDFDBG( printf ( "(%d/%d) ", points [j+ii]. x ( ), points [j+ii]. y ( ))); + QPDFDBG( printf ( "\n" )); + + m_painter-> drawPolyline ( points, j, len ); + } + j += len; + } + qApp-> processEvents ( ); +} + +void QOutputDev::fill ( GfxState *state ) +{ + doFill ( state, true ); +} + +void QOutputDev::eoFill ( GfxState *state ) +{ + doFill ( state, false ); +} + +// +// X doesn't color the pixels on the right-most and bottom-most +// borders of a polygon. This means that one-pixel-thick polygons +// are not colored at all. I think this is supposed to be a +// feature, but I can't figure out why. So after it fills a +// polygon, it also draws lines around the border. This is done +// only for single-component polygons, since it's not very +// compatible with the compound polygon kludge (see convertPath()). +// +void QOutputDev::doFill ( GfxState *state, bool winding ) +{ + QPointArray points; + QArray lengths; + + // transform points + int n = convertPath ( state, points, lengths ); + + QPDFDBG( printf ( "FILLING: %d POLYS\n", n )); + + QPen oldpen = m_painter-> pen ( ); + m_painter-> setPen ( QPen ( NoPen )); + + // draw each subpath + int j = 0; + for ( int i = 0; i < n; i++ ) { + int len = lengths [i]; + + if ( len >= 3 ) { + QPDFDBG( printf ( " - POLY %d: ", i )); + QPDFDBG( for ( int ii = 0; ii < len; ii++ )) + QPDFDBG( printf ( "(%d/%d) ", points [j+ii]. x ( ), points [j+ii]. y ( ))); + QPDFDBG( printf ( "\n" )); + + m_painter-> drawPolygon ( points, winding, j, len ); + } + j += len; + } + m_painter-> setPen ( oldpen ); + + qApp-> processEvents ( ); +} + +void QOutputDev::clip ( GfxState *state ) +{ + doClip ( state, true ); +} + +void QOutputDev::eoClip ( GfxState *state ) +{ + doClip ( state, false ); +} + +void QOutputDev::doClip ( GfxState *state, bool winding ) +{ + QPointArray points; + QArray lengths; + + // transform points + int n = convertPath ( state, points, lengths ); + + QRegion region; + + QPDFDBG( printf ( "CLIPPING: %d POLYS\n", n )); + + // draw each subpath + int j = 0; + for ( int i = 0; i < n; i++ ) { + int len = lengths [i]; + + if ( len >= 3 ) { + QPointArray dummy; + dummy. setRawData ( points. data ( ) + j, len ); + + QPDFDBG( printf ( " - POLY %d: ", i )); + QPDFDBG( for ( int ii = 0; ii < len; ii++ ) printf ( "(%d/%d) ", points [j+ii]. x ( ), points [j+ii]. y ( ))); + QPDFDBG( printf ( "\n" )); + + region |= QRegion ( dummy, winding ); + + dummy. resetRawData ( points. data ( ) + j, len ); + } + j += len; + } + + if ( m_painter-> hasClipping ( )) + region &= m_painter-> clipRegion ( ); + +// m_painter-> setClipRegion ( region ); +// m_painter-> setClipping ( true ); + +// m_painter-> fillRect ( 0, 0, m_pixmap-> width ( ), m_pixmap-> height ( ), red ); +// m_painter-> drawText ( points [0]. x ( ) + 10, points [0]. y ( ) + 10, "Bla bla" ); + qApp-> processEvents ( ); +} + +// +// Transform points in the path and convert curves to line segments. +// Builds a set of subpaths and returns the number of subpaths. +// If is set, close any unclosed subpaths and activate a +// kludge for polygon fills: First, it divides up the subpaths into +// non-overlapping polygons by simply comparing bounding rectangles. +// Then it connects subaths within a single compound polygon to a single +// point so that X can fill the polygon (sort of). +// +int QOutputDev::convertPath ( GfxState *state, QPointArray &points, QArray &lengths ) +{ + GfxPath *path = state-> getPath ( ); + int n = path-> getNumSubpaths ( ); + + lengths. resize ( n ); + + // do each subpath + for ( int i = 0; i < n; i++ ) { + // transform the points + lengths [i] = convertSubpath ( state, path-> getSubpath ( i ), points ); + } + + return n; +} + +// +// Transform points in a single subpath and convert curves to line +// segments. +// +int QOutputDev::convertSubpath ( GfxState *state, GfxSubpath *subpath, QPointArray &points ) +{ + int oldcnt = points. count ( ); + + fp_t x0, y0, x1, y1, x2, y2, x3, y3; + + int m = subpath-> getNumPoints ( ); + int i = 0; + + while ( i < m ) { + if ( i >= 1 && subpath-> getCurve ( i )) { + state-> transform ( subpath-> getX ( i - 1 ), subpath-> getY ( i - 1 ), &x0, &y0 ); + state-> transform ( subpath-> getX ( i ), subpath-> getY ( i ), &x1, &y1 ); + state-> transform ( subpath-> getX ( i + 1 ), subpath-> getY ( i + 1 ), &x2, &y2 ); + state-> transform ( subpath-> getX ( i + 2 ), subpath-> getY ( i + 2 ), &x3, &y3 ); + + QPointArray tmp; + tmp. setPoints ( 4, lrint ( x0 ), lrint ( y0 ), lrint ( x1 ), lrint ( y1 ), + lrint ( x2 ), lrint ( y2 ), lrint ( x3 ), lrint ( y3 )); + +#if QT_VERSION < 300 + tmp = tmp. quadBezier ( ); + + for ( uint loop = 0; loop < tmp. count ( ); loop++ ) { + QPoint p = tmp. point ( loop ); + points. putPoints ( points. count ( ), 1, p. x ( ), p. y ( )); + } +#else + tmp = tmp. cubicBezier ( ); + points. putPoints ( points. count ( ), tmp. count ( ), tmp ); +#endif + + i += 3; + } + else { + state-> transform ( subpath-> getX ( i ), subpath-> getY ( i ), &x1, &y1 ); + + points. putPoints ( points. count ( ), 1, lrint ( x1 ), lrint ( y1 )); + ++i; + } + } + return points. count ( ) - oldcnt; +} + + +void QOutputDev::beginString ( GfxState *state, GString */*s*/ ) +{ + m_text-> beginString ( state, state->getCurX(), state->getCurY() ); +} + +void QOutputDev::endString ( GfxState */*state*/ ) +{ + m_text-> endString ( ); +} + +void QOutputDev::drawChar ( GfxState *state, fp_t x, fp_t y, + fp_t dx, fp_t dy, fp_t originX, fp_t originY, + CharCode code, Unicode *u, int uLen ) +{ + fp_t x1, y1, dx1, dy1; + + if ( uLen > 0 ) + m_text-> addChar ( state, x, y, dx, dy, u, uLen ); + + // check for invisible text -- this is used by Acrobat Capture + if (( state-> getRender ( ) & 3 ) == 3 ) { + return; + } + + x -= originX; + y -= originY; + state-> transform ( x, y, &x1, &y1 ); + state-> transformDelta ( dx, dy, &dx1, &dy1 ); + + + if ( uLen > 0 ) { + QString str; + QFontMetrics fm = m_painter-> fontMetrics ( ); + + for ( int i = 0; i < uLen; i++ ) { + QChar c = QChar ( u [i] ); + + if ( fm. inFont ( c )) { + str [i] = QChar ( u [i] ); + } + else { + str [i] = ' '; + QPDFDBG( printf ( "CHARACTER NOT IN FONT: %hx\n", c. unicode ( ))); + } + } + + if (( uLen == 1 ) && ( str [0] == ' ' )) + return; + + + fp_t m11, m12, m21, m22; + + state-> getFontTransMat ( &m11, &m12, &m21, &m22 ); + m11 *= state-> getHorizScaling ( ); + m12 *= state-> getHorizScaling ( ); + + fp_t fsize = m_painter-> font ( ). pixelSize ( ); + +#ifndef QT_NO_TRANSFORMATIONS + QWMatrix oldmat; + + bool dorot = (( m12 < -0.1 ) || ( m12 > 0.1 )) && (( m21 < -0.1 ) || ( m21 > 0.1 )); + + if ( dorot ) { + oldmat = m_painter-> worldMatrix ( ); + + // std::cerr << std::endl << "ROTATED: " << m11 << ", " << m12 << ", " << m21 << ", " << m22 << " / SIZE: " << fsize << " / TEXT: " << str. local8Bit ( ) << endl << endl; + + QWMatrix mat ( lrint ( m11 / fsize ), lrint ( m12 / fsize ), -lrint ( m21 / fsize ), -lrint ( m22 / fsize ), lrint ( x1 ), lrint ( y1 )); + + m_painter-> setWorldMatrix ( mat ); + + x1 = 0; + y1 = 0; + } +#endif + + QPen oldpen = m_painter-> pen ( ); + + if (!( state-> getRender ( ) & 1 )) { + QPen fillpen = oldpen; + + fillpen. setColor ( m_painter-> brush ( ). color ( )); + m_painter-> setPen ( fillpen ); + } + + if ( fsize > 5 ) + m_painter-> drawText ( lrint ( x1 ), lrint ( y1 ), str ); + else + m_painter-> fillRect ( lrint ( x1 ), lrint ( y1 ), lrint ( QMAX( fp_t(1), dx1 )), lrint ( QMAX( fsize, dy1 )), m_painter-> pen ( ). color ( )); + + m_painter-> setPen ( oldpen ); + +#ifndef QT_NO_TRANSFORMATIONS + if ( dorot ) + m_painter-> setWorldMatrix ( oldmat ); +#endif + + QPDFDBG( printf ( "DRAW TEXT: \"%s\" at (%ld/%ld)\n", str. local8Bit ( ). data ( ), lrint ( x1 ), lrint ( y1 ))); + } + else if ( code != 0 ) { + // some PDF files use CID 0, which is .notdef, so just ignore it + qWarning ( "Unknown character (CID=%d Unicode=%hx)\n", code, (unsigned short) ( uLen > 0 ? u [0] : (Unicode) 0 )); + } + qApp-> processEvents ( ); +} + + + +void QOutputDev::drawImageMask ( GfxState *state, Object */*ref*/, Stream *str, int width, int height, GBool invert, GBool inlineImg ) +{ + // get CTM, check for singular matrix + fp_t *ctm = state-> getCTM ( ); + + if ( fabs ( ctm [0] * ctm [3] - ctm [1] * ctm [2] ) < 0.000001 ) { + qWarning ( "Singular CTM in drawImage\n" ); + + if ( inlineImg ) { + str-> reset ( ); + int j = height * (( width + 7 ) / 8 ); + for ( int i = 0; i < j; i++ ) + str->getChar(); + + str->close(); + } + return; + } + + GfxRGB rgb; + state-> getFillRGB ( &rgb ); + uint val = ( lrint ( rgb. r * 255 ) & 0xff ) << 16 | ( lrint ( rgb. g * 255 ) & 0xff ) << 8 | ( lrint ( rgb. b * 255 ) & 0xff ); + + + QImage img ( width, height, 32 ); + img. setAlphaBuffer ( true ); + + QPDFDBG( printf ( "IMAGE MASK (%dx%d)\n", width, height )); + + // initialize the image stream + ImageStream *imgStr = new ImageStream ( str, width, 1, 1 ); + imgStr-> reset ( ); + + uchar **scanlines = img. jumpTable ( ); + + if ( ctm [3] > 0 ) + scanlines += ( height - 1 ); + + for ( int y = 0; y < height; y++ ) { + QRgb *scanline = (QRgb *) *scanlines; + + if ( ctm [0] < 0 ) + scanline += ( width - 1 ); + + for ( int x = 0; x < width; x++ ) { + Guchar alpha; + + imgStr-> getPixel ( &alpha ); + + if ( invert ) + alpha ^= 1; + + *scanline = ( alpha == 0 ) ? 0xff000000 | val : val; + + ctm [0] < 0 ? scanline-- : scanline++; + } + ctm [3] > 0 ? scanlines-- : scanlines++; + + qApp-> processEvents ( ); + } + +#ifndef QT_NO_TRANSFORMATIONS + QWMatrix mat ( ctm [0] / width, ctm [1], ctm [2], ctm [3] / height, ctm [4], ctm [5] ); + + //std::cerr << "MATRIX T=" << mat. dx ( ) << "/" << mat. dy ( ) << std::endl + // << " - M=" << mat. m11 ( ) << "/" << mat. m12 ( ) << "/" << mat. m21 ( ) << "/" << mat. m22 ( ) << std::endl; + + QWMatrix oldmat = m_painter-> worldMatrix ( ); + m_painter-> setWorldMatrix ( mat, true ); + +#ifdef QWS + QPixmap pm; + pm. convertFromImage ( img ); + m_painter-> drawPixmap ( 0, 0, pm ); +#else + m_painter-> drawImage ( QPoint ( 0, 0 ), img ); +#endif + + m_painter-> setWorldMatrix ( oldmat ); + +#else + if (( ctm [1] < -0.1 ) || ( ctm [1] > 0.1 ) || ( ctm [2] < -0.1 ) || ( ctm [2] > 0.1 )) { + QPDFDBG( printf ( "### ROTATED / SHEARED / ETC -- CANNOT DISPLAY THIS IMAGE\n" )); + } + else { + int x = lrint ( ctm [4] ); + int y = lrint ( ctm [5] ); + + int w = lrint ( ctm [0] ); + int h = lrint ( ctm [3] ); + + if ( w < 0 ) { + x += w; + w = -w; + } + if ( h < 0 ) { + y += h; + h = -h; + } + + QPDFDBG( printf ( "DRAWING IMAGE MASKED: %d/%d - %dx%d\n", x, y, w, h )); + + img = img. smoothScale ( w, h ); + qApp-> processEvents ( ); + m_painter-> drawImage ( x, y, img ); + } + +#endif + + delete imgStr; + qApp-> processEvents ( ); +} + + +void QOutputDev::drawImage(GfxState *state, Object */*ref*/, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg ) +{ + int nComps, nVals, nBits; + + // image parameters + nComps = colorMap->getNumPixelComps ( ); + nVals = width * nComps; + nBits = colorMap-> getBits ( ); + + // get CTM, check for singular matrix + fp_t *ctm = state-> getCTM ( ); + + if ( fabs ( ctm [0] * ctm [3] - ctm [1] * ctm [2] ) < 0.000001 ) { + qWarning ( "Singular CTM in drawImage\n" ); + + if ( inlineImg ) { + str-> reset ( ); + int j = height * (( nVals * nBits + 7 ) / 8 ); + for ( int i = 0; i < j; i++ ) + str->getChar(); + + str->close(); + } + return; + } + + QImage img ( width, height, 32 ); + + if ( maskColors ) + img. setAlphaBuffer ( true ); + + QPDFDBG( printf ( "IMAGE (%dx%d)\n", width, height )); + + // initialize the image stream + ImageStream *imgStr = new ImageStream ( str, width, nComps, nBits ); + imgStr-> reset ( ); + + Guchar pixBuf [gfxColorMaxComps]; + GfxRGB rgb; + + + uchar **scanlines = img. jumpTable ( ); + + if ( ctm [3] > 0 ) + scanlines += ( height - 1 ); + + for ( int y = 0; y < height; y++ ) { + QRgb *scanline = (QRgb *) *scanlines; + + if ( ctm [0] < 0 ) + scanline += ( width - 1 ); + + for ( int x = 0; x < width; x++ ) { + imgStr-> getPixel ( pixBuf ); + colorMap-> getRGB ( pixBuf, &rgb ); + + uint val = ( lrint ( rgb. r * 255 ) & 0xff ) << 16 | ( lrint ( rgb. g * 255 ) & 0xff ) << 8 | ( lrint ( rgb. b * 255 ) & 0xff ); + + if ( maskColors ) { + for ( int k = 0; k < nComps; ++k ) { + if (( pixBuf [k] < maskColors [2 * k] ) || ( pixBuf [k] > maskColors [2 * k] )) { + val |= 0xff000000; + break; + } + } + } + *scanline = val; + + ctm [0] < 0 ? scanline-- : scanline++; + } + ctm [3] > 0 ? scanlines-- : scanlines++; + + qApp-> processEvents ( ); + } + + +#ifndef QT_NO_TRANSFORMATIONS + QWMatrix mat ( ctm [0] / width, ctm [1], ctm [2], ctm [3] / height, ctm [4], ctm [5] ); + + // std::cerr << "MATRIX T=" << mat. dx ( ) << "/" << mat. dy ( ) << std::endl + // << " - M=" << mat. m11 ( ) << "/" << mat. m12 ( ) << "/" << mat. m21 ( ) << "/" << mat. m22 ( ) << std::endl; + + QWMatrix oldmat = m_painter-> worldMatrix ( ); + m_painter-> setWorldMatrix ( mat, true ); + +#ifdef QWS + QPixmap pm; + pm. convertFromImage ( img ); + m_painter-> drawPixmap ( 0, 0, pm ); +#else + m_painter-> drawImage ( QPoint ( 0, 0 ), img ); +#endif + + m_painter-> setWorldMatrix ( oldmat ); + +#else // QT_NO_TRANSFORMATIONS + + if (( ctm [1] < -0.1 ) || ( ctm [1] > 0.1 ) || ( ctm [2] < -0.1 ) || ( ctm [2] > 0.1 )) { + QPDFDBG( printf ( "### ROTATED / SHEARED / ETC -- CANNOT DISPLAY THIS IMAGE\n" )); + } + else { + int x = lrint ( ctm [4] ); + int y = lrint ( ctm [5] ); + + int w = lrint ( ctm [0] ); + int h = lrint ( ctm [3] ); + + if ( w < 0 ) { + x += w; + w = -w; + } + if ( h < 0 ) { + y += h; + h = -h; + } + + QPDFDBG( printf ( "DRAWING IMAGE: %d/%d - %dx%d\n", x, y, w, h )); + + img = img. smoothScale ( w, h ); + qApp-> processEvents ( ); + m_painter-> drawImage ( x, y, img ); + } + +#endif + + + delete imgStr; + qApp-> processEvents ( ); +} + + + +bool QOutputDev::findText ( const QString &str, QRect &r, bool top, bool bottom ) +{ + int l, t, w, h; + r. rect ( &l, &t, &w, &h ); + + bool res = findText ( str, l, t, w, h, top, bottom ); + + r. setRect ( l, t, w, h ); + return res; +} + +bool QOutputDev::findText ( const QString &str, int &l, int &t, int &w, int &h, bool top, bool bottom ) +{ + bool found = false; + uint len = str. length ( ); + Unicode *s = new Unicode [len]; + + for ( uint i = 0; i < len; i++ ) + s [i] = str [i]. unicode ( ); + + fp_t x1 = (fp_t) l; + fp_t y1 = (fp_t) t; + fp_t x2 = (fp_t) l + w - 1; + fp_t y2 = (fp_t) t + h - 1; + + if ( m_text-> findText ( s, len, top, bottom, &x1, &y1, &x2, &y2 )) { + l = lrint ( x1 ); + t = lrint ( y1 ); + w = lrint ( x2 ) - l + 1; + h = lrint ( y2 ) - t + 1; + found = true; + } + delete [] s; + + return found; +} + +GBool QOutputDev::findText ( Unicode *s, int len, GBool top, GBool bottom, int *xMin, int *yMin, int *xMax, int *yMax ) +{ + bool found = false; + fp_t xMin1 = (double) *xMin; + fp_t yMin1 = (double) *yMin; + fp_t xMax1 = (double) *xMax; + fp_t yMax1 = (double) *yMax; + + if ( m_text-> findText ( s, len, top, bottom, &xMin1, &yMin1, &xMax1, &yMax1 )) { + *xMin = lrint ( xMin1 ); + *xMax = lrint ( xMax1 ); + *yMin = lrint ( yMin1 ); + *yMax = lrint ( yMax1 ); + found = true; + } + return found; +} + +QString QOutputDev::getText ( int l, int t, int w, int h ) +{ + GString *gstr = m_text-> getText ( l, t, l + w - 1, t + h - 1 ); + QString str = gstr-> getCString ( ); + delete gstr; + return str; +} + +QString QOutputDev::getText ( const QRect &r ) +{ + return getText ( r. left ( ), r. top ( ), r. width ( ), r. height ( )); +} + + + +void QOutputDev::drawContents ( QPainter *p, int clipx, int clipy, int clipw, int cliph ) +{ + if ( m_pixmap ) + p-> drawPixmap ( clipx, clipy, *m_pixmap, clipx, clipy, clipw, cliph ); + else + p-> fillRect ( clipx, clipy, clipw, cliph, white ); +} diff --git a/kpdf/QOutputDev.h b/kpdf/QOutputDev.h new file mode 100644 index 000000000..7493c1cd6 --- /dev/null +++ b/kpdf/QOutputDev.h @@ -0,0 +1,181 @@ + +//======================================================================== +// +// XOutputDev.h +// +// Copyright 1996 Derek B. Noonburg +// +//======================================================================== + +#ifndef QOUTPUTDEV_H +#define QOUTPUTDEV_H + +#ifdef __GNUC__ +#pragma interface +#endif + +#include "aconf.h" +#include + +#include + +class Object; + +#include "config.h" +#include "CharTypes.h" +#include "GlobalParams.h" +#include "OutputDev.h" + +class GString; +class GList; +struct GfxRGB; +class GfxFont; +class GfxSubpath; +class TextPage; +class XOutputFontCache; +class Link; +class Catalog; +class DisplayFontParam; +class UnicodeMap; +class CharCodeToUnicode; + + +class QPainter; +class QPixmap; +class QPointArray; + +typedef double fp_t; + +//------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------ + + +//------------------------------------------------------------------------ +// Misc types +//------------------------------------------------------------------------ + + +//------------------------------------------------------------------------ +// XOutputDev +//------------------------------------------------------------------------ + +class QOutputDev : public QScrollView, public OutputDev { + Q_OBJECT + +public: + + // Constructor. + QOutputDev( QWidget *parent = 0, const char *name = 0, int flags = 0 ); + + // Destructor. + virtual ~QOutputDev(); + + //---- get info about output device + + // Does this device use upside-down coordinates? + // (Upside-down means (0,0) is the top left corner of the page.) + virtual GBool upsideDown() { return gTrue; } + + // Does this device use drawChar() or drawString()? + virtual GBool useDrawChar() { return gTrue; } + + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() { return gFalse; } + + // Does this device need non-text content? + virtual GBool needNonText() { return gFalse; } + + //----- initialization and control + + // Start a page. + virtual void startPage(int pageNum, GfxState *state); + + // End a page. + virtual void endPage(); + + //----- link borders + virtual void drawLink(Link *link, Catalog *catalog); + + //----- save/restore graphics state + virtual void saveState(GfxState *state); + virtual void restoreState(GfxState *state); + + //----- update graphics state + virtual void updateAll(GfxState *state); + virtual void updateCTM(GfxState *state, fp_t m11, fp_t m12, + fp_t m21, fp_t m22, fp_t m31, fp_t m32); + virtual void updateLineDash(GfxState *state); + virtual void updateFlatness(GfxState *state); + virtual void updateLineJoin(GfxState *state); + virtual void updateLineCap(GfxState *state); + virtual void updateMiterLimit(GfxState *state); + virtual void updateLineWidth(GfxState *state); + virtual void updateFillColor(GfxState *state); + virtual void updateStrokeColor(GfxState *state); + + //----- update text state + virtual void updateFont(GfxState *state); + + //----- path painting + virtual void stroke(GfxState *state); + virtual void fill(GfxState *state); + virtual void eoFill(GfxState *state); + + //----- path clipping + virtual void clip(GfxState *state); + virtual void eoClip(GfxState *state); + + //----- text drawing + virtual void beginString(GfxState *state, GString *s); + virtual void endString(GfxState *state); + virtual void drawChar(GfxState *state, fp_t x, fp_t y, + fp_t dx, fp_t dy, + fp_t originX, fp_t originY, + CharCode code, Unicode *u, int uLen); + + //----- image drawing + virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg); + virtual void drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg); + + // Find a string. If is true, starts looking at ,; + // otherwise starts looking at top of page. If is true, + // stops looking at ,; otherwise stops looking at bottom + // of page. If found, sets the text bounding rectange and returns + // true; otherwise returns false. + GBool findText ( Unicode *s, int len, GBool top, GBool bottom, int *xMin, int *yMin, int *xMax, int *yMax ); + + //----- special QT access + + bool findText ( const QString &str, int &l, int &t, int &w, int &h, bool top = 0, bool bottom = 0 ); + bool findText ( const QString &str, QRect &r, bool top = 0, bool bottom = 0 ); + + // Get the text which is inside the specified rectangle. + QString getText ( int left, int top, int width, int height ); + QString getText ( const QRect &r ); + +protected: + virtual void drawContents ( QPainter *p, int, int, int, int ); + +private: + QPixmap *m_pixmap; // pixmap to draw into + QPainter *m_painter; + + TextPage *m_text; // text from the current page + +private: + QFont matchFont ( GfxFont *, fp_t m11, fp_t m12, fp_t m21, fp_t m22 ); + + void updateLineAttrs ( GfxState *state, GBool updateDash ); + void doFill ( GfxState *state, bool winding ); + void doClip ( GfxState *state, bool winding ); + int convertPath ( GfxState *state, QPointArray &points, QArray &lengths ); + int convertSubpath ( GfxState *state, GfxSubpath *subpath, QPointArray &points ); +}; + +#endif diff --git a/kpdf/kpdf_part.cpp b/kpdf/kpdf_part.cpp index a7f097e2d..92d41e5f2 100644 --- a/kpdf/kpdf_part.cpp +++ b/kpdf/kpdf_part.cpp @@ -29,7 +29,6 @@ Part::Part(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, const QStringList & /*args*/ ) : KParts::ReadOnlyPart(parent, name), - m_pagePixmap(1, 1), m_doc(0), m_currentPage(0), m_zoomMode(FixedFactor), @@ -42,22 +41,8 @@ Part::Part(QWidget *parentWidget, const char *widgetName, // we need an instance setInstance(KPDFPartFactory::instance()); - m_canvas = new Canvas(parentWidget, widgetName); - setWidget(m_canvas); - - m_pageWidget = new PageWidget(m_canvas->viewport()); - m_canvas->addChild(m_pageWidget); - - connect(m_pageWidget, SIGNAL(linkClicked(LinkAction*)), - SLOT(executeAction(LinkAction*))); - - Pixmap pixmap = m_pagePixmap.handle(); - Display* display = m_pagePixmap.x11Display(); - Colormap colormap = m_pagePixmap.x11Colormap(); - int screen = m_pagePixmap.x11Screen(); - - m_outputDev = new XOutputDev(display, pixmap, 0, colormap, false, - WhitePixel(display, screen), false, 5); + m_outputDev = new QOutputDev(parentWidget, widgetName); + setWidget(m_outputDev); // create our actions KStdAction::find (this, SLOT(find()), @@ -88,7 +73,6 @@ Part::Part(QWidget *parentWidget, const char *widgetName, Part::~Part() { - delete m_outputDev; } KAboutData* @@ -129,8 +113,7 @@ Part::openFile() // just for fun, set the status bar // emit setStatusBarText( QString::number( m_doc->getNumPages() ) ); - m_pageWidget->setPDFDocument(m_doc); - m_outputDev->startDoc(m_doc->getXRef()); + m_doc->displayPage( m_outputDev , 1, 72, 0, false ); displayPage(1); return true; @@ -154,9 +137,9 @@ Part::displayPage(int pageNumber, float /*zoomFactor*/) { const double pageAR = pageWidth/pageHeight; // Aspect ratio - const int canvasWidth = m_canvas->contentsRect().width(); - const int canvasHeight = m_canvas->contentsRect().height(); - const int scrollBarWidth = m_canvas->verticalScrollBar()->width(); + const int canvasWidth = m_outputDev->contentsRect().width(); + const int canvasHeight = m_outputDev->contentsRect().height(); + const int scrollBarWidth = m_outputDev->verticalScrollBar()->width(); // Calculate the height so that the page fits the viewport width // assuming that we need a vertical scrollbar. @@ -186,17 +169,9 @@ Part::displayPage(int pageNumber, float /*zoomFactor*/) const float ppp = basePpp * m_zoomFactor; // pixels per point - m_pagePixmap.resize(ceil(pageWidth*ppp), ceil(pageHeight*ppp)); - m_pageWidget->setFixedSize(m_pagePixmap.size()); - m_pageWidget->setErasePixmap(m_pagePixmap); - m_pageWidget->setPixelsPerPoint(ppp); - - m_outputDev->setPixmap(m_pagePixmap.handle(), - m_pagePixmap.width(), m_pagePixmap.height()); - m_doc->displayPage(m_outputDev, pageNumber, int(ppp*72.0), 0, true); - m_pageWidget->show(); + m_outputDev->show(); m_currentPage = pageNumber; } diff --git a/kpdf/kpdf_part.h b/kpdf/kpdf_part.h index 2c9dc4a43..b6a305810 100644 --- a/kpdf/kpdf_part.h +++ b/kpdf/kpdf_part.h @@ -8,6 +8,8 @@ #include #include +#include + class QPainter; class QPixmap; class QWidget; @@ -85,11 +87,8 @@ namespace KPDF void executeAction(LinkAction*); private: - Canvas* m_canvas; - QPixmap m_pagePixmap; - PageWidget* m_pageWidget; PDFDoc* m_doc; - XOutputDev* m_outputDev; + QOutputDev* m_outputDev; KToggleAction* m_fitToWidth; diff --git a/kpdf/kpdf_shell.cpp b/kpdf/kpdf_shell.cpp index 67c3dff51..5bbaaecb7 100644 --- a/kpdf/kpdf_shell.cpp +++ b/kpdf/kpdf_shell.cpp @@ -77,7 +77,7 @@ Shell::setupActions() KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection()); KStdAction::quit(kapp, SLOT(quit()), actionCollection()); - createStandardStatusBarAction(); + //createStandardStatusBarAction(); setStandardToolBarMenuEnabled(true); KStdAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection()); diff --git a/xpdf/Makefile.am b/xpdf/Makefile.am index ac6f46b42..e1f7a4d2d 100644 --- a/xpdf/Makefile.am +++ b/xpdf/Makefile.am @@ -21,6 +21,5 @@ noinst_HEADERS = Annot.h Array.h BuiltinFont.h BuiltinFontTables.h \ OutputDev.h PBMOutputDev.h PDFDoc.h PDFDocEncoding.cc PSOutputDev.h \ PSTokenizer.h Page.h Parser.h SFont.h Stream-CCITT.h Stream.h \ TextOutputDev.h UTF8.h UnicodeMap.h UnicodeMapTables.h \ - XOutputDev.h XPDFApp.h XPDFCore.h XPDFTree.h XPDFTreeP.h XPDFViewer.h \ - XPixmapOutputDev.h XRef.h config.h xpdf-ltk.h + XOutputDev.h XRef.h config.h xpdf-ltk.h