Skip to content

Commit

Permalink
[layouts] Avoid rasterizing the whole layout when only a single item …
Browse files Browse the repository at this point in the history
…has opacity set

Instead, only rasterize that one item and pre-apply it's opacity
to the rasterized version. This keeps all the rest of the layout
content as vectors/text.
  • Loading branch information
nyalldawson committed Dec 10, 2018
1 parent 7f4123b commit d08ecc2
Show file tree
Hide file tree
Showing 14 changed files with 81 additions and 16 deletions.
17 changes: 17 additions & 0 deletions python/core/auto_generated/layout/qgslayoutitem.sip.in
Expand Up @@ -238,6 +238,13 @@ Base class for graphical items within a :py:class:`QgsLayout`.
UndoCustomCommand,
};

enum Flag
{
FlagOverridesPaint,
};
typedef QFlags<QgsLayoutItem::Flag> Flags;


explicit QgsLayoutItem( QgsLayout *layout, bool manageZValue = true );
%Docstring
Constructor for QgsLayoutItem, with the specified parent ``layout``.
Expand Down Expand Up @@ -279,6 +286,13 @@ upon creation.
.. seealso:: :py:func:`id`

.. seealso:: :py:func:`setId`
%End

virtual Flags itemFlags() const;
%Docstring
Returns the item's flags, which indicate how the item behaves.

.. versionadded:: 3.4.3
%End

QString id() const;
Expand Down Expand Up @@ -1166,6 +1180,9 @@ Applies any present data defined size overrides to the specified layout ``size``

};

QFlags<QgsLayoutItem::Flag> operator|(QgsLayoutItem::Flag f1, QFlags<QgsLayoutItem::Flag> f2);





Expand Down
2 changes: 2 additions & 0 deletions python/core/auto_generated/layout/qgslayoutitemlegend.sip.in
Expand Up @@ -67,6 +67,8 @@ The caller takes responsibility for deleting the returned object.

virtual QIcon icon() const;

virtual QgsLayoutItem::Flags itemFlags() const;

virtual QString displayName() const;


Expand Down
2 changes: 2 additions & 0 deletions python/core/auto_generated/layout/qgslayoutitemmap.sip.in
Expand Up @@ -41,6 +41,8 @@ Constructor for QgsLayoutItemMap, with the specified parent ``layout``.

virtual QIcon icon() const;

virtual QgsLayoutItem::Flags itemFlags() const;


void assignFreeId();
%Docstring
Expand Down
2 changes: 0 additions & 2 deletions python/core/auto_generated/layout/qgslayoutitempicture.sip.in
Expand Up @@ -286,8 +286,6 @@ Forces a recalculation of the picture's frame size

virtual void refreshDataDefinedProperty( QgsLayoutObject::DataDefinedProperty property = QgsLayoutObject::AllProperties );

virtual bool containsAdvancedEffects() const;


signals:
void pictureRotationChanged( double newRotation );
Expand Down
26 changes: 22 additions & 4 deletions src/core/layout/qgslayoutitem.cpp
Expand Up @@ -27,6 +27,7 @@
#include "qgslayoutundostack.h"
#include "qgslayoutpagecollection.h"
#include "qgslayoutitempage.h"
#include "qgsimageoperation.h"
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QUuid>
Expand Down Expand Up @@ -123,6 +124,11 @@ int QgsLayoutItem::type() const
return QgsLayoutItemRegistry::LayoutItem;
}

QgsLayoutItem::Flags QgsLayoutItem::itemFlags() const
{
return nullptr;
}

void QgsLayoutItem::setId( const QString &id )
{
if ( id == mId )
Expand Down Expand Up @@ -326,6 +332,8 @@ void QgsLayoutItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *it
drawFrame( context );
p.end();

QgsImageOperation::multiplyOpacity( image, mEvaluatedOpacity );

painter->save();
// scale painter from mm to dots
painter->scale( 1.0 / context.scaleFactor(), 1.0 / context.scaleFactor() );
Expand Down Expand Up @@ -854,7 +862,9 @@ void QgsLayoutItem::setBlendMode( const QPainter::CompositionMode mode )
void QgsLayoutItem::setItemOpacity( double opacity )
{
mOpacity = opacity;
refreshOpacity( true );
refreshOpacity( mItemCachedImage.isNull() );
if ( !mItemCachedImage.isNull() )
invalidateCache();
}

bool QgsLayoutItem::excludeFromExports() const
Expand All @@ -870,12 +880,13 @@ void QgsLayoutItem::setExcludeFromExports( bool exclude )

bool QgsLayoutItem::containsAdvancedEffects() const
{
return false;
return itemFlags() & Flag::FlagOverridesPaint ? false : mEvaluatedOpacity < 1.0;
}

bool QgsLayoutItem::requiresRasterization() const
{
return itemOpacity() < 1.0 || blendMode() != QPainter::CompositionMode_SourceOver;
return ( itemFlags() & Flag::FlagOverridesPaint && itemOpacity() < 1.0 ) ||
blendMode() != QPainter::CompositionMode_SourceOver;
}

double QgsLayoutItem::estimatedFrameBleed() const
Expand Down Expand Up @@ -1360,7 +1371,14 @@ void QgsLayoutItem::refreshOpacity( bool updateItem )
double opacity = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::Opacity, createExpressionContext(), mOpacity * 100.0 );

// Set the QGraphicItem's opacity
setOpacity( opacity / 100.0 );
mEvaluatedOpacity = opacity / 100.0;

if ( itemFlags() & QgsLayoutItem::FlagOverridesPaint )
{
// item handles it's own painting, so it won't use the built-in opacity handling in QgsLayoutItem::paint, and
// we have to rely on QGraphicsItem opacity to handle this
setOpacity( mEvaluatedOpacity );
}

if ( updateItem )
{
Expand Down
20 changes: 19 additions & 1 deletion src/core/layout/qgslayoutitem.h
Expand Up @@ -287,6 +287,16 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
UndoCustomCommand, //!< Base id for plugin based item undo commands
};

/**
* Flags for controlling how an item behaves.
* \since QGIS 3.4.3
*/
enum Flag
{
FlagOverridesPaint = 1 << 1, //!< Item overrides the default layout item painting method
};
Q_DECLARE_FLAGS( Flags, Flag )

/**
* Constructor for QgsLayoutItem, with the specified parent \a layout.
*
Expand Down Expand Up @@ -324,6 +334,12 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
*/
virtual QString uuid() const { return mUuid; }

/**
* Returns the item's flags, which indicate how the item behaves.
* \since QGIS 3.4.3
*/
virtual Flags itemFlags() const;

/**
* Returns the item's ID name. This is not necessarily unique, and duplicate ID names may exist
* for a layout.
Expand Down Expand Up @@ -1109,6 +1125,7 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt

//! Item opacity, between 0 and 1
double mOpacity = 1.0;
double mEvaluatedOpacity = 1.0;

QImage mItemCachedImage;
double mItemCacheDpi = -1;
Expand Down Expand Up @@ -1137,7 +1154,6 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
void preparePainter( QPainter *painter );
bool shouldDrawAntialiased() const;
bool shouldDrawDebugRect() const;

QSizeF applyMinimumSize( QSizeF targetSize );
QSizeF applyFixedSize( QSizeF targetSize );
QgsLayoutPoint applyDataDefinedPosition( const QgsLayoutPoint &position );
Expand All @@ -1157,6 +1173,8 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
friend class QgsCompositionConverter;
};

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsLayoutItem::Flags )

#endif //QGSLAYOUTITEM_H


Expand Down
5 changes: 5 additions & 0 deletions src/core/layout/qgslayoutitemlegend.cpp
Expand Up @@ -64,6 +64,11 @@ QIcon QgsLayoutItemLegend::icon() const
return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemLegend.svg" ) );
}

QgsLayoutItem::Flags QgsLayoutItemLegend::itemFlags() const
{
return QgsLayoutItem::FlagOverridesPaint;
}

void QgsLayoutItemLegend::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget )
{
if ( !painter )
Expand Down
1 change: 1 addition & 0 deletions src/core/layout/qgslayoutitemlegend.h
Expand Up @@ -78,6 +78,7 @@ class CORE_EXPORT QgsLayoutItemLegend : public QgsLayoutItem

int type() const override;
QIcon icon() const override;
QgsLayoutItem::Flags itemFlags() const override;
//Overridden to show legend title
QString displayName() const override;

Expand Down
5 changes: 5 additions & 0 deletions src/core/layout/qgslayoutitemmap.cpp
Expand Up @@ -77,6 +77,11 @@ QIcon QgsLayoutItemMap::icon() const
return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemMap.svg" ) );
}

QgsLayoutItem::Flags QgsLayoutItemMap::itemFlags() const
{
return QgsLayoutItem::FlagOverridesPaint;
}

void QgsLayoutItemMap::assignFreeId()
{
if ( !mLayout )
Expand Down
1 change: 1 addition & 0 deletions src/core/layout/qgslayoutitemmap.h
Expand Up @@ -71,6 +71,7 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem

int type() const override;
QIcon icon() const override;
QgsLayoutItem::Flags itemFlags() const override;

/**
* Sets the map id() to a number not yet used in the layout. The existing id() is kept if it is not in use.
Expand Down
8 changes: 0 additions & 8 deletions src/core/layout/qgslayoutitempicture.cpp
Expand Up @@ -669,14 +669,6 @@ void QgsLayoutItemPicture::refreshDataDefinedProperty( const QgsLayoutObject::Da
QgsLayoutItem::refreshDataDefinedProperty( property );
}

bool QgsLayoutItemPicture::containsAdvancedEffects() const
{
if ( QgsLayoutItem::containsAdvancedEffects() )
return true;

return mMode == FormatSVG && itemOpacity() < 1.0;
}

void QgsLayoutItemPicture::setPicturePath( const QString &path )
{
mSourcePath = path;
Expand Down
1 change: 0 additions & 1 deletion src/core/layout/qgslayoutitempicture.h
Expand Up @@ -259,7 +259,6 @@ class CORE_EXPORT QgsLayoutItemPicture: public QgsLayoutItem
void recalculateSize();

void refreshDataDefinedProperty( QgsLayoutObject::DataDefinedProperty property = QgsLayoutObject::AllProperties ) override;
bool containsAdvancedEffects() const override;

signals:
//! Is emitted on picture rotation change
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/georeferencer/qgsresidualplotitem.cpp
Expand Up @@ -27,6 +27,11 @@ QgsResidualPlotItem::QgsResidualPlotItem( QgsLayout *layout )
setBackgroundEnabled( false );
}

QgsLayoutItem::Flags QgsResidualPlotItem::itemFlags() const
{
return QgsLayoutItem::FlagOverridesPaint;
}

void QgsResidualPlotItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget )
{
Q_UNUSED( itemStyle );
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/georeferencer/qgsresidualplotitem.h
Expand Up @@ -30,6 +30,8 @@ class QgsResidualPlotItem: public QgsLayoutItem
public:
explicit QgsResidualPlotItem( QgsLayout *layout );

QgsLayoutItem::Flags itemFlags() const override;

//! \brief Reimplementation of QCanvasItem::paint
void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget ) override;

Expand Down

0 comments on commit d08ecc2

Please sign in to comment.