Commit bda1d76f authored by Oliver Sander's avatar Oliver Sander Committed by Albert Astals Cid
Browse files

ArthurOutputDev: Replace the QPainter by a stack of QPainters

This patch lays some groundwork for the support of transparency
groups.  Transparency groups temporarily create new painters.
These get painted upon, and then the resulting new painting
will be drawn at once onto the original PaintDevice.  To implement
this, we need a stack of painters rather than a single one.
The first painter on the stack is the original one.  Opening a
transparency group pushes a new painter onto the stack, and
all drawing operations always go to the painter on the top
of the stack.
parent 71b04b79
......@@ -89,9 +89,9 @@ private:
//------------------------------------------------------------------------
ArthurOutputDev::ArthurOutputDev(QPainter *painter):
m_painter(painter),
m_fontHinting(NoHinting)
{
m_painter.push(painter);
m_currentBrush = QBrush(Qt::SolidPattern);
m_fontEngine = 0;
}
......@@ -115,7 +115,7 @@ void ArthurOutputDev::startDoc(XRef *xrefA) {
globalParams->getEnableFreeType(),
isHintingEnabled,
isSlightHinting,
m_painter->testRenderHint(QPainter::TextAntialiasing));
m_painter.top()->testRenderHint(QPainter::TextAntialiasing));
#endif
}
......@@ -126,11 +126,11 @@ void ArthurOutputDev::startPage(int pageNum, GfxState *state, XRef *xref)
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();
m_painter.top()->save();
m_painter.top()->setPen(fillColour);
m_painter.top()->setBrush(fill);
m_painter.top()->drawRect(0, 0, w, h);
m_painter.top()->restore();
}
void ArthurOutputDev::endPage() {
......@@ -143,12 +143,12 @@ void ArthurOutputDev::saveState(GfxState *state)
m_rawFontStack.push(m_rawFont);
m_codeToGIDStack.push(m_codeToGID);
m_painter->save();
m_painter.top()->save();
}
void ArthurOutputDev::restoreState(GfxState *state)
{
m_painter->restore();
m_painter.top()->restore();
m_codeToGID = m_codeToGIDStack.top();
m_codeToGIDStack.pop();
......@@ -169,7 +169,7 @@ void ArthurOutputDev::updateAll(GfxState *state)
// 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]));
m_painter.top()->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
......@@ -186,7 +186,7 @@ void ArthurOutputDev::updateCTM(GfxState *state, double m11, double m12,
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);
m_painter.top()->setTransform(update, true);
}
void ArthurOutputDev::updateLineDash(GfxState *state)
......@@ -203,7 +203,7 @@ void ArthurOutputDev::updateLineDash(GfxState *state)
if (dashLength==0)
{
m_currentPen.setStyle(Qt::SolidLine);
m_painter->setPen(m_currentPen);
m_painter.top()->setPen(m_currentPen);
return;
}
......@@ -215,7 +215,7 @@ void ArthurOutputDev::updateLineDash(GfxState *state)
}
m_currentPen.setDashPattern(pattern);
m_currentPen.setDashOffset(dashStart);
m_painter->setPen(m_currentPen);
m_painter.top()->setPen(m_currentPen);
}
void ArthurOutputDev::updateFlatness(GfxState *state)
......@@ -239,7 +239,7 @@ void ArthurOutputDev::updateLineJoin(GfxState *state)
m_currentPen.setJoinStyle(Qt::BevelJoin);
break;
}
m_painter->setPen(m_currentPen);
m_painter.top()->setPen(m_currentPen);
}
void ArthurOutputDev::updateLineCap(GfxState *state)
......@@ -255,19 +255,19 @@ void ArthurOutputDev::updateLineCap(GfxState *state)
m_currentPen.setCapStyle(Qt::SquareCap);
break;
}
m_painter->setPen(m_currentPen);
m_painter.top()->setPen(m_currentPen);
}
void ArthurOutputDev::updateMiterLimit(GfxState *state)
{
m_currentPen.setMiterLimit(state->getMiterLimit());
m_painter->setPen(m_currentPen);
m_painter.top()->setPen(m_currentPen);
}
void ArthurOutputDev::updateLineWidth(GfxState *state)
{
m_currentPen.setWidthF(state->getLineWidth());
m_painter->setPen(m_currentPen);
m_painter.top()->setPen(m_currentPen);
// The updateLineDash method needs to know the line width, but it is sometimes
// called before the updateLineWidth method. To make sure that the last call
// to updateLineDash before a drawing operation is always with the correct line
......@@ -291,7 +291,7 @@ void ArthurOutputDev::updateStrokeColor(GfxState *state)
state->getStrokeRGB(&rgb);
penColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), penColour.alphaF());
m_currentPen.setColor(penColour);
m_painter->setPen(m_currentPen);
m_painter.top()->setPen(m_currentPen);
}
void ArthurOutputDev::updateBlendMode(GfxState * state)
......@@ -306,42 +306,42 @@ void ArthurOutputDev::updateBlendMode(GfxState * state)
switch(blendMode){
case gfxBlendMultiply:
m_painter->setCompositionMode(QPainter::CompositionMode_Multiply);
m_painter.top()->setCompositionMode(QPainter::CompositionMode_Multiply);
break;
case gfxBlendScreen:
m_painter->setCompositionMode(QPainter::CompositionMode_Screen);
m_painter.top()->setCompositionMode(QPainter::CompositionMode_Screen);
break;
case gfxBlendDarken:
m_painter->setCompositionMode(QPainter::CompositionMode_Darken);
m_painter.top()->setCompositionMode(QPainter::CompositionMode_Darken);
break;
case gfxBlendLighten:
m_painter->setCompositionMode(QPainter::CompositionMode_Lighten);
m_painter.top()->setCompositionMode(QPainter::CompositionMode_Lighten);
break;
case gfxBlendColorDodge:
m_painter->setCompositionMode(QPainter::CompositionMode_ColorDodge);
m_painter.top()->setCompositionMode(QPainter::CompositionMode_ColorDodge);
break;
case gfxBlendColorBurn:
m_painter->setCompositionMode(QPainter::CompositionMode_ColorBurn);
m_painter.top()->setCompositionMode(QPainter::CompositionMode_ColorBurn);
break;
case gfxBlendHardLight:
m_painter->setCompositionMode(QPainter::CompositionMode_HardLight);
m_painter.top()->setCompositionMode(QPainter::CompositionMode_HardLight);
break;
case gfxBlendSoftLight:
m_painter->setCompositionMode(QPainter::CompositionMode_SoftLight);
m_painter.top()->setCompositionMode(QPainter::CompositionMode_SoftLight);
break;
case gfxBlendDifference:
m_painter->setCompositionMode(QPainter::CompositionMode_Difference);
m_painter.top()->setCompositionMode(QPainter::CompositionMode_Difference);
break;
case gfxBlendExclusion:
m_painter->setCompositionMode(QPainter::CompositionMode_Exclusion);
m_painter.top()->setCompositionMode(QPainter::CompositionMode_Exclusion);
break;
case gfxBlendColor:
m_painter->setCompositionMode(QPainter::CompositionMode_Plus);
m_painter.top()->setCompositionMode(QPainter::CompositionMode_Plus);
break;
default:
qDebug() << "Unsupported blend mode, falling back to CompositionMode_SourceOver";
case gfxBlendNormal:
m_painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
m_painter.top()->setCompositionMode(QPainter::CompositionMode_SourceOver);
break;
}
}
......@@ -358,7 +358,7 @@ void ArthurOutputDev::updateStrokeOpacity(GfxState *state)
QColor penColour= m_currentPen.color();
penColour.setAlphaF(state->getStrokeOpacity());
m_currentPen.setColor(penColour);
m_painter->setPen(m_currentPen);
m_painter.top()->setPen(m_currentPen);
}
void ArthurOutputDev::updateFont(GfxState *state)
......@@ -672,27 +672,27 @@ static QPainterPath convertPath(GfxState *state, GfxPath *path, Qt::FillRule fil
void ArthurOutputDev::stroke(GfxState *state)
{
m_painter->strokePath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentPen );
m_painter.top()->strokePath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentPen );
}
void ArthurOutputDev::fill(GfxState *state)
{
m_painter->fillPath( convertPath( state, state->getPath(), Qt::WindingFill ), m_currentBrush );
m_painter.top()->fillPath( convertPath( state, state->getPath(), Qt::WindingFill ), m_currentBrush );
}
void ArthurOutputDev::eoFill(GfxState *state)
{
m_painter->fillPath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentBrush );
m_painter.top()->fillPath( convertPath( state, state->getPath(), Qt::OddEvenFill ), m_currentBrush );
}
void ArthurOutputDev::clip(GfxState *state)
{
m_painter->setClipPath(convertPath( state, state->getPath(), Qt::WindingFill ), Qt::IntersectClip );
m_painter.top()->setClipPath(convertPath( state, state->getPath(), Qt::WindingFill ), Qt::IntersectClip );
}
void ArthurOutputDev::eoClip(GfxState *state)
{
m_painter->setClipPath(convertPath( state, state->getPath(), Qt::OddEvenFill ), Qt::IntersectClip );
m_painter.top()->setClipPath(convertPath( state, state->getPath(), Qt::OddEvenFill ), Qt::IntersectClip );
}
void ArthurOutputDev::drawChar(GfxState *state, double x, double y,
......@@ -723,7 +723,7 @@ void ArthurOutputDev::drawChar(GfxState *state, double x, double y,
glyphRun.setRawFont(*m_rawFont);
// Store the QPainter state; we need to modify it temporarily
m_painter->save();
m_painter.top()->save();
// Apply the text matrix to the glyph. The glyph is not scaled by the font size,
// because the font in m_rawFont already has the correct size.
......@@ -734,7 +734,7 @@ void ArthurOutputDev::drawChar(GfxState *state, double x, double y,
// Make the glyph position the coordinate origin -- that's our center of scaling
const double *textMat = state->getTextMat();
m_painter->translate(QPointF(glyphPosition.x(),glyphPosition.y()));
m_painter.top()->translate(QPointF(glyphPosition.x(),glyphPosition.y()));
QTransform textTransform(textMat[0] * state->getHorizScaling(),
textMat[1] * state->getHorizScaling(),
......@@ -743,7 +743,7 @@ void ArthurOutputDev::drawChar(GfxState *state, double x, double y,
0,
0);
m_painter->setTransform(textTransform,true);
m_painter.top()->setTransform(textTransform,true);
// We are painting a filled glyph here. But QPainter uses the pen to draw even filled text,
// not the brush. (see, e.g., http://doc.qt.io/qt-5/qpainter.html#setPen )
......@@ -756,13 +756,13 @@ void ArthurOutputDev::drawChar(GfxState *state, double x, double y,
state->getFillRGB(&rgb);
QColor fontColor;
fontColor.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), state->getFillOpacity());
m_painter->setPen(fontColor);
m_painter.top()->setPen(fontColor);
// Actually draw the glyph
m_painter->drawGlyphRun(QPointF(-glyphPosition.x(),-glyphPosition.y()), glyphRun);
m_painter.top()->drawGlyphRun(QPointF(-glyphPosition.x(),-glyphPosition.y()), glyphRun);
// Restore transformation and pen color
m_painter->restore();
m_painter.top()->restore();
}
}
......@@ -917,7 +917,7 @@ void ArthurOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
// 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 );
m_painter.top()->drawImage( QRect(0,0,1,1), image );
delete imgStr;
}
......@@ -987,6 +987,6 @@ void ArthurOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *
// 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 );
m_painter.top()->drawImage( QRect(0,0,1,1), image );
}
......@@ -172,7 +172,12 @@ public:
GBool isReverseVideo() { return gFalse; }
private:
QPainter *m_painter;
// 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;
FontHinting m_fontHinting;
QPen m_currentPen;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment