ArthurOutputDev.cc 21.1 KB
Newer Older
1 2 3 4 5
//========================================================================
//
// ArthurOutputDev.cc
//
// Copyright 2003 Glyph & Cog, LLC
6 7 8 9 10 11 12
//
//========================================================================

//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
13 14 15
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
16
// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
17
// Copyright (C) 2005-2009, 2011, 2012, 2014, 2015 Albert Astals Cid <aacid@kde.org>
Pino Toscano's avatar
Pino Toscano committed
18
// Copyright (C) 2008, 2010 Pino Toscano <pino@kde.org>
Albert Astals Cid's avatar
Albert Astals Cid committed
19
// Copyright (C) 2009, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
20
// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
21
// Copyright (C) 2010 Matthias Fauconneau <matthias.fauconneau@gmail.com>
22
// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
Thomas Freitag's avatar
Thomas Freitag committed
23
// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
24
// Copyright (C) 2013 Dominik Haumann <dhaumann@kde.org>
25 26 27
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
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
//
//========================================================================

#include <config.h>

#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif

#include <string.h>
#include <math.h>

#include "goo/gfile.h"
#include "GlobalParams.h"
#include "Error.h"
#include "Object.h"
#include "GfxState.h"
#include "GfxFont.h"
#include "Link.h"
#include "FontEncodingTables.h"
#include <fofi/FoFiTrueType.h>
#include "ArthurOutputDev.h"

#include <QtCore/QtDebug>
#include <QtGui/QPainterPath>
//------------------------------------------------------------------------

55
#ifdef HAVE_SPLASH
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
#include "splash/SplashFontFileID.h"
#include "splash/SplashFontFile.h"
#include "splash/SplashFontEngine.h"
#include "splash/SplashFont.h"
#include "splash/SplashMath.h"
#include "splash/SplashPath.h"
#include "splash/SplashGlyphBitmap.h"
//------------------------------------------------------------------------
// SplashOutFontFileID
//------------------------------------------------------------------------

class SplashOutFontFileID: public SplashFontFileID {
public:

  SplashOutFontFileID(Ref *rA) { r = *rA; }

  ~SplashOutFontFileID() {}

Albert Astals Cid's avatar
Albert Astals Cid committed
74
  GBool matches(SplashFontFileID *id) override {
75 76 77 78 79 80 81 82 83
    return ((SplashOutFontFileID *)id)->r.num == r.num &&
           ((SplashOutFontFileID *)id)->r.gen == r.gen;
  }

private:

  Ref r;
};

84
#endif
85

86 87 88 89 90
//------------------------------------------------------------------------
// ArthurOutputDev
//------------------------------------------------------------------------

ArthurOutputDev::ArthurOutputDev(QPainter *painter):
91 92
  m_painter(painter),
  m_fontHinting(NoHinting)
93 94
{
  m_currentBrush = QBrush(Qt::SolidPattern);
95
  m_fontEngine = 0;
96
  m_font = 0;
97 98 99 100
}

ArthurOutputDev::~ArthurOutputDev()
{
101
#ifdef HAVE_SPLASH
102
  delete m_fontEngine;
103
#endif
104 105 106
}

void ArthurOutputDev::startDoc(XRef *xrefA) {
107
  xref = xrefA;
108
#ifdef HAVE_SPLASH
Krzysztof Kowalczyk's avatar
Krzysztof Kowalczyk committed
109
  delete m_fontEngine;
110 111 112 113

  const bool isHintingEnabled = m_fontHinting != NoHinting;
  const bool isSlightHinting = m_fontHinting == SlightHinting;

114 115
  m_fontEngine = new SplashFontEngine(
#if HAVE_T1LIB_H
Krzysztof Kowalczyk's avatar
Krzysztof Kowalczyk committed
116
  globalParams->getEnableT1lib(),
117 118
#endif
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
Krzysztof Kowalczyk's avatar
Krzysztof Kowalczyk committed
119
  globalParams->getEnableFreeType(),
120 121
  isHintingEnabled,
  isSlightHinting,
122
#endif
123
  m_painter->testRenderHint(QPainter::TextAntialiasing));
124
#endif
125 126
}

Thomas Freitag's avatar
Thomas Freitag committed
127
void ArthurOutputDev::startPage(int pageNum, GfxState *state, XRef *xref)
128
{
129 130 131 132 133 134 135 136 137 138
  // fill page with white background.
  int w = static_cast<int>(state->getPageWidth());
  int h = static_cast<int>(state->getPageHeight());
  QColor fillColour(Qt::white);
  QBrush fill(fillColour);
  m_painter->save();
  m_painter->setPen(fillColour);
  m_painter->setBrush(fill);
  m_painter->drawRect(0, 0, w, h);
  m_painter->restore();
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
}

void ArthurOutputDev::endPage() {
}

void ArthurOutputDev::saveState(GfxState *state)
{
  m_painter->save();
}

void ArthurOutputDev::restoreState(GfxState *state)
{
  m_painter->restore();
}

void ArthurOutputDev::updateAll(GfxState *state)
{
156
  OutputDev::updateAll(state);
157 158 159 160
  m_needFontUpdate = gTrue;
}

// This looks wrong - why aren't adjusting the matrix?
161 162 163 164
void ArthurOutputDev::updateCTM(GfxState *state, double m11, double m12,
				double m21, double m22,
				double m31, double m32)
{
165 166 167 168
  updateLineDash(state);
  updateLineJoin(state);
  updateLineCap(state);
  updateLineWidth(state);
169 170 171 172
}

void ArthurOutputDev::updateLineDash(GfxState *state)
{
173 174 175 176 177 178 179 180 181 182 183
  double *dashPattern;
  int dashLength;
  double dashStart;
  state->getLineDash(&dashPattern, &dashLength, &dashStart);
  QVector<qreal> pattern(dashLength);
  for (int i = 0; i < dashLength; ++i) {
    pattern[i] = dashPattern[i];
  }
  m_currentPen.setDashPattern(pattern);
  m_currentPen.setDashOffset(dashStart);
  m_painter->setPen(m_currentPen);
184 185 186 187
}

void ArthurOutputDev::updateFlatness(GfxState *state)
{
188
  // qDebug() << "updateFlatness";
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
}

void ArthurOutputDev::updateLineJoin(GfxState *state)
{
  switch (state->getLineJoin()) {
  case 0:
    m_currentPen.setJoinStyle(Qt::MiterJoin);
    break;
  case 1:
    m_currentPen.setJoinStyle(Qt::RoundJoin);
    break;
  case 2:
    m_currentPen.setJoinStyle(Qt::BevelJoin);
    break;
  }
  m_painter->setPen(m_currentPen);
}

void ArthurOutputDev::updateLineCap(GfxState *state)
{
  switch (state->getLineCap()) {
  case 0:
    m_currentPen.setCapStyle(Qt::FlatCap);
    break;
  case 1:
    m_currentPen.setCapStyle(Qt::RoundCap);
    break;
  case 2:
    m_currentPen.setCapStyle(Qt::SquareCap);
    break;
  }
  m_painter->setPen(m_currentPen);
}

void ArthurOutputDev::updateMiterLimit(GfxState *state)
{
Pino Toscano's avatar
Pino Toscano committed
225 226
  m_currentPen.setMiterLimit(state->getMiterLimit());
  m_painter->setPen(m_currentPen);
227 228 229 230
}

void ArthurOutputDev::updateLineWidth(GfxState *state)
{
231
  m_currentPen.setWidthF(state->getLineWidth());
232 233 234 235 236 237 238 239
  m_painter->setPen(m_currentPen);
}

void ArthurOutputDev::updateFillColor(GfxState *state)
{
  GfxRGB rgb;
  QColor brushColour = m_currentBrush.color();
  state->getFillRGB(&rgb);
240
  brushColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), brushColour.alphaF());
241 242 243 244 245 246 247 248
  m_currentBrush.setColor(brushColour);
}

void ArthurOutputDev::updateStrokeColor(GfxState *state)
{
  GfxRGB rgb;
  QColor penColour = m_currentPen.color();
  state->getStrokeRGB(&rgb);
249
  penColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), penColour.alphaF());
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
  m_currentPen.setColor(penColour);
  m_painter->setPen(m_currentPen);
}

void ArthurOutputDev::updateFillOpacity(GfxState *state)
{
  QColor brushColour= m_currentBrush.color();
  brushColour.setAlphaF(state->getFillOpacity());
  m_currentBrush.setColor(brushColour);
}

void ArthurOutputDev::updateStrokeOpacity(GfxState *state)
{
  QColor penColour= m_currentPen.color();
  penColour.setAlphaF(state->getStrokeOpacity());
  m_currentPen.setColor(penColour);
  m_painter->setPen(m_currentPen);
}

void ArthurOutputDev::updateFont(GfxState *state)
{
271
#ifdef HAVE_SPLASH
272
  GfxFont *gfxFont;
273
  GfxFontLoc *fontLoc;
274 275 276
  GfxFontType fontType;
  SplashOutFontFileID *id;
  SplashFontFile *fontFile;
277
  SplashFontSrc *fontsrc = NULL;
278 279
  FoFiTrueType *ff;
  Object refObj, strObj;
280
  GooString *fileName;
281
  char *tmpBuf;
Albert Astals Cid's avatar
Albert Astals Cid committed
282
  int tmpBufLen = 0;
Albert Astals Cid's avatar
Albert Astals Cid committed
283
  int *codeToGID;
284 285
  double *textMat;
  double m11, m12, m21, m22, fontSize;
286
  SplashCoord mat[4];
Albert Astals Cid's avatar
Albert Astals Cid committed
287
  int n;
288
  int faceIndex = 0;
289
  SplashCoord matrix[6];
290 291 292

  m_needFontUpdate = false;
  m_font = NULL;
293 294
  fileName = NULL;
  tmpBuf = NULL;
295
  fontLoc = NULL;
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311

  if (!(gfxFont = state->getFont())) {
    goto err1;
  }
  fontType = gfxFont->getType();
  if (fontType == fontType3) {
    goto err1;
  }

  // check the font file cache
  id = new SplashOutFontFileID(gfxFont->getID());
  if ((fontFile = m_fontEngine->getFontFile(id))) {
    delete id;

  } else {

312
    if (!(fontLoc = gfxFont->locateFont(xref, NULL))) {
313 314 315 316 317 318 319 320 321
      error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
	    gfxFont->getName() ? gfxFont->getName()->getCString()
	                       : "(unnamed)");
      goto err2;
    }

    // embedded font
    if (fontLoc->locType == gfxFontLocEmbedded) {
      // if there is an embedded font, read it to memory
322 323
      tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen);
      if (! tmpBuf)
324 325
	goto err2;

326 327 328 329
    // external font
    } else { // gfxFontLocExternal
      fileName = fontLoc->path;
      fontType = fontLoc->fontType;
330 331
    }

332 333 334 335
    fontsrc = new SplashFontSrc;
    if (fileName)
      fontsrc->setFile(fileName, gFalse);
    else
336
      fontsrc->setBuf(tmpBuf, tmpBufLen, gTrue);
337
    
338 339 340 341 342
    // load the font file
    switch (fontType) {
    case fontType1:
      if (!(fontFile = m_fontEngine->loadType1Font(
			   id,
343
			   fontsrc,
344
			   (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
345
	error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
346 347 348 349 350 351 352 353
	      gfxFont->getName() ? gfxFont->getName()->getCString()
	                         : "(unnamed)");
	goto err2;
      }
      break;
    case fontType1C:
      if (!(fontFile = m_fontEngine->loadType1CFont(
			   id,
354
			   fontsrc,
355
			   (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
356
	error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
357 358 359 360 361
	      gfxFont->getName() ? gfxFont->getName()->getCString()
	                         : "(unnamed)");
	goto err2;
      }
      break;
362 363 364 365
    case fontType1COT:
      if (!(fontFile = m_fontEngine->loadOpenTypeT1CFont(
			   id,
			   fontsrc,
366
			   (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) {
367
	error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
368 369
	      gfxFont->getName() ? gfxFont->getName()->getCString()
	                         : "(unnamed)");
370 371
	goto err2;
      }
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
      break;
    case fontTrueType:
    case fontTrueTypeOT:
	if (fileName)
	 ff = FoFiTrueType::load(fileName->getCString());
	else
	ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
      if (ff) {
	codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
	n = 256;
	delete ff;
      } else {
	codeToGID = NULL;
	n = 0;
      }
387 388
      if (!(fontFile = m_fontEngine->loadTrueTypeFont(
			   id,
389
			   fontsrc,
390
			   codeToGID, n))) {
391
	error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
392 393 394 395 396 397 398 399 400
	      gfxFont->getName() ? gfxFont->getName()->getCString()
	                         : "(unnamed)");
	goto err2;
      }
      break;
    case fontCIDType0:
    case fontCIDType0C:
      if (!(fontFile = m_fontEngine->loadCIDFont(
			   id,
401
			   fontsrc))) {
402
	error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
403 404 405 406 407
	      gfxFont->getName() ? gfxFont->getName()->getCString()
	                         : "(unnamed)");
	goto err2;
      }
      break;
408
    case fontCIDType0COT:
Albert Astals Cid's avatar
Albert Astals Cid committed
409 410 411 412 413 414 415 416 417
      if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
	n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
	codeToGID = (int *)gmallocn(n, sizeof(int));
	memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
	       n * sizeof(int));
      } else {
	codeToGID = NULL;
	n = 0;
      }      
418 419
      if (!(fontFile = m_fontEngine->loadOpenTypeCFFFont(
			   id,
Albert Astals Cid's avatar
Albert Astals Cid committed
420 421
			   fontsrc,
			   codeToGID, n))) {
422
	error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
423 424 425 426 427
	      gfxFont->getName() ? gfxFont->getName()->getCString()
	                         : "(unnamed)");
	goto err2;
      }
      break;
428
    case fontCIDType2:
429 430 431 432 433 434
    case fontCIDType2OT:
      codeToGID = NULL;
      n = 0;
      if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
	n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
	if (n) {
Albert Astals Cid's avatar
Albert Astals Cid committed
435
	  codeToGID = (int *)gmallocn(n, sizeof(int));
436 437 438 439 440 441 442 443 444 445 446 447 448
	  memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
		  n * sizeof(Gushort));
	}
      } else {
	if (fileName)
	  ff = FoFiTrueType::load(fileName->getCString());
	else
	  ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
	if (! ff)
	  goto err2;
	codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n);
	delete ff;
      }
449 450
      if (!(fontFile = m_fontEngine->loadTrueTypeFont(
			   id,
451
			   fontsrc,
452
			   codeToGID, n, faceIndex))) {
453
	error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
454 455 456 457 458 459 460 461 462 463
	      gfxFont->getName() ? gfxFont->getName()->getCString()
	                         : "(unnamed)");
	goto err2;
      }
      break;
    default:
      // this shouldn't happen
      goto err2;
    }
  }
464

465
  // get the font matrix
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
  textMat = state->getTextMat();
  fontSize = state->getFontSize();
  m11 = textMat[0] * fontSize * state->getHorizScaling();
  m12 = textMat[1] * fontSize * state->getHorizScaling();
  m21 = textMat[2] * fontSize;
  m22 = textMat[3] * fontSize;

  {
  QMatrix painterMatrix = m_painter->worldMatrix();
  matrix[0] = painterMatrix.m11();
  matrix[1] = painterMatrix.m12();
  matrix[2] = painterMatrix.m21();
  matrix[3] = painterMatrix.m22();
  matrix[4] = painterMatrix.dx();
  matrix[5] = painterMatrix.dy();
  }
482

483 484 485
  // create the scaled font
  mat[0] = m11;  mat[1] = -m12;
  mat[2] = m21;  mat[3] = -m22;
486
  m_font = m_fontEngine->getFont(fontFile, mat, matrix);
487

488
  delete fontLoc;
489 490
  if (fontsrc && !fontsrc->isFile)
      fontsrc->unref();
491 492 493 494
  return;

 err2:
  delete id;
495
  delete fontLoc;
496
 err1:
497 498
  if (fontsrc && !fontsrc->isFile)
      fontsrc->unref();
499
  return;
500
#endif
501 502
}

503
static QPainterPath convertPath(GfxState *state, GfxPath *path, Qt::FillRule fillRule)
504 505 506 507 508 509
{
  GfxSubpath *subpath;
  double x1, y1, x2, y2, x3, y3;
  int i, j;

  QPainterPath qPath;
510
  qPath.setFillRule(fillRule);
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
  for (i = 0; i < path->getNumSubpaths(); ++i) {
    subpath = path->getSubpath(i);
    if (subpath->getNumPoints() > 0) {
      state->transform(subpath->getX(0), subpath->getY(0), &x1, &y1);
      qPath.moveTo(x1, y1);
      j = 1;
      while (j < subpath->getNumPoints()) {
	if (subpath->getCurve(j)) {
	  state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
	  state->transform(subpath->getX(j+1), subpath->getY(j+1), &x2, &y2);
	  state->transform(subpath->getX(j+2), subpath->getY(j+2), &x3, &y3);
	  qPath.cubicTo( x1, y1, x2, y2, x3, y3);
	  j += 3;
	} else {
	  state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
	  qPath.lineTo(x1, y1);
	  ++j;
	}
      }
      if (subpath->isClosed()) {
	qPath.closeSubpath();
      }
    }
  }
  return qPath;
}

void ArthurOutputDev::stroke(GfxState *state)
{
540
  m_painter->strokePath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentPen );
541 542 543 544
}

void ArthurOutputDev::fill(GfxState *state)
{
545
  m_painter->fillPath( convertPath( state, state->getPath(), Qt::WindingFill ), m_currentBrush );
546 547 548 549
}

void ArthurOutputDev::eoFill(GfxState *state)
{
550
  m_painter->fillPath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentBrush );
551 552 553 554
}

void ArthurOutputDev::clip(GfxState *state)
{
555
  m_painter->setClipPath(convertPath( state, state->getPath(), Qt::WindingFill ) );
556 557 558 559
}

void ArthurOutputDev::eoClip(GfxState *state)
{
560
  m_painter->setClipPath(convertPath( state, state->getPath(), Qt::OddEvenFill ) );
561 562
}

563 564 565
void ArthurOutputDev::drawChar(GfxState *state, double x, double y,
			       double dx, double dy,
			       double originX, double originY,
566
			       CharCode code, int nBytes, Unicode *u, int uLen) {
567
#ifdef HAVE_SPLASH
568
  double x1, y1;
569
  double x2, y2;
570
//   SplashPath *path;
571 572 573 574 575
  int render;

  if (m_needFontUpdate) {
    updateFont(state);
  }
576 577 578
  if (!m_font) {
    return;
  }
579 580 581 582 583 584 585

  // check for invisible text -- this is used by Acrobat Capture
  render = state->getRender();
  if (render == 3) {
    return;
  }

586 587 588
  x -= originX;
  y -= originY;

589 590
  // fill
  if (!(render & 1)) {
591 592 593 594 595 596
    SplashPath * fontPath;
    fontPath = m_font->getGlyphPath(code);
    if (fontPath) {
      QPainterPath qPath;
      qPath.setFillRule(Qt::WindingFill);
      for (int i = 0; i < fontPath->length; ++i) {
597 598 599 600
        // SplashPath.flags: bitwise or allowed
        if (fontPath->flags[i] & splashPathLast || fontPath->flags[i] & splashPathClosed) {
            qPath.closeSubpath();
        }
601 602 603
        if (fontPath->flags[i] & splashPathFirst) {
            state->transform(fontPath->pts[i].x+x, -fontPath->pts[i].y+y, &x1, &y1);
            qPath.moveTo(x1,y1);
604 605
        }
        if (fontPath->flags[i] & splashPathCurve) {
606 607 608 609 610 611 612 613 614 615 616 617 618
            state->transform(fontPath->pts[i].x+x, -fontPath->pts[i].y+y, &x1, &y1);
            state->transform(fontPath->pts[i+1].x+x, -fontPath->pts[i+1].y+y, &x2, &y2);
            qPath.quadTo(x1,y1,x2,y2);
            ++i;
        }
        // FIXME fix this
        // 	else if (fontPath->flags[i] & splashPathArcCW) {
        // 	  qDebug() << "Need to implement arc";
        // 	}
        else {
            state->transform(fontPath->pts[i].x+x, -fontPath->pts[i].y+y, &x1, &y1);
            qPath.lineTo(x1,y1);
        }
619
      }
620 621 622
      GfxRGB rgb;
      QColor brushColour = m_currentBrush.color();
      state->getFillRGB(&rgb);
623
      brushColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), state->getFillOpacity());
624
      m_painter->setBrush(brushColour);
625 626
      m_painter->setPen(Qt::NoPen);
      m_painter->drawPath(qPath);
627
      delete fontPath;
628
    }
629
  }
630

631 632
  // stroke
  if ((render & 3) == 1 || (render & 3) == 2) {
633 634 635 636 637 638 639 640
    qDebug() << "no stroke";
    /*
    if ((path = m_font->getGlyphPath(code))) {
      path->offset((SplashCoord)x1, (SplashCoord)y1);
      splash->stroke(path);
      delete path;
    }
    */
641 642 643 644
  }

  // clip
  if (render & 4) {
645 646 647 648 649 650 651 652 653 654 655
    qDebug() << "no clip";
    /*
    path = m_font->getGlyphPath(code);
    path->offset((SplashCoord)x1, (SplashCoord)y1);
    if (textClipPath) {
      textClipPath->append(path);
      delete path;
    } else {
      textClipPath = path;
    }
    */
656
  }
657
#endif
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
}

GBool ArthurOutputDev::beginType3Char(GfxState *state, double x, double y,
				      double dx, double dy,
				      CharCode code, Unicode *u, int uLen)
{
  return gFalse;
}

void ArthurOutputDev::endType3Char(GfxState *state)
{
}

void ArthurOutputDev::type3D0(GfxState *state, double wx, double wy)
{
}

void ArthurOutputDev::type3D1(GfxState *state, double wx, double wy,
			      double llx, double lly, double urx, double ury)
{
}

void ArthurOutputDev::endTextObject(GfxState *state)
{
}


void ArthurOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
				    int width, int height, GBool invert,
687
				    GBool interpolate, GBool inlineImg)
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
{
  qDebug() << "drawImageMask";
#if 0
  unsigned char *buffer;
  unsigned char *dest;
  cairo_surface_t *image;
  cairo_pattern_t *pattern;
  int x, y;
  ImageStream *imgStr;
  Guchar *pix;
  double *ctm;
  cairo_matrix_t matrix;
  int invert_bit;
  int row_stride;

  row_stride = (width + 3) & ~3;
  buffer = (unsigned char *) malloc (height * row_stride);
  if (buffer == NULL) {
    error(-1, "Unable to allocate memory for image.");
    return;
  }

  /* TODO: Do we want to cache these? */
  imgStr = new ImageStream(str, width, 1, 1);
  imgStr->reset();

  invert_bit = invert ? 1 : 0;

  for (y = 0; y < height; y++) {
    pix = imgStr->getLine();
    dest = buffer + y * row_stride;
    for (x = 0; x < width; x++) {

      if (pix[x] ^ invert_bit)
	*dest++ = 0;
      else
	*dest++ = 255;
    }
  }

  image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_A8,
					  width, height, row_stride);
  if (image == NULL)
    return;
  pattern = cairo_pattern_create_for_surface (image);
  if (pattern == NULL)
    return;

  ctm = state->getCTM();
  LOG (printf ("drawImageMask %dx%d, matrix: %f, %f, %f, %f, %f, %f\n",
	       width, height, ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]));
  matrix.xx = ctm[0] / width;
  matrix.xy = -ctm[2] / height;
  matrix.yx = ctm[1] / width;
  matrix.yy = -ctm[3] / height;
  matrix.x0 = ctm[2] + ctm[4];
  matrix.y0 = ctm[3] + ctm[5];
  cairo_matrix_invert (&matrix);
  cairo_pattern_set_matrix (pattern, &matrix);

  cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST);
  /* FIXME: Doesn't the image mask support any colorspace? */
  cairo_set_source_rgb (cairo, fill_color.r, fill_color.g, fill_color.b);
  cairo_mask (cairo, pattern);

  cairo_pattern_destroy (pattern);
  cairo_surface_destroy (image);
  free (buffer);
756
  imgStr->close ();
757 758 759 760 761 762 763 764
  delete imgStr;
#endif
}

//TODO: lots more work here.
void ArthurOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
				int width, int height,
				GfxImageColorMap *colorMap,
765
				GBool interpolate, int *maskColors, GBool inlineImg)
766
{
767 768
  unsigned int *data;
  unsigned int *line;
769 770 771
  int x, y;
  ImageStream *imgStr;
  Guchar *pix;
Krzysztof Kowalczyk's avatar
Krzysztof Kowalczyk committed
772
  int i;
773 774
  double *ctm;
  QMatrix matrix;
775 776
  QImage image;
  int stride;
777 778 779 780 781 782 783
  
  /* TODO: Do we want to cache these? */
  imgStr = new ImageStream(str, width,
			   colorMap->getNumPixelComps(),
			   colorMap->getBits());
  imgStr->reset();
  
784 785 786 787 788 789 790
  image = QImage(width, height, QImage::Format_ARGB32);
  data = (unsigned int *)image.bits();
  stride = image.bytesPerLine()/4;
  for (y = 0; y < height; y++) {
    pix = imgStr->getLine();
    line = data+y*stride;
    colorMap->getRGBLine(pix, line, width);
791

792
    if (maskColors) {
793
      for (x = 0; x < width; x++) {
794 795 796 797 798 799 800 801 802
        for (i = 0; i < colorMap->getNumPixelComps(); ++i) {
            if (pix[i] < maskColors[2*i] * 255||
                pix[i] > maskColors[2*i+1] * 255) {
                *line = *line | 0xff000000;
                break;
            }
        }
        pix += colorMap->getNumPixelComps();
        line++;
803
      }
804 805
    } else {
      for (x = 0; x < width; x++) { *line = *line | 0xff000000; line++; }
806 807 808 809
    }
  }

  ctm = state->getCTM();
810
  matrix.setMatrix(ctm[0] / width, ctm[1] / width, -ctm[2] / height, -ctm[3] / height, ctm[2] + ctm[4], ctm[3] + ctm[5]);
811

812
  m_painter->setMatrix(matrix, true);
813
  m_painter->drawImage( QPoint(0,0), image );
814
  delete imgStr;
815 816

}