diff options
-rw-r--r-- | basegfx/source/matrix/b2dhommatrixtools.cxx | 41 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dpolygon.cxx | 2 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dpolygontools.cxx | 33 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dpolypolygoncutter.cxx | 77 | ||||
-rw-r--r-- | basegfx/source/polygon/b2dpolypolygontools.cxx | 17 | ||||
-rw-r--r-- | include/basegfx/matrix/b2dhommatrixtools.hxx | 6 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolygontools.hxx | 5 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolypolygontools.hxx | 5 | ||||
-rw-r--r-- | include/basegfx/tuple/b2dtuple.hxx | 4 | ||||
-rw-r--r-- | include/basegfx/tuple/b3dtuple.hxx | 4 | ||||
-rw-r--r-- | sc/source/ui/inc/output.hxx | 2 | ||||
-rw-r--r-- | sc/source/ui/view/gridwin.cxx | 8 | ||||
-rw-r--r-- | sc/source/ui/view/output.cxx | 34 | ||||
-rw-r--r-- | vcl/source/gdi/region.cxx | 5 | ||||
-rw-r--r-- | vcl/win/source/gdi/salgdi.cxx | 80 |
15 files changed, 282 insertions, 41 deletions
diff --git a/basegfx/source/matrix/b2dhommatrixtools.cxx b/basegfx/source/matrix/b2dhommatrixtools.cxx index 5666064d7933..3e39fd5e4df6 100644 --- a/basegfx/source/matrix/b2dhommatrixtools.cxx +++ b/basegfx/source/matrix/b2dhommatrixtools.cxx @@ -357,6 +357,47 @@ namespace basegfx return aRetval; } + + /// special for the case to map from source range to target range + B2DHomMatrix createSourceRangeTargetRangeTransform( + const B2DRange& rSourceRange, + const B2DRange& rTargetRange) + { + B2DHomMatrix aRetval; + + if(&rSourceRange == &rTargetRange) + { + return aRetval; + } + + if(!fTools::equalZero(rSourceRange.getMinX()) || !fTools::equalZero(rSourceRange.getMinY())) + { + aRetval.set(0, 2, -rSourceRange.getMinX()); + aRetval.set(1, 2, -rSourceRange.getMinY()); + } + + const double fSourceW(rSourceRange.getWidth()); + const double fSourceH(rSourceRange.getHeight()); + const bool bDivX(!fTools::equalZero(fSourceW) && !fTools::equal(fSourceW, 1.0)); + const bool bDivY(!fTools::equalZero(fSourceH) && !fTools::equal(fSourceH, 1.0)); + const double fScaleX(bDivX ? rTargetRange.getWidth() / fSourceW : rTargetRange.getWidth()); + const double fScaleY(bDivY ? rTargetRange.getHeight() / fSourceH : rTargetRange.getHeight()); + + if(!fTools::equalZero(fScaleX) || !fTools::equalZero(fScaleY)) + { + aRetval.scale(fScaleX, fScaleY); + } + + if(!fTools::equalZero(rTargetRange.getMinX()) || !fTools::equalZero(rTargetRange.getMinY())) + { + aRetval.translate( + rTargetRange.getMinX(), + rTargetRange.getMinY()); + } + + return aRetval; + } + } // end of namespace tools } // end of namespace basegfx diff --git a/basegfx/source/polygon/b2dpolygon.cxx b/basegfx/source/polygon/b2dpolygon.cxx index 6b661f9d42ad..a24cab41edcb 100644 --- a/basegfx/source/polygon/b2dpolygon.cxx +++ b/basegfx/source/polygon/b2dpolygon.cxx @@ -1252,7 +1252,7 @@ namespace basegfx { OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); - if(getB2DPoint(nIndex) != rValue) + if(mpPolygon->getPoint(nIndex) != rValue) { mpPolygon->setPoint(nIndex, rValue); } diff --git a/basegfx/source/polygon/b2dpolygontools.cxx b/basegfx/source/polygon/b2dpolygontools.cxx index 59b2813d3614..de75b15f9efe 100644 --- a/basegfx/source/polygon/b2dpolygontools.cxx +++ b/basegfx/source/polygon/b2dpolygontools.cxx @@ -3193,6 +3193,39 @@ namespace basegfx } } + bool containsOnlyHorizontalAndVerticalEdges(const B2DPolygon& rCandidate) + { + if(rCandidate.areControlPointsUsed()) + { + return false; + } + + const sal_uInt32 nPointCount(rCandidate.count()); + + if(nPointCount < 2) + { + return true; + } + + const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount + 1 : nPointCount); + basegfx::B2DPoint aLast(rCandidate.getB2DPoint(0)); + + for(sal_uInt32 a(1); a < nEdgeCount; a++) + { + const sal_uInt32 nNextIndex(a % nPointCount); + const basegfx::B2DPoint aCurrent(rCandidate.getB2DPoint(nNextIndex)); + + if(!basegfx::fTools::equal(aLast.getX(), aCurrent.getX()) && !basegfx::fTools::equal(aLast.getY(), aCurrent.getY())) + { + return false; + } + + aLast = aCurrent; + } + + return true; + } + } // end of namespace tools } // end of namespace basegfx diff --git a/basegfx/source/polygon/b2dpolypolygoncutter.cxx b/basegfx/source/polygon/b2dpolypolygoncutter.cxx index f30d9228c226..22b9d4fffad4 100644 --- a/basegfx/source/polygon/b2dpolypolygoncutter.cxx +++ b/basegfx/source/polygon/b2dpolypolygoncutter.cxx @@ -104,6 +104,8 @@ namespace basegfx typedef ::std::vector< PN > PNV; typedef ::std::vector< VN > VNV; typedef ::std::vector< SN > SNV; + typedef ::std::pair< basegfx::B2DPoint /*orig*/, basegfx::B2DPoint /*repl*/ > CorrectionPair; + typedef ::std::vector< CorrectionPair > CorrectionTable; ////////////////////////////////////////////////////////////////////////////// @@ -114,6 +116,7 @@ namespace basegfx PNV maPNV; VNV maVNV; SNV maSNV; + CorrectionTable maCorrectionTable; unsigned mbIsCurve : 1; unsigned mbChanged : 1; @@ -438,13 +441,44 @@ namespace basegfx void impSolve() { - // sort by point to identify common nodes + // sort by point to identify common nodes easier ::std::sort(maSNV.begin(), maSNV.end()); // handle common nodes const sal_uInt32 nNodeCount(maSNV.size()); + sal_uInt32 a(0); - for(sal_uInt32 a(0); a < nNodeCount - 1; a++) + // snap unsharp-equal points + if(nNodeCount) + { + basegfx::B2DPoint* pLast(&maSNV[0].mpPN->maPoint); + + for(a = 1; a < nNodeCount; a++) + { + basegfx::B2DPoint* pCurrent(&maSNV[a].mpPN->maPoint); + + if(pLast->equal(*pCurrent) && (pLast->getX() != pCurrent->getX() || pLast->getY() != pCurrent->getY())) + { + const basegfx::B2DPoint aMiddle((*pLast + *pCurrent) * 0.5); + + if(pLast->getX() != aMiddle.getX() || pLast->getY() != aMiddle.getY()) + { + maCorrectionTable.push_back(CorrectionPair(*pLast, aMiddle)); + *pLast = aMiddle; + } + + if(pCurrent->getX() != aMiddle.getX() || pCurrent->getY() != aMiddle.getY()) + { + maCorrectionTable.push_back(CorrectionPair(*pCurrent, aMiddle)); + *pCurrent = aMiddle; + } + } + + pLast = pCurrent; + } + } + + for(a = 0; a < nNodeCount - 1; a++) { // test a before using it, not after. Also use nPointCount instead of aSortNodes.size() PN& rPNb = *(maSNV[a].mpPN); @@ -614,8 +648,45 @@ namespace basegfx } else { + const sal_uInt32 nCorrectionSize(maCorrectionTable.size()); + // no change, return original - return maOriginal; + if(!nCorrectionSize) + { + return maOriginal; + } + + // apply coordinate corrections to ensure inside/outside correctness after solving + const sal_uInt32 nPolygonCount(maOriginal.count()); + basegfx::B2DPolyPolygon aRetval(maOriginal); + + for(sal_uInt32 a(0); a < nPolygonCount; a++) + { + basegfx::B2DPolygon aTemp(aRetval.getB2DPolygon(a)); + const sal_uInt32 nPointCount(aTemp.count()); + bool bChanged; + + for(sal_uInt32 b(0); b < nPointCount; b++) + { + const basegfx::B2DPoint aCandidate(aTemp.getB2DPoint(b)); + + for(sal_uInt32 c(0); c < nCorrectionSize; c++) + { + if(maCorrectionTable[c].first.getX() == aCandidate.getX() && maCorrectionTable[c].first.getY() == aCandidate.getY()) + { + aTemp.setB2DPoint(b, maCorrectionTable[c].second); + bChanged = true; + } + } + } + + if(bChanged) + { + aRetval.setB2DPolygon(a, aTemp); + } + } + + return aRetval; } } }; diff --git a/basegfx/source/polygon/b2dpolypolygontools.cxx b/basegfx/source/polygon/b2dpolypolygontools.cxx index c2b18eff4e44..b7db01c29e28 100644 --- a/basegfx/source/polygon/b2dpolypolygontools.cxx +++ b/basegfx/source/polygon/b2dpolypolygontools.cxx @@ -498,6 +498,23 @@ namespace basegfx return aRetval; } + bool containsOnlyHorizontalAndVerticalEdges(const B2DPolyPolygon& rCandidate) + { + if(rCandidate.areControlPointsUsed()) + { + return false; + } + + for(sal_uInt32 a(0); a < rCandidate.count(); a++) + { + if(!containsOnlyHorizontalAndVerticalEdges(rCandidate.getB2DPolygon(a))) + { + return false; + } + } + + return true; + } } // end of namespace tools } // end of namespace basegfx diff --git a/include/basegfx/matrix/b2dhommatrixtools.hxx b/include/basegfx/matrix/b2dhommatrixtools.hxx index ed255360f831..39682c06331a 100644 --- a/include/basegfx/matrix/b2dhommatrixtools.hxx +++ b/include/basegfx/matrix/b2dhommatrixtools.hxx @@ -23,6 +23,7 @@ #include <sal/types.h> #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/vector/b2dvector.hxx> +#include <basegfx/range/b2drange.hxx> #include <basegfx/basegfxdllapi.h> @@ -127,6 +128,11 @@ namespace basegfx fRadiant); } + /// special for the case to map from source range to target range + B2DHomMatrix createSourceRangeTargetRangeTransform( + const B2DRange& rSourceRange, + const B2DRange& rTargetRange); + } // end of namespace tools } // end of namespace basegfx diff --git a/include/basegfx/polygon/b2dpolygontools.hxx b/include/basegfx/polygon/b2dpolygontools.hxx index dce479847d65..3be763bd18ad 100644 --- a/include/basegfx/polygon/b2dpolygontools.hxx +++ b/include/basegfx/polygon/b2dpolygontools.hxx @@ -434,6 +434,11 @@ namespace basegfx */ BASEGFX_DLLPUBLIC B2DPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolygon& rCandidate); + /** returns true if the Polygon only contains horizontal or vertical edges + so that it could be represented by RegionBands + */ + bool containsOnlyHorizontalAndVerticalEdges(const B2DPolygon& rCandidate); + } // end of namespace tools } // end of namespace basegfx diff --git a/include/basegfx/polygon/b2dpolypolygontools.hxx b/include/basegfx/polygon/b2dpolypolygontools.hxx index 01c1306de82d..092294eeb966 100644 --- a/include/basegfx/polygon/b2dpolypolygontools.hxx +++ b/include/basegfx/polygon/b2dpolypolygontools.hxx @@ -234,6 +234,11 @@ namespace basegfx */ BASEGFX_DLLPUBLIC B2DPolyPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolyPolygon& rCandidate); + /** returns true if the Polygon only contains horizontal or vertical edges + so that it could be represented by RegionBands + */ + bool containsOnlyHorizontalAndVerticalEdges(const B2DPolyPolygon& rCandidate); + } // end of namespace tools } // end of namespace basegfx diff --git a/include/basegfx/tuple/b2dtuple.hxx b/include/basegfx/tuple/b2dtuple.hxx index ac2b78f76447..f21124b5ca43 100644 --- a/include/basegfx/tuple/b2dtuple.hxx +++ b/include/basegfx/tuple/b2dtuple.hxx @@ -215,12 +215,12 @@ namespace basegfx bool operator==( const B2DTuple& rTup ) const { - return equal(rTup); + return mfX == rTup.mfX && mfY == rTup.mfY; } bool operator!=( const B2DTuple& rTup ) const { - return !equal(rTup); + return mfX != rTup.mfX || mfY != rTup.mfY; } B2DTuple& operator=( const B2DTuple& rTup ) diff --git a/include/basegfx/tuple/b3dtuple.hxx b/include/basegfx/tuple/b3dtuple.hxx index 9d8d080db807..d974f86abe28 100644 --- a/include/basegfx/tuple/b3dtuple.hxx +++ b/include/basegfx/tuple/b3dtuple.hxx @@ -240,12 +240,12 @@ namespace basegfx bool operator==( const B3DTuple& rTup ) const { - return equal(rTup); + return mfX == rTup.mfX && mfY == rTup.mfY && mfZ == rTup.mfZ; } bool operator!=( const B3DTuple& rTup ) const { - return !equal(rTup); + return mfX != rTup.mfX || mfY != rTup.mfY || mfZ != rTup.mfZ; } B3DTuple& operator=( const B3DTuple& rTup ) diff --git a/sc/source/ui/inc/output.hxx b/sc/source/ui/inc/output.hxx index 7e9af7f45a8e..cefeca8ec542 100644 --- a/sc/source/ui/inc/output.hxx +++ b/sc/source/ui/inc/output.hxx @@ -312,7 +312,7 @@ public: void DrawSelectiveObjects(const sal_uInt16 nLayer); sal_Bool SetChangedClip(); // sal_False = not - PolyPolygon GetChangedArea(); + Region GetChangedAreaRegion(); void FindChanged(); void SetPagebreakMode( ScPageBreakData* pPageData ); diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index 29016c2f4140..2b4e65784d61 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -4609,10 +4609,12 @@ void ScGridWindow::UpdateFormulas() aOutputData.FindChanged(); - PolyPolygon aChangedPoly( aOutputData.GetChangedArea() ); // logic (PixelToLogic) - if ( aChangedPoly.Count() ) + // #i122149# do not use old GetChangedArea() which used polygon-based Regions, but use + // the region-band based new version; anyways, only rectangles are added + Region aChangedRegion( aOutputData.GetChangedAreaRegion() ); // logic (PixelToLogic) + if(!aChangedRegion.IsEmpty()) { - Invalidate(Region(aChangedPoly)); + Invalidate(aChangedRegion); } CheckNeedsRepaint(); // #i90362# used to be called via Draw() - still needed here diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx index 6a5c8e65f28f..37b8c3166c03 100644 --- a/sc/source/ui/view/output.cxx +++ b/sc/source/ui/view/output.cxx @@ -1867,42 +1867,46 @@ drawinglayer::processor2d::BaseProcessor2D* ScOutputData::CreateProcessor2D( ) // Drucker -PolyPolygon ScOutputData::GetChangedArea() +Region ScOutputData::GetChangedAreaRegion() { - PolyPolygon aPoly; - + Region aRegion; Rectangle aDrawingRect; + bool bHad(false); + long nPosY = nScrY; + SCSIZE nArrY; + aDrawingRect.Left() = nScrX; aDrawingRect.Right() = nScrX+nScrW-1; - sal_Bool bHad = false; - long nPosY = nScrY; - SCSIZE nArrY; - for (nArrY=1; nArrY+1<nArrCount; nArrY++) + for(nArrY=1; nArrY+1<nArrCount; nArrY++) { RowInfo* pThisRowInfo = &pRowInfo[nArrY]; - if ( pThisRowInfo->bChanged ) + if(pThisRowInfo->bChanged) { - if (!bHad) + if(!bHad) { aDrawingRect.Top() = nPosY; - bHad = sal_True; + bHad = true; } + aDrawingRect.Bottom() = nPosY + pRowInfo[nArrY].nHeight - 1; } - else if (bHad) + else if(bHad) { - aPoly.Insert( Polygon( mpDev->PixelToLogic(aDrawingRect) ) ); + aRegion.Union(mpDev->PixelToLogic(aDrawingRect)); bHad = false; } + nPosY += pRowInfo[nArrY].nHeight; } - if (bHad) - aPoly.Insert( Polygon( mpDev->PixelToLogic(aDrawingRect) ) ); + if(bHad) + { + aRegion.Union(mpDev->PixelToLogic(aDrawingRect)); + } - return aPoly; + return aRegion; } sal_Bool ScOutputData::SetChangedClip() diff --git a/vcl/source/gdi/region.cxx b/vcl/source/gdi/region.cxx index e715d0230ccb..3ddc53daaefd 100644 --- a/vcl/source/gdi/region.cxx +++ b/vcl/source/gdi/region.cxx @@ -1271,9 +1271,10 @@ Rectangle Region::GetBoundRect() const } else { + // #i122149# corrected rounding, no need for ceil() and floor() here return Rectangle( - static_cast<sal_Int32>(floor(aRange.getMinX())), static_cast<sal_Int32>(floor(aRange.getMinY())), - static_cast<sal_Int32>(ceil(aRange.getMaxX())), static_cast<sal_Int32>(ceil(aRange.getMaxY()))); + basegfx::fround(aRange.getMinX()), basegfx::fround(aRange.getMinY()), + basegfx::fround(aRange.getMaxX()), basegfx::fround(aRange.getMaxY())); } } diff --git a/vcl/win/source/gdi/salgdi.cxx b/vcl/win/source/gdi/salgdi.cxx index 8928d519cc18..e3a660f3f7b1 100644 --- a/vcl/win/source/gdi/salgdi.cxx +++ b/vcl/win/source/gdi/salgdi.cxx @@ -20,20 +20,18 @@ #include <stdio.h> #include <string.h> - #include <svsys.h> #include <rtl/strbuf.hxx> - #include <tools/debug.hxx> #include <tools/poly.hxx> - #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> - +#include <basegfx/polygon/b2dpolypolygontools.hxx> #include <win/wincomp.hxx> #include <win/saldata.hxx> #include <win/salgdi.h> #include <win/salframe.h> +#include <basegfx/matrix/b2dhommatrixtools.hxx> // ======================================================================= @@ -846,8 +844,40 @@ bool WinSalGraphics::setClipRegion( const Region& i_rClip ) mhRegion = 0; } - if( i_rClip.HasPolyPolygonOrB2DPolyPolygon() ) + bool bUsePolygon(i_rClip.HasPolyPolygonOrB2DPolyPolygon()); + static bool bTryToAvoidPolygon(true); + + // #i122149# try to avoid usage of PolyPolygon ClipRegions when PolyPolygon is no curve + // and only contains horizontal/vertical edges. In that case, use the fallback + // in GetRegionRectangles which will use Region::GetAsRegionBand() which will do + // the correct polygon-to-RegionBand transformation. + // Background is that when using the same Rectangle as rectangle or as Polygon + // clip region will lead to different results; the polygon-based one will be + // one pixel less to the right and down (see GDI docu for CreatePolygonRgn). This + // again is because of the polygon-nature and it's classic handling when filling. + // This also means that all cases which use a 'true' polygon-based incarnation of + // a Region should know what they do - it may lead to repaint errors. + if(bUsePolygon && bTryToAvoidPolygon) + { + const basegfx::B2DPolyPolygon aPolyPolygon( i_rClip.GetAsB2DPolyPolygon() ); + + if(!aPolyPolygon.areControlPointsUsed()) + { + if(basegfx::tools::containsOnlyHorizontalAndVerticalEdges(aPolyPolygon)) + { + bUsePolygon = false; + } + } + } + + if(bUsePolygon) { + // #i122149# check the comment above to know that this may lead to potentioal repaint + // problems. It may be solved (if needed) by scaling the polygon by one in X + // and Y. Currently the workaround to only use it if really unavoidable will + // solve most cases. When someone is really using polygon-based Regions he + // should know what he is doing. + // Added code to do that scaling to check if it works, testing it. const basegfx::B2DPolyPolygon aPolyPolygon( i_rClip.GetAsB2DPolyPolygon() ); const sal_uInt32 nCount(aPolyPolygon.count()); @@ -856,21 +886,38 @@ bool WinSalGraphics::setClipRegion( const Region& i_rClip ) std::vector< POINT > aPolyPoints; aPolyPoints.reserve( 1024 ); std::vector< INT > aPolyCounts( nCount, 0 ); + basegfx::B2DHomMatrix aExpand; + static bool bExpandByOneInXandY(true); - for(sal_uInt32 a(0); a < nCount; a++) + if(bExpandByOneInXandY) { - basegfx::B2DPolygon aPoly(aPolyPolygon.getB2DPolygon(a)); + const basegfx::B2DRange aRangeS(aPolyPolygon.getB2DRange()); + const basegfx::B2DRange aRangeT(aRangeS.getMinimum(), aRangeS.getMaximum() + basegfx::B2DTuple(1.0, 1.0)); + aExpand = basegfx::B2DHomMatrix(basegfx::tools::createSourceRangeTargetRangeTransform(aRangeS, aRangeT)); + } - aPoly = basegfx::tools::adaptiveSubdivideByDistance( aPoly, 1 ); - const sal_uInt32 nPoints = aPoly.count(); + for(sal_uInt32 a(0); a < nCount; a++) + { + const basegfx::B2DPolygon aPoly( + basegfx::tools::adaptiveSubdivideByDistance( + aPolyPolygon.getB2DPolygon(a), + 1)); + const sal_uInt32 nPoints(aPoly.count()); aPolyCounts[a] = nPoints; for( sal_uInt32 b = 0; b < nPoints; b++ ) { - basegfx::B2DPoint aPt( aPoly.getB2DPoint( b ) ); + basegfx::B2DPoint aPt(aPoly.getB2DPoint(b)); + + if(bExpandByOneInXandY) + { + aPt = aExpand * aPt; + } + POINT aPOINT; - aPOINT.x = (LONG)aPt.getX(); - aPOINT.y = (LONG)aPt.getY(); + // #i122149# do correct rounding + aPOINT.x = basegfx::fround(aPt.getX()); + aPOINT.y = basegfx::fround(aPt.getY()); aPolyPoints.push_back( aPOINT ); } } @@ -993,7 +1040,16 @@ bool WinSalGraphics::setClipRegion( const Region& i_rClip ) } if( mhRegion ) + { SelectClipRgn( getHDC(), mhRegion ); + + // debug code if you weant to check range of the newly applied ClipRegion + //RECT aBound; + //const int aRegionType = GetRgnBox(mhRegion, &aBound); + // + //bool bBla = true; + } + return mhRegion != 0; } |