ArthurOutputDev.cc 21.5 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
// Copyright (C) 2017 Oliver Sander <oliver.sander@tu-dresden.de>
26 27 28
//
// 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
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
//
//========================================================================

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

56
#ifdef HAVE_SPLASH
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
#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
75
  GBool matches(SplashFontFileID *id) override {
76 77 78 79 80 81 82 83 84
    return ((SplashOutFontFileID *)id)->r.num == r.num &&
           ((SplashOutFontFileID *)id)->r.gen == r.gen;
  }

private:

  Ref r;
};

85
#endif
86

87 88 89 90 91
//------------------------------------------------------------------------
// ArthurOutputDev
//------------------------------------------------------------------------

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

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

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

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

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

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

void ArthurOutputDev::endPage() {
}

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

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

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

161 162 163 164 165 166 167 168
// Set CTM (Current Transformation Matrix) to a fixed matrix
void ArthurOutputDev::setDefaultCTM(double *ctm)
{
  m_painter->setTransform(QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]));
}

// Update the CTM (Current Transformation Matrix), i.e., compose the old
// CTM with a new matrix.
169 170 171 172
void ArthurOutputDev::updateCTM(GfxState *state, double m11, double m12,
				double m21, double m22,
				double m31, double m32)
{
173 174 175 176
  updateLineDash(state);
  updateLineJoin(state);
  updateLineCap(state);
  updateLineWidth(state);
177 178 179 180 181

  QTransform update(m11, m12, m21, m22, m31, m32);

  // We could also set (rather than update) the painter transformation to state->getCMT();
  m_painter->setTransform(update, true);
182 183 184 185
}

void ArthurOutputDev::updateLineDash(GfxState *state)
{
186 187 188 189 190 191 192 193 194 195 196
  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);
197 198 199 200
}

void ArthurOutputDev::updateFlatness(GfxState *state)
{
201
  // qDebug() << "updateFlatness";
202 203 204 205 206 207
}

void ArthurOutputDev::updateLineJoin(GfxState *state)
{
  switch (state->getLineJoin()) {
  case 0:
208 209 210 211
    // The correct style here is Qt::SvgMiterJoin, *not* Qt::MiterJoin.
    // The two differ in what to do if the miter limit is exceeded.
    // See https://bugs.freedesktop.org/show_bug.cgi?id=102356
    m_currentPen.setJoinStyle(Qt::SvgMiterJoin);
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    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
241 242
  m_currentPen.setMiterLimit(state->getMiterLimit());
  m_painter->setPen(m_currentPen);
243 244 245 246
}

void ArthurOutputDev::updateLineWidth(GfxState *state)
{
247
  m_currentPen.setWidthF(state->getLineWidth());
248 249 250 251 252 253 254 255
  m_painter->setPen(m_currentPen);
}

void ArthurOutputDev::updateFillColor(GfxState *state)
{
  GfxRGB rgb;
  QColor brushColour = m_currentBrush.color();
  state->getFillRGB(&rgb);
256
  brushColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), brushColour.alphaF());
257 258 259 260 261 262 263 264
  m_currentBrush.setColor(brushColour);
}

void ArthurOutputDev::updateStrokeColor(GfxState *state)
{
  GfxRGB rgb;
  QColor penColour = m_currentPen.color();
  state->getStrokeRGB(&rgb);
265
  penColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), penColour.alphaF());
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
  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)
{
287
#ifdef HAVE_SPLASH
288
  GfxFont *gfxFont;
289
  GfxFontLoc *fontLoc;
290 291 292
  GfxFontType fontType;
  SplashOutFontFileID *id;
  SplashFontFile *fontFile;
293
  SplashFontSrc *fontsrc = NULL;
294 295
  FoFiTrueType *ff;
  Object refObj, strObj;
296
  GooString *fileName;
297
  char *tmpBuf;
Albert Astals Cid's avatar
Albert Astals Cid committed
298
  int tmpBufLen = 0;
Albert Astals Cid's avatar
Albert Astals Cid committed
299
  int *codeToGID;
300 301
  double *textMat;
  double m11, m12, m21, m22, fontSize;
302
  SplashCoord mat[4];
Albert Astals Cid's avatar
Albert Astals Cid committed
303
  int n;
304
  int faceIndex = 0;
305
  SplashCoord matrix[6];
306 307 308

  m_needFontUpdate = false;
  m_font = NULL;
309 310
  fileName = NULL;
  tmpBuf = NULL;
311
  fontLoc = NULL;
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327

  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 {

328
    if (!(fontLoc = gfxFont->locateFont(xref, NULL))) {
329 330 331 332 333 334 335 336 337
      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
338 339
      tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen);
      if (! tmpBuf)
340 341
	goto err2;

342 343 344 345
    // external font
    } else { // gfxFontLocExternal
      fileName = fontLoc->path;
      fontType = fontLoc->fontType;
346 347
    }

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

481
  // get the font matrix
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
  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();
  }
498

499 500 501
  // create the scaled font
  mat[0] = m11;  mat[1] = -m12;
  mat[2] = m21;  mat[3] = -m22;
502
  m_font = m_fontEngine->getFont(fontFile, mat, matrix);
503

504
  delete fontLoc;
505 506
  if (fontsrc && !fontsrc->isFile)
      fontsrc->unref();
507 508 509 510
  return;

 err2:
  delete id;
511
  delete fontLoc;
512
 err1:
513 514
  if (fontsrc && !fontsrc->isFile)
      fontsrc->unref();
515
  return;
516
#endif
517 518
}

519
static QPainterPath convertPath(GfxState *state, GfxPath *path, Qt::FillRule fillRule)
520 521 522 523 524
{
  GfxSubpath *subpath;
  int i, j;

  QPainterPath qPath;
525
  qPath.setFillRule(fillRule);
526 527 528
  for (i = 0; i < path->getNumSubpaths(); ++i) {
    subpath = path->getSubpath(i);
    if (subpath->getNumPoints() > 0) {
529
      qPath.moveTo(subpath->getX(0), subpath->getY(0));
530 531 532
      j = 1;
      while (j < subpath->getNumPoints()) {
	if (subpath->getCurve(j)) {
533 534 535
          qPath.cubicTo( subpath->getX(j),   subpath->getY(j),
                         subpath->getX(j+1), subpath->getY(j+1),
                         subpath->getX(j+2), subpath->getY(j+2));
536 537
	  j += 3;
	} else {
538
	  qPath.lineTo(subpath->getX(j), subpath->getY(j));
539 540 541 542 543 544 545 546 547 548 549 550 551
	  ++j;
	}
      }
      if (subpath->isClosed()) {
	qPath.closeSubpath();
      }
    }
  }
  return qPath;
}

void ArthurOutputDev::stroke(GfxState *state)
{
552
  m_painter->strokePath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentPen );
553 554 555 556
}

void ArthurOutputDev::fill(GfxState *state)
{
557
  m_painter->fillPath( convertPath( state, state->getPath(), Qt::WindingFill ), m_currentBrush );
558 559 560 561
}

void ArthurOutputDev::eoFill(GfxState *state)
{
562
  m_painter->fillPath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentBrush );
563 564 565 566
}

void ArthurOutputDev::clip(GfxState *state)
{
567
  m_painter->setClipPath(convertPath( state, state->getPath(), Qt::WindingFill ) );
568 569 570 571
}

void ArthurOutputDev::eoClip(GfxState *state)
{
572
  m_painter->setClipPath(convertPath( state, state->getPath(), Qt::OddEvenFill ) );
573 574
}

575 576 577
void ArthurOutputDev::drawChar(GfxState *state, double x, double y,
			       double dx, double dy,
			       double originX, double originY,
578
			       CharCode code, int nBytes, Unicode *u, int uLen) {
579
#ifdef HAVE_SPLASH
580
//   SplashPath *path;
581 582 583 584 585
  int render;

  if (m_needFontUpdate) {
    updateFont(state);
  }
586 587 588
  if (!m_font) {
    return;
  }
589 590 591 592 593 594 595

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

596 597 598
  x -= originX;
  y -= originY;

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

638 639
  // stroke
  if ((render & 3) == 1 || (render & 3) == 2) {
640 641 642 643 644 645 646 647
    qDebug() << "no stroke";
    /*
    if ((path = m_font->getGlyphPath(code))) {
      path->offset((SplashCoord)x1, (SplashCoord)y1);
      splash->stroke(path);
      delete path;
    }
    */
648 649 650 651
  }

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

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,
694
				    GBool interpolate, GBool inlineImg)
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 756 757 758 759 760 761 762
{
  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);
763
  imgStr->close ();
764 765 766 767 768 769 770 771
  delete imgStr;
#endif
}

//TODO: lots more work here.
void ArthurOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
				int width, int height,
				GfxImageColorMap *colorMap,
772
				GBool interpolate, int *maskColors, GBool inlineImg)
773
{
774 775
  unsigned int *data;
  unsigned int *line;
776 777 778
  int x, y;
  ImageStream *imgStr;
  Guchar *pix;
Krzysztof Kowalczyk's avatar
Krzysztof Kowalczyk committed
779
  int i;
780 781
  QImage image;
  int stride;
782 783 784 785 786 787 788
  
  /* TODO: Do we want to cache these? */
  imgStr = new ImageStream(str, width,
			   colorMap->getNumPixelComps(),
			   colorMap->getBits());
  imgStr->reset();
  
789 790 791 792 793
  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();
794 795 796
    // Invert the vertical coordinate: y is increasing from top to bottom
    // on the page, but y is increasing bottom to top in the picture.
    line = data+(height-1-y)*stride;
797
    colorMap->getRGBLine(pix, line, width);
798

799
    if (maskColors) {
800
      for (x = 0; x < width; x++) {
801 802 803 804 805 806 807 808 809
        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++;
810
      }
811 812
    } else {
      for (x = 0; x < width; x++) { *line = *line | 0xff000000; line++; }
813 814 815
    }
  }

816 817 818
  // At this point, the QPainter coordinate transformation (CTM) is such
  // that QRect(0,0,1,1) is exactly the area of the image.
  m_painter->drawImage( QRect(0,0,1,1), image );
819
  delete imgStr;
820 821

}