ArthurOutputDev.cc 21.2 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 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 25 26
//
// 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
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
//
//========================================================================

#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>
//------------------------------------------------------------------------

54
#ifdef HAVE_SPLASH
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
#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() {}

  GBool matches(SplashFontFileID *id) {
    return ((SplashOutFontFileID *)id)->r.num == r.num &&
           ((SplashOutFontFileID *)id)->r.gen == r.gen;
  }

private:

  Ref r;
};

83
#endif
84

85 86 87 88 89
//------------------------------------------------------------------------
// ArthurOutputDev
//------------------------------------------------------------------------

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

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

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

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

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

Thomas Freitag's avatar
Thomas Freitag committed
126
void ArthurOutputDev::startPage(int pageNum, GfxState *state, XRef *xref)
127
{
128 129 130 131 132 133 134 135 136 137
  // 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();
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
}

void ArthurOutputDev::endPage() {
}

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

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

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

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

void ArthurOutputDev::updateLineDash(GfxState *state)
{
172 173 174 175 176 177 178 179 180 181 182
  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);
183 184 185 186
}

void ArthurOutputDev::updateFlatness(GfxState *state)
{
187
  // qDebug() << "updateFlatness";
188 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
}

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
224 225
  m_currentPen.setMiterLimit(state->getMiterLimit());
  m_painter->setPen(m_currentPen);
226 227 228 229
}

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

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

void ArthurOutputDev::updateStrokeColor(GfxState *state)
{
  GfxRGB rgb;
  QColor penColour = m_currentPen.color();
  state->getStrokeRGB(&rgb);
248
  penColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), penColour.alphaF());
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
  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)
{
270
#ifdef HAVE_SPLASH
271
  GfxFont *gfxFont;
272
  GfxFontLoc *fontLoc;
273 274 275
  GfxFontType fontType;
  SplashOutFontFileID *id;
  SplashFontFile *fontFile;
276
  SplashFontSrc *fontsrc = NULL;
277 278
  FoFiTrueType *ff;
  Object refObj, strObj;
279
  GooString *fileName;
280 281
  char *tmpBuf;
  int tmpBufLen;
Albert Astals Cid's avatar
Albert Astals Cid committed
282
  int *codeToGID;
283 284
  double *textMat;
  double m11, m12, m21, m22, fontSize;
285
  SplashCoord mat[4];
Albert Astals Cid's avatar
Albert Astals Cid committed
286
  int n;
287
  int faceIndex = 0;
288
  SplashCoord matrix[6];
289 290 291

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

  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 {

311 312 313 314 315 316 317 318 319 320
    if (!(fontLoc = gfxFont->locateFont(xref, gFalse))) {
      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
321 322
      tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen);
      if (! tmpBuf)
323 324
	goto err2;

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

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

464
  // get the font matrix
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
  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();
  }
481

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

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

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

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

  QPainterPath qPath;
509
  qPath.setFillRule(fillRule);
510 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
  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)
{
539
  m_painter->strokePath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentPen );
540 541 542 543
}

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

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

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

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

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

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

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

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

588 589
  // fill
  if (!(render & 1)) {
590 591 592 593 594 595
    SplashPath * fontPath;
    fontPath = m_font->getGlyphPath(code);
    if (fontPath) {
      QPainterPath qPath;
      qPath.setFillRule(Qt::WindingFill);
      for (int i = 0; i < fontPath->length; ++i) {
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
        if (fontPath->flags[i] & splashPathFirst) {
            state->transform(fontPath->pts[i].x+x, -fontPath->pts[i].y+y, &x1, &y1);
            qPath.moveTo(x1,y1);
        } else if (fontPath->flags[i] & splashPathCurve) {
            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);
        }
        if (fontPath->flags[i] & splashPathLast) {
            qPath.closeSubpath();
        }
616
      }
617 618 619
      GfxRGB rgb;
      QColor brushColour = m_currentBrush.color();
      state->getFillRGB(&rgb);
620
      brushColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), state->getFillOpacity());
621 622 623
      m_painter->setBrush(brushColour);
      QColor penColour = m_currentPen.color();
      state->getStrokeRGB(&rgb);
624
      penColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), state->getStrokeOpacity());
625
      m_painter->setPen(penColour);
626
      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

}