[Libreoffice-commits] core.git: vcl/source
Chris Sherlock (via logerrit)
logerrit at kemper.freedesktop.org
Tue May 26 16:28:33 UTC 2020
vcl/source/gdi/print2.cxx | 730 +++++++++++++++++++++-------------------------
1 file changed, 342 insertions(+), 388 deletions(-)
New commits:
commit 067342f063fa3ea6773297eea89e45cabbf04a56
Author: Chris Sherlock <chris.sherlock79 at gmail.com>
AuthorDate: Tue May 26 03:53:03 2020 +1000
Commit: Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Tue May 26 18:27:57 2020 +0200
tdf#133216 - Objects are not printed (Win-only)
Seem to have been introduced in commit 6fa6704a7e7c6970b7a7c:6
"vcl: move functionality out of checkRect(), rendering function obsolete"
This reverts:
commit 7b47a96b20122863e77aa1918e878372b3485c9f.
"vcl: refactor code into GenerateConnectedComponents()"
commit 5ef0f7dfafd8b83818c831914467f93e47a5bb2f.
"vcl: refactor code into GenerateIntersectingConnectedComponents()"
commit 93649784ddbb7d9ca779d14fd60fb97385325d17.
"vcl: move stage 1 functionality into DetectBackground()"
commit 34a699f1894f30f68c3243784586617e01e60ab6.
"vcl: refactor by creating GetActionAfterBackgroundAction() function"
commit f85769f61b2d2380750be564c6de47f28be35b8a.
"vcl: refactor by creating RecordMapModeChanges() function"
commit 8318a636336dd6d6b5862a3366f85f96c64d8243.
"vcl: refactor by creating SetBackgroundColorAndBounds() function"
commit f0ca5a0c447f4fe4667693d744af61eaeb0625ee.
"vcl: move functionality into FindIncompletelyOccludedBackground()"
commit 449f23c44ccdf6d2bfe7baa143d32d8f585aef4b.
"vcl: new local function setComponentsSizeAndColor()"
commit 6fa6704a7e7c6970b7a7c695a4a548f8dc693d03.
"vcl: move functionality out of checkRect(), rendering function obsolete"
Change-Id: Ic85397c1b69f2b529cff90206387d017692cecf2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94804
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>
diff --git a/vcl/source/gdi/print2.cxx b/vcl/source/gdi/print2.cxx
index 887351fe8e33..89fec06ff466 100644
--- a/vcl/source/gdi/print2.cxx
+++ b/vcl/source/gdi/print2.cxx
@@ -92,18 +92,31 @@ bool DoesActionHandleTransparency( const MetaAction& rAct )
bool doesRectCoverWithUniformColor(
tools::Rectangle const & rPrevRect,
tools::Rectangle const & rCurrRect,
- VirtualDevice const * pMapModeVDev)
+ OutputDevice const & rMapModeVDev)
{
// shape needs to fully cover previous content, and have uniform
// color
- return (pMapModeVDev->LogicToPixel(rCurrRect).IsInside(rPrevRect) &&
- pMapModeVDev->IsFillColor());
+ return (rMapModeVDev.LogicToPixel(rCurrRect).IsInside(rPrevRect) &&
+ rMapModeVDev.IsFillColor());
}
-void setComponentsSizeAndColor(ConnectedComponents &rBackgroundComponent, tools::Rectangle const & rRect, Color const& rColor)
+/** Check whether rCurrRect rectangle fully covers io_rPrevRect - if
+ yes, return true and update o_rBgColor
+ */
+bool checkRect( tools::Rectangle& io_rPrevRect,
+ Color& o_rBgColor,
+ const tools::Rectangle& rCurrRect,
+ OutputDevice const & rMapModeVDev )
{
- rBackgroundComponent.aBounds = rRect;
- rBackgroundComponent.aBgColor = rColor;
+ bool bRet = doesRectCoverWithUniformColor(io_rPrevRect, rCurrRect, rMapModeVDev);
+
+ if( bRet )
+ {
+ io_rPrevRect = rCurrRect;
+ o_rBgColor = rMapModeVDev.GetFillColor();
+ }
+
+ return bRet;
}
/** #107169# Convert BitmapEx to Bitmap with appropriately blended
@@ -609,440 +622,389 @@ tools::Rectangle ImplCalcActionBounds( const MetaAction& rAct, const OutputDevic
return tools::Rectangle();
}
-int FindIncompletelyOccludedBackground(ConnectedComponents& rBackgroundComponent, GDIMetaFile const & rMtf, VirtualDevice* pMapModeVDev)
+} // end anon namespace
+
+bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, GDIMetaFile& rOutMtf,
+ long nMaxBmpDPIX, long nMaxBmpDPIY,
+ bool bReduceTransparency, bool bTransparencyAutoMode,
+ bool bDownsampleBitmaps,
+ const Color& rBackground
+ )
{
- MetaAction* pCurrAct=const_cast<GDIMetaFile&>(rMtf).FirstAction();
+ MetaAction* pCurrAct;
+ bool bTransparent( false );
- int nActionNum = 0;
- int nLastBgAction = -1;
- bool bStillBackground=true; // true until first non-bg action
+ rOutMtf.Clear();
- while( pCurrAct && bStillBackground )
+ if(!bReduceTransparency || bTransparencyAutoMode)
+ bTransparent = rInMtf.HasTransparentActions();
+
+ // #i10613# Determine set of connected components containing transparent objects. These are
+ // then processed as bitmaps, the original actions are removed from the metafile.
+ if( !bTransparent )
{
- switch( pCurrAct->GetType() )
- {
- case MetaActionType::RECT:
- {
- const tools::Rectangle aRect(
- static_cast<const MetaRectAction*>(pCurrAct)->GetRect());
+ // nothing transparent -> just copy
+ rOutMtf = rInMtf;
+ }
+ else
+ {
+ // #i10613#
+ // This works as follows: we want a number of distinct sets of
+ // connected components, where each set contains metafile
+ // actions that are intersecting (note: there are possibly
+ // more actions contained as are directly intersecting,
+ // because we can only produce rectangular bitmaps later
+ // on. Thus, each set of connected components is the smallest
+ // enclosing, axis-aligned rectangle that completely bounds a
+ // number of intersecting metafile actions, plus any action
+ // that would otherwise be cut in two). Therefore, we
+ // iteratively add metafile actions from the original metafile
+ // to this connected components list (aCCList), by checking
+ // each element's bounding box against intersection with the
+ // metaaction at hand.
+ // All those intersecting elements are removed from aCCList
+ // and collected in a temporary list (aCCMergeList). After all
+ // elements have been checked, the aCCMergeList elements are
+ // merged with the metaaction at hand into one resulting
+ // connected component, with one big bounding box, and
+ // inserted into aCCList again.
+ // The time complexity of this algorithm is O(n^3), where n is
+ // the number of metafile actions, and it finds all distinct
+ // regions of rectangle-bounded connected components. This
+ // algorithm was designed by AF.
- if (!doesRectCoverWithUniformColor(rBackgroundComponent.aBounds, aRect, pMapModeVDev))
- {
- setComponentsSizeAndColor(rBackgroundComponent, aRect, pMapModeVDev->GetFillColor());
- bStillBackground=false; // incomplete occlusion of background
- }
- else
- {
- nLastBgAction=nActionNum; // this _is_ background
- }
- break;
- }
- case MetaActionType::POLYGON:
- {
- const tools::Polygon aPoly(
- static_cast<const MetaPolygonAction*>(pCurrAct)->GetPolygon());
- const tools::Rectangle aRect(aPoly.GetBoundRect());
+ // STAGE 1: Detect background
- if (!basegfx::utils::isRectangle(aPoly.getB2DPolygon()) ||
- !doesRectCoverWithUniformColor(rBackgroundComponent.aBounds, aRect, pMapModeVDev))
- {
- setComponentsSizeAndColor(rBackgroundComponent, aRect, pMapModeVDev->GetFillColor());
- bStillBackground=false; // incomplete occlusion of background
- }
- else
+ // Receives uniform background content, and is _not_ merged
+ // nor checked for intersection against other aCCList elements
+ ConnectedComponents aBackgroundComponent;
+
+ // Read the configuration value of minimal object area where transparency will be removed
+ double fReduceTransparencyMinArea = officecfg::Office::Common::VCL::ReduceTransparencyMinArea::get() / 100.0;
+ SAL_WARN_IF(fReduceTransparencyMinArea > 1.0, "vcl",
+ "Value of ReduceTransparencyMinArea config option is too high");
+ SAL_WARN_IF(fReduceTransparencyMinArea < 0.0, "vcl",
+ "Value of ReduceTransparencyMinArea config option is too low");
+ fReduceTransparencyMinArea = std::clamp(fReduceTransparencyMinArea, 0.0, 1.0);
+
+ // create an OutputDevice to record mapmode changes and the like
+ ScopedVclPtrInstance< VirtualDevice > aMapModeVDev;
+ aMapModeVDev->mnDPIX = mnDPIX;
+ aMapModeVDev->mnDPIY = mnDPIY;
+ aMapModeVDev->EnableOutput(false);
+
+ int nLastBgAction, nActionNum;
+
+ // weed out page-filling background objects (if they are
+ // uniformly coloured). Keeping them outside the other
+ // connected components often prevents whole-page bitmap
+ // generation.
+ bool bStillBackground=true; // true until first non-bg action
+ nActionNum=0; nLastBgAction=-1;
+ pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
+ if( rBackground != COL_TRANSPARENT )
+ {
+ aBackgroundComponent.aBgColor = rBackground;
+ aBackgroundComponent.aBounds = GetBackgroundComponentBounds();
+ }
+ while( pCurrAct && bStillBackground )
+ {
+ switch( pCurrAct->GetType() )
+ {
+ case MetaActionType::RECT:
{
- nLastBgAction=nActionNum; // this _is_ background
+ if( !checkRect(
+ aBackgroundComponent.aBounds,
+ aBackgroundComponent.aBgColor,
+ static_cast<const MetaRectAction*>(pCurrAct)->GetRect(),
+ *aMapModeVDev) )
+ bStillBackground=false; // incomplete occlusion of background
+ else
+ nLastBgAction=nActionNum; // this _is_ background
+ break;
}
- break;
- }
- case MetaActionType::POLYPOLYGON:
- {
- const tools::PolyPolygon aPoly(
- static_cast<const MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon());
- const tools::Rectangle aRect(aPoly.GetBoundRect());
-
- if (aPoly.Count() != 1 ||
- !basegfx::utils::isRectangle(aPoly[0].getB2DPolygon()) ||
- !doesRectCoverWithUniformColor(rBackgroundComponent.aBounds, aRect, pMapModeVDev))
+ case MetaActionType::POLYGON:
{
- setComponentsSizeAndColor(rBackgroundComponent, aRect, pMapModeVDev->GetFillColor());
- bStillBackground=false; // incomplete occlusion of background
+ const tools::Polygon aPoly(
+ static_cast<const MetaPolygonAction*>(pCurrAct)->GetPolygon());
+ if( !basegfx::utils::isRectangle(
+ aPoly.getB2DPolygon()) ||
+ !checkRect(
+ aBackgroundComponent.aBounds,
+ aBackgroundComponent.aBgColor,
+ aPoly.GetBoundRect(),
+ *aMapModeVDev) )
+ bStillBackground=false; // incomplete occlusion of background
+ else
+ nLastBgAction=nActionNum; // this _is_ background
+ break;
}
- else
+ case MetaActionType::POLYPOLYGON:
{
- nLastBgAction=nActionNum; // this _is_ background
+ const tools::PolyPolygon aPoly(
+ static_cast<const MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon());
+ if( aPoly.Count() != 1 ||
+ !basegfx::utils::isRectangle(
+ aPoly[0].getB2DPolygon()) ||
+ !checkRect(
+ aBackgroundComponent.aBounds,
+ aBackgroundComponent.aBgColor,
+ aPoly.GetBoundRect(),
+ *aMapModeVDev) )
+ bStillBackground=false; // incomplete occlusion of background
+ else
+ nLastBgAction=nActionNum; // this _is_ background
+ break;
}
- break;
- }
- case MetaActionType::WALLPAPER:
- {
- const tools::Rectangle aRect(
- static_cast<const MetaWallpaperAction*>(pCurrAct)->GetRect());
-
- if (!doesRectCoverWithUniformColor(rBackgroundComponent.aBounds, aRect, pMapModeVDev))
+ case MetaActionType::WALLPAPER:
{
- setComponentsSizeAndColor(rBackgroundComponent, aRect, pMapModeVDev->GetFillColor());
- bStillBackground=false; // incomplete occlusion of background
+ if( !checkRect(
+ aBackgroundComponent.aBounds,
+ aBackgroundComponent.aBgColor,
+ static_cast<const MetaWallpaperAction*>(pCurrAct)->GetRect(),
+ *aMapModeVDev) )
+ bStillBackground=false; // incomplete occlusion of background
+ else
+ nLastBgAction=nActionNum; // this _is_ background
+ break;
}
- else
+ default:
{
- nLastBgAction=nActionNum; // this _is_ background
+ if( ImplIsNotTransparent( *pCurrAct,
+ *aMapModeVDev ) )
+ bStillBackground=false; // non-transparent action, possibly
+ // not uniform
+ else
+ // extend current bounds (next uniform action
+ // needs to fully cover this area)
+ aBackgroundComponent.aBounds.Union(
+ ImplCalcActionBounds(*pCurrAct, *aMapModeVDev) );
+ break;
}
- break;
- }
- default:
- {
- if (ImplIsNotTransparent( *pCurrAct, *pMapModeVDev))
- bStillBackground=false; // non-transparent action, possibly not uniform
- else
- // extend current bounds (next uniform action needs to fully cover this area)
- rBackgroundComponent.aBounds.Union(ImplCalcActionBounds(*pCurrAct, *pMapModeVDev));
- break;
}
- }
- // execute action to get correct MapModes etc.
- pCurrAct->Execute(pMapModeVDev);
+ // execute action to get correct MapModes etc.
+ pCurrAct->Execute( aMapModeVDev.get() );
- pCurrAct=const_cast<GDIMetaFile&>(rMtf).NextAction();
- ++nActionNum;
- }
+ pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
+ ++nActionNum;
+ }
- return nLastBgAction;
-}
+ aMapModeVDev->ClearStack(); // clean up aMapModeVDev
-int GetActionAfterBackgroundAction(ConnectedComponents& rBackgroundComponent, MetaAction* pCurrAct,
- GDIMetaFile const & rMtf, int nLastBgAction,
- VirtualDevice* const pMapModeVDev)
-{
- pMapModeVDev->ClearStack(); // clean up pMapModeVDev
+ // fast-forward until one after the last background action
+ // (need to reconstruct map mode vdev state)
+ nActionNum=0;
+ pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
+ while( pCurrAct && nActionNum<=nLastBgAction )
+ {
+ // up to and including last ink-generating background
+ // action go to background component
+ aBackgroundComponent.aComponentList.emplace_back(
+ pCurrAct, nActionNum );
+
+ // execute action to get correct MapModes etc.
+ pCurrAct->Execute( aMapModeVDev.get() );
+ pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
+ ++nActionNum;
+ }
- // fast-forward until one after the last background action
- // (need to reconstruct map mode vdev state)
- int nActionNum=0;
- pCurrAct=const_cast<GDIMetaFile&>(rMtf).FirstAction();
- while(pCurrAct && nActionNum <= nLastBgAction)
- {
- // up to and including last ink-generating background
- // action go to background component
- rBackgroundComponent.aComponentList.emplace_back(pCurrAct, nActionNum);
-
- // execute action to get correct MapModes etc.
- pCurrAct->Execute(pMapModeVDev);
- pCurrAct=const_cast<GDIMetaFile&>(rMtf).NextAction();
- ++nActionNum;
- }
+ // STAGE 2: Generate connected components list
- return nActionNum;
-}
+ ::std::vector<ConnectedComponents> aCCList; // contains distinct sets of connected components as elements.
-void RecordMapModeChanges(VirtualDevice* pMapModeVDev, sal_uInt32 nDPIX, sal_uInt32 nDPIY)
-{
- pMapModeVDev->SetDPIX(nDPIX);
- pMapModeVDev->SetDPIY(nDPIY);
- pMapModeVDev->EnableOutput(false);
-}
+ // iterate over all actions (start where background action
+ // search left off)
+ for( ;
+ pCurrAct;
+ pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
+ {
+ // execute action to get correct MapModes etc.
+ pCurrAct->Execute( aMapModeVDev.get() );
-void SetBackgroundColorAndBounds(ConnectedComponents& rBackgroundComponent, Color const & rBackground, tools::Rectangle const& rBounds)
-{
- if( rBackground != COL_TRANSPARENT )
- {
- rBackgroundComponent.aBgColor = rBackground;
- rBackgroundComponent.aBounds = rBounds;
- }
-}
+ // cache bounds of current action
+ const tools::Rectangle aBBCurrAct( ImplCalcActionBounds(*pCurrAct, *aMapModeVDev) );
-int DetectBackground(ConnectedComponents& rBackgroundComponent, MetaAction* pCurrAct,
- Color const & rBackgroundColor, tools::Rectangle const& rRectBounds,
- GDIMetaFile const & rMtf, VirtualDevice* pMapModeVDev,
- sal_uInt32 nDPIX, sal_uInt32 nDPIY)
-{
- RecordMapModeChanges(pMapModeVDev, nDPIX, nDPIY);
-
- // weed out page-filling background objects (if they are
- // uniformly coloured). Keeping them outside the other
- // connected components often prevents whole-page bitmap
- // generation.
- SetBackgroundColorAndBounds(rBackgroundComponent, rBackgroundColor, rRectBounds);
- int nLastBgAction = FindIncompletelyOccludedBackground(rBackgroundComponent, rMtf, pMapModeVDev);
- int nActionNum = GetActionAfterBackgroundAction(rBackgroundComponent, pCurrAct, rMtf, nLastBgAction, pMapModeVDev);
- return nActionNum;
-}
+ // accumulate collected bounds here, initialize with current action
+ tools::Rectangle aTotalBounds( aBBCurrAct ); // thus, aTotalComponents.aBounds is empty
+ // for non-output-generating actions
+ bool bTreatSpecial( false );
+ ConnectedComponents aTotalComponents;
-bool GenerateIntersectingConnectedComponents(::std::vector<ConnectedComponents>& rConnectedComponents,
- ConnectedComponents& rTotalComponents,
- tools::Rectangle & rTotalBounds, bool bTreatSpecial)
-{
- bool bSomeComponentsChanged;
- // now, this is unfortunate: since changing anyone of
- // the aCCList elements (e.g. by merging or addition
- // of an action) might generate new intersection with
- // other aCCList elements, have to repeat the whole
- // element scanning, until nothing changes anymore.
- // Thus, this loop here makes us O(n^3) in the worst
- // case.
- do
- {
- // only loop here if 'intersects' branch below was hit
- bSomeComponentsChanged = false;
+ // STAGE 2.1: Search for intersecting cc entries
- // iterate over all current members of aCCList
- for( auto aCurrCC=rConnectedComponents.begin(); aCurrCC != rConnectedComponents.end(); )
- {
- // first check if current element's bounds are
- // empty. This ensures that empty actions are not
- // merged into one component, as a matter of fact,
- // they have no position.
+ // if aBBCurrAct is empty, it will intersect with no
+ // aCCList member. Thus, we can save the check.
+ // Furthermore, this ensures that non-output-generating
+ // actions get their own aCCList entry, which is necessary
+ // when copying them to the output metafile (see stage 4
+ // below).
// #107169# Wholly transparent objects need
// not be considered for connected components,
// too. Just put each of them into a separate
// component.
- if( !aCurrCC->aBounds.IsEmpty() &&
- !aCurrCC->bIsFullyTransparent &&
- aCurrCC->aBounds.IsOver(rTotalBounds))
- {
- // union the intersecting aCCList element into aTotalComponents
+ aTotalComponents.bIsFullyTransparent = !ImplIsNotTransparent(*pCurrAct, *aMapModeVDev);
- // calc union bounding box
- rTotalBounds.Union( aCurrCC->aBounds );
+ if( !aBBCurrAct.IsEmpty() &&
+ !aTotalComponents.bIsFullyTransparent )
+ {
+ if( !aBackgroundComponent.aComponentList.empty() &&
+ !aBackgroundComponent.aBounds.IsInside(aTotalBounds) )
+ {
+ // it seems the background is not large enough. to
+ // be on the safe side, combine with this component.
+ aTotalBounds.Union( aBackgroundComponent.aBounds );
- // extract all aCurr actions to aTotalComponents
- rTotalComponents.aComponentList.splice(rTotalComponents.aComponentList.end(),
- aCurrCC->aComponentList);
+ // extract all aCurr actions to aTotalComponents
+ aTotalComponents.aComponentList.splice( aTotalComponents.aComponentList.end(),
+ aBackgroundComponent.aComponentList );
- if (aCurrCC->bIsSpecial)
- bTreatSpecial = true;
+ if( aBackgroundComponent.bIsSpecial )
+ bTreatSpecial = true;
+ }
- // remove and delete aCurrCC element from list (we've now merged its content)
- aCurrCC = rConnectedComponents.erase(aCurrCC);
+ bool bSomeComponentsChanged;
- // at least one component changed, need to rescan everything
- bSomeComponentsChanged = true;
- }
- else
- {
- ++aCurrCC;
- }
- }
- }
- while(bSomeComponentsChanged);
+ // now, this is unfortunate: since changing anyone of
+ // the aCCList elements (e.g. by merging or addition
+ // of an action) might generate new intersection with
+ // other aCCList elements, have to repeat the whole
+ // element scanning, until nothing changes anymore.
+ // Thus, this loop here makes us O(n^3) in the worst
+ // case.
+ do
+ {
+ // only loop here if 'intersects' branch below was hit
+ bSomeComponentsChanged = false;
- return bTreatSpecial;
-}
+ // iterate over all current members of aCCList
+ for( auto aCurrCC=aCCList.begin(); aCurrCC != aCCList.end(); )
+ {
+ // first check if current element's bounds are
+ // empty. This ensures that empty actions are not
+ // merged into one component, as a matter of fact,
+ // they have no position.
+
+ // #107169# Wholly transparent objects need
+ // not be considered for connected components,
+ // too. Just put each of them into a separate
+ // component.
+ if( !aCurrCC->aBounds.IsEmpty() &&
+ !aCurrCC->bIsFullyTransparent &&
+ aCurrCC->aBounds.IsOver( aTotalBounds ) )
+ {
+ // union the intersecting aCCList element into aTotalComponents
-int GenerateConnectedComponents(::std::vector<ConnectedComponents>& rConnectedComponents, ConnectedComponents& rBackgroundComponent, MetaAction* pCurrAct, int nActionNum, GDIMetaFile const & rMtf, VirtualDevice *pMapModeVDev)
-{
- // iterate over all actions (start where background action search left off)
- for( ;
- pCurrAct;
- pCurrAct=const_cast<GDIMetaFile&>(rMtf).NextAction(), ++nActionNum )
- {
- // execute action to get correct MapModes etc.
- pCurrAct->Execute(pMapModeVDev);
-
- // cache bounds of current action
- const tools::Rectangle aBBCurrAct( ImplCalcActionBounds(*pCurrAct, *pMapModeVDev) );
-
- // accumulate collected bounds here, initialize with current action
- tools::Rectangle aTotalBounds( aBBCurrAct ); // thus, aTotalComponents.aBounds is empty for
- // non-output-generating actions
- bool bTreatSpecial( false );
- ConnectedComponents aTotalComponents;
-
- // STAGE 2.1: Search for intersecting cc entries
-
- // if aBBCurrAct is empty, it will intersect with no
- // rConnectedComponentst member. Thus, we can save the check.
- // Furthermore, this ensures that non-output-generating
- // actions get their own rConnectedComponents entry, which is necessary
- // when copying them to the output metafile (see stage 4
- // below).
-
- // #107169# Wholly transparent objects need
- // not be considered for connected components,
- // too. Just put each of them into a separate
- // component.
- aTotalComponents.bIsFullyTransparent = !ImplIsNotTransparent(*pCurrAct, *pMapModeVDev);
-
- if( !aBBCurrAct.IsEmpty() &&
- !aTotalComponents.bIsFullyTransparent )
- {
- if( !rBackgroundComponent.aComponentList.empty() &&
- !rBackgroundComponent.aBounds.IsInside(aTotalBounds) )
- {
- // it seems the background is not large enough. to
- // be on the safe side, combine with this component.
- aTotalBounds.Union(rBackgroundComponent.aBounds);
+ // calc union bounding box
+ aTotalBounds.Union( aCurrCC->aBounds );
- // extract all aCurr actions to aTotalComponents
- aTotalComponents.aComponentList.splice(aTotalComponents.aComponentList.end(),
- rBackgroundComponent.aComponentList);
+ // extract all aCurr actions to aTotalComponents
+ aTotalComponents.aComponentList.splice( aTotalComponents.aComponentList.end(),
+ aCurrCC->aComponentList );
- if (rBackgroundComponent.bIsSpecial)
- bTreatSpecial = true;
- }
+ if( aCurrCC->bIsSpecial )
+ bTreatSpecial = true;
- bTreatSpecial = GenerateIntersectingConnectedComponents(rConnectedComponents, aTotalComponents, aTotalBounds, bTreatSpecial);
- }
+ // remove and delete aCurrCC element from list (we've now merged its content)
+ aCurrCC = aCCList.erase( aCurrCC );
- // STAGE 2.2: Determine special state for cc element
-
- // now test whether the whole connected component must be
- // treated specially (i.e. rendered as a bitmap): if the
- // added action is the very first action, or all actions
- // before it are completely transparent, the connected
- // component need not be treated specially, not even if
- // the added action contains transparency. This is because
- // painting of transparent objects on _white background_
- // works without alpha compositing (you just calculate the
- // color). Note that for the test "all objects before me
- // are transparent" no sorting is necessary, since the
- // added metaaction pCurrAct is always in the order the
- // metafile is painted. Generally, the order of the
- // metaactions in the ConnectedComponents are not
- // guaranteed to be the same as in the metafile.
- if( bTreatSpecial )
- {
- // prev component(s) special -> this one, too
- aTotalComponents.bIsSpecial = true;
- }
- else if(!pCurrAct->IsTransparent())
- {
- // added action and none of prev components special ->
- // this one normal, too
- aTotalComponents.bIsSpecial = false;
- }
- else
- {
- // added action is special and none of prev components
- // special -> do the detailed tests
+ // at least one component changed, need to rescan everything
+ bSomeComponentsChanged = true;
+ }
+ else
+ {
+ ++aCurrCC;
+ }
+ }
+ }
+ while( bSomeComponentsChanged );
+ }
- // can the action handle transparency correctly
- // (i.e. when painted on white background, does the
- // action still look correct)?
- if( !DoesActionHandleTransparency( *pCurrAct ) )
+ // STAGE 2.2: Determine special state for cc element
+
+ // now test whether the whole connected component must be
+ // treated specially (i.e. rendered as a bitmap): if the
+ // added action is the very first action, or all actions
+ // before it are completely transparent, the connected
+ // component need not be treated specially, not even if
+ // the added action contains transparency. This is because
+ // painting of transparent objects on _white background_
+ // works without alpha compositing (you just calculate the
+ // color). Note that for the test "all objects before me
+ // are transparent" no sorting is necessary, since the
+ // added metaaction pCurrAct is always in the order the
+ // metafile is painted. Generally, the order of the
+ // metaactions in the ConnectedComponents are not
+ // guaranteed to be the same as in the metafile.
+ if( bTreatSpecial )
{
- // no, action cannot handle its transparency on
- // a printer device, render to bitmap
+ // prev component(s) special -> this one, too
aTotalComponents.bIsSpecial = true;
}
+ else if(!pCurrAct->IsTransparent())
+ {
+ // added action and none of prev components special ->
+ // this one normal, too
+ aTotalComponents.bIsSpecial = false;
+ }
else
{
- // yes, action can handle its transparency, so
- // check whether we're on white background
- if( aTotalComponents.aComponentList.empty() )
+ // added action is special and none of prev components
+ // special -> do the detailed tests
+
+ // can the action handle transparency correctly
+ // (i.e. when painted on white background, does the
+ // action still look correct)?
+ if( !DoesActionHandleTransparency( *pCurrAct ) )
{
- // nothing between pCurrAct and page
- // background -> don't be special
- aTotalComponents.bIsSpecial = false;
+ // no, action cannot handle its transparency on
+ // a printer device, render to bitmap
+ aTotalComponents.bIsSpecial = true;
}
else
{
- // #107169# Fixes above now ensure that _no_
- // object in the list is fully transparent. Thus,
- // if the component list is not empty above, we
- // must assume that we have to treat this
- // component special.
-
- // there are non-transparent objects between
- // pCurrAct and the empty sheet of paper -> be
- // special, then
- aTotalComponents.bIsSpecial = true;
+ // yes, action can handle its transparency, so
+ // check whether we're on white background
+ if( aTotalComponents.aComponentList.empty() )
+ {
+ // nothing between pCurrAct and page
+ // background -> don't be special
+ aTotalComponents.bIsSpecial = false;
+ }
+ else
+ {
+ // #107169# Fixes above now ensure that _no_
+ // object in the list is fully transparent. Thus,
+ // if the component list is not empty above, we
+ // must assume that we have to treat this
+ // component special.
+
+ // there are non-transparent objects between
+ // pCurrAct and the empty sheet of paper -> be
+ // special, then
+ aTotalComponents.bIsSpecial = true;
+ }
}
}
- }
- // STAGE 2.3: Add newly generated CC list element
+ // STAGE 2.3: Add newly generated CC list element
- // set new bounds and add action to list
- aTotalComponents.aBounds = aTotalBounds;
- aTotalComponents.aComponentList.emplace_back(
- pCurrAct, nActionNum );
+ // set new bounds and add action to list
+ aTotalComponents.aBounds = aTotalBounds;
+ aTotalComponents.aComponentList.emplace_back(
+ pCurrAct, nActionNum );
- // add aTotalComponents as a new entry to rConnectedComponents
- rConnectedComponents.push_back( aTotalComponents );
-
- SAL_WARN_IF( aTotalComponents.aComponentList.empty(), "vcl",
- "Printer::GetPreparedMetaFile empty component" );
- SAL_WARN_IF( aTotalComponents.aBounds.IsEmpty() && (aTotalComponents.aComponentList.size() != 1), "vcl",
- "Printer::GetPreparedMetaFile non-output generating actions must be solitary");
- SAL_WARN_IF( aTotalComponents.bIsFullyTransparent && (aTotalComponents.aComponentList.size() != 1), "vcl",
- "Printer::GetPreparedMetaFile fully transparent actions must be solitary");
- }
-
- return nActionNum;
-}
-
-} // end anon namespace
-
-bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, GDIMetaFile& rOutMtf,
- long nMaxBmpDPIX, long nMaxBmpDPIY,
- bool bReduceTransparency, bool bTransparencyAutoMode,
- bool bDownsampleBitmaps,
- const Color& rBackground
- )
-{
- MetaAction* pCurrAct = nullptr;
- bool bTransparent( false );
+ // add aTotalComponents as a new entry to aCCList
+ aCCList.push_back( aTotalComponents );
- rOutMtf.Clear();
-
- if(!bReduceTransparency || bTransparencyAutoMode)
- bTransparent = rInMtf.HasTransparentActions();
-
- // #i10613# Determine set of connected components containing transparent objects. These are
- // then processed as bitmaps, the original actions are removed from the metafile.
- if( !bTransparent )
- {
- // nothing transparent -> just copy
- rOutMtf = rInMtf;
- }
- else
- {
- // #i10613#
- // This works as follows: we want a number of distinct sets of
- // connected components, where each set contains metafile
- // actions that are intersecting (note: there are possibly
- // more actions contained as are directly intersecting,
- // because we can only produce rectangular bitmaps later
- // on. Thus, each set of connected components is the smallest
- // enclosing, axis-aligned rectangle that completely bounds a
- // number of intersecting metafile actions, plus any action
- // that would otherwise be cut in two). Therefore, we
- // iteratively add metafile actions from the original metafile
- // to this connected components list (aCCList), by checking
- // each element's bounding box against intersection with the
- // metaaction at hand.
- // All those intersecting elements are removed from aCCList
- // and collected in a temporary list (aCCMergeList). After all
- // elements have been checked, the aCCMergeList elements are
- // merged with the metaaction at hand into one resulting
- // connected component, with one big bounding box, and
- // inserted into aCCList again.
- // The time complexity of this algorithm is O(n^3), where n is
- // the number of metafile actions, and it finds all distinct
- // regions of rectangle-bounded connected components. This
- // algorithm was designed by AF.
-
- // STAGE 1: Detect background
-
- // create an OutputDevice to record mapmode changes and the like
- ScopedVclPtrInstance< VirtualDevice > aMapModeVDev;
-
- // Receives uniform background content, and is _not_ merged
- // nor checked for intersection against other aCCList elements
- ConnectedComponents aBackgroundComponent;
-
- int nActionNum = DetectBackground(aBackgroundComponent, pCurrAct,
- rBackground, GetBackgroundComponentBounds(),
- rInMtf, aMapModeVDev.get(),
- mnDPIX, mnDPIY);
-
- // STAGE 2: Generate connected components list
-
- ::std::vector<ConnectedComponents> aCCList; // contains sets of connected components as elements.
- nActionNum = GenerateConnectedComponents(aCCList, aBackgroundComponent, pCurrAct, nActionNum, rInMtf, aMapModeVDev.get());
+ SAL_WARN_IF( aTotalComponents.aComponentList.empty(), "vcl",
+ "Printer::GetPreparedMetaFile empty component" );
+ SAL_WARN_IF( aTotalComponents.aBounds.IsEmpty() && (aTotalComponents.aComponentList.size() != 1), "vcl",
+ "Printer::GetPreparedMetaFile non-output generating actions must be solitary");
+ SAL_WARN_IF( aTotalComponents.bIsFullyTransparent && (aTotalComponents.aComponentList.size() != 1), "vcl",
+ "Printer::GetPreparedMetaFile fully transparent actions must be solitary");
+ }
// well now, we've got the list of disjunct connected
// components. Now we've got to create a map, which contains
@@ -1098,14 +1060,6 @@ bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf,
const tools::Rectangle aOutputRect( aPageOffset, aTmpSize );
bool bTiling = dynamic_cast<Printer*>(this) != nullptr;
- // Read the configuration value of minimal object area where transparency will be removed
- double fReduceTransparencyMinArea = officecfg::Office::Common::VCL::ReduceTransparencyMinArea::get() / 100.0;
- SAL_WARN_IF(fReduceTransparencyMinArea > 1.0, "vcl",
- "Value of ReduceTransparencyMinArea config option is too high");
- SAL_WARN_IF(fReduceTransparencyMinArea < 0.0, "vcl",
- "Value of ReduceTransparencyMinArea config option is too low");
- fReduceTransparencyMinArea = std::clamp(fReduceTransparencyMinArea, 0.0, 1.0);
-
// iterate over all aCCList members and generate bitmaps for the special ones
for (auto & currentItem : aCCList)
{
More information about the Libreoffice-commits
mailing list