blob: fa36e8cd2122c2b1c4bca57dcb33634b15f4cef7 [file] [log] [blame]
// ArthurOutputDev.h
// Copyright 2003 Glyph & Cog, LLC
// Modified under the Poppler project -
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
// Copyright (C) 2005 Brad Hards <>
// Copyright (C) 2005, 2018, 2019 Albert Astals Cid <>
// Copyright (C) 2009, 2011 Carlos Garcia Campos <>
// Copyright (C) 2010 Pino Toscano <>
// Copyright (C) 2011 Andreas Hartmetz <>
// Copyright (C) 2013 Thomas Freitag <>
// Copyright (C) 2013 Mihai Niculescu <>
// Copyright (C) 2017, 2018 Oliver Sander <>
// 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
#include <memory>
#include <map>
#include <stack>
#include "OutputDev.h"
#include "GfxState.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include <QtGui/QPainter>
class GfxState;
class PDFDoc;
class QRawFont;
class ArthurType3Font;
// ArthurOutputDev - Qt 5 QPainter renderer
class ArthurOutputDev: public OutputDev {
* Describes how fonts are distorted (aka hinted) to fit the pixel grid.
* More hinting means sharper edges and less adherence to the true letter shapes.
enum FontHinting {
NoHinting = 0, ///< Font shapes are left unchanged
SlightHinting, ///< Font shapes are distorted vertically only
FullHinting ///< Font shapes are distorted horizontally and vertically
// Constructor.
ArthurOutputDev(QPainter *painter );
// Destructor.
void setFontHinting(FontHinting hinting) { m_fontHinting = hinting; }
//----- get info about output device
// Does this device use upside-down coordinates?
// (Upside-down means (0,0) is the top left corner of the page.)
bool upsideDown() override { return true; }
// Does this device use drawChar() or drawString()?
bool useDrawChar() override { return true; }
// Does this device implement shaded fills (aka gradients) natively?
// If this returns false, these shaded fills
// will be reduced to a series of other drawing operations.
// type==2 is 'axial shading'
bool useShadedFills(int type) override { return type == 2; }
// Does this device use beginType3Char/endType3Char? Otherwise,
// text in Type 3 fonts will be drawn with drawChar/drawString.
bool interpretType3Chars() override { return false; }
//----- initialization and control
// Set Current Transformation Matrix to a fixed matrix given in ctm[0],...,ctm[5]
void setDefaultCTM(const double *ctm) override;
// Start a page.
void startPage(int pageNum, GfxState *state, XRef *xref) override;
// End a page.
void endPage() override;
//----- save/restore graphics state
void saveState(GfxState *state) override;
void restoreState(GfxState *state) override;
//----- update graphics state
void updateAll(GfxState *state) override;
void updateCTM(GfxState *state, double m11, double m12,
double m21, double m22, double m31, double m32) override;
void updateLineDash(GfxState *state) override;
void updateFlatness(GfxState *state) override;
void updateLineJoin(GfxState *state) override;
void updateLineCap(GfxState *state) override;
void updateMiterLimit(GfxState *state) override;
void updateLineWidth(GfxState *state) override;
void updateFillColor(GfxState *state) override;
void updateStrokeColor(GfxState *state) override;
void updateBlendMode(GfxState *state) override;
void updateFillOpacity(GfxState *state) override;
void updateStrokeOpacity(GfxState *state) override;
//----- update text state
void updateFont(GfxState *state) override;
//----- path painting
void stroke(GfxState *state) override;
void fill(GfxState *state) override;
void eoFill(GfxState *state) override;
bool axialShadedFill(GfxState * state, GfxAxialShading *shading, double tMin, double tMax) override;
//----- path clipping
void clip(GfxState *state) override;
void eoClip(GfxState *state) override;
//----- text drawing
// virtual void drawString(GfxState *state, GooString *s);
void drawChar(GfxState *state, double x, double y,
double dx, double dy,
double originX, double originY,
CharCode code, int nBytes, const Unicode *u, int uLen) override;
void endTextObject(GfxState *state) override;
//----- image drawing
void drawImageMask(GfxState *state, Object *ref, Stream *str,
int width, int height, bool invert,
bool interpolate, bool inlineImg) override;
void drawImage(GfxState *state, Object *ref, Stream *str,
int width, int height, GfxImageColorMap *colorMap,
bool interpolate, const int *maskColors, bool inlineImg) override;
void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
int width, int height,
GfxImageColorMap *colorMap,
bool interpolate,
Stream *maskStr,
int maskWidth, int maskHeight,
GfxImageColorMap *maskColorMap,
bool maskInterpolate) override;
//----- Type 3 font operators
void type3D0(GfxState *state, double wx, double wy) override;
void type3D1(GfxState *state, double wx, double wy,
double llx, double lly, double urx, double ury) override;
//----- transparency groups and soft masks
virtual void beginTransparencyGroup(GfxState *state, const double *bbox,
GfxColorSpace *blendingColorSpace,
bool isolated, bool knockout,
bool forSoftMask) override;
virtual void endTransparencyGroup(GfxState *state) override;
virtual void paintTransparencyGroup(GfxState *state, const double *bbox) override;
//----- special access
// Called to indicate that a new PDF document has been loaded.
void startDoc(PDFDoc* doc);
bool isReverseVideo() { return false; }
// The stack of QPainters is used to implement transparency groups. When such a group
// is opened, annew Painter that paints onto a QPicture is pushed onto the stack.
// It is popped again when the transparency group ends.
std::stack<QPainter*> m_painter;
// This is the corresponding stack of QPicture objects
std::stack<QPicture*> m_qpictures;
// endTransparencyGroup removes a QPicture from the stack, but stores
// it here for later use in paintTransparencyGroup.
QPicture* m_lastTransparencyGroupPicture;
FontHinting m_fontHinting;
QPen m_currentPen;
// The various stacks are used to implement the 'saveState' and 'restoreState' methods
std::stack<QPen> m_currentPenStack;
QBrush m_currentBrush;
std::stack<QBrush> m_currentBrushStack;
bool m_needFontUpdate; // set when the font needs to be updated
PDFDoc* m_doc;
XRef *xref; // xref table for current document
// The current font in use
QRawFont* m_rawFont;
std::stack<QRawFont*> m_rawFontStack;
ArthurType3Font* m_currentType3Font;
std::stack<ArthurType3Font*> m_type3FontStack;
// Cache all fonts by their Ref and font size
using ArthurFontID = std::pair<Ref,double>;
std::map<ArthurFontID,std::unique_ptr<QRawFont> > m_rawFontCache;
std::map<ArthurFontID,std::unique_ptr<ArthurType3Font> > m_type3FontCache;
std::map<Ref,const int*> m_codeToGIDCache;
// The table that maps character codes to glyph indexes
const int* m_codeToGID;
std::stack<const int*> m_codeToGIDStack;
FT_Library m_ftLibrary;
// as of FT 2.1.8, CID fonts are indexed by CID instead of GID
bool m_useCIDs;