1
//========================================================================
5
// Copyright 2003 Glyph & Cog, LLC
7
//========================================================================
9
//========================================================================
11
// Modified under the Poppler project - http://poppler.freedesktop.org
13
// All changes made under the Poppler project to this file are licensed
14
// under GPL version 2 or later
16
// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
17
// Copyright (C) 2005-2009 Albert Astals Cid <aacid@kde.org>
18
// Copyright (C) 2008, 2010 Pino Toscano <pino@kde.org>
19
// Copyright (C) 2009 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>
23
// To see a description of the changes please see the Changelog file that
24
// came with your tarball or type make ChangeLog if you are building from git
26
//========================================================================
30
#ifdef USE_GCC_PRAGMAS
31
#pragma implementation
37
#include "goo/gfile.h"
38
#include "GlobalParams.h"
44
#include "CharCodeToUnicode.h"
45
#include "FontEncodingTables.h"
46
#include <fofi/FoFiTrueType.h>
47
#include "ArthurOutputDev.h"
49
#include <QtCore/QtDebug>
50
#include <QtGui/QPainterPath>
51
//------------------------------------------------------------------------
54
#include "splash/SplashFontFileID.h"
55
#include "splash/SplashFontFile.h"
56
#include "splash/SplashFontEngine.h"
57
#include "splash/SplashFont.h"
58
#include "splash/SplashMath.h"
59
#include "splash/SplashPath.h"
60
#include "splash/SplashGlyphBitmap.h"
61
//------------------------------------------------------------------------
62
// SplashOutFontFileID
63
//------------------------------------------------------------------------
65
class SplashOutFontFileID: public SplashFontFileID {
68
SplashOutFontFileID(Ref *rA) { r = *rA; }
70
~SplashOutFontFileID() {}
72
GBool matches(SplashFontFileID *id) {
73
return ((SplashOutFontFileID *)id)->r.num == r.num &&
74
((SplashOutFontFileID *)id)->r.gen == r.gen;
84
//------------------------------------------------------------------------
86
//------------------------------------------------------------------------
88
ArthurOutputDev::ArthurOutputDev(QPainter *painter):
91
m_currentBrush = QBrush(Qt::SolidPattern);
96
ArthurOutputDev::~ArthurOutputDev()
103
void ArthurOutputDev::startDoc(XRef *xrefA) {
107
m_fontEngine = new SplashFontEngine(
109
globalParams->getEnableT1lib(),
111
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
112
globalParams->getEnableFreeType(),
115
m_painter->testRenderHint(QPainter::TextAntialiasing));
119
void ArthurOutputDev::startPage(int pageNum, GfxState *state)
121
// fill page with white background.
122
int w = static_cast<int>(state->getPageWidth());
123
int h = static_cast<int>(state->getPageHeight());
124
QColor fillColour(Qt::white);
125
QBrush fill(fillColour);
127
m_painter->setPen(fillColour);
128
m_painter->setBrush(fill);
129
m_painter->drawRect(0, 0, w, h);
130
m_painter->restore();
133
void ArthurOutputDev::endPage() {
136
void ArthurOutputDev::drawLink(Link *link, Catalog *catalog)
140
void ArthurOutputDev::saveState(GfxState *state)
145
void ArthurOutputDev::restoreState(GfxState *state)
147
m_painter->restore();
150
void ArthurOutputDev::updateAll(GfxState *state)
152
OutputDev::updateAll(state);
153
m_needFontUpdate = gTrue;
156
// This looks wrong - why aren't adjusting the matrix?
157
void ArthurOutputDev::updateCTM(GfxState *state, double m11, double m12,
158
double m21, double m22,
159
double m31, double m32)
161
updateLineDash(state);
162
updateLineJoin(state);
163
updateLineCap(state);
164
updateLineWidth(state);
167
void ArthurOutputDev::updateLineDash(GfxState *state)
172
state->getLineDash(&dashPattern, &dashLength, &dashStart);
173
QVector<qreal> pattern(dashLength);
174
for (int i = 0; i < dashLength; ++i) {
175
pattern[i] = dashPattern[i];
177
m_currentPen.setDashPattern(pattern);
178
m_currentPen.setDashOffset(dashStart);
179
m_painter->setPen(m_currentPen);
182
void ArthurOutputDev::updateFlatness(GfxState *state)
184
// qDebug() << "updateFlatness";
187
void ArthurOutputDev::updateLineJoin(GfxState *state)
189
switch (state->getLineJoin()) {
191
m_currentPen.setJoinStyle(Qt::MiterJoin);
194
m_currentPen.setJoinStyle(Qt::RoundJoin);
197
m_currentPen.setJoinStyle(Qt::BevelJoin);
200
m_painter->setPen(m_currentPen);
203
void ArthurOutputDev::updateLineCap(GfxState *state)
205
switch (state->getLineCap()) {
207
m_currentPen.setCapStyle(Qt::FlatCap);
210
m_currentPen.setCapStyle(Qt::RoundCap);
213
m_currentPen.setCapStyle(Qt::SquareCap);
216
m_painter->setPen(m_currentPen);
219
void ArthurOutputDev::updateMiterLimit(GfxState *state)
221
m_currentPen.setMiterLimit(state->getMiterLimit());
222
m_painter->setPen(m_currentPen);
225
void ArthurOutputDev::updateLineWidth(GfxState *state)
227
m_currentPen.setWidthF(state->getLineWidth());
228
m_painter->setPen(m_currentPen);
231
void ArthurOutputDev::updateFillColor(GfxState *state)
234
QColor brushColour = m_currentBrush.color();
235
state->getFillRGB(&rgb);
236
brushColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), brushColour.alphaF());
237
m_currentBrush.setColor(brushColour);
240
void ArthurOutputDev::updateStrokeColor(GfxState *state)
243
QColor penColour = m_currentPen.color();
244
state->getStrokeRGB(&rgb);
245
penColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), penColour.alphaF());
246
m_currentPen.setColor(penColour);
247
m_painter->setPen(m_currentPen);
250
void ArthurOutputDev::updateFillOpacity(GfxState *state)
252
QColor brushColour= m_currentBrush.color();
253
brushColour.setAlphaF(state->getFillOpacity());
254
m_currentBrush.setColor(brushColour);
257
void ArthurOutputDev::updateStrokeOpacity(GfxState *state)
259
QColor penColour= m_currentPen.color();
260
penColour.setAlphaF(state->getStrokeOpacity());
261
m_currentPen.setColor(penColour);
262
m_painter->setPen(m_currentPen);
265
void ArthurOutputDev::updateFont(GfxState *state)
269
GfxFontType fontType;
270
SplashOutFontFileID *id;
271
SplashFontFile *fontFile;
272
SplashFontSrc *fontsrc = NULL;
275
Object refObj, strObj;
280
DisplayFontParam *dfp;
282
double m11, m12, m21, m22, fontSize;
286
SplashCoord matrix[6];
288
m_needFontUpdate = false;
294
if (!(gfxFont = state->getFont())) {
297
fontType = gfxFont->getType();
298
if (fontType == fontType3) {
302
// check the font file cache
303
id = new SplashOutFontFileID(gfxFont->getID());
304
if ((fontFile = m_fontEngine->getFontFile(id))) {
309
// if there is an embedded font, write it to disk
310
if (gfxFont->getEmbeddedFontID(&embRef)) {
311
tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen);
314
// if there is an external font file, use it
315
} else if (!(fileName = gfxFont->getExtFontFile())) {
317
// look for a display font mapping or a substitute font
319
if (gfxFont->getName()) {
320
dfp = globalParams->getDisplayFont(gfxFont);
323
error(-1, "Couldn't find a font for '%s'",
324
gfxFont->getName() ? gfxFont->getName()->getCString()
330
fileName = dfp->t1.fileName;
331
fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
334
fileName = dfp->tt.fileName;
335
fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
336
faceIndex = dfp->tt.faceIndex;
341
fontsrc = new SplashFontSrc;
343
fontsrc->setFile(fileName, gFalse);
345
fontsrc->setBuf(tmpBuf, tmpBufLen, gTrue);
347
// load the font file
350
if (!(fontFile = m_fontEngine->loadType1Font(
353
((Gfx8BitFont *)gfxFont)->getEncoding()))) {
354
error(-1, "Couldn't create a font for '%s'",
355
gfxFont->getName() ? gfxFont->getName()->getCString()
361
if (!(fontFile = m_fontEngine->loadType1CFont(
364
((Gfx8BitFont *)gfxFont)->getEncoding()))) {
365
error(-1, "Couldn't create a font for '%s'",
366
gfxFont->getName() ? gfxFont->getName()->getCString()
372
if (!(fontFile = m_fontEngine->loadOpenTypeT1CFont(
375
((Gfx8BitFont *)gfxFont)->getEncoding()))) {
376
error(-1, "Couldn't create a font for '%s'",
377
gfxFont->getName() ? gfxFont->getName()->getCString()
385
ff = FoFiTrueType::load(fileName->getCString());
387
ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
389
codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
396
if (!(fontFile = m_fontEngine->loadTrueTypeFont(
400
error(-1, "Couldn't create a font for '%s'",
401
gfxFont->getName() ? gfxFont->getName()->getCString()
408
if (!(fontFile = m_fontEngine->loadCIDFont(
411
error(-1, "Couldn't create a font for '%s'",
412
gfxFont->getName() ? gfxFont->getName()->getCString()
417
case fontCIDType0COT:
418
if (!(fontFile = m_fontEngine->loadOpenTypeCFFFont(
421
error(-1, "Couldn't create a font for '%s'",
422
gfxFont->getName() ? gfxFont->getName()->getCString()
431
if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
432
n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
434
codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
435
memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
436
n * sizeof(Gushort));
440
ff = FoFiTrueType::load(fileName->getCString());
442
ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
445
codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n);
448
if (!(fontFile = m_fontEngine->loadTrueTypeFont(
451
codeToGID, n, faceIndex))) {
452
error(-1, "Couldn't create a font for '%s'",
453
gfxFont->getName() ? gfxFont->getName()->getCString()
459
// this shouldn't happen
464
// get the font matrix
465
textMat = state->getTextMat();
466
fontSize = state->getFontSize();
467
m11 = textMat[0] * fontSize * state->getHorizScaling();
468
m12 = textMat[1] * fontSize * state->getHorizScaling();
469
m21 = textMat[2] * fontSize;
470
m22 = textMat[3] * fontSize;
473
QMatrix painterMatrix = m_painter->worldMatrix();
474
matrix[0] = painterMatrix.m11();
475
matrix[1] = painterMatrix.m12();
476
matrix[2] = painterMatrix.m21();
477
matrix[3] = painterMatrix.m22();
478
matrix[4] = painterMatrix.dx();
479
matrix[5] = painterMatrix.dy();
482
// create the scaled font
483
mat[0] = m11; mat[1] = -m12;
484
mat[2] = m21; mat[3] = -m22;
485
m_font = m_fontEngine->getFont(fontFile, mat, matrix);
487
if (fontsrc && !fontsrc->isFile)
494
if (fontsrc && !fontsrc->isFile)
500
static QPainterPath convertPath(GfxState *state, GfxPath *path, Qt::FillRule fillRule)
503
double x1, y1, x2, y2, x3, y3;
507
qPath.setFillRule(fillRule);
508
for (i = 0; i < path->getNumSubpaths(); ++i) {
509
subpath = path->getSubpath(i);
510
if (subpath->getNumPoints() > 0) {
511
state->transform(subpath->getX(0), subpath->getY(0), &x1, &y1);
512
qPath.moveTo(x1, y1);
514
while (j < subpath->getNumPoints()) {
515
if (subpath->getCurve(j)) {
516
state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
517
state->transform(subpath->getX(j+1), subpath->getY(j+1), &x2, &y2);
518
state->transform(subpath->getX(j+2), subpath->getY(j+2), &x3, &y3);
519
qPath.cubicTo( x1, y1, x2, y2, x3, y3);
522
state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
523
qPath.lineTo(x1, y1);
527
if (subpath->isClosed()) {
528
qPath.closeSubpath();
535
void ArthurOutputDev::stroke(GfxState *state)
537
m_painter->strokePath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentPen );
540
void ArthurOutputDev::fill(GfxState *state)
542
m_painter->fillPath( convertPath( state, state->getPath(), Qt::WindingFill ), m_currentBrush );
545
void ArthurOutputDev::eoFill(GfxState *state)
547
m_painter->fillPath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentBrush );
550
void ArthurOutputDev::clip(GfxState *state)
552
m_painter->setClipPath(convertPath( state, state->getPath(), Qt::WindingFill ) );
555
void ArthurOutputDev::eoClip(GfxState *state)
557
m_painter->setClipPath(convertPath( state, state->getPath(), Qt::OddEvenFill ) );
560
void ArthurOutputDev::drawChar(GfxState *state, double x, double y,
561
double dx, double dy,
562
double originX, double originY,
563
CharCode code, int nBytes, Unicode *u, int uLen) {
570
if (m_needFontUpdate) {
577
// check for invisible text -- this is used by Acrobat Capture
578
render = state->getRender();
588
SplashPath * fontPath;
589
fontPath = m_font->getGlyphPath(code);
592
qPath.setFillRule(Qt::WindingFill);
593
for (int i = 0; i < fontPath->length; ++i) {
594
if (fontPath->flags[i] & splashPathFirst) {
595
state->transform(fontPath->pts[i].x+x, -fontPath->pts[i].y+y, &x1, &y1);
597
} else if (fontPath->flags[i] & splashPathCurve) {
598
state->transform(fontPath->pts[i].x+x, -fontPath->pts[i].y+y, &x1, &y1);
599
state->transform(fontPath->pts[i+1].x+x, -fontPath->pts[i+1].y+y, &x2, &y2);
600
qPath.quadTo(x1,y1,x2,y2);
604
// else if (fontPath->flags[i] & splashPathArcCW) {
605
// qDebug() << "Need to implement arc";
608
state->transform(fontPath->pts[i].x+x, -fontPath->pts[i].y+y, &x1, &y1);
611
if (fontPath->flags[i] & splashPathLast) {
612
qPath.closeSubpath();
616
QColor brushColour = m_currentBrush.color();
617
state->getFillRGB(&rgb);
618
brushColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), state->getFillOpacity());
619
m_painter->setBrush(brushColour);
620
QColor penColour = m_currentPen.color();
621
state->getStrokeRGB(&rgb);
622
penColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), state->getStrokeOpacity());
623
m_painter->setPen(penColour);
624
m_painter->drawPath( qPath );
630
if ((render & 3) == 1 || (render & 3) == 2) {
631
qDebug() << "no stroke";
633
if ((path = m_font->getGlyphPath(code))) {
634
path->offset((SplashCoord)x1, (SplashCoord)y1);
635
splash->stroke(path);
643
qDebug() << "no clip";
645
path = m_font->getGlyphPath(code);
646
path->offset((SplashCoord)x1, (SplashCoord)y1);
648
textClipPath->append(path);
658
GBool ArthurOutputDev::beginType3Char(GfxState *state, double x, double y,
659
double dx, double dy,
660
CharCode code, Unicode *u, int uLen)
665
void ArthurOutputDev::endType3Char(GfxState *state)
669
void ArthurOutputDev::type3D0(GfxState *state, double wx, double wy)
673
void ArthurOutputDev::type3D1(GfxState *state, double wx, double wy,
674
double llx, double lly, double urx, double ury)
678
void ArthurOutputDev::endTextObject(GfxState *state)
683
void ArthurOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
684
int width, int height, GBool invert,
685
GBool interpolate, GBool inlineImg)
687
qDebug() << "drawImageMask";
689
unsigned char *buffer;
691
cairo_surface_t *image;
692
cairo_pattern_t *pattern;
697
cairo_matrix_t matrix;
701
row_stride = (width + 3) & ~3;
702
buffer = (unsigned char *) malloc (height * row_stride);
703
if (buffer == NULL) {
704
error(-1, "Unable to allocate memory for image.");
708
/* TODO: Do we want to cache these? */
709
imgStr = new ImageStream(str, width, 1, 1);
712
invert_bit = invert ? 1 : 0;
714
for (y = 0; y < height; y++) {
715
pix = imgStr->getLine();
716
dest = buffer + y * row_stride;
717
for (x = 0; x < width; x++) {
719
if (pix[x] ^ invert_bit)
726
image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_A8,
727
width, height, row_stride);
730
pattern = cairo_pattern_create_for_surface (image);
734
ctm = state->getCTM();
735
LOG (printf ("drawImageMask %dx%d, matrix: %f, %f, %f, %f, %f, %f\n",
736
width, height, ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]));
737
matrix.xx = ctm[0] / width;
738
matrix.xy = -ctm[2] / height;
739
matrix.yx = ctm[1] / width;
740
matrix.yy = -ctm[3] / height;
741
matrix.x0 = ctm[2] + ctm[4];
742
matrix.y0 = ctm[3] + ctm[5];
743
cairo_matrix_invert (&matrix);
744
cairo_pattern_set_matrix (pattern, &matrix);
746
cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST);
747
/* FIXME: Doesn't the image mask support any colorspace? */
748
cairo_set_source_rgb (cairo, fill_color.r, fill_color.g, fill_color.b);
749
cairo_mask (cairo, pattern);
751
cairo_pattern_destroy (pattern);
752
cairo_surface_destroy (image);
759
//TODO: lots more work here.
760
void ArthurOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
761
int width, int height,
762
GfxImageColorMap *colorMap,
763
GBool interpolate, int *maskColors, GBool inlineImg)
773
int is_identity_transform;
777
/* TODO: Do we want to cache these? */
778
imgStr = new ImageStream(str, width,
779
colorMap->getNumPixelComps(),
780
colorMap->getBits());
783
/* ICCBased color space doesn't do any color correction
784
* so check its underlying color space as well */
785
is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB ||
786
(colorMap->getColorSpace()->getMode() == csICCBased &&
787
((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB);
789
image = QImage(width, height, QImage::Format_ARGB32);
790
data = (unsigned int *)image.bits();
791
stride = image.bytesPerLine()/4;
792
for (y = 0; y < height; y++) {
793
pix = imgStr->getLine();
794
line = data+y*stride;
795
colorMap->getRGBLine(pix, line, width);
798
for (x = 0; x < width; x++) {
799
for (i = 0; i < colorMap->getNumPixelComps(); ++i) {
800
if (pix[i] < maskColors[2*i] * 255||
801
pix[i] > maskColors[2*i+1] * 255) {
802
*line = *line | 0xff000000;
806
pix += colorMap->getNumPixelComps();
810
for (x = 0; x < width; x++) { *line = *line | 0xff000000; line++; }
814
ctm = state->getCTM();
815
matrix.setMatrix(ctm[0] / width, ctm[1] / width, -ctm[2] / height, -ctm[3] / height, ctm[2] + ctm[4], ctm[3] + ctm[5]);
817
m_painter->setMatrix(matrix, true);
818
m_painter->drawImage( QPoint(0,0), image );