drawinglayer/source/primitive2d/wrongspellprimitive2d.cxx | 102 +++++++++---- include/basegfx/curve/b2dcubicbezier.hxx | 2 include/drawinglayer/primitive2d/wrongspellprimitive2d.hxx | 4 3 files changed, 81 insertions(+), 27 deletions(-)
New commits: commit 8bdddee0897034976bbbea57eedf4c7611228d5d Author: Armin Le Grand (Collabora) <armin.le.gr...@me.com> AuthorDate: Fri Aug 23 14:39:34 2024 +0200 Commit: Armin Le Grand <armin.le.gr...@me.com> CommitDate: Fri Aug 23 16:36:59 2024 +0200 CairoSDPR: Adapt WrongSpell Primitive to View-Independent Change-Id: If739dd9f28f56874978c7b3a76e1234e5f430c9f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172319 Tested-by: Jenkins Reviewed-by: Armin Le Grand <armin.le.gr...@me.com> diff --git a/drawinglayer/source/primitive2d/wrongspellprimitive2d.cxx b/drawinglayer/source/primitive2d/wrongspellprimitive2d.cxx index 6084814ae71f..b583dd9901a1 100644 --- a/drawinglayer/source/primitive2d/wrongspellprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/wrongspellprimitive2d.cxx @@ -19,9 +19,10 @@ #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx> #include <basegfx/polygon/b2dpolygon.hxx> -#include <drawinglayer/primitive2d/PolygonWavePrimitive2D.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/curve/b2dcubicbezier.hxx> +#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx> #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> -#include <drawinglayer/geometry/viewinformation2d.hxx> #include <utility> @@ -29,43 +30,95 @@ namespace drawinglayer::primitive2d { Primitive2DReference WrongSpellPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const { - // ATM this decompose is view-independent, what the original VCL-Display is not. To mimic - // the old behaviour here if wanted it is necessary to add get2DDecomposition and implement - // it similar to the usage in e.g. HelplinePrimitive2D. Remembering the ViewTransformation - // should be enough then. - // The view-independent wavelines work well (if You ask me). Maybe the old VCL-Behaviour is only - // in place because it was not possible/too expensive at that time to scale the wavelines with the - // view... - // With the VCL-PixelRenderer this will not even be used since it implements WrongSpellPrimitive2D - // directly and mimics the old VCL-Display there. If You implemented a new renderer without - // direct WrongSpellPrimitive2D support, You may want to do the described change here. + // This *was* a view-independent primitive before (see before this commit), + // but was never really used, but handled in various processors anyways. + // Since the current VCL primitve renderer and it's functions used in + // VCL do render this always in one discrete pixel size I decided to + // adapt this primitive to do that, too, but - due to being a primitive - + // with the correct invalidate/hit-ranges etc. + // I use here DiscreteMetricDependentPrimitive2D which already implements + // buffering and providing the discrete size using 'getDiscreteUnit()' plus + // the needed updates to buffering, what makes the rest simple. + // NOTE: If one day the (in my opinion) also good looking view-independent + // version should be needed again, just revert this change + if (basegfx::fTools::lessOrEqual(getStop(), getStart())) + { + // stop smaller or equal to start, done + return nullptr; + } // get the font height (part of scale), so decompose the matrix basegfx::B2DVector aScale, aTranslate; double fRotate, fShearX; getTransformation().decompose(aScale, aTranslate, fRotate, fShearX); + constexpr double constMinimumFontHeight(5.0); + if (aScale.getY() / getDiscreteUnit() < constMinimumFontHeight) + { + // font height smaller constMinimumFontHeight pixels -> decompose to empty + return nullptr; + } + // calculate distances based on a static default (to allow testing in debugger) static const double fDefaultDistance(0.03); const double fFontHeight(aScale.getY()); const double fUnderlineDistance(fFontHeight * fDefaultDistance); - const double fWaveWidth(2.0 * fUnderlineDistance); // the Y-distance needs to be relative to FontHeight since the points get // transformed with the transformation containing that scale already. const double fRelativeUnderlineDistance(basegfx::fTools::equalZero(aScale.getY()) ? 0.0 : fUnderlineDistance / aScale.getY()); - basegfx::B2DPoint aStart(getStart(), fRelativeUnderlineDistance); - basegfx::B2DPoint aStop(getStop(), fRelativeUnderlineDistance); - basegfx::B2DPolygon aPolygon; - aPolygon.append(getTransformation() * aStart); - aPolygon.append(getTransformation() * aStop); + // get start/stop positions and WaveLength, base all calculations for discrete + // waveline on these initial values + basegfx::B2DPoint aStart(getTransformation() * basegfx::B2DPoint(getStart(), fRelativeUnderlineDistance)); + const basegfx::B2DPoint aStop(getTransformation() * basegfx::B2DPoint(getStop(), fRelativeUnderlineDistance)); + const double fWaveLength(getDiscreteUnit() * 8); + + // get pre-calculated vector and controlPoint for one wave segment + basegfx::B2DVector aVector(aStop - aStart); + double fLength(aVector.getLength()); + aVector.normalize(); + basegfx::B2DVector aControl(basegfx::getPerpendicular(aVector)); + aVector *= fWaveLength; + aControl = aControl * (fWaveLength * 0.5) + aVector * 0.5; + + // create geometry + basegfx::B2DPolygon aWave; + aWave.append(aStart); + + while (fLength > fWaveLength) + { + // one WaveSegment per WaveLength + basegfx::B2DPoint aNew(aStart + aVector); + aWave.appendBezierSegment( + aStart + aControl, + aNew - aControl, + aNew); + aStart = aNew; + fLength -= fWaveLength; + } - // prepare line attribute - const attribute::LineAttribute aLineAttribute(getColor()); + if (fLength > fWaveLength * 0.2) + { + // if rest is more than 20% of WaveLength, create + // remaining snippet and add it + basegfx::B2DPoint aNew(aStart + aVector); + basegfx::B2DCubicBezier aRest( + aStart, + aStart + aControl, + aNew - aControl, + aNew); + aRest = aRest.snippet(0.0, fLength/fWaveLength); + aWave.appendBezierSegment( + aRest.getControlPointA(), + aRest.getControlPointB(), + aRest.getEndPoint()); + } - // create the waveline primitive - return new PolygonWavePrimitive2D(aPolygon, aLineAttribute, fWaveWidth, 0.5 * fWaveWidth); + // create & return primitive + return new PolygonHairlinePrimitive2D( + aWave, + getColor()); } WrongSpellPrimitive2D::WrongSpellPrimitive2D( @@ -73,7 +126,8 @@ namespace drawinglayer::primitive2d double fStart, double fStop, const basegfx::BColor& rColor) - : maTransformation(std::move(aTransformation)), + : DiscreteMetricDependentPrimitive2D(), + maTransformation(std::move(aTransformation)), mfStart(fStart), mfStop(fStop), maColor(rColor) @@ -82,7 +136,7 @@ namespace drawinglayer::primitive2d bool WrongSpellPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const { - if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) + if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive)) { const WrongSpellPrimitive2D& rCompare = static_cast<const WrongSpellPrimitive2D&>(rPrimitive); diff --git a/include/basegfx/curve/b2dcubicbezier.hxx b/include/basegfx/curve/b2dcubicbezier.hxx index 9d79fbeb5f9d..00a46b6333f2 100644 --- a/include/basegfx/curve/b2dcubicbezier.hxx +++ b/include/basegfx/curve/b2dcubicbezier.hxx @@ -159,7 +159,7 @@ namespace basegfx void split(double t, B2DCubicBezier* pBezierA, B2DCubicBezier* pBezierB) const; // extract snippet from fStart to fEnd from this bezier - SAL_DLLPRIVATE B2DCubicBezier snippet(double fStart, double fEnd) const; + B2DCubicBezier snippet(double fStart, double fEnd) const; // get range including control points B2DRange getRange() const; diff --git a/include/drawinglayer/primitive2d/wrongspellprimitive2d.hxx b/include/drawinglayer/primitive2d/wrongspellprimitive2d.hxx index 9a903f9f3db1..e3b743c8d6fe 100644 --- a/include/drawinglayer/primitive2d/wrongspellprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/wrongspellprimitive2d.hxx @@ -21,7 +21,7 @@ #include <drawinglayer/drawinglayerdllapi.h> -#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx> +#include <drawinglayer/primitive2d/primitivetools2d.hxx> #include <basegfx/color/bcolor.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> @@ -44,7 +44,7 @@ namespace drawinglayer::primitive2d The geometric definition defines a line on the X-Axis (no Y-coordinates) which will when transformed by Transformation, create the coordinate data. */ - class DRAWINGLAYER_DLLPUBLIC WrongSpellPrimitive2D final : public BufferedDecompositionPrimitive2D + class DRAWINGLAYER_DLLPUBLIC WrongSpellPrimitive2D final : public DiscreteMetricDependentPrimitive2D { private: /// geometry definition