QOutputDevPixmap.cpp 25.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
///========================================================================
//
// QOutputDevPixmap.cc
//
// Copyright 1996 Derek B. Noonburg
// CopyRight 2002 Robert Griebl
//
//========================================================================

#ifdef __GNUC__
#pragma implementation
#endif

#include <aconf.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <iostream>

#include <GString.h>
#include <Object.h>
#include <Stream.h>
#include <Link.h>
#include <GfxState.h>
#include <GfxFont.h>
#include <UnicodeMap.h>
#include <CharCodeToUnicode.h>
#include <FontFile.h>
#include <Error.h>
#include <TextOutputDev.h>
#include <Catalog.h>


#include <qpixmap.h>
#include <qcolor.h>
#include <qimage.h>
#include <qpainter.h>
#include <qdict.h>
#include <qtimer.h>
#include <qapplication.h>
#include <qclipboard.h>

#include "QOutputDevPixmap.h"

//#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 },
89

90 91 92
	{ 0,                       0,           false, false, QFont::AnyStyle }
};

93
QFont QOutputDevPixmap::matchFont ( GfxFont *gfxFont, fp_t m11, fp_t m12, fp_t m21, fp_t m22 )
94 95
{
	static QDict<QOutFontSubst> stdfonts;
96 97

	// build dict for std. fonts on first invocation
98 99 100
	if ( stdfonts. isEmpty ( )) {
		for ( QOutFontSubst *ptr = qStdFonts; ptr-> m_name; ptr++ ) {
			stdfonts. insert ( QString ( ptr-> m_name ), ptr );
101
		}
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
	}

	// 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 ( ) : "<n/a>" ),
	         size,
	         gfxFont-> isBold ( ),
	         gfxFont-> isItalic ( ),
	         gfxFont-> isFixedWidth ( ),
	         gfxFont-> isSerif ( ),
	         gfxFont-> isSymbolic ( ),
	         gfxFont-> isCIDFont ( ),
	         ( gfxFont-> getEmbeddedFontName ( ) ? gfxFont-> getEmbeddedFontName ( ) : "<n/a>" ),
	         (double) m11, (double) m12, (double) m21, (double) m22 ));


	QString fname (( gfxFont-> getName ( )) ? gfxFont-> getName ( )-> getCString ( ) : "<n/a>" );

	QFont f;
	f. setPixelSize ( size > 0 ? size : 8 ); // type3 fonts misbehave sometimes

	// fast lookup for std. fonts
	QOutFontSubst *subst = stdfonts [fname];
127

128 129 130
	if ( subst ) {
		if ( subst-> m_sname )
			f. setFamily ( subst-> m_sname );
131
		f. setStyleHint ( subst-> m_hint, (QFont::StyleStrategy) ( QFont::PreferOutline | QFont::PreferQuality ));
132 133 134 135 136
		f. setBold ( subst-> m_bold );
		f. setItalic ( subst-> m_italic );
	}
	else {
		QFont::StyleHint sty;
137

138 139 140 141 142 143
		if ( gfxFont-> isSerif ( ))
			sty = QFont::Serif;
		else if ( gfxFont-> isFixedWidth ( ))
			sty = QFont::TypeWriter;
		else
			sty = QFont::Helvetica;
144 145

		f. setStyleHint ( sty, (QFont::StyleStrategy) ( QFont::PreferOutline | QFont::PreferQuality ));
146 147 148
		f. setBold ( gfxFont-> isBold ( ) > 0 );
		f. setItalic ( gfxFont-> isItalic ( ) > 0 );
		f. setFixedPitch ( gfxFont-> isFixedWidth ( ) > 0 );
149 150

		// common specifiers in font names
151
		if ( fname. contains ( "Oblique" ) || fname. contains ( "Italic" ))
152
			f. setItalic ( true );
153 154 155 156 157 158 159 160
		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 );
161
	}
162 163
	// 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 )))) {
164 165
		f. setItalic ( true );
	}
166 167 168 169 170 171 172 173 174 175 176 177 178
	return f;
}

//------------------------------------------------------------------------
// QOutputDevPixmap
//------------------------------------------------------------------------

QOutputDevPixmap::QOutputDevPixmap () : m_pixmap(0), m_painter(0)
{
	// create text object
	m_text = new TextPage ( gFalse );
}

179
QOutputDevPixmap::~QOutputDevPixmap ( )
180 181 182
{
	// could be NULL
	if (m_pixmap) delete m_pixmap;
183

184 185 186 187
	delete m_text;
}


188
void QOutputDevPixmap::startPage ( int /*pageNum*/, GfxState *state )
189 190 191
{
	if (m_painter) delete m_painter;
	if (m_pixmap) delete m_pixmap;
192

193 194 195 196
	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 ( ))));
197

198
	m_pixmap-> fill ( Qt::white ); // clear window
199
	m_text-> clear ( ); // cleat text object
200 201
}

202
void QOutputDevPixmap::endPage ( )
203 204
{
	m_text-> coalesce ( );
205

206 207 208 209
	delete m_painter;
	m_painter = 0;
}

210
void QOutputDevPixmap::drawLink ( Link *link, Catalog /* *catalog */ )
211 212 213 214
{
	fp_t x1, y1, x2, y2, w;

	link-> getBorder ( &x1, &y1, &x2, &y2, &w );
215

216 217
	if ( w > 0 ) {
		int x, y, dx, dy;
218

219 220
		cvtUserToDev ( x1, y1, &x,  &y );
		cvtUserToDev ( x2, y2, &dx, &dy );
221

222 223 224 225 226 227 228
		QPen oldpen = m_painter-> pen ( );
		m_painter-> setPen ( Qt::blue );
		m_painter-> drawRect ( x, y, dx, dy );
		m_painter-> setPen ( oldpen );
	}
}

229
void QOutputDevPixmap::saveState ( GfxState */*state*/ )
230 231 232
{
	QPDFDBG( printf ( "SAVE (CLIP=%d/%d)\n",  m_painter-> hasClipping ( ), !m_painter-> clipRegion ( ). isEmpty ( )));

233
	m_painter-> save ( );
234 235
}

236
void QOutputDevPixmap::restoreState ( GfxState */*state*/ )
237
{
238
    if (! m_painter) return;
239
	m_painter-> restore ( );
240

241 242 243 244 245
//	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 ( )));
}

246
void QOutputDevPixmap::updateAll ( GfxState *state )
247 248 249 250 251 252 253 254 255
{
	updateLineAttrs ( state, gTrue );
//	updateFlatness ( state );
//	updateMiterLimit ( state );
	updateFillColor ( state );
	updateStrokeColor ( state );
	updateFont ( state );
}

256
void QOutputDevPixmap::updateCTM ( GfxState *state, fp_t /*m11*/, fp_t /*m12*/, fp_t /*m21*/, fp_t /*m22*/, fp_t /*m31*/, fp_t /*m32*/ )
257 258 259 260
{
	updateLineAttrs ( state, gTrue );
}

261
void QOutputDevPixmap::updateLineDash ( GfxState *state )
262 263 264 265
{
	updateLineAttrs ( state, gTrue );
}

266
void QOutputDevPixmap::updateFlatness ( GfxState */*state*/ )
267 268 269 270 271
{
	// not supported
	QPDFDBG( printf ( "updateFlatness not supported !\n" ));
}

272
void QOutputDevPixmap::updateLineJoin ( GfxState *state )
273 274 275 276
{
	updateLineAttrs ( state, gFalse );
}

277
void QOutputDevPixmap::updateLineCap ( GfxState *state )
278 279 280 281 282
{
	updateLineAttrs ( state, gFalse );
}

// unimplemented
283
void QOutputDevPixmap::updateMiterLimit ( GfxState */*state*/ )
284 285 286 287
{
	QPDFDBG( printf ( "updateMiterLimit not supported !\n" ));
}

288
void QOutputDevPixmap::updateLineWidth ( GfxState *state )
289 290 291 292
{
	updateLineAttrs ( state, gFalse );
}

293
void QOutputDevPixmap::updateLineAttrs ( GfxState *state, GBool updateDash )
294 295 296 297 298 299 300 301 302 303
{
	fp_t *dashPattern;
	int dashLength;
	fp_t dashStart;

	Qt::PenCapStyle  cap;
	Qt::PenJoinStyle join;
	int width;

	width = lrint ( state-> getTransformedLineWidth ( ));
304

305 306 307 308 309 310 311 312 313
	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;
	}
314

315 316 317 318 319 320 321 322 323
	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;
	}
324

325 326 327 328 329 330 331 332 333 334 335 336
	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
337
/*
338 339 340 341 342 343 344 345 346 347 348 349 350
		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);
*/
	}
}

351
void QOutputDevPixmap::updateFillColor ( GfxState *state )
352 353 354 355 356 357 358
{
	GfxRGB rgb;
	state-> getFillRGB ( &rgb );

	m_painter-> setBrush ( q_col ( rgb ));
}

359
void QOutputDevPixmap::updateStrokeColor ( GfxState *state )
360 361 362
{
	GfxRGB rgb;
	state-> getStrokeRGB ( &rgb );
363

364 365 366 367 368
	QPen pen = m_painter-> pen ( );
	pen. setColor ( q_col ( rgb ));
	m_painter-> setPen ( pen );
}

369
void QOutputDevPixmap::updateFont ( GfxState *state )
370 371 372
{
	fp_t m11, m12, m21, m22;
	GfxFont *gfxFont = state-> getFont ( );
373

374 375
	if ( !gfxFont )
		return;
376

377 378 379
	state-> getFontTransMat ( &m11, &m12, &m21, &m22 );
	m11 *= state-> getHorizScaling ( );
	m12 *= state-> getHorizScaling ( );
380

381
	QFont font = matchFont ( gfxFont, m11, m12, m21, m22 );
382

383 384 385 386
	m_painter-> setFont ( font );
	m_text-> updateFont ( state );
}

387
void QOutputDevPixmap::stroke ( GfxState *state )
388 389
{
	QPointArray points;
390
	QMemArray<int> lengths;
391 392 393 394 395

	// transform points
	int n = convertPath ( state, points, lengths );

	QPDFDBG( printf ( "DRAWING: %d POLYS\n", n ));
396

397 398 399 400
	// draw each subpath
	int j = 0;
	for ( int i = 0; i < n; i++ ) {
		int len = lengths [i];
401

402 403 404 405 406
		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" ));
407

408
			m_painter-> drawPolyline ( points, j, len );
409
		}
410 411 412 413
		j += len;
	}
}

414
void QOutputDevPixmap::fill ( GfxState *state )
415 416 417 418
{
	doFill ( state, true );
}

419
void QOutputDevPixmap::eoFill ( GfxState *state )
420 421 422 423 424 425 426 427 428 429 430 431 432
{
	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()).
//
433
void QOutputDevPixmap::doFill ( GfxState *state, bool winding )
434 435
{
	QPointArray points;
436
	QMemArray<int> lengths;
437 438 439 440 441

	// transform points
	int n = convertPath ( state, points, lengths );

	QPDFDBG( printf ( "FILLING: %d POLYS\n", n ));
442

443 444
	QPen oldpen = m_painter-> pen ( );
	m_painter-> setPen ( QPen ( Qt::NoPen ));
445

446 447 448 449
	// draw each subpath
	int j = 0;
	for ( int i = 0; i < n; i++ ) {
		int len = lengths [i];
450

451 452 453 454 455
		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" ));
456

457
			m_painter-> drawPolygon ( points, winding, j, len );
458
		}
459 460 461 462 463 464
		j += len;
	}
	m_painter-> setPen ( oldpen );

}

465
void QOutputDevPixmap::clip ( GfxState *state )
466 467 468 469
{
	doClip ( state, true );
}

470
void QOutputDevPixmap::eoClip ( GfxState *state )
471 472 473 474
{
	doClip ( state, false );
}

475
void QOutputDevPixmap::doClip ( GfxState *state, bool winding )
476 477
{
	QPointArray points;
478
	QMemArray<int> lengths;
479 480 481 482 483

	// transform points
	int n = convertPath ( state, points, lengths );

	QRegion region;
484

485
	QPDFDBG( printf ( "CLIPPING: %d POLYS\n", n ));
486

487 488 489 490
	// draw each subpath
	int j = 0;
	for ( int i = 0; i < n; i++ ) {
		int len = lengths [i];
491 492

		if ( len >= 3 ) {
493 494
			QPointArray dummy;
			dummy. setRawData ( points. data ( ) + j, len );
495

496 497 498
			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" ));
499

500
			region |= QRegion ( dummy, winding );
501

502
			dummy. resetRawData ( points. data ( ) + j, len );
503
		}
504 505
		j += len;
	}
506

507 508 509 510 511
	if ( m_painter-> hasClipping ( ))
		region &= m_painter-> clipRegion ( );

//	m_painter-> setClipRegion ( region );
//	m_painter-> setClipping ( true );
512

513 514 515 516 517 518 519 520 521 522 523 524 525
//	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 <fillHack> 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).
//
526
int QOutputDevPixmap::convertPath ( GfxState *state, QPointArray &points, QMemArray<int> &lengths ) 
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
{
	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 QOutputDevPixmap::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;
554

555 556 557 558 559 560
	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 );
561

562 563 564 565 566 567
			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 ( );
568

569 570 571 572 573 574
			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 ( );
575
			points. putPoints ( points. count ( ), tmp. count ( ), tmp );
576 577 578
#endif

			i += 3;
579
		}
580 581
		else {
			state-> transform ( subpath-> getX ( i ), subpath-> getY ( i ), &x1, &y1 );
582 583

			points. putPoints ( points. count ( ), 1, lrint ( x1 ), lrint ( y1 ));
584 585 586 587 588 589 590
			++i;
		}
	}
	return points. count ( ) - oldcnt;
}


591
void QOutputDevPixmap::beginString ( GfxState *state, GString */*s*/ )
592 593 594 595
{
	m_text-> beginString ( state, state->getCurX(), state->getCurY() );
}

596
void QOutputDevPixmap::endString ( GfxState */*state*/ )
597 598 599 600 601 602
{
	m_text-> endString ( );
}

void QOutputDevPixmap::drawChar ( GfxState *state, fp_t x, fp_t y,
                           fp_t dx, fp_t dy, fp_t originX, fp_t originY,
603
                           CharCode code, Unicode *u, int uLen )
604 605
{
	fp_t x1, y1, dx1, dy1;
606

607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
	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 ( );
624

625 626
		for ( int i = 0; i < uLen; i++ ) {
			QChar c = QChar ( u [i] );
627

628 629 630 631 632 633 634 635
			if ( fm. inFont ( c )) {
				str [i] = QChar ( u [i] );
			}
			else {
				str [i] = ' ';
				QPDFDBG( printf ( "CHARACTER NOT IN FONT: %hx\n", c. unicode ( )));
			}
		}
636

637 638
		if (( uLen == 1 ) && ( str [0] == ' ' ))
			return;
639 640


641
		fp_t m11, m12, m21, m22;
642

643 644 645
		state-> getFontTransMat ( &m11, &m12, &m21, &m22 );
		m11 *= state-> getHorizScaling ( );
		m12 *= state-> getHorizScaling ( );
646

647 648 649 650 651
		fp_t fsize = m_painter-> font ( ). pixelSize ( );

#ifndef QT_NO_TRANSFORMATIONS
		QWMatrix oldmat;

652 653 654
		bool dorot = (( m12 < -0.1 ) || ( m12 > 0.1 )) && (( m21 < -0.1 ) || ( m21 > 0.1 ));

		if ( dorot ) {
655 656 657
			oldmat = m_painter-> worldMatrix ( );

			// std::cerr << std::endl << "ROTATED: " << m11 << ", " << m12 << ", " << m21 << ", " << m22 << " / SIZE: " << fsize << " / TEXT: " << str. local8Bit ( ) << endl << endl;
658

659
			QWMatrix mat ( lrint ( m11 / fsize ), lrint ( m12 / fsize ), -lrint ( m21 / fsize ), -lrint ( m22 / fsize ), lrint ( x1 ), lrint ( y1 ));
660

661 662 663
			m_painter-> setWorldMatrix ( mat );

			x1 = 0;
664
			y1 = 0;
665 666
		}
#endif
667

668
		QPen oldpen = m_painter-> pen ( );
669

670 671
		if (!( state-> getRender ( ) & 1 )) {
			QPen fillpen = oldpen;
672

673 674
			fillpen. setColor ( m_painter-> brush ( ). color ( ));
			m_painter-> setPen ( fillpen );
675
		}
676 677 678 679 680

		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 ( ));
681

682
		m_painter-> setPen ( oldpen );
683

684 685 686
#ifndef QT_NO_TRANSFORMATIONS
		if ( dorot )
			m_painter-> setWorldMatrix ( oldmat );
687 688
#endif

689
		QPDFDBG( printf ( "DRAW TEXT: \"%s\" at (%ld/%ld)\n", str. local8Bit ( ). data ( ), lrint ( x1 ), lrint ( y1 )));
690
	}
691 692 693 694 695 696 697 698
	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 ));
	}
}



699
void QOutputDevPixmap::drawImageMask ( GfxState *state, Object */*ref*/, Stream *str, int width, int height, GBool invert, GBool inlineImg )
700 701 702
{
	// get CTM, check for singular matrix
	fp_t *ctm = state-> getCTM ( );
703

704 705
	if ( fabs ( ctm [0] * ctm [3] - ctm [1] * ctm [2] ) < 0.000001 ) {
		qWarning ( "Singular CTM in drawImage\n" );
706

707 708 709 710 711 712 713 714 715 716
		if ( inlineImg ) {
			str-> reset ( );
			int j = height * (( width + 7 ) / 8 );
			for ( int i = 0; i < j; i++ )
				str->getChar();

			str->close();
		}
		return;
	}
717 718

	GfxRGB rgb;
719 720
	state-> getFillRGB ( &rgb );
	uint val = ( lrint ( rgb. r * 255 ) & 0xff ) << 16 | ( lrint ( rgb. g * 255 ) & 0xff ) << 8 | ( lrint ( rgb. b * 255 ) & 0xff );
721 722 723


	QImage img ( width, height, 32 );
724 725 726 727 728 729 730 731 732
	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 ( );
733

734 735
	if ( ctm [3] > 0 )
		scanlines += ( height - 1 );
736

737 738
	for ( int y = 0; y < height; y++ ) {
		QRgb *scanline = (QRgb *) *scanlines;
739

740 741
		if ( ctm [0] < 0 )
			scanline += ( width - 1 );
742

743 744
		for ( int x = 0; x < width; x++ ) {
			Guchar alpha;
745

746
			imgStr-> getPixel ( &alpha );
747

748 749
			if ( invert )
				alpha ^= 1;
750

751
			*scanline = ( alpha == 0 ) ? 0xff000000 | val : val;
752

753 754 755 756
			ctm [0] < 0 ? scanline-- : scanline++;
		}
		ctm [3] > 0 ? scanlines-- : scanlines++;
	}
757 758

#ifndef QT_NO_TRANSFORMATIONS
759
	QWMatrix mat ( ctm [0] / width, ctm [1], ctm [2], ctm [3] / height, ctm [4], ctm [5] );
760 761

	//std::cerr << "MATRIX T=" << mat. dx ( ) << "/" << mat. dy ( ) << std::endl
762
	//         << " - M=" << mat. m11 ( ) << "/" << mat. m12 ( ) << "/" << mat. m21 ( ) << "/" << mat. m22 ( ) << std::endl;
763

764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
	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] );
784

785 786
		int w = lrint ( ctm [0] );
		int h = lrint ( ctm [3] );
787

788 789 790 791 792 793 794 795
		if ( w < 0 ) {
			x += w;
			w = -w;
		}
		if ( h < 0 ) {
			y += h;
			h = -h;
		}
796

797 798 799 800 801 802 803
		QPDFDBG( printf ( "DRAWING IMAGE MASKED: %d/%d - %dx%d\n", x, y, w, h ));

		img = img. smoothScale ( w, h );
		m_painter-> drawImage ( x, y, img );
	}

#endif
804 805

	delete imgStr;
806 807 808
}


809
void QOutputDevPixmap::drawImage(GfxState *state, Object */*ref*/, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg )
810 811
{
	int nComps, nVals, nBits;
812

813 814 815 816 817 818 819
	// image parameters
	nComps = colorMap->getNumPixelComps ( );
	nVals = width * nComps;
	nBits = colorMap-> getBits ( );

	// get CTM, check for singular matrix
	fp_t *ctm = state-> getCTM ( );
820

821 822
	if ( fabs ( ctm [0] * ctm [3] - ctm [1] * ctm [2] ) < 0.000001 ) {
		qWarning ( "Singular CTM in drawImage\n" );
823

824 825 826 827 828 829 830 831 832 833 834 835
		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 );
836

837 838 839 840 841 842 843 844 845 846 847
	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;
848

849 850

	uchar **scanlines = img. jumpTable ( );
851

852 853
	if ( ctm [3] > 0 )
		scanlines += ( height - 1 );
854

855 856
	for ( int y = 0; y < height; y++ ) {
		QRgb *scanline = (QRgb *) *scanlines;
857

858 859
		if ( ctm [0] < 0 )
			scanline += ( width - 1 );
860

861 862 863
		for ( int x = 0; x < width; x++ ) {
			imgStr-> getPixel ( pixBuf );
			colorMap-> getRGB ( pixBuf, &rgb );
864

865
			uint val = ( lrint ( rgb. r * 255 ) & 0xff ) << 16 | ( lrint ( rgb. g * 255 ) & 0xff ) << 8 | ( lrint ( rgb. b * 255 ) & 0xff );
866

867 868
			if ( maskColors ) {
				for ( int k = 0; k < nComps; ++k ) {
869
					if (( pixBuf [k] < maskColors [2 * k] ) || ( pixBuf [k] > maskColors [2 * k] )) {
870 871 872 873 874 875
						val |= 0xff000000;
						break;
					}
				}
			}
			*scanline = val;
876

877 878 879
			ctm [0] < 0 ? scanline-- : scanline++;
		}
		ctm [3] > 0 ? scanlines-- : scanlines++;
880

881 882 883
	}


884
#ifndef QT_NO_TRANSFORMATIONS
885 886
	QWMatrix mat ( ctm [0] / width, ctm [1], ctm [2], ctm [3] / height, ctm [4], ctm [5] );

887
	// std::cerr << "MATRIX T=" << mat. dx ( ) << "/" << mat. dy ( ) << std::endl
888 889 890 891 892 893 894 895 896
	//          << " - 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 );
897 898
#else
	m_painter-> drawImage ( QPoint ( 0, 0 ), img );
899 900 901 902 903 904 905 906 907 908 909 910
#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] );
911

912 913
		int w = lrint ( ctm [0] );
		int h = lrint ( ctm [3] );
914

915 916 917 918 919 920 921 922
		if ( w < 0 ) {
			x += w;
			w = -w;
		}
		if ( h < 0 ) {
			y += h;
			h = -h;
		}
923

924 925
		QPDFDBG( printf ( "DRAWING IMAGE: %d/%d - %dx%d\n", x, y, w, h ));

926
		img = img. smoothScale ( w, h );
927 928
		m_painter-> drawImage ( x, y, img );
	}
929

930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
#endif


	delete imgStr;
}



bool QOutputDevPixmap::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 QOutputDevPixmap::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];
954

955 956 957 958 959 960 961 962
	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;

963
	if ( m_text-> findText ( s, len, top, bottom, &x1, &y1, &x2, &y2 )) {
964 965 966 967 968 969 970
		l = lrint ( x1 );
		t = lrint ( y1 );
		w = lrint ( x2 ) - l + 1;
		h = lrint ( y2 ) - t + 1;
		found = true;
	}
	delete [] s;
971

972 973 974 975 976 977 978 979 980 981
	return found;
}

GBool QOutputDevPixmap::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;
982

983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
	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 QOutputDevPixmap::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;
998
	return str;
999