From 40e46103f878599f2f98f1990ce881d8b9e2de21 Mon Sep 17 00:00:00 2001 From: Andy Goossens Date: Wed, 24 Dec 2003 11:27:57 +0000 Subject: [PATCH] this is obviously broken as hell reverted "only code layout changes" commit CCMAIL: Christophe.Devriese@student.kuleuven.ac.be was this compiled before you made your commit? svn path=/trunk/kdegraphics/kpdf/; revision=274666 --- kpdf/QOutputDevPixmap.cpp | 507 +++++++++++++++++++++++++++++++++++++- 1 file changed, 497 insertions(+), 10 deletions(-) diff --git a/kpdf/QOutputDevPixmap.cpp b/kpdf/QOutputDevPixmap.cpp index 5801e48f1..eab53140d 100644 --- a/kpdf/QOutputDevPixmap.cpp +++ b/kpdf/QOutputDevPixmap.cpp @@ -59,7 +59,485 @@ static inline long int round( float x ) { static_cast( x + x > 0 ? 0.5 static inline QColor q_col ( const GfxRGB &rgb ) { return QColor ( round ( rgb. r * 255 ), round ( rgb. g * 255 ), round ( rgb. b * 255 )); -convertSubpath ( state, path-> getSubpath ( i ), points ); +} +#endif + +//------------------------------------------------------------------------ +// Font substitutions +//------------------------------------------------------------------------ + +struct QOutFontSubst { + const char * m_name; + const char * m_sname; + bool m_bold; + bool m_italic; + QFont::StyleHint m_hint; +}; + +static QOutFontSubst qPixmapStdFonts [] = { + { "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 QOutputDevPixmap::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 = qPixmapStdFonts; ptr-> m_name; ptr++ ) { + stdfonts. insert ( QString ( ptr-> m_name ), ptr ); + } + } + + // compute size and normalized transform matrix + int size = round ( 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; +} + +//------------------------------------------------------------------------ +// QOutputDevPixmap +//------------------------------------------------------------------------ + +QOutputDevPixmap::QOutputDevPixmap () : m_pixmap(0), m_painter(0) +{ + // create text object + m_text = new TextPage ( gFalse ); +} + +QOutputDevPixmap::~QOutputDevPixmap ( ) +{ + // could be NULL + if (m_pixmap) delete m_pixmap; + + delete m_text; +} + + +void QOutputDevPixmap::startPage ( int /*pageNum*/, GfxState *state ) +{ + if (m_painter) delete m_painter; + if (m_pixmap) delete m_pixmap; + + m_pixmap = new QPixmap ( round ( state-> getPageWidth ( )), round ( state-> getPageHeight ( ))); + m_painter = new QPainter ( m_pixmap ); + + QPDFDBG( printf ( "NEW PIXMAP (%ld x %ld)\n", round ( state-> getPageWidth ( )), round ( state-> getPageHeight ( )))); + + m_pixmap-> fill ( Qt::white ); // clear window + m_text-> clear ( ); // cleat text object +} + +void QOutputDevPixmap::endPage ( ) +{ + m_text-> coalesce ( true ); + + delete m_painter; + m_painter = 0; +} + +void QOutputDevPixmap::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 ( Qt::blue ); + m_painter-> drawRect ( x, y, dx, dy ); + m_painter-> setPen ( oldpen ); + } +} + +void QOutputDevPixmap::saveState ( GfxState */*state*/ ) +{ + QPDFDBG( printf ( "SAVE (CLIP=%d/%d)\n", m_painter-> hasClipping ( ), !m_painter-> clipRegion ( ). isEmpty ( ))); + + m_painter-> save ( ); +} + +void QOutputDevPixmap::restoreState ( GfxState */*state*/ ) +{ + if (! m_painter) return; + 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 QOutputDevPixmap::updateAll ( GfxState *state ) +{ + updateLineAttrs ( state, gTrue ); +// updateFlatness ( state ); +// updateMiterLimit ( state ); + updateFillColor ( state ); + updateStrokeColor ( state ); + updateFont ( state ); +} + +void QOutputDevPixmap::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 QOutputDevPixmap::updateLineDash ( GfxState *state ) +{ + updateLineAttrs ( state, gTrue ); +} + +void QOutputDevPixmap::updateFlatness ( GfxState */*state*/ ) +{ + // not supported + QPDFDBG( printf ( "updateFlatness not supported !\n" )); +} + +void QOutputDevPixmap::updateLineJoin ( GfxState *state ) +{ + updateLineAttrs ( state, gFalse ); +} + +void QOutputDevPixmap::updateLineCap ( GfxState *state ) +{ + updateLineAttrs ( state, gFalse ); +} + +// unimplemented +void QOutputDevPixmap::updateMiterLimit ( GfxState */*state*/ ) +{ + QPDFDBG( printf ( "updateMiterLimit not supported !\n" )); +} + +void QOutputDevPixmap::updateLineWidth ( GfxState *state ) +{ + updateLineAttrs ( state, gFalse ); +} + +void QOutputDevPixmap::updateLineAttrs ( GfxState *state, GBool updateDash ) +{ + fp_t *dashPattern; + int dashLength; + fp_t dashStart; + + Qt::PenCapStyle cap; + Qt::PenJoinStyle join; + int width; + + width = round ( state-> getTransformedLineWidth ( )); + + switch ( state-> getLineCap ( )) { + case 0: cap = Qt::FlatCap; break; + case 1: cap = Qt::RoundCap; break; + case 2: cap = Qt::SquareCap; break; + default: + qWarning ( "Bad line cap style (%d)\n", state-> getLineCap ( )); + cap = Qt::FlatCap; + break; + } + + switch (state->getLineJoin()) { + case 0: join = Qt::MiterJoin; break; + case 1: join = Qt::RoundJoin; break; + case 2: join = Qt::BevelJoin; break; + default: + qWarning ( "Bad line join style (%d)\n", state->getLineJoin ( )); + join = Qt::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 ? Qt::DashLine : Qt::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 QOutputDevPixmap::updateFillColor ( GfxState *state ) +{ + GfxRGB rgb; + state-> getFillRGB ( &rgb ); + + m_painter-> setBrush ( q_col ( rgb )); +} + +void QOutputDevPixmap::updateStrokeColor ( GfxState *state ) +{ + GfxRGB rgb; + state-> getStrokeRGB ( &rgb ); + + QPen pen = m_painter-> pen ( ); + pen. setColor ( q_col ( rgb )); + m_painter-> setPen ( pen ); +} + +void QOutputDevPixmap::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 QOutputDevPixmap::stroke ( GfxState *state ) +{ + QPointArray points; + QMemArray 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; + } +} + +void QOutputDevPixmap::fill ( GfxState *state ) +{ + doFill ( state, true ); +} + +void QOutputDevPixmap::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 QOutputDevPixmap::doFill ( GfxState *state, bool winding ) +{ + QPointArray points; + QMemArray 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 ( Qt::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 ); + +} + +void QOutputDevPixmap::clip ( GfxState *state ) +{ + doClip ( state, true ); +} + +void QOutputDevPixmap::eoClip ( GfxState *state ) +{ + doClip ( state, false ); +} + +void QOutputDevPixmap::doClip ( GfxState *state, bool winding ) +{ + QPointArray points; + QMemArray 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" ); +} + +// +// 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 QOutputDevPixmap::convertPath ( GfxState *state, QPointArray &points, QMemArray &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; @@ -79,18 +557,27 @@ int QOutputDevPixmap::convertSubpath ( GfxState *state, GfxSubpath *subpath, QPo 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 ); + 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, round ( x0 ), round ( y0 ), round ( x1 ), round ( y1 ), + tmp. setPoints ( 4, round ( x0 ), round ( y0 ), round ( x1 ), round ( y1 ), round ( x2 ), round ( y2 ), round ( x3 ), round ( y3 )); - tmp = tmp.cubicBezier(); - points.putPoints ( points.count(), tmp. count(), tmp ); +#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; } @@ -105,7 +592,7 @@ int QOutputDevPixmap::convertSubpath ( GfxState *state, GfxSubpath *subpath, QPo } -void QOutputDevPixmap::beginString ( GfxState *state, GString * /*s*/ ) +void QOutputDevPixmap::beginString ( GfxState *state, GString */*s*/ ) { m_text-> beginWord ( state, state->getCurX(), state->getCurY() ); }