diff options
3 files changed, 242 insertions, 266 deletions
diff --git a/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx b/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx index b6b85390a711..4367d8e3eb1a 100644 --- a/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx @@ -28,6 +28,8 @@ #include <drawinglayer/primitive2d/transformprimitive2d.hxx> #include <drawinglayer/primitive2d/maskprimitive2d.hxx> #include <drawinglayer/geometry/viewinformation2d.hxx> +#include <sal/log.hxx> +#include <cmath> using namespace com::sun::star; @@ -102,131 +104,191 @@ namespace drawinglayer::primitive2d if(rEntries.empty()) { - // no fill at all + // no fill at all, done + return; } - else - { - const sal_uInt32 nCount(rEntries.size()); - if(1 == nCount) + // sort maGradientEntries by offset, small to big + std::sort(maGradientEntries.begin(), maGradientEntries.end()); + + // gradient with at least two colors + bool bAllInvisible(true); + bool bInvalidEntries(false); + + for(const SvgGradientEntry& rCandidate : rEntries) + { + if(basegfx::fTools::equalZero(rCandidate.getOpacity())) { - // fill with single existing color - setSingleEntry(); + // invisible + mbFullyOpaque = false; + } + else if(basegfx::fTools::equal(rCandidate.getOpacity(), 1.0)) + { + // completely opaque + bAllInvisible = false; } else { - // sort maGradientEntries when more than one - std::sort(maGradientEntries.begin(), maGradientEntries.end()); + // opacity + bAllInvisible = false; + mbFullyOpaque = false; + } - // gradient with at least two colors - bool bAllInvisible(true); + if(!basegfx::fTools::betweenOrEqualEither(rCandidate.getOffset(), 0.0, 1.0)) + { + bInvalidEntries = true; + } + } - for(sal_uInt32 a(0); a < nCount; a++) - { - const SvgGradientEntry& rCandidate = rEntries[a]; + if(bAllInvisible) + { + // all invisible, nothing to do + return; + } - if(basegfx::fTools::equalZero(rCandidate.getOpacity())) - { - // invisible - mbFullyOpaque = false; - } - else if(basegfx::fTools::equal(rCandidate.getOpacity(), 1.0)) - { - // completely opaque - bAllInvisible = false; - } - else - { - // opacity - bAllInvisible = false; - mbFullyOpaque = false; - } - } + if(bInvalidEntries) + { + // invalid entries, do nothing + SAL_WARN("drawinglayer", "SvgGradientHelper got invalid SvgGradientEntries outside [0.0 .. 1.0]"); + return; + } - if(bAllInvisible) - { - // all invisible, nothing to do - } - else - { - const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange()); + const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange()); - if(aPolyRange.isEmpty()) - { - // no range to fill, nothing to do - } - else - { - const double fPolyWidth(aPolyRange.getWidth()); - const double fPolyHeight(aPolyRange.getHeight()); - - if(basegfx::fTools::equalZero(fPolyWidth) || basegfx::fTools::equalZero(fPolyHeight)) - { - // no width/height to fill, nothing to do - } - else - { - mbCreatesContent = true; - } - } - } - } + if(aPolyRange.isEmpty()) + { + // no range to fill, nothing to do + return; + } + + const double fPolyWidth(aPolyRange.getWidth()); + const double fPolyHeight(aPolyRange.getHeight()); + + if(basegfx::fTools::equalZero(fPolyWidth) || basegfx::fTools::equalZero(fPolyHeight)) + { + // no width/height to fill, nothing to do + return; + } + + mbCreatesContent = true; + + if(1 == rEntries.size()) + { + // fill with single existing color + setSingleEntry(); } } - double SvgGradientHelper::createRun( - Primitive2DContainer& rTargetColor, - Primitive2DContainer& rTargetOpacity, - double fPos, - double fMax, - const SvgGradientEntryVector& rEntries, - sal_Int32 nOffset) const + const SvgGradientEntry& SvgGradientHelper::FindEntryLessOrEqual( + sal_Int32& rInt, + const double fFrac) const { - const sal_uInt32 nCount(rEntries.size()); + const bool bMirror(SpreadMethod::Reflect == getSpreadMethod() && 0 != rInt % 2); + const SvgGradientEntryVector& rCurrent(bMirror ? getMirroredGradientEntries() : getGradientEntries()); - if(nCount) + for(SvgGradientEntryVector::const_reverse_iterator aIter(rCurrent.rbegin()); aIter != rCurrent.rend(); aIter++) { - const SvgGradientEntry& rStart = rEntries[0]; - const bool bCreateStartPad(fPos < 0.0 && SpreadMethod::Pad == getSpreadMethod()); - const bool bCreateStartFill(rStart.getOffset() > 0.0); - sal_uInt32 nIndex(0); + if(basegfx::fTools::lessOrEqual(aIter->getOffset(), fFrac)) + { + return *aIter; + } + } - if(bCreateStartPad || bCreateStartFill) - { - const SvgGradientEntry aTemp(bCreateStartPad ? fPos : 0.0, rStart.getColor(), rStart.getOpacity()); + // walk over gap to the left, be prepared for missing 0.0/1.0 entries + rInt--; + const bool bMirror2(SpreadMethod::Reflect == getSpreadMethod() && 0 != rInt % 2); + const SvgGradientEntryVector& rCurrent2(bMirror2 ? getMirroredGradientEntries() : getGradientEntries()); + return rCurrent2.back(); + } - createAtom(rTargetColor, rTargetOpacity, aTemp, rStart, nOffset); - fPos = rStart.getOffset(); - } + const SvgGradientEntry& SvgGradientHelper::FindEntryMore( + sal_Int32& rInt, + const double fFrac) const + { + const bool bMirror(SpreadMethod::Reflect == getSpreadMethod() && 0 != rInt % 2); + const SvgGradientEntryVector& rCurrent(bMirror ? getMirroredGradientEntries() : getGradientEntries()); + + for(SvgGradientEntryVector::const_iterator aIter(rCurrent.begin()); aIter != rCurrent.end(); aIter++) + { + if(basegfx::fTools::more(aIter->getOffset(), fFrac)) + { + return *aIter; + } + } - while(fPos < 1.0 && nIndex + 1 < nCount) + // walk over gap to the right, be prepared for missing 0.0/1.0 entries + rInt++; + const bool bMirror2(SpreadMethod::Reflect == getSpreadMethod() && 0 != rInt % 2); + const SvgGradientEntryVector& rCurrent2(bMirror2 ? getMirroredGradientEntries() : getGradientEntries()); + return rCurrent2.front(); + } + + // tdf#124424 Adapted creation of color runs to do in a single effort. Previous + // version tried to do this from [0.0 .. 1.0] and to re-use transformed versions + // in the caller if SpreadMethod was on some repeat mode, but had problems when + // e.g. like in the bugdoc from the task a negative-only fStart/fEnd run was + // requested in which case it did nothing. Even when reusing the spread might + // not have been a full one from [0.0 .. 1.0]. + // This gets complicated due to mirrored runs, but also for gradient definitions + // with missing entries for 0.0 and 1.0 in which case these have to be guessed + // to be there with same parametrisation as their nearest existing entries. These + // *could* have been added at checkPreconditions() but would then create unnecessary + // spreads on zone overlaps. + void SvgGradientHelper::createRun( + Primitive2DContainer& rTargetColor, + Primitive2DContainer& rTargetOpacity, + double fStart, + double fEnd) const + { + if(SpreadMethod::Pad == getSpreadMethod()) + { + if(fStart < 0.0) { - const SvgGradientEntry& rCandidateA = rEntries[nIndex++]; - const SvgGradientEntry& rCandidateB = rEntries[nIndex]; + const SvgGradientEntry& rFront(getGradientEntries().front()); + const SvgGradientEntry aTemp(fStart, rFront.getColor(), rFront.getOpacity()); + createAtom(rTargetColor, rTargetOpacity, aTemp, rFront, 0, 0); + fStart = rFront.getOffset(); + } - createAtom(rTargetColor, rTargetOpacity, rCandidateA, rCandidateB, nOffset); - fPos = rCandidateB.getOffset(); + if(fEnd < 1.0) + { + const SvgGradientEntry& rBack(getGradientEntries().back()); + const SvgGradientEntry aTemp(fEnd, rBack.getColor(), rBack.getOpacity()); + createAtom(rTargetColor, rTargetOpacity, rBack, aTemp, 0, 0); + fEnd = rBack.getOffset(); } + } - const SvgGradientEntry& rEnd = rEntries[nCount - 1]; - const bool bCreateEndPad(fPos < fMax && SpreadMethod::Pad == getSpreadMethod()); - const bool bCreateEndFill(rEnd.getOffset() < 1.0); + while(fStart < fEnd) + { + double fInt(0.0); + double fFrac(std::modf(fStart, &fInt)); - if(bCreateEndPad || bCreateEndFill) + if(fFrac < 0.0) { - fPos = bCreateEndPad ? fMax : 1.0; - const SvgGradientEntry aTemp(fPos, rEnd.getColor(), rEnd.getOpacity()); + fInt -= 1; + fFrac = 1.0 + fFrac; + } + + sal_Int32 nIntLeft(static_cast<sal_Int32>(fInt)); + sal_Int32 nIntRight(nIntLeft); - createAtom(rTargetColor, rTargetOpacity, rEnd, aTemp, nOffset); + const SvgGradientEntry& rLeft(FindEntryLessOrEqual(nIntLeft, fFrac)); + const SvgGradientEntry& rRight(FindEntryMore(nIntRight, fFrac)); + createAtom(rTargetColor, rTargetOpacity, rLeft, rRight, nIntLeft, nIntRight); + + const double fNextfStart(static_cast<double>(nIntRight) + rRight.getOffset()); + + if(basegfx::fTools::more(fNextfStart, fStart)) + { + fStart = fNextfStart; + } + else + { + SAL_WARN("drawinglayer", "SvgGradientHelper spread error"); + fStart += 1.0; } } - else - { - OSL_ENSURE(false, "GradientAtom creation without ColorStops (!)"); - fPos = fMax; - } - - return fPos; } void SvgGradientHelper::createResult( @@ -276,6 +338,7 @@ namespace drawinglayer::primitive2d : maGradientTransform(rGradientTransform), maPolyPolygon(rPolyPolygon), maGradientEntries(rGradientEntries), + maMirroredGradientEntries(), maStart(rStart), maSpreadMethod(aSpreadMethod), mbPreconditionsChecked(false), @@ -290,6 +353,36 @@ namespace drawinglayer::primitive2d { } + const SvgGradientEntryVector& SvgGradientHelper::getMirroredGradientEntries() const + { + if(maMirroredGradientEntries.empty() && !getGradientEntries().empty()) + { + const_cast< SvgGradientHelper* >(this)->createMirroredGradientEntries(); + } + + return maMirroredGradientEntries; + } + + void SvgGradientHelper::createMirroredGradientEntries() + { + if(maMirroredGradientEntries.empty() && !getGradientEntries().empty()) + { + const sal_uInt32 nCount(getGradientEntries().size()); + maMirroredGradientEntries.clear(); + maMirroredGradientEntries.reserve(nCount); + + for(sal_uInt32 a(0); a < nCount; a++) + { + const SvgGradientEntry& rCandidate = getGradientEntries()[nCount - 1 - a]; + + maMirroredGradientEntries.emplace_back( + 1.0 - rCandidate.getOffset(), + rCandidate.getColor(), + rCandidate.getOpacity()); + } + } + } + bool SvgGradientHelper::operator==(const SvgGradientHelper& rSvgGradientHelper) const { const SvgGradientHelper& rCompare = rSvgGradientHelper; @@ -330,7 +423,8 @@ namespace drawinglayer::primitive2d Primitive2DContainer& rTargetOpacity, const SvgGradientEntry& rFrom, const SvgGradientEntry& rTo, - sal_Int32 nOffset) const + sal_Int32 nOffsetFrom, + sal_Int32 nOffsetTo) const { // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] with (rFrom.getOffset() > rTo.getOffset()) if(rFrom.getOffset() == rTo.getOffset()) @@ -341,8 +435,8 @@ namespace drawinglayer::primitive2d { rTargetColor.push_back( new SvgLinearAtomPrimitive2D( - rFrom.getColor(), rFrom.getOffset() + nOffset, - rTo.getColor(), rTo.getOffset() + nOffset)); + rFrom.getColor(), rFrom.getOffset() + nOffsetFrom, + rTo.getColor(), rTo.getOffset() + nOffsetTo)); if(!getFullyOpaque()) { @@ -353,8 +447,8 @@ namespace drawinglayer::primitive2d rTargetOpacity.push_back( new SvgLinearAtomPrimitive2D( - aColorFrom, rFrom.getOffset() + nOffset, - aColorTo, rTo.getOffset() + nOffset)); + aColorFrom, rFrom.getOffset() + nOffsetFrom, + aColorTo, rTo.getOffset() + nOffsetTo)); } } } @@ -441,92 +535,12 @@ namespace drawinglayer::primitive2d 1.0, aUnitRange.getHeight(), 0.0, aUnitRange.getMinY())); aUnitGradientToObject = aUnitGradientToObject * aPreMultiply; - // create central run, may also already do all necessary when - // SpreadMethod::Pad is set as SpreadMethod and/or the range is smaller - double fPos(createRun(aTargetColor, aTargetOpacity, aUnitRange.getMinX(), aUnitRange.getMaxX(), getGradientEntries(), 0)); - - if(fPos < aUnitRange.getMaxX()) - { - // can only happen when SpreadMethod is SpreadMethod::Reflect or SpreadMethod::Repeat, - // else the start and end pads are already created and fPos == aUnitRange.getMaxX(). - // Its possible to express the repeated linear gradient by adding the - // transformed central run. Create it this way - Primitive2DContainer aTargetColorEntries(aTargetColor.maybeInvert()); - Primitive2DContainer aTargetOpacityEntries(aTargetOpacity.maybeInvert()); - aTargetColor.clear(); - aTargetOpacity.clear(); - - if(!aTargetColorEntries.empty()) - { - // add original central run as group primitive - aTargetColor.push_back(new GroupPrimitive2D(aTargetColorEntries)); - - if(!aTargetOpacityEntries.empty()) - { - aTargetOpacity.push_back(new GroupPrimitive2D(aTargetOpacityEntries)); - } - - // add negative runs - fPos = 0.0; - sal_Int32 nOffset(0); - - while(fPos > aUnitRange.getMinX()) - { - fPos -= 1.0; - nOffset++; - - basegfx::B2DHomMatrix aTransform; - const bool bMirror(SpreadMethod::Reflect == getSpreadMethod() && (nOffset % 2)); - - if(bMirror) - { - aTransform.scale(-1.0, 1.0); - aTransform.translate(fPos + 1.0, 0.0); - } - else - { - aTransform.translate(fPos, 0.0); - } - - aTargetColor.push_back(new TransformPrimitive2D(aTransform, aTargetColorEntries)); - - if(!aTargetOpacityEntries.empty()) - { - aTargetOpacity.push_back(new TransformPrimitive2D(aTransform, aTargetOpacityEntries)); - } - } - - // add positive runs - fPos = 1.0; - nOffset = 1; - - while(fPos < aUnitRange.getMaxX()) - { - basegfx::B2DHomMatrix aTransform; - const bool bMirror(SpreadMethod::Reflect == getSpreadMethod() && (nOffset % 2)); - - if(bMirror) - { - aTransform.scale(-1.0, 1.0); - aTransform.translate(fPos + 1.0, 0.0); - } - else - { - aTransform.translate(fPos, 0.0); - } - - aTargetColor.push_back(new TransformPrimitive2D(aTransform, aTargetColorEntries)); - - if(!aTargetOpacityEntries.empty()) - { - aTargetOpacity.push_back(new TransformPrimitive2D(aTransform, aTargetOpacityEntries)); - } - - fPos += 1.0; - nOffset++; - } - } - } + // create full color run, including all SpreadMethod variants + createRun( + aTargetColor, + aTargetOpacity, + aUnitRange.getMinX(), + aUnitRange.getMaxX()); } createResult(rContainer, aTargetColor, aTargetOpacity, aUnitGradientToObject); @@ -600,7 +614,8 @@ namespace drawinglayer::primitive2d Primitive2DContainer& rTargetOpacity, const SvgGradientEntry& rFrom, const SvgGradientEntry& rTo, - sal_Int32 nOffset) const + sal_Int32 nOffsetFrom, + sal_Int32 nOffsetTo) const { // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] with (rFrom.getOffset() > rTo.getOffset()) if(rFrom.getOffset() == rTo.getOffset()) @@ -609,8 +624,8 @@ namespace drawinglayer::primitive2d } else { - const double fScaleFrom(rFrom.getOffset() + nOffset); - const double fScaleTo(rTo.getOffset() + nOffset); + const double fScaleFrom(rFrom.getOffset() + nOffsetFrom); + const double fScaleTo(rTo.getOffset() + nOffsetTo); if(isFocalSet()) { @@ -658,36 +673,6 @@ namespace drawinglayer::primitive2d } } - const SvgGradientEntryVector& SvgRadialGradientPrimitive2D::getMirroredGradientEntries() const - { - if(maMirroredGradientEntries.empty() && !getGradientEntries().empty()) - { - const_cast< SvgRadialGradientPrimitive2D* >(this)->createMirroredGradientEntries(); - } - - return maMirroredGradientEntries; - } - - void SvgRadialGradientPrimitive2D::createMirroredGradientEntries() - { - if(maMirroredGradientEntries.empty() && !getGradientEntries().empty()) - { - const sal_uInt32 nCount(getGradientEntries().size()); - maMirroredGradientEntries.clear(); - maMirroredGradientEntries.reserve(nCount); - - for(sal_uInt32 a(0); a < nCount; a++) - { - const SvgGradientEntry& rCandidate = getGradientEntries()[nCount - 1 - a]; - - maMirroredGradientEntries.emplace_back( - 1.0 - rCandidate.getOffset(), - rCandidate.getColor(), - rCandidate.getOpacity()); - } - } - } - void SvgRadialGradientPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const { if(!getPreconditionsChecked()) @@ -774,35 +759,12 @@ namespace drawinglayer::primitive2d const_cast< SvgRadialGradientPrimitive2D* >(this)->maFocalLength = fMax; } - // create central run, may also already do all necessary when - // SpreadMethod::Pad is set as SpreadMethod and/or the range is smaller - double fPos(createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getGradientEntries(), 0)); - - if(fPos < fMax) - { - // can only happen when SpreadMethod is SpreadMethod::Reflect or SpreadMethod::Repeat, - // else the start and end pads are already created and fPos == fMax. - // For radial there is no way to transform the already created - // central run, it needs to be created from 1.0 to fMax - sal_Int32 nOffset(1); - - while(fPos < fMax) - { - const bool bMirror(SpreadMethod::Reflect == getSpreadMethod() && (nOffset % 2)); - - if(bMirror) - { - createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getMirroredGradientEntries(), nOffset); - } - else - { - createRun(aTargetColor, aTargetOpacity, 0.0, fMax, getGradientEntries(), nOffset); - } - - nOffset++; - fPos += 1.0; - } - } + // create full color run, including all SpreadMethod variants + createRun( + aTargetColor, + aTargetOpacity, + 0.0, + fMax); } createResult(rContainer, aTargetColor, aTargetOpacity, aUnitGradientToObject, true); @@ -824,7 +786,6 @@ namespace drawinglayer::primitive2d maFocal(rStart), maFocalVector(0.0, 0.0), maFocalLength(0.0), - maMirroredGradientEntries(), mbFocalSet(false) { if(pFocal && !pFocal->equal(getStart())) diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx index 936afec29364..9b16f6af51a3 100644 --- a/drawinglayer/source/tools/emfphelperdata.cxx +++ b/drawinglayer/source/tools/emfphelperdata.cxx @@ -877,11 +877,23 @@ namespace emfplushelper if (brush->type == BrushTypeLinearGradient) { + // support for public enum EmfPlusWrapMode basegfx::B2DPoint aStartPoint = Map(brush->firstPointX, brush->firstPointY); aStartPoint = aPolygonTransformation * aStartPoint; basegfx::B2DPoint aEndPoint = Map(brush->firstPointX + brush->secondPointX, brush->firstPointY + brush->secondPointY); aEndPoint = aPolygonTransformation * aEndPoint; + // support for public enum EmfPlusWrapMode + drawinglayer::primitive2d::SpreadMethod aSpreadMethod(drawinglayer::primitive2d::SpreadMethod::Pad); + switch(brush->wrapMode) + { + case 0 : aSpreadMethod = drawinglayer::primitive2d::SpreadMethod::Repeat; break; + case 1 : + case 2 : + case 3 : aSpreadMethod = drawinglayer::primitive2d::SpreadMethod::Reflect; break; + default: break; + } + // create the same one used for SVG mrTargetHolders.Current().append( std::make_unique<drawinglayer::primitive2d::SvgLinearGradientPrimitive2D>( @@ -891,7 +903,7 @@ namespace emfplushelper aStartPoint, aEndPoint, false, // do not use UnitCoordinates - drawinglayer::primitive2d::SpreadMethod::Pad)); + aSpreadMethod)); } else // BrushTypePathGradient { diff --git a/include/drawinglayer/primitive2d/svggradientprimitive2d.hxx b/include/drawinglayer/primitive2d/svggradientprimitive2d.hxx index c130368bf5b9..871a4aea822d 100644 --- a/include/drawinglayer/primitive2d/svggradientprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/svggradientprimitive2d.hxx @@ -101,6 +101,9 @@ namespace drawinglayer /// the gradient definition SvgGradientEntryVector maGradientEntries; + // internal helper for case SpreadMethod::Reflect + SvgGradientEntryVector maMirroredGradientEntries; + /// start and/or center point basegfx::B2DPoint maStart; @@ -117,6 +120,12 @@ namespace drawinglayer // (related to SVG's gradientUnits (userSpaceOnUse|objectBoundingBox) bool mbUseUnitCoordinates : 1; + /// local helpers + const SvgGradientEntryVector& getMirroredGradientEntries() const; + void createMirroredGradientEntries(); + const SvgGradientEntry& FindEntryLessOrEqual(sal_Int32& rInt, const double fFrac) const; + const SvgGradientEntry& FindEntryMore(sal_Int32& rInt,const double fFrac) const; + protected: /// local helpers void createSingleGradientEntryFill(Primitive2DContainer& rContainer) const; @@ -125,14 +134,13 @@ namespace drawinglayer Primitive2DContainer& rTargetOpacity, const SvgGradientEntry& rFrom, const SvgGradientEntry& rTo, - sal_Int32 nOffset) const = 0; - double createRun( + sal_Int32 nOffsetFrom, + sal_Int32 nOffsetTo) const = 0; + void createRun( Primitive2DContainer& rTargetColor, Primitive2DContainer& rTargetOpacity, - double fPos, - double fMax, - const SvgGradientEntryVector& rEntries, - sal_Int32 nOffset) const; + double fStart, + double fEnd) const; virtual void checkPreconditions(); void createResult( Primitive2DContainer& rContainer, @@ -191,7 +199,8 @@ namespace drawinglayer Primitive2DContainer& rTargetOpacity, const SvgGradientEntry& rFrom, const SvgGradientEntry& rTo, - sal_Int32 nOffset) const override; + sal_Int32 nOffsetFrom, + sal_Int32 nOffsetTo) const override; virtual void checkPreconditions() override; /// local decomposition. @@ -243,22 +252,16 @@ namespace drawinglayer basegfx::B2DVector maFocalVector; double maFocalLength; - // internal helper for case SpreadMethod::Reflect - SvgGradientEntryVector maMirroredGradientEntries; - bool mbFocalSet : 1; /// local helpers - const SvgGradientEntryVector& getMirroredGradientEntries() const; - void createMirroredGradientEntries(); - - /// local helpers virtual void createAtom( Primitive2DContainer& rTargetColor, Primitive2DContainer& rTargetOpacity, const SvgGradientEntry& rFrom, const SvgGradientEntry& rTo, - sal_Int32 nOffset) const override; + sal_Int32 nOffsetFrom, + sal_Int32 nOffsetTo) const override; virtual void checkPreconditions() override; /// local decomposition. |