drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx | 2 editeng/inc/outleeng.hxx | 2 editeng/source/editeng/editeng.cxx | 4 editeng/source/editeng/impedit.hxx | 2 editeng/source/editeng/impedit3.cxx | 885 +++---------- editeng/source/outliner/outleeng.cxx | 6 editeng/source/outliner/outliner.cxx | 105 - include/editeng/editeng.hxx | 2 include/editeng/outliner.hxx | 13 sd/source/ui/view/outlview.cxx | 79 - 10 files changed, 335 insertions(+), 765 deletions(-)
New commits: commit 83ffcdd964611c739e5235e829d015c4965b55d7 Author: Armin Le Grand (collabora) <[email protected]> AuthorDate: Mon Aug 4 14:15:15 2025 +0200 Commit: Armin Le Grand <[email protected]> CommitDate: Mon Aug 4 20:35:16 2025 +0200 StripPortions: Further simplify EditEngine Since 6c8b8020510f8816c40a42e6c3a7fde12012b142 which is 'StripPortions: full Primitive usage for EditEngine Paint' all DrawText_To* methods were already using a full conversion to Primitives which then get painted directly, see commit comment there. Since then no complaints/errors came up I now continue to move EditEngine to Primitive usage. Lots of code for the still also existing DirectPaint gets removed. I also drive forward changes to have less parameters for the ImpEditEngine::StripAllPortions method. It is already cleared by the former possible rotation, this can (and is) replaced by embedding the result to a transform primitive doing that rotation. I changed two of three using methods to strip always to position (0, 0) which can also be unified to embedding to a transformation. The third one will need some more work here due to doing wild things in Outliner mode in Impress (callbacks & creating Primitives in fixed positions for which an embedding translate would be wrong). When being able to strip without position and rotation the result will be usable to be buffered, so the goal is to re-use that, transformed as needed (translate, scale, rotate, ...) as long as the text itself does not change. Change-Id: I52ab548ccbb1b5b3b16c50451a314bc7f3b39d93 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188918 Tested-by: Jenkins Reviewed-by: Armin Le Grand <[email protected]> diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index 95769d43212d..7f826a9b040c 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -1470,7 +1470,7 @@ void VclMetafileProcessor2D::processTextHierarchyBulletPrimitive2D( // process recursively and add MetaFile comment process(rBulletPrimitive); - // in Outliner::PaintOrStripBullet(), a MetafileComment for bullets is added, too. The + // in Outliner::StripBullet(), a MetafileComment for bullets is added, too. The // "XTEXT_EOC" is used, use here, too. mpMetaFile->AddAction(new MetaCommentAction("XTEXT_EOC"_ostr)); diff --git a/editeng/inc/outleeng.hxx b/editeng/inc/outleeng.hxx index b9def51b9ff0..ea0aac27056a 100644 --- a/editeng/inc/outleeng.hxx +++ b/editeng/inc/outleeng.hxx @@ -35,7 +35,7 @@ public: OutlinerEditEng( Outliner* pOwner, SfxItemPool* pPool ); virtual ~OutlinerEditEng() override; - virtual void ProcessFirstLineOfParagraph(sal_Int32 nPara, const Point& rStartPos, const Point& rOrigin, Degree10 nOrientation, OutputDevice& rOutDev, StripPortionsHelper* pStripPortionsHelper) override; + virtual void ProcessFirstLineOfParagraph(sal_Int32 nPara, const Point& rStartPos, OutputDevice& rOutDev, StripPortionsHelper& rStripPortionsHelper) override; virtual void ParagraphInserted( sal_Int32 nNewParagraph ) override; virtual void ParagraphDeleted( sal_Int32 nDeletedParagraph ) override; diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx index b9a23c68f4d2..ac2530ec67aa 100644 --- a/editeng/source/editeng/editeng.cxx +++ b/editeng/source/editeng/editeng.cxx @@ -1079,7 +1079,7 @@ void EditEngine::StripPortions(StripPortionsHelper& rStripPortionsHelper) } } - getImpl().PaintOrStrip(*aTmpDev, aBigRect, Point(), 0_deg10, &rStripPortionsHelper); + getImpl().StripAllPortions(*aTmpDev, aBigRect, Point(), rStripPortionsHelper); } void EditEngine::GetPortions( sal_Int32 nPara, std::vector<sal_Int32>& rList ) @@ -1569,7 +1569,7 @@ EditEngine::CreateTransferable(const ESelection& rSelection) // ====================== Virtual Methods ======================== -void EditEngine::ProcessFirstLineOfParagraph(sal_Int32, const Point&, const Point&, Degree10, OutputDevice&, StripPortionsHelper*) +void EditEngine::ProcessFirstLineOfParagraph(sal_Int32, const Point&, OutputDevice&, StripPortionsHelper&) { } diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx index 8e61f99c8dd6..792bddf36efb 100644 --- a/editeng/source/editeng/impedit.hxx +++ b/editeng/source/editeng/impedit.hxx @@ -1003,7 +1003,7 @@ public: void UpdateViews( EditView* pCurView = nullptr ); Point CalculateTextPaintStartPosition(ImpEditView& rView) const; void DrawText_ToEditView( TextHierarchyBreakup& rHelper, ImpEditView* pView, const tools::Rectangle& rRect, OutputDevice* pTargetDevice ); - void PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipRect, Point aStartPos, Degree10 nOrientation = 0_deg10, StripPortionsHelper* pStripPortionsHelper = nullptr); + void StripAllPortions( OutputDevice& rOutDev, tools::Rectangle aClipRect, Point aStartPos, StripPortionsHelper& rStripPortionsHelper); bool MouseButtonUp( const MouseEvent& rMouseEvent, EditView* pView ); bool MouseButtonDown( const MouseEvent& rMouseEvent, EditView* pView ); diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx index 7ddae54bd77d..18cb268d07f5 100644 --- a/editeng/source/editeng/impedit3.cxx +++ b/editeng/source/editeng/impedit3.cxx @@ -96,6 +96,8 @@ #include <basegfx/polygon/b2dpolygontools.hxx> #include <drawinglayer/primitive2d/transformprimitive2d.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/color/bcolormodifier.hxx> +#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> #include <unicode/uchar.h> @@ -106,8 +108,6 @@ using namespace ::com::sun::star::linguistic2; constexpr OUString CH_HYPH = u"-"_ustr; -constexpr tools::Long WRONG_SHOW_MIN = 5; - #if (OSL_DEBUG_LEVEL > 1) || defined ( DBG_UTIL ) bool ImpEditEngine::bDebugPaint = false; #endif @@ -160,92 +160,6 @@ AsianCompressionFlags GetCharTypeForCompression( sal_Unicode cChar ) } } -static void lcl_DrawRedLines( OutputDevice& rOutDev, - tools::Long nFontHeight, - const Point& rPoint, - size_t nIndex, - size_t nMaxEnd, - KernArraySpan pDXArray, - WrongList const * pWrongs, - Degree10 nOrientation, - const Point& rOrigin, - bool bVertical, - bool bIsRightToLeft ) -{ - // But only if font is not too small... - tools::Long nHeight = rOutDev.LogicToPixel(Size(0, nFontHeight)).Height(); - if (WRONG_SHOW_MIN >= nHeight) - return; - - size_t nEnd, nStart = nIndex; - bool bWrong = pWrongs->NextWrong(nStart, nEnd); - - while (bWrong) - { - if (nStart >= nMaxEnd) - break; - - if (nStart < nIndex) // Corrected - nStart = nIndex; - - if (nEnd > nMaxEnd) - nEnd = nMaxEnd; - - Point aPoint1(rPoint); - if (bVertical) - { - // VCL doesn't know that the text is vertical, and is manipulating - // the positions a little bit in y direction... - tools::Long nOnePixel = rOutDev.PixelToLogic(Size(0, 1)).Height(); - tools::Long nCorrect = 2 * nOnePixel; - aPoint1.AdjustY(-nCorrect); - aPoint1.AdjustX(-nCorrect); - } - if (nStart > nIndex) - { - if (!bVertical) - { - // since for RTL portions rPoint is on the visual right end of the portion - // (i.e. at the start of the first RTL char) we need to subtract the offset - // for RTL portions... - aPoint1.AdjustX((bIsRightToLeft ? -1 : 1) * pDXArray[nStart - nIndex - 1]); - } - else - aPoint1.AdjustY(pDXArray[nStart - nIndex - 1]); - } - Point aPoint2(rPoint); - assert(nEnd > nIndex && "RedLine: aPnt2?"); - if (!bVertical) - { - // since for RTL portions rPoint is on the visual right end of the portion - // (i.e. at the start of the first RTL char) we need to subtract the offset - // for RTL portions... - aPoint2.AdjustX((bIsRightToLeft ? -1 : 1) * pDXArray[nEnd - nIndex - 1]); - } - else - { - aPoint2.AdjustY(pDXArray[nEnd - nIndex - 1]); - } - - if (nOrientation) - { - rOrigin.RotateAround(aPoint1, nOrientation); - rOrigin.RotateAround(aPoint2, nOrientation); - } - - { - vcl::ScopedAntialiasing a(rOutDev, true); - rOutDev.DrawWaveLine(aPoint1, aPoint2); - } - - nStart = nEnd + 1; - if (nEnd < nMaxEnd) - bWrong = pWrongs->NextWrong(nStart, nEnd); - else - bWrong = false; - } -} - void ImpEditEngine::UpdateViews( EditView* pCurView ) { if ( !IsUpdateLayout() || IsFormatting() || maInvalidRect.IsEmpty() ) @@ -3361,65 +3275,75 @@ Point ImpEditEngine::MoveToNextLine( return rMovePos - aOld; } -void ImpEditEngine::DrawText_ToPosition( OutputDevice& rOutDev, const Point& rStartPos, Degree10 nOrientation ) +void ImpEditEngine::DrawText_ToPosition( + OutputDevice& rOutDev, const Point& rStartPos, Degree10 nOrientation ) { - if( rOutDev.GetConnectMetaFile() ) - rOutDev.Push(); - // Create with 2 points, as with positive points it will end up with // LONGMAX as Size, Bottom and Right in the range > LONGMAX. - tools::Rectangle aBigRect( -0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF ); - Point aStartPos( rStartPos ); + const tools::Rectangle aBigRect( -0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF ); + + // extract Primitives + TextHierarchyBreakup aHelper; + StripAllPortions(rOutDev, aBigRect, Point(), aHelper); + if (aHelper.getTextPortionPrimitives().empty()) + // no Primitives, done + return; + + // get content + drawinglayer::primitive2d::Primitive2DContainer aContent(aHelper.getTextPortionPrimitives()); + + // calculate StartPos + Point aStartPos( rStartPos ); if ( IsEffectivelyVertical() ) { aStartPos.AdjustX(GetPaperSize().Width() ); rStartPos.RotateAround(aStartPos, nOrientation); } - static bool bUsePrimitives(nullptr == std::getenv("DISBALE_EDITENGINE_ON_PRIMITIVES")); + basegfx::B2DHomMatrix aTransform; - if (bUsePrimitives) + if (0_deg10 != nOrientation) { - // extract Primitives. - // Do not use Orientation, that will be added below as transformation - TextHierarchyBreakup aHelper; - PaintOrStrip(rOutDev, aBigRect, aStartPos, 0_deg10, &aHelper); - - if (aHelper.getTextPortionPrimitives().empty()) - // no Primitives, done - return; - - // create ViewInformation2D based on target OutputDevice - drawinglayer::geometry::ViewInformation2D aViewInformation2D; - aViewInformation2D.setViewTransformation(rOutDev.GetViewTransformation()); - - // get content - drawinglayer::primitive2d::Primitive2DContainer aContent(aHelper.getTextPortionPrimitives()); + // if we have an Orientation, add rotation. Note that input value is + // 10th degree and wrong oriented for a right-hand coordinate system (sigh) + // add rotation around (0, 0) before translation to StartPos + const double fAngle(-toRadians(nOrientation)); + aTransform = basegfx::utils::createRotateB2DHomMatrix(fAngle); + } - if (0_deg10 != nOrientation) - { - // if we have an Orientation, add rotation. Note that input value is - // 10th degree and wrong oriented for a right-hand coordinate system (sigh) - const double fAngle(-toRadians(nOrientation)); - aContent = drawinglayer::primitive2d::Primitive2DContainer{ - new drawinglayer::primitive2d::TransformPrimitive2D( - basegfx::utils::createRotateAroundPoint(aStartPos.X(), aStartPos.Y(), fAngle), - std::move(aContent))}; - } + if (0 != aStartPos.X() || 0 != aStartPos.Y()) + { + // translate by aStartPos + aTransform *= basegfx::utils::createTranslateB2DHomMatrix(aStartPos.X(), aStartPos.Y()); + } - // create PrimitiveProcessor and render to target - std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> xProcessor( - drawinglayer::processor2d::createProcessor2DFromOutputDevice(rOutDev, aViewInformation2D)); - xProcessor->process(aContent); + if (!aTransform.isIdentity()) + { + // embed to transformation + aContent = drawinglayer::primitive2d::Primitive2DContainer{ + new drawinglayer::primitive2d::TransformPrimitive2D( + aTransform, + std::move(aContent))}; } - else + + static bool bBlendForTest(false); + if(bBlendForTest) { - PaintOrStrip(rOutDev, aBigRect, aStartPos, nOrientation); + aContent = drawinglayer::primitive2d::Primitive2DContainer{ + new drawinglayer::primitive2d::ModifiedColorPrimitive2D( + std::move(aContent), + std::make_shared<basegfx::BColorModifier_interpolate>(COL_LIGHTRED.getBColor(), 0.5)) }; } - if (rOutDev.GetConnectMetaFile()) - rOutDev.Pop(); + // create ViewInformation2D based on target OutputDevice + drawinglayer::geometry::ViewInformation2D aViewInformation2D; + aViewInformation2D.setViewTransformation(rOutDev.GetViewTransformation()); + + // create PrimitiveProcessor and render to target + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> xProcessor( + drawinglayer::processor2d::createProcessor2DFromOutputDevice(rOutDev, aViewInformation2D)); + xProcessor->process(aContent); } void ImpEditEngine::DrawText_ToRectangle( OutputDevice& rOutDev, const tools::Rectangle& rOutRect, const Point& rStartDocPos, bool bHardClip ) @@ -3429,11 +3353,43 @@ void ImpEditEngine::DrawText_ToRectangle( OutputDevice& rOutDev, const tools::Re DumpData(false); #endif - // Align to the pixel boundary, so that it becomes exactly the same - // as Paint () - tools::Rectangle aOutRect( rOutDev.LogicToPixel( rOutRect ) ); - aOutRect = rOutDev.PixelToLogic( aOutRect ); + // get aOutRect and align to the pixel boundary, so that it + // becomes exactly the same as Paint() + const tools::Rectangle aOutRect(rOutDev.PixelToLogic(rOutDev.LogicToPixel(rOutRect))); + const tools::Rectangle aClipRect(0, 0, aOutRect.GetWidth(), aOutRect.GetHeight()); + + // extract Primitives + TextHierarchyBreakup aHelper; + StripAllPortions(rOutDev, aClipRect, Point(), aHelper); + + if (aHelper.getTextPortionPrimitives().empty()) + // no Primitives, done + return; + + // create ViewInformation2D based on target OutputDevice + drawinglayer::geometry::ViewInformation2D aViewInformation2D; + aViewInformation2D.setViewTransformation(rOutDev.GetViewTransformation()); + + // get content and it's range, plus ClipRange + drawinglayer::primitive2d::Primitive2DContainer aContent(aHelper.getTextPortionPrimitives()); + const basegfx::B2DRange aContentRange(aContent.getB2DRange(aViewInformation2D)); + const basegfx::B2DRange aClipRange(vcl::unotools::b2DRectangleFromRectangle(aClipRect)); + + if (!aContentRange.overlaps(aClipRange)) + // no overlap, nothing visible + return; + + if (bHardClip && !aClipRange.isInside(aContentRange)) + { + // not completely inside aClipRange and clipping requested + // Embed to MaskPrimitive2D + aContent = drawinglayer::primitive2d::Primitive2DContainer{ + new drawinglayer::primitive2d::MaskPrimitive2D( + basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aClipRange)), + std::move(aContent))}; + } + // calculate StartPos Point aStartPos; if ( !IsEffectivelyVertical() ) { @@ -3446,127 +3402,51 @@ void ImpEditEngine::DrawText_ToRectangle( OutputDevice& rOutDev, const tools::Re aStartPos.setY( aOutRect.Top() - rStartDocPos.X() ); } - static bool bUsePrimitives(nullptr == std::getenv("DISBALE_EDITENGINE_ON_PRIMITIVES")); - - if (bUsePrimitives) + if (0 != aStartPos.X() || 0 != aStartPos.Y()) { - // extract Primitives - TextHierarchyBreakup aHelper; - PaintOrStrip(rOutDev, aOutRect, aStartPos, 0_deg10, &aHelper); - - if (aHelper.getTextPortionPrimitives().empty()) - // no Primitives, done - return; - - // create ViewInformation2D based on target OutputDevice - drawinglayer::geometry::ViewInformation2D aViewInformation2D; - aViewInformation2D.setViewTransformation(rOutDev.GetViewTransformation()); - const basegfx::B2DRange aClipRange(vcl::unotools::b2DRectangleFromRectangle(aOutRect)); - aViewInformation2D.setViewport(aClipRange); - - // get content and it's range - drawinglayer::primitive2d::Primitive2DContainer aContent(aHelper.getTextPortionPrimitives()); - const basegfx::B2DRange aContentRange(aContent.getB2DRange(aViewInformation2D)); - - if (!aContentRange.overlaps(aClipRange)) - // no overlap, nothing visible - return; - - if (bHardClip && !aClipRange.isInside(aContentRange)) - { - // not completely inside aClipRange and clipping requested - // Embed to MaskPrimitive2D - aContent = drawinglayer::primitive2d::Primitive2DContainer{ - new drawinglayer::primitive2d::MaskPrimitive2D( - basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aClipRange)), - std::move(aContent))}; - } - - // create PrimitiveProcessor and render to target - std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> xProcessor( - drawinglayer::processor2d::createProcessor2DFromOutputDevice(rOutDev, aViewInformation2D)); - xProcessor->process(aContent); + // embed to StartPos translation + aContent = drawinglayer::primitive2d::Primitive2DContainer{ + new drawinglayer::primitive2d::TransformPrimitive2D( + basegfx::utils::createTranslateB2DHomMatrix(aStartPos.X(), aStartPos.Y()), + std::move(aContent))}; } - else - { - bool bClipRegion = rOutDev.IsClipRegion(); - bool bMetafile = rOutDev.GetConnectMetaFile(); - vcl::Region aOldRegion = rOutDev.GetClipRegion(); - - // If one existed => intersection! - // Use Push/pop for creating the Meta file - if ( bMetafile ) - rOutDev.Push(); - // Always use the Intersect method, it is a must for Metafile! - if ( bHardClip ) - { - // Clip only if necessary... - if (!IsFormatted()) - FormatDoc(); - tools::Long nTextWidth = !IsEffectivelyVertical() ? CalcTextWidth(true) : GetTextHeight(); - if ( rStartDocPos.X() || rStartDocPos.Y() || - ( rOutRect.GetHeight() < static_cast<tools::Long>(GetTextHeight()) ) || - ( rOutRect.GetWidth() < nTextWidth ) ) - { - // Some printer drivers cause problems if characters graze the - // ClipRegion, therefore rather add a pixel more ... - tools::Rectangle aClipRect( aOutRect ); - if ( rOutDev.GetOutDevType() == OUTDEV_PRINTER ) - { - Size aPixSz( 1, 0 ); - aPixSz = rOutDev.PixelToLogic( aPixSz ); - aClipRect.AdjustRight(aPixSz.Width() ); - aClipRect.AdjustBottom(aPixSz.Width() ); - } - rOutDev.IntersectClipRegion( aClipRect ); - } - } - - PaintOrStrip(rOutDev, aOutRect, aStartPos); - - if ( bMetafile ) - rOutDev.Pop(); - else if ( bClipRegion ) - rOutDev.SetClipRegion( aOldRegion ); - else - rOutDev.SetClipRegion(); + static bool bBlendForTest(false); + if(bBlendForTest) + { + aContent = drawinglayer::primitive2d::Primitive2DContainer{ + new drawinglayer::primitive2d::ModifiedColorPrimitive2D( + std::move(aContent), + std::make_shared<basegfx::BColorModifier_interpolate>(COL_LIGHTRED.getBColor(), 0.5)) }; } + + // create PrimitiveProcessor and render to target + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> xProcessor( + drawinglayer::processor2d::createProcessor2DFromOutputDevice(rOutDev, aViewInformation2D)); + xProcessor->process(aContent); } // TODO: use IterateLineAreas in ImpEditEngine::Paint, to avoid algorithm duplication -void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipRect, Point aStartPos, Degree10 nOrientation, StripPortionsHelper* pStripPortionsHelper) +void ImpEditEngine::StripAllPortions( OutputDevice& rOutDev, tools::Rectangle aClipRect, Point aStartPos, StripPortionsHelper& rStripPortionsHelper) { - if ( !IsUpdateLayout() && !pStripPortionsHelper ) + if ( !IsUpdateLayout() ) return; if ( !IsFormatted() ) FormatDoc(); - tools::Long nFirstVisXPos = - rOutDev.GetMapMode().GetOrigin().X(); - tools::Long nFirstVisYPos = - rOutDev.GetMapMode().GetOrigin().Y(); - DBG_ASSERT( GetParaPortions().Count(), "No ParaPortion?!" ); SvxFont aTmpFont = GetParaPortions().getRef(0).GetNode()->GetCharAttribs().GetDefFont(); - vcl::PDFExtOutDevData* const pPDFExtOutDevData = dynamic_cast< vcl::PDFExtOutDevData* >( rOutDev.GetExtOutDevData() ); // In the case of rotated text is aStartPos considered TopLeft because // other information is missing, and since the whole object is shown anyway // un-scrolled. // The rectangle is infinite. const Point aOrigin( aStartPos ); - - // #110496# Added some more optional metafile comments. This - // change: factored out some duplicated code. - GDIMetaFile* pMtf = rOutDev.GetConnectMetaFile(); - const bool bMetafileValid( pMtf != nullptr ); - const tools::Long nVertLineSpacing = CalcVertLineSpacing(aStartPos); - sal_Int16 nColumn = 0; // Over all the paragraphs... - for (sal_Int32 nParaPortion = 0; nParaPortion < GetParaPortions().Count(); nParaPortion++) { ParaPortion const& rParaPortion = GetParaPortions().getRef(nParaPortion); @@ -3575,9 +3455,6 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR if (rParaPortion.IsVisible() && rParaPortion.IsInvalid()) return; - if ( pPDFExtOutDevData ) - pPDFExtOutDevData->WrapBeginStructureElement(vcl::pdf::StructElement::Paragraph); - const tools::Long nParaHeight = rParaPortion.GetHeight(); if (rParaPortion.IsVisible() && ( ( !IsEffectivelyVertical() && ( ( aStartPos.Y() + nParaHeight ) > aClipRect.Top() ) ) || @@ -3621,13 +3498,13 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR // Why not just also call when stripping portions? This will give the correct values // and needs no position corrections in OutlinerEditEng::DrawingText which tries to call - // PaintOrStripBullet correctly; exactly what GetEditEnginePtr()->ProcessFirstLineOfParagraph + // StripBullet correctly; exactly what GetEditEnginePtr()->ProcessFirstLineOfParagraph // does, too. No change for not-layouting (painting). if(0 == nLine) // && !bStripOnly) { Point aLineStart(aStartPos); adjustYDirectionAware(aLineStart, -nLineHeight); - GetEditEnginePtr()->ProcessFirstLineOfParagraph(nParaPortion, aLineStart, aOrigin, nOrientation, rOutDev, pStripPortionsHelper);//, rDrawPortion, rDrawBullet); + GetEditEnginePtr()->ProcessFirstLineOfParagraph(nParaPortion, aLineStart, /*aOrigin, nOrientation,*/ rOutDev, rStripPortionsHelper); // Remember whether a bullet was painted. const SfxBoolItem& rBulletState = mpEditEngine->GetParaAttrib(nParaPortion, EE_PARA_BULLETSTATE); @@ -3670,29 +3547,26 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR SeekCursor(rParaPortion.GetNode(), nIndex, aTmpFont, &rOutDev); const auto* pRuby = static_cast<const SvxRubyItem*>(pRubyAttr->GetItem()); - if (pStripPortionsHelper) - { - const bool bEndOfLine(nPortion == pLine->GetEndPortion()); - const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines); - - const Color aOverlineColor(rOutDev.GetOverlineColor()); - const Color aTextLineColor(rOutDev.GetTextLineColor()); - - Point aRubyPos = aTmpPos; - aRubyPos.AdjustX(pRubyInfo->nXOffset); - aRubyPos.AdjustY(-pRubyInfo->nYOffset); - - auto nPrevSz = aTmpFont.GetFontSize(); - aTmpFont.SetFontSize(nPrevSz / 2); - - const DrawPortionInfo aInfo( - aRubyPos, pRuby->GetText(), 0, pRuby->GetText().getLength(), - {}, {}, aTmpFont, nParaPortion, 0, nullptr, nullptr, - bEndOfLine, bEndOfParagraph, false, nullptr, aOverlineColor, - aTextLineColor); - pStripPortionsHelper->processDrawPortionInfo(aInfo); - aTmpFont.SetFontSize(nPrevSz); - } + const bool bEndOfLine(nPortion == pLine->GetEndPortion()); + const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines); + + const Color aOverlineColor(rOutDev.GetOverlineColor()); + const Color aTextLineColor(rOutDev.GetTextLineColor()); + + Point aRubyPos = aTmpPos; + aRubyPos.AdjustX(pRubyInfo->nXOffset); + aRubyPos.AdjustY(-pRubyInfo->nYOffset); + + auto nPrevSz = aTmpFont.GetFontSize(); + aTmpFont.SetFontSize(nPrevSz / 2); + + const DrawPortionInfo aInfo( + aRubyPos, pRuby->GetText(), 0, pRuby->GetText().getLength(), + {}, {}, aTmpFont, nParaPortion, 0, nullptr, nullptr, + bEndOfLine, bEndOfParagraph, false, nullptr, aOverlineColor, + aTextLineColor); + rStripPortionsHelper.processDrawPortionInfo(aInfo); + aTmpFont.SetFontSize(nPrevSz); } } @@ -3704,8 +3578,6 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR { SeekCursor(rParaPortion.GetNode(), nIndex + 1, aTmpFont, &rOutDev); - bool bDrawFrame = false; - if ( ( rTextPortion.GetKind() == PortionKind::FIELD ) && !aTmpFont.IsTransparent() && ( GetBackgroundColor() != COL_AUTO ) && GetBackgroundColor().IsDark() && ( IsAutoColorEnabled() && ( rOutDev.GetOutDevType() != OUTDEV_PRINTER ) ) ) @@ -3713,7 +3585,6 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR aTmpFont.SetTransparent( true ); rOutDev.SetFillColor(); rOutDev.SetLineColor( GetAutoColor() ); - bDrawFrame = true; } #if OSL_DEBUG_LEVEL > 2 @@ -3850,7 +3721,7 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR //It is not perfect, it still use lineBreaksList, so it won’t seek //word ends to wrap text there, but it would be difficult to change //this due to needed adaptations in EditEngine - if (pStripPortionsHelper && !bParsingFields && pExtraInfo && !pExtraInfo->lineBreaksList.empty()) + if (!bParsingFields && pExtraInfo && !pExtraInfo->lineBreaksList.empty()) { bParsingFields = true; itSubLines = pExtraInfo->lineBreaksList.begin(); @@ -3916,19 +3787,6 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR aTmpFont.QuickGetTextSize( GetRefDevice(), aText, nTextStart, nTextLen, &aTmpDXArray ); pDXArray = KernArraySpan(aTmpDXArray); - - // add a meta file comment if we record to a metafile - if( !pStripPortionsHelper && bMetafileValid ) - { - const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem()); - if( pFieldItem ) - { - const SvxFieldData* pFieldData = pFieldItem->GetField(); - if( pFieldData ) - pMtf->AddAction( pFieldData->createBeginComment() ); - } - } - } else if ( rTextPortion.GetKind() == PortionKind::HYPHENATOR ) { @@ -3945,8 +3803,6 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR pDXArray = aTmpDXArray; } - tools::Long nTxtWidth = rTextPortion.GetSize().Width(); - Point aOutPos( aTmpPos ); Point aRedLineTmpPos = aTmpPos; // In RTL portions spell markup pos should be at the start of the @@ -3954,298 +3810,104 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR if (rTextPortion.IsRightToLeft()) aRedLineTmpPos.AdjustX(rTextPortion.GetSize().Width() ); - if (pStripPortionsHelper) + EEngineData::WrongSpellVector aWrongSpellVector; + + if(GetStatus().DoOnlineSpelling() && rTextPortion.GetLen()) { - EEngineData::WrongSpellVector aWrongSpellVector; + WrongList* pWrongs = rParaPortion.GetNode()->GetWrongList(); - if(GetStatus().DoOnlineSpelling() && rTextPortion.GetLen()) + if(pWrongs && !pWrongs->empty()) { - WrongList* pWrongs = rParaPortion.GetNode()->GetWrongList(); + size_t nStart = nIndex, nEnd = 0; + bool bWrong = pWrongs->NextWrong(nStart, nEnd); + const size_t nMaxEnd(nIndex + rTextPortion.GetLen()); - if(pWrongs && !pWrongs->empty()) + while(bWrong) { - size_t nStart = nIndex, nEnd = 0; - bool bWrong = pWrongs->NextWrong(nStart, nEnd); - const size_t nMaxEnd(nIndex + rTextPortion.GetLen()); - - while(bWrong) + if(nStart >= nMaxEnd) { - if(nStart >= nMaxEnd) - { - break; - } - - if(nStart < o3tl::make_unsigned(nIndex)) - { - nStart = nIndex; - } - - if(nEnd > nMaxEnd) - { - nEnd = nMaxEnd; - } - - // add to vector - aWrongSpellVector.emplace_back(nStart, nEnd); - - // goto next index - nStart = nEnd + 1; - - if(nEnd < nMaxEnd) - { - bWrong = pWrongs->NextWrong(nStart, nEnd); - } - else - { - bWrong = false; - } + break; } - } - } - - const SvxFieldData* pFieldData = nullptr; - - if(PortionKind::FIELD == rTextPortion.GetKind()) - { - const EditCharAttrib* pAttr = rParaPortion.GetNode()->GetCharAttribs().FindFeature(nIndex); - const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem()); - - if(pFieldItem) - { - pFieldData = pFieldItem->GetField(); - } - } - - // support for EOC, EOW, EOS TEXT comments. To support that, - // the locale is needed. With the locale and a XBreakIterator it is - // possible to re-create the text marking info on primitive level - const lang::Locale aLocale(GetLocale(EditPaM(rParaPortion.GetNode(), nIndex + 1))); - - // create EOL and EOP bools - const bool bEndOfLine(nPortion == pLine->GetEndPortion()); - const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines); - - // get Overline color (from ((const SvxOverlineItem*)GetItem())->GetColor() in - // consequence, but also already set at rOutDev) - const Color aOverlineColor(rOutDev.GetOverlineColor()); - - // get TextLine color (from ((const SvxUnderlineItem*)GetItem())->GetColor() in - // consequence, but also already set at rOutDev) - const Color aTextLineColor(rOutDev.GetTextLineColor()); - - // Unicode code points conversion according to ctl text numeral setting - aText = convertDigits(aText, nTextStart, nTextLen, - ImplCalcDigitLang(aTmpFont.GetLanguage())); - - // StripPortions() data callback - const DrawPortionInfo aInfo( - aOutPos, aText, nTextStart, nTextLen, pDXArray, pKashidaArray, - aTmpFont, nParaPortion, rTextPortion.GetRightToLeftLevel(), - !aWrongSpellVector.empty() ? &aWrongSpellVector : nullptr, - pFieldData, - bEndOfLine, bEndOfParagraph, false, // support for EOL/EOP TEXT comments - &aLocale, - aOverlineColor, - aTextLineColor); - pStripPortionsHelper->processDrawPortionInfo(aInfo); - - // #108052# remember that EOP is written already for this ParaPortion - if(bEndOfParagraph) - { - bEndOfParagraphWritten = true; - } - } - else - { - short nEsc = aTmpFont.GetEscapement(); - if ( nOrientation ) - { - // In case of high/low do it yourself: - if ( aTmpFont.GetEscapement() ) - { - tools::Long nDiff = aTmpFont.GetFontSize().Height() * aTmpFont.GetEscapement() / 100L; - adjustYDirectionAware(aOutPos, -nDiff); - aRedLineTmpPos = aOutPos; - aTmpFont.SetEscapement( 0 ); - } - aOrigin.RotateAround(aOutPos, nOrientation); - aTmpFont.SetOrientation( aTmpFont.GetOrientation()+nOrientation ); - aTmpFont.SetPhysFont(rOutDev); - - } - - // Take only what begins in the visible range: - // Important, because of a bug in some graphic cards - // when transparent font, output when negative - if ( nOrientation || ( !IsEffectivelyVertical() && ( ( aTmpPos.X() + nTxtWidth ) >= nFirstVisXPos ) ) - || ( IsEffectivelyVertical() && ( ( aTmpPos.Y() + nTxtWidth ) >= nFirstVisYPos ) ) ) - { - if ( nEsc && ( aTmpFont.GetUnderline() != LINESTYLE_NONE ) ) - { - // Paint the high/low without underline, - // Display the Underline on the - // base line of the original font height... - // But only if there was something underlined before! - bool bSpecialUnderline = false; - EditCharAttrib* pPrev = rParaPortion.GetNode()->GetCharAttribs().FindAttrib( EE_CHAR_ESCAPEMENT, nIndex ); - if ( pPrev ) + if(nStart < o3tl::make_unsigned(nIndex)) { - SvxFont aDummy; - // Underscore in front? - if ( pPrev->GetStart() ) - { - SeekCursor( rParaPortion.GetNode(), pPrev->GetStart(), aDummy ); - if ( aDummy.GetUnderline() != LINESTYLE_NONE ) - bSpecialUnderline = true; - } - if ( !bSpecialUnderline && ( pPrev->GetEnd() < rParaPortion.GetNode()->Len() ) ) - { - SeekCursor( rParaPortion.GetNode(), pPrev->GetEnd()+1, aDummy ); - if ( aDummy.GetUnderline() != LINESTYLE_NONE ) - bSpecialUnderline = true; - } + nStart = nIndex; } - if ( bSpecialUnderline ) - { - Size aSz = aTmpFont.GetPhysTxtSize( &rOutDev, aText, nTextStart, nTextLen ); - sal_uInt8 nProp = aTmpFont.GetPropr(); - aTmpFont.SetEscapement( 0 ); - aTmpFont.SetPropr( 100 ); - aTmpFont.SetPhysFont(rOutDev); - OUStringBuffer aBlanks(nTextLen); - comphelper::string::padToLength( aBlanks, nTextLen, ' ' ); - Point aUnderlinePos( aOutPos ); - if ( nOrientation ) - { - aUnderlinePos = aTmpPos; - aOrigin.RotateAround(aUnderlinePos, nOrientation); - } - rOutDev.DrawStretchText( aUnderlinePos, aSz.Width(), aBlanks.makeStringAndClear(), 0, nTextLen ); - aTmpFont.SetUnderline( LINESTYLE_NONE ); - if ( !nOrientation ) - aTmpFont.SetEscapement( nEsc ); - aTmpFont.SetPropr( nProp ); - aTmpFont.SetPhysFont(rOutDev); - } - } - Point aRealOutPos( aOutPos ); - if ( ( rTextPortion.GetKind() == PortionKind::TEXT ) - && rTextPortion.GetExtraInfos() && rTextPortion.GetExtraInfos()->bCompressed - && rTextPortion.GetExtraInfos()->bFirstCharIsRightPunctuation ) - { - aRealOutPos.AdjustX(rTextPortion.GetExtraInfos()->nPortionOffsetX ); - } - - // RTL portions with (#i37132#) - // compressed blank should not paint this blank: - if ( rTextPortion.IsRightToLeft() && nTextLen >= 2 && - pDXArray[ nTextLen - 1 ] == - pDXArray[ nTextLen - 2 ] && - ' ' == aText[nTextStart + nTextLen - 1] ) - --nTextLen; - - // PDF export: - const SvxFieldData* pFieldData = nullptr; - if (pPDFExtOutDevData) - { - if (rTextPortion.GetKind() == PortionKind::FIELD) + if(nEnd > nMaxEnd) { - const EditCharAttrib* pAttr = rParaPortion.GetNode()->GetCharAttribs().FindFeature(nIndex); - const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem()); - if (pFieldItem) - { - pFieldData = pFieldItem->GetField(); - auto pUrlField = dynamic_cast<const SvxURLField*>(pFieldData); - if (pUrlField) - if (pPDFExtOutDevData->GetIsExportTaggedPDF()) - pPDFExtOutDevData->WrapBeginStructureElement(vcl::pdf::StructElement::Link, u"Link"_ustr); - } + nEnd = nMaxEnd; } - } - // output directly - aTmpFont.QuickDrawText( &rOutDev, aRealOutPos, aText, nTextStart, nTextLen, pDXArray, pKashidaArray ); + // add to vector + aWrongSpellVector.emplace_back(nStart, nEnd); - if ( bDrawFrame ) - { - Point aTopLeft( aTmpPos ); - aTopLeft.AdjustY( -(pLine->GetMaxAscent()) ); - if ( nOrientation ) - aOrigin.RotateAround(aTopLeft, nOrientation); - tools::Rectangle aRect( aTopLeft, rTextPortion.GetSize() ); - rOutDev.DrawRect( aRect ); - } + // goto next index + nStart = nEnd + 1; - // PDF export: - if (pPDFExtOutDevData) - { - if (auto pUrlField = dynamic_cast<const SvxURLField*>(pFieldData)) + if(nEnd < nMaxEnd) { - Point aTopLeft(aTmpPos); - aTopLeft.AdjustY(-(pLine->GetMaxAscent())); - - tools::Rectangle aRect(aTopLeft, rTextPortion.GetSize()); - vcl::PDFExtOutDevBookmarkEntry aBookmark; - aBookmark.nLinkId = pPDFExtOutDevData->CreateLink(aRect, pUrlField->GetName()); - aBookmark.aBookmark = pUrlField->GetURL(); - std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks(); - rBookmarks.push_back(aBookmark); - - if (pPDFExtOutDevData->GetIsExportTaggedPDF()) - { - pPDFExtOutDevData->SetStructureAttributeNumerical(vcl::PDFWriter::LinkAnnotation, aBookmark.nLinkId); - pPDFExtOutDevData->EndStructureElement(); - } + bWrong = pWrongs->NextWrong(nStart, nEnd); } - } - } - - const WrongList* const pWrongList = rParaPortion.GetNode()->GetWrongList(); - if ( GetStatus().DoOnlineSpelling() && pWrongList && !pWrongList->empty() && rTextPortion.GetLen() ) - { - {//#105750# adjust LinePos for superscript or subscript text - short _nEsc = aTmpFont.GetEscapement(); - if( _nEsc ) + else { - tools::Long nShift = (_nEsc * aTmpFont.GetFontSize().Height()) / 100L; - adjustYDirectionAware(aRedLineTmpPos, -nShift); + bWrong = false; } } - rOutDev.Push(vcl::PushFlags::LINECOLOR); - rOutDev.SetLineColor( GetColorConfig().GetColorValue( svtools::SPELL ).nColor ); - lcl_DrawRedLines(rOutDev, aTmpFont.GetFontSize().Height(), aRedLineTmpPos, - static_cast<size_t>(nIndex), static_cast<size_t>(nIndex) + rTextPortion.GetLen(), - pDXArray, rParaPortion.GetNode()->GetWrongList(), nOrientation, - aOrigin, IsEffectivelyVertical(), rTextPortion.IsRightToLeft()); - rOutDev.Pop(); } } - rOutDev.Pop(); + const SvxFieldData* pFieldData = nullptr; - if ( rTextPortion.GetKind() == PortionKind::FIELD ) + if(PortionKind::FIELD == rTextPortion.GetKind()) { - // add a meta file comment if we record to a metafile - if( !pStripPortionsHelper && bMetafileValid ) - { - const EditCharAttrib* pAttr = rParaPortion.GetNode()->GetCharAttribs().FindFeature(nIndex); - assert( pAttr && "Field not found" ); - - const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem()); - DBG_ASSERT( pFieldItem != nullptr, "Wrong type of field!" ); + const EditCharAttrib* pAttr = rParaPortion.GetNode()->GetCharAttribs().FindFeature(nIndex); + const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem()); - if( pFieldItem ) - { - const SvxFieldData* pFieldData = pFieldItem->GetField(); - if( pFieldData ) - pMtf->AddAction( SvxFieldData::createEndComment() ); - } + if(pFieldItem) + { + pFieldData = pFieldItem->GetField(); } - } + // support for EOC, EOW, EOS TEXT comments. To support that, + // the locale is needed. With the locale and a XBreakIterator it is + // possible to re-create the text marking info on primitive level + const lang::Locale aLocale(GetLocale(EditPaM(rParaPortion.GetNode(), nIndex + 1))); + + // create EOL and EOP bools + const bool bEndOfLine(nPortion == pLine->GetEndPortion()); + const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines); + + // get Overline color (from ((const SvxOverlineItem*)GetItem())->GetColor() in + // consequence, but also already set at rOutDev) + const Color aOverlineColor(rOutDev.GetOverlineColor()); + + // get TextLine color (from ((const SvxUnderlineItem*)GetItem())->GetColor() in + // consequence, but also already set at rOutDev) + const Color aTextLineColor(rOutDev.GetTextLineColor()); + + // Unicode code points conversion according to ctl text numeral setting + aText = convertDigits(aText, nTextStart, nTextLen, + ImplCalcDigitLang(aTmpFont.GetLanguage())); + + // StripPortions() data callback + const DrawPortionInfo aInfo( + aOutPos, aText, nTextStart, nTextLen, pDXArray, pKashidaArray, + aTmpFont, nParaPortion, rTextPortion.GetRightToLeftLevel(), + !aWrongSpellVector.empty() ? &aWrongSpellVector : nullptr, + pFieldData, + bEndOfLine, bEndOfParagraph, false, // support for EOL/EOP TEXT comments + &aLocale, + aOverlineColor, + aTextLineColor); + rStripPortionsHelper.processDrawPortionInfo(aInfo); + + // #108052# remember that EOP is written already for this ParaPortion + if(bEndOfParagraph) + { + bEndOfParagraphWritten = true; + } } break; case PortionKind::TAB: @@ -4272,35 +3934,26 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR comphelper::string::padToLength(aBuf, nChars, rTextPortion.GetExtraValue()); OUString aText(aBuf.makeStringAndClear()); - if (pStripPortionsHelper) - { - // create EOL and EOP bools - const bool bEndOfLine(nPortion == pLine->GetEndPortion()); - const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines); - - const Color aOverlineColor(rOutDev.GetOverlineColor()); - const Color aTextLineColor(rOutDev.GetTextLineColor()); - - // StripPortions() data callback - const DrawPortionInfo aInfo( - aTmpPos, aText, 0, aText.getLength(), {}, {}, - aTmpFont, nParaPortion, 0, - nullptr, - nullptr, - bEndOfLine, bEndOfParagraph, false, - nullptr, - aOverlineColor, - aTextLineColor); - pStripPortionsHelper->processDrawPortionInfo(aInfo); - } - else - { - // direct paint needed - aTmpFont.QuickDrawText( &rOutDev, aTmpPos, aText, 0, aText.getLength(), {} ); - rOutDev.DrawStretchText( aTmpPos, rTextPortion.GetSize().Width(), aText ); - } + // create EOL and EOP bools + const bool bEndOfLine(nPortion == pLine->GetEndPortion()); + const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines); + + const Color aOverlineColor(rOutDev.GetOverlineColor()); + const Color aTextLineColor(rOutDev.GetTextLineColor()); + + // StripPortions() data callback + const DrawPortionInfo aInfo( + aTmpPos, aText, 0, aText.getLength(), {}, {}, + aTmpFont, nParaPortion, 0, + nullptr, + nullptr, + bEndOfLine, bEndOfParagraph, false, + nullptr, + aOverlineColor, + aTextLineColor); + rStripPortionsHelper.processDrawPortionInfo(aInfo); } - else if (pStripPortionsHelper) + else { // #i108052# When stripping, a callback for _empty_ paragraphs is also needed. // This was optimized away (by not rendering the space-only tab portion), so do @@ -4320,7 +3973,7 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR nullptr, aOverlineColor, aTextLineColor); - pStripPortionsHelper->processDrawPortionInfo(aInfo); + rStripPortionsHelper.processDrawPortionInfo(aInfo); } } break; @@ -4356,7 +4009,7 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR // that the reason for #i108052# was fixed/removed again, so this is a try to fix // the number of paragraphs (and counting empty ones) now independent from the // changes in EditEngine behaviour. - if(!bEndOfParagraphWritten && !bPaintBullet && pStripPortionsHelper) + if(!bEndOfParagraphWritten && !bPaintBullet) { const Color aOverlineColor(rOutDev.GetOverlineColor()); const Color aTextLineColor(rOutDev.GetTextLineColor()); @@ -4370,7 +4023,7 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR nullptr, aOverlineColor, aTextLineColor); - pStripPortionsHelper->processDrawPortionInfo(aInfo); + rStripPortionsHelper.processDrawPortionInfo(aInfo); } } else @@ -4378,9 +4031,6 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR adjustYDirectionAware(aStartPos, nParaHeight); } - if ( pPDFExtOutDevData ) - pPDFExtOutDevData->EndStructureElement(); - // no more visible actions? if (getYOverflowDirectionAware(aStartPos, aClipRect)) break; @@ -4418,9 +4068,9 @@ void ImpEditEngine::DrawText_ToEditView( TextHierarchyBreakup& rHelper, ImpEditV tools::Rectangle aClipRect( pView->GetOutputArea() ); aClipRect.Intersection( rRect ); - OutputDevice& rTarget = pTargetDevice ? *pTargetDevice : *pView->GetWindow()->GetOutDev(); - - const Point aStartPos(CalculateTextPaintStartPosition(*pView)); + if (aClipRect.IsEmpty()) + // no area, no paint + return; // If Doc-width < Output Area,Width and not wrapped fields, // the fields usually protrude if > line. @@ -4435,60 +4085,55 @@ void ImpEditEngine::DrawText_ToEditView( TextHierarchyBreakup& rHelper, ImpEditV aClipRect.SetRight( nMaxX ); } - static bool bUsePrimitives(nullptr == std::getenv("DISBALE_EDITENGINE_ON_PRIMITIVES")); - - if (bUsePrimitives) - { - // extract Primitives - PaintOrStrip(rTarget, aClipRect, aStartPos, 0_deg10, &rHelper); - - if (rHelper.getTextPortionPrimitives().empty()) - // no Primitives, done - return; + // extract Primitives + OutputDevice& rTarget = pTargetDevice ? *pTargetDevice : *pView->GetWindow()->GetOutDev(); + const Point aStartPos(CalculateTextPaintStartPosition(*pView)); + StripAllPortions(rTarget, aClipRect, aStartPos, rHelper); - // create ViewInformation2D based on target OutputDevice - drawinglayer::geometry::ViewInformation2D aViewInformation2D; - aViewInformation2D.setViewTransformation(rTarget.GetViewTransformation()); - const basegfx::B2DRange aClipRange(vcl::unotools::b2DRectangleFromRectangle(aClipRect)); - aViewInformation2D.setViewport(aClipRange); + if (rHelper.getTextPortionPrimitives().empty()) + // no Primitives, done + return; - // get content and it's range - drawinglayer::primitive2d::Primitive2DContainer aContent(rHelper.getTextPortionPrimitives()); - const basegfx::B2DRange aContentRange(aContent.getB2DRange(aViewInformation2D)); + // create ViewInformation2D based on target OutputDevice + drawinglayer::geometry::ViewInformation2D aViewInformation2D; + aViewInformation2D.setViewTransformation(rTarget.GetViewTransformation()); - if (!aContentRange.overlaps(aClipRange)) - // no overlap, nothing visible - return; + // get content and it's range + drawinglayer::primitive2d::Primitive2DContainer aContent(rHelper.getTextPortionPrimitives()); + const basegfx::B2DRange aContentRange(aContent.getB2DRange(aViewInformation2D)); + const basegfx::B2DRange aClipRange(vcl::unotools::b2DRectangleFromRectangle(aClipRect)); - if (!aClipRange.isInside(aContentRange)) - { - // not completely inside aClipRange, clipping needed. - // Embed to MaskPrimitive2D - aContent = drawinglayer::primitive2d::Primitive2DContainer{ - new drawinglayer::primitive2d::MaskPrimitive2D( - basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aClipRange)), - std::move(aContent))}; - } + if (!aContentRange.overlaps(aClipRange)) + // no overlap, nothing visible + return; - // create PrimitiveProcessor and render to target - std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> xProcessor( - drawinglayer::processor2d::createProcessor2DFromOutputDevice(rTarget, aViewInformation2D)); - xProcessor->process(aContent); - } - else + if (!aClipRange.isInside(aContentRange)) { - bool bClipRegion = rTarget.IsClipRegion(); - vcl::Region aOldRegion = rTarget.GetClipRegion(); - rTarget.IntersectClipRegion( aClipRect ); - - PaintOrStrip(rTarget, aClipRect, aStartPos); + // not completely inside aClipRange, clipping needed. + // Embed to MaskPrimitive2D + aContent = drawinglayer::primitive2d::Primitive2DContainer{ + new drawinglayer::primitive2d::MaskPrimitive2D( + basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aClipRange)), + std::move(aContent))}; + } - if ( bClipRegion ) - rTarget.SetClipRegion( aOldRegion ); - else - rTarget.SetClipRegion(); + static bool bBlendForTest(false); + if(bBlendForTest) + { + aContent = drawinglayer::primitive2d::Primitive2DContainer{ + new drawinglayer::primitive2d::ModifiedColorPrimitive2D( + std::move(aContent), + std::make_shared<basegfx::BColorModifier_interpolate>(COL_LIGHTRED.getBColor(), 0.5)) }; } + // create PrimitiveProcessor and render to target + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> xProcessor( + drawinglayer::processor2d::createProcessor2DFromOutputDevice(rTarget, aViewInformation2D)); + xProcessor->process(aContent); + // It is NECESSARY to destruct the PrimitiveProcessor here get the paint + // updated, else XOR may be out of sync here, e.g. in OutlinerView in Presentation (!) + xProcessor.reset(); + pView->DrawSelectionXOR(pView->GetEditSelection(), nullptr, &rTarget); } diff --git a/editeng/source/outliner/outleeng.cxx b/editeng/source/outliner/outleeng.cxx index 92dcbfb78fab..7fda1ef47c72 100644 --- a/editeng/source/outliner/outleeng.cxx +++ b/editeng/source/outliner/outleeng.cxx @@ -39,15 +39,15 @@ OutlinerEditEng::~OutlinerEditEng() { } -void OutlinerEditEng::ProcessFirstLineOfParagraph(sal_Int32 nPara, const Point& rStartPos, const Point& rOrigin, Degree10 nOrientation, OutputDevice& rOutDev, StripPortionsHelper* pStripPortionsHelper) +void OutlinerEditEng::ProcessFirstLineOfParagraph(sal_Int32 nPara, const Point& rStartPos, OutputDevice& rOutDev, StripPortionsHelper& rStripPortionsHelper) { if( GetControlWord() & EEControlBits::OUTLINER ) { - PaintFirstLineInfo aInfo(nPara, rStartPos, &rOutDev, pStripPortionsHelper); + PaintFirstLineInfo aInfo(nPara, rStartPos, &rOutDev, rStripPortionsHelper); pOwner->maPaintFirstLineHdl.Call( &aInfo ); } - pOwner->PaintOrStripBullet(nPara, rStartPos, rOrigin, nOrientation, rOutDev, pStripPortionsHelper); + pOwner->StripBullet(nPara, rStartPos, rOutDev, rStripPortionsHelper); } const SvxNumberFormat* OutlinerEditEng::GetNumberFormat( sal_Int32 nPara ) const diff --git a/editeng/source/outliner/outliner.cxx b/editeng/source/outliner/outliner.cxx index f9f5ac0f72ab..404a3bfa299a 100644 --- a/editeng/source/outliner/outliner.cxx +++ b/editeng/source/outliner/outliner.cxx @@ -870,10 +870,8 @@ vcl::Font Outliner::ImpCalcBulletFont( sal_Int32 nPara ) const return aBulletFont; } -void Outliner::PaintOrStripBullet( - sal_Int32 nPara, const Point& rStartPos, const Point& rOrigin, - Degree10 nOrientation, OutputDevice& rOutDev, - StripPortionsHelper* pStripPortionsHelper) +void Outliner::StripBullet( + sal_Int32 nPara, const Point& rStartPos, OutputDevice& rOutDev, StripPortionsHelper& rStripPortionsHelper) { bool bDrawBullet = false; @@ -939,17 +937,6 @@ void Outliner::PaintOrStripBullet( } } - if ( nOrientation ) - { - // Both TopLeft and bottom left is not quite correct, - // since in EditEngine baseline ... - rOrigin.RotateAround(aTextPos, nOrientation); - - vcl::Font aRotatedFont( std::move(aBulletFont) ); - aRotatedFont.SetOrientation( nOrientation ); - rOutDev.SetFont( aRotatedFont ); - } - // VCL will take care of brackets and so on... vcl::text::ComplexTextLayoutFlags nLayoutMode = rOutDev.GetLayoutMode(); nLayoutMode &= ~vcl::text::ComplexTextLayoutFlags(vcl::text::ComplexTextLayoutFlags::BiDiRtl|vcl::text::ComplexTextLayoutFlags::BiDiStrong); @@ -957,29 +944,22 @@ void Outliner::PaintOrStripBullet( nLayoutMode |= vcl::text::ComplexTextLayoutFlags::BiDiRtl | vcl::text::ComplexTextLayoutFlags::TextOriginLeft | vcl::text::ComplexTextLayoutFlags::BiDiStrong; rOutDev.SetLayoutMode( nLayoutMode ); - if (pStripPortionsHelper) - { - const SvxFont aSvxFont(rOutDev.GetFont()); - KernArray aBuf; - rOutDev.GetTextArray( pPara->GetText(), &aBuf ); - - if(bSymbol) - { - // aTextPos is Bottom, go to Baseline - FontMetric aMetric(rOutDev.GetFontMetric()); - aTextPos.AdjustY( -(aMetric.GetDescent()) ); - } + const SvxFont aSvxFont(rOutDev.GetFont()); + KernArray aBuf; + rOutDev.GetTextArray( pPara->GetText(), &aBuf ); - const DrawPortionInfo aInfo( - aTextPos, pPara->GetText(), 0, pPara->GetText().getLength(), aBuf, {}, - aSvxFont, nPara, bRightToLeftPara ? 1 : 0, nullptr, nullptr, false, false, true, nullptr, Color(), Color()); - pStripPortionsHelper->processDrawPortionInfo(aInfo); - } - else + if(bSymbol) { - rOutDev.DrawText( aTextPos, pPara->GetText() ); + // aTextPos is Bottom, go to Baseline + FontMetric aMetric(rOutDev.GetFontMetric()); + aTextPos.AdjustY( -(aMetric.GetDescent()) ); } + const DrawPortionInfo aInfo( + aTextPos, pPara->GetText(), 0, pPara->GetText().getLength(), aBuf, {}, + aSvxFont, nPara, bRightToLeftPara ? 1 : 0, nullptr, nullptr, false, false, true, nullptr, Color(), Color()); + rStripPortionsHelper.processDrawPortionInfo(aInfo); + rOutDev.SetFont( aOldFont ); } else @@ -1009,55 +989,18 @@ void Outliner::PaintOrStripBullet( } } - if (pStripPortionsHelper) - { - // call something analog to aDrawPortionHdl (if set) and feed it something - // analog to DrawPortionInfo... - // created aDrawBulletHdl, Set/GetDrawBulletHdl. - // created DrawBulletInfo and added handling to sdrtextdecomposition.cxx - DrawBulletInfo aDrawBulletInfo( - *pFmt->GetBrush()->GetGraphicObject(), - aBulletPos, - pPara->aBulSize); - pStripPortionsHelper->processDrawBulletInfo(aDrawBulletInfo); - } - else - { - pFmt->GetBrush()->GetGraphicObject()->Draw(rOutDev, aBulletPos, pPara->aBulSize); - } + // call something analog to aDrawPortionHdl (if set) and feed it something + // analog to DrawPortionInfo... + // created aDrawBulletHdl, Set/GetDrawBulletHdl. + // created DrawBulletInfo and added handling to sdrtextdecomposition.cxx + DrawBulletInfo aDrawBulletInfo( + *pFmt->GetBrush()->GetGraphicObject(), + aBulletPos, + pPara->aBulSize); + rStripPortionsHelper.processDrawBulletInfo(aDrawBulletInfo); } } } - - // In case of collapsed subparagraphs paint a line before the text. - if( !pParaList->HasChildren(pPara) || pParaList->HasVisibleChildren(pPara) || pStripPortionsHelper || nOrientation ) - return; - - tools::Long nWidth = rOutDev.PixelToLogic( Size( 10, 0 ) ).Width(); - - Point aStartPos, aEndPos; - if ( !bVertical ) - { - aStartPos.setY( rStartPos.Y() + aBulletArea.Bottom() ); - if ( !bRightToLeftPara ) - aStartPos.setX( rStartPos.X() + aBulletArea.Right() ); - else - aStartPos.setX( rStartPos.X() + GetPaperSize().Width() - aBulletArea.Left() ); - aEndPos = aStartPos; - aEndPos.AdjustX(nWidth ); - } - else - { - aStartPos.setX( rStartPos.X() - aBulletArea.Bottom() ); - aStartPos.setY( rStartPos.Y() + aBulletArea.Right() ); - aEndPos = aStartPos; - aEndPos.AdjustY(nWidth ); - } - - const Color& rOldLineColor = rOutDev.GetLineColor(); - rOutDev.SetLineColor( COL_BLACK ); - rOutDev.DrawLine( aStartPos, aEndPos ); - rOutDev.SetLineColor( rOldLineColor ); } void Outliner::InvalidateBullet(sal_Int32 nPara) @@ -1513,7 +1456,7 @@ tools::Rectangle Outliner::ImpCalcBulletArea( sal_Int32 nPara, bool bAdjust, boo ParagraphInfos aInfos = pEditEngine->GetParagraphInfos( nPara ); if ( aInfos.bValid ) { - aTopLeft.setY( /* aInfos.nFirstLineOffset + */ // nFirstLineOffset is already added to the StartPos (PaintOrStripBullet) from the EditEngine + aTopLeft.setY( /* aInfos.nFirstLineOffset + */ // nFirstLineOffset is already added to the StartPos (StripBullet) from the EditEngine aInfos.nFirstLineHeight - aInfos.nFirstLineTextHeight + aInfos.nFirstLineTextHeight / 2 - aBulletSize.Height() / 2 ); diff --git a/include/editeng/editeng.hxx b/include/editeng/editeng.hxx index ca00ddd807d6..c53ad6ff764e 100644 --- a/include/editeng/editeng.hxx +++ b/include/editeng/editeng.hxx @@ -489,7 +489,7 @@ public: SAL_DLLPRIVATE void SetBeginPasteOrDropHdl( const Link<PasteOrDropInfos&,void>& rLink ); SAL_DLLPRIVATE void SetEndPasteOrDropHdl( const Link<PasteOrDropInfos&,void>& rLink ); - virtual void ProcessFirstLineOfParagraph(sal_Int32 nPara, const Point& rStartPos, const Point& rOrigin, Degree10 nOrientation, OutputDevice& rOutDev, StripPortionsHelper* pStripPortionsHelper); + virtual void ProcessFirstLineOfParagraph(sal_Int32 nPara, const Point& rStartPos, OutputDevice& rOutDev, StripPortionsHelper& rStripPortionsHelper); virtual void ParagraphInserted( sal_Int32 nNewParagraph ); virtual void ParagraphDeleted( sal_Int32 nDeletedParagraph ); diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx index 92d7117f5796..80aee72f0070 100644 --- a/include/editeng/outliner.hxx +++ b/include/editeng/outliner.hxx @@ -407,10 +407,10 @@ struct EDITENG_DLLPUBLIC PaintFirstLineInfo sal_Int32 mnPara; const Point& mrStartPos; VclPtr<OutputDevice> mpOutDev; - StripPortionsHelper* mpStripPortionsHelper; + StripPortionsHelper& mrStripPortionsHelper; - PaintFirstLineInfo( sal_Int32 nPara, const Point& rStartPos, OutputDevice* pOutDev, StripPortionsHelper* pStripPortionsHelper ) - : mnPara( nPara ), mrStartPos( rStartPos ), mpOutDev( pOutDev ), mpStripPortionsHelper( pStripPortionsHelper ) + PaintFirstLineInfo( sal_Int32 nPara, const Point& rStartPos, OutputDevice* pOutDev, StripPortionsHelper& rStripPortionsHelper ) + : mnPara( nPara ), mrStartPos( rStartPos ), mpOutDev( pOutDev ), mrStripPortionsHelper( rStripPortionsHelper ) {} }; @@ -579,11 +579,8 @@ protected: SAL_DLLPRIVATE void StyleSheetChanged( SfxStyleSheet const * pStyle ); SAL_DLLPRIVATE void InvalidateBullet(sal_Int32 nPara); - SAL_DLLPRIVATE void PaintOrStripBullet( - sal_Int32 nPara, const Point& rStartPos, - const Point& rOrigin, Degree10 nOrientation, - OutputDevice& rOutDev, - StripPortionsHelper* pStripPortionsHelper); + SAL_DLLPRIVATE void StripBullet( + sal_Int32 nPara, const Point& rStartPos, OutputDevice& rOutDev, StripPortionsHelper& rStripPortionsHelper); // used by OutlinerEditEng. Allows Outliner objects to provide // bullet access to the EditEngine. diff --git a/sd/source/ui/view/outlview.cxx b/sd/source/ui/view/outlview.cxx index a076ffe61ada..4d6799a521fa 100644 --- a/sd/source/ui/view/outlview.cxx +++ b/sd/source/ui/view/outlview.cxx @@ -1583,23 +1583,15 @@ IMPL_LINK(OutlineView, PaintingFirstLineHdl, PaintFirstLineInfo*, pInfo, void) Point aImagePos( pInfo->mrStartPos ); aImagePos.AdjustX(aOutSize.Width() - aImageSize.Width() - aOffset.Width() ) ; aImagePos.AdjustY((aOutSize.Height() - aImageSize.Height()) / 2 ); - static bool bUsePrimitives(nullptr == std::getenv("DISBALE_EDITENGINE_ON_PRIMITIVES")); - if (bUsePrimitives && pInfo->mpStripPortionsHelper) - { - // create BitmapPrimitive2D and add directly - const drawinglayer::primitive2d::Primitive2DReference xBitmap( - new drawinglayer::primitive2d::BitmapPrimitive2D( - BitmapEx(maSlideImage.GetBitmap()), - basegfx::utils::createScaleTranslateB2DHomMatrix( - aImageSize.Width(), aImageSize.Height(), - aImagePos.X(), aImagePos.Y()))); - pInfo->mpStripPortionsHelper->directlyAddB2DPrimitive(xBitmap); - } - else - { - pInfo->mpOutDev->DrawImage( aImagePos, aImageSize, maSlideImage ); - } + // create BitmapPrimitive2D and add directly + const drawinglayer::primitive2d::Primitive2DReference xBitmap( + new drawinglayer::primitive2d::BitmapPrimitive2D( + BitmapEx(maSlideImage.GetBitmap()), + basegfx::utils::createScaleTranslateB2DHomMatrix( + aImageSize.Width(), aImageSize.Height(), + aImagePos.X(), aImagePos.Y()))); + pInfo->mrStripPortionsHelper.directlyAddB2DPrimitive(xBitmap); const bool bVertical = mrOutliner.IsVertical(); const bool bRightToLeftPara = rEditEngine.IsRightToLeft( pInfo->mnPara ); @@ -1635,37 +1627,30 @@ IMPL_LINK(OutlineView, PaintingFirstLineHdl, PaintFirstLineInfo*, pInfo, void) aTextPos.AdjustX(nBulletHeight / 2 ); } - if (bUsePrimitives && pInfo->mpStripPortionsHelper) - { - // create TextSimplePortionPrimitive2D and add directly - basegfx::B2DVector aFontSize; - const vcl::Font& rFont(pInfo->mpOutDev->GetFont()); - drawinglayer::attribute::FontAttribute aFontAttr( - drawinglayer::primitive2d::getFontAttributeFromVclFont(aFontSize, rFont, false, false)); - const FontMetric aFontMetric(pInfo->mpOutDev->GetFontMetric(rFont)); - const double fTextOffsetY(aFontMetric.GetAscent()); - const basegfx::B2DHomMatrix aTextTransform( - basegfx::utils::createScaleTranslateB2DHomMatrix( - aFontSize.getX(), aFontSize.getY(), - aTextPos.X(), aTextPos.Y() + fTextOffsetY)); - - const drawinglayer::primitive2d::Primitive2DReference xText( - new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( - aTextTransform, - aPageText, - 0, - aPageText.getLength(), - std::vector<double>(), - {}, - std::move(aFontAttr), - css::lang::Locale(), - pInfo->mpOutDev->GetTextColor().getBColor())); - pInfo->mpStripPortionsHelper->directlyAddB2DPrimitive(xText); - } - else - { - pInfo->mpOutDev->DrawText( aTextPos, aPageText ); - } + // create TextSimplePortionPrimitive2D and add directly + basegfx::B2DVector aFontSize; + const vcl::Font& rFont(pInfo->mpOutDev->GetFont()); + drawinglayer::attribute::FontAttribute aFontAttr( + drawinglayer::primitive2d::getFontAttributeFromVclFont(aFontSize, rFont, false, false)); + const FontMetric aFontMetric(pInfo->mpOutDev->GetFontMetric(rFont)); + const double fTextOffsetY(aFontMetric.GetAscent()); + const basegfx::B2DHomMatrix aTextTransform( + basegfx::utils::createScaleTranslateB2DHomMatrix( + aFontSize.getX(), aFontSize.getY(), + aTextPos.X(), aTextPos.Y() + fTextOffsetY)); + + const drawinglayer::primitive2d::Primitive2DReference xText( + new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( + aTextTransform, + aPageText, + 0, + aPageText.getLength(), + std::vector<double>(), + {}, + std::move(aFontAttr), + css::lang::Locale(), + pInfo->mpOutDev->GetTextColor().getBColor())); + pInfo->mrStripPortionsHelper.directlyAddB2DPrimitive(xText); } void OutlineView::UpdateParagraph( sal_Int32 nPara )
