diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index dc2383c29411..95769d43212d 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -1384,6 +1384,7 @@ void VclMetafileProcessor2D::processTextHierarchyFieldPrimitive2D( // thus do the MetafileAction embedding stuff but just handle recursively. static constexpr OString aCommentStringCommon("FIELD_SEQ_BEGIN"_ostr); OUString aURL; + const bool bIsExportTaggedPDF(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportTaggedPDF()); switch (rFieldPrimitive.getType()) { @@ -1406,6 +1407,10 @@ void VclMetafileProcessor2D::processTextHierarchyFieldPrimitive2D( mpMetaFile->AddAction(new MetaCommentAction( aCommentStringCommon, 0, reinterpret_cast(aURL.getStr()), 2 * aURL.getLength())); + + if (bIsExportTaggedPDF) + mpPDFExtOutDevData->WrapBeginStructureElement(vcl::pdf::StructElement::Link, + u"Link"_ustr); } break; @@ -1436,6 +1441,13 @@ void VclMetafileProcessor2D::processTextHierarchyFieldPrimitive2D( aBookmark.aBookmark = aURL; std::vector& rBookmarks = mpPDFExtOutDevData->GetBookmarks(); rBookmarks.push_back(aBookmark); + + if (bIsExportTaggedPDF) + { + mpPDFExtOutDevData->SetStructureAttributeNumerical(vcl::PDFWriter::LinkAnnotation, + aBookmark.nLinkId); + mpPDFExtOutDevData->EndStructureElement(); + } } void VclMetafileProcessor2D::processTextHierarchyLinePrimitive2D( diff --git a/editeng/source/editeng/StripPortionsHelper.cxx b/editeng/source/editeng/StripPortionsHelper.cxx index 61e9e939ca69..71391194734b 100644 --- a/editeng/source/editeng/StripPortionsHelper.cxx +++ b/editeng/source/editeng/StripPortionsHelper.cxx @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -648,6 +649,12 @@ void TextHierarchyBreakup::processDrawBulletInfo(const DrawBulletInfo& rDrawBull maTextPortionPrimitives.push_back(pNewPrimitive); } +void TextHierarchyBreakup::directlyAddB2DPrimitive( + const drawinglayer::primitive2d::Primitive2DReference& rSource) +{ + maTextPortionPrimitives.push_back(rSource); +} + TextHierarchyBreakup::TextHierarchyBreakup() : maTextPortionPrimitives() , maLinePrimitives() @@ -685,4 +692,32 @@ TextHierarchyBreakup::getTextPortionPrimitives() return maParagraphPrimitives; } +sal_Int16 TextHierarchyBreakupOutliner::getOutlineLevelFromParagraph(sal_Int32 nPara) const +{ + sal_Int16 nDepth(mrOutliner.GetDepth(nPara)); + EBulletInfo eInfo(mrOutliner.GetBulletInfo(nPara)); + // Pass -1 to signal VclMetafileProcessor2D that there is no active + // bullets/numbering in this paragraph (i.e. this is normal text) + return eInfo.bVisible ? nDepth : -1; +} + +sal_Int32 TextHierarchyBreakupOutliner::getParagraphCount() const +{ + return mrOutliner.GetParagraphCount(); +} + +TextHierarchyBreakupOutliner::TextHierarchyBreakupOutliner(Outliner& rOutliner) + : TextHierarchyBreakup() + , mrOutliner(rOutliner) +{ +} + +TextHierarchyBreakupOutliner::TextHierarchyBreakupOutliner( + Outliner& rOutliner, const basegfx::B2DHomMatrix& rNewTransformA, + const basegfx::B2DHomMatrix& rNewTransformB) + : TextHierarchyBreakup(rNewTransformA, rNewTransformB) + , mrOutliner(rOutliner) +{ +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx index 3429ec7717f1..ae94c4c9b3f0 100644 --- a/editeng/source/editeng/editview.cxx +++ b/editeng/source/editeng/editview.cxx @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -401,9 +402,20 @@ Point EditView::CalculateTextPaintStartPosition() const return getImpEditEngine().CalculateTextPaintStartPosition(getImpl()); } +void EditView::DrawText_ToEditView( TextHierarchyBreakup& rHelper, const tools::Rectangle& rRect, OutputDevice* pTargetDevice ) +{ + getImpEditEngine().DrawText_ToEditView(rHelper, &getImpl(), rRect, pTargetDevice); +} + void EditView::DrawText_ToEditView( const tools::Rectangle& rRect, OutputDevice* pTargetDevice ) { - getImpEditEngine().DrawText_ToEditView(&getImpl(), rRect, pTargetDevice); + // use TextHierarchyBreakup to get all text embedded to the + // TextHierarchy.*Primitive2D groupings for better processing + TextHierarchyBreakup aHelper; + + // hand that Helper over to DrawText_ToEditView at the EditEngine + // for usage + getImpEditEngine().DrawText_ToEditView(aHelper, &getImpl(), rRect, pTargetDevice); } void EditView::setEditEngine(EditEngine& rEditEngine) diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx index eca225e8ca0c..32bcbd1337d1 100644 --- a/editeng/source/editeng/impedit.hxx +++ b/editeng/source/editeng/impedit.hxx @@ -1003,7 +1003,7 @@ public: void DrawText_ToRectangle( OutputDevice& rOutDev, const tools::Rectangle& rOutRect, const Point& rStartDocPos, bool bHardClip ); void UpdateViews( EditView* pCurView = nullptr ); Point CalculateTextPaintStartPosition(ImpEditView& rView) const; - void DrawText_ToEditView( ImpEditView* pView, const tools::Rectangle& rRect, OutputDevice* pTargetDevice ); + 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); bool MouseButtonUp( const MouseEvent& rMouseEvent, EditView* pView ); diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx index 373967943123..7ddae54bd77d 100644 --- a/editeng/source/editeng/impedit3.cxx +++ b/editeng/source/editeng/impedit3.cxx @@ -88,6 +88,15 @@ #include +#include +#include +#include +#include +#include +#include +#include +#include + #include using namespace ::com::sun::star; @@ -3354,18 +3363,61 @@ Point ImpEditEngine::MoveToNextLine( 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 ); - if( rOutDev.GetConnectMetaFile() ) - rOutDev.Push(); Point aStartPos( rStartPos ); + if ( IsEffectivelyVertical() ) { aStartPos.AdjustX(GetPaperSize().Width() ); rStartPos.RotateAround(aStartPos, nOrientation); } - PaintOrStrip(rOutDev, aBigRect, aStartPos, nOrientation); + + static bool bUsePrimitives(nullptr == std::getenv("DISBALE_EDITENGINE_ON_PRIMITIVES")); + + if (bUsePrimitives) + { + // 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 (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))}; + } + + // create PrimitiveProcessor and render to target + std::unique_ptr xProcessor( + drawinglayer::processor2d::createProcessor2DFromOutputDevice(rOutDev, aViewInformation2D)); + xProcessor->process(aContent); + } + else + { + PaintOrStrip(rOutDev, aBigRect, aStartPos, nOrientation); + } + if (rOutDev.GetConnectMetaFile()) rOutDev.Pop(); } @@ -3394,48 +3446,92 @@ void ImpEditEngine::DrawText_ToRectangle( OutputDevice& rOutDev, const tools::Re aStartPos.setY( aOutRect.Top() - rStartDocPos.X() ); } - bool bClipRegion = rOutDev.IsClipRegion(); - bool bMetafile = rOutDev.GetConnectMetaFile(); - vcl::Region aOldRegion = rOutDev.GetClipRegion(); + static bool bUsePrimitives(nullptr == std::getenv("DISBALE_EDITENGINE_ON_PRIMITIVES")); - // 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 ) + if (bUsePrimitives) { - // Clip only if necessary... - if (!IsFormatted()) - FormatDoc(); - tools::Long nTextWidth = !IsEffectivelyVertical() ? CalcTextWidth(true) : GetTextHeight(); - if ( rStartDocPos.X() || rStartDocPos.Y() || - ( rOutRect.GetHeight() < static_cast(GetTextHeight()) ) || - ( rOutRect.GetWidth() < nTextWidth ) ) + // 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)) { - // 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 ); + // 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 xProcessor( + drawinglayer::processor2d::createProcessor2DFromOutputDevice(rOutDev, aViewInformation2D)); + xProcessor->process(aContent); } - - PaintOrStrip(rOutDev, aOutRect, aStartPos); - - if ( bMetafile ) - rOutDev.Pop(); - else if ( bClipRegion ) - rOutDev.SetClipRegion( aOldRegion ); else - rOutDev.SetClipRegion(); + { + 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(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(); + } } // TODO: use IterateLineAreas in ImpEditEngine::Paint, to avoid algorithm duplication @@ -3822,7 +3918,7 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR pDXArray = KernArraySpan(aTmpDXArray); // add a meta file comment if we record to a metafile - if( bMetafileValid ) + if( !pStripPortionsHelper && bMetafileValid ) { const SvxFieldItem* pFieldItem = dynamic_cast(pAttr->GetItem()); if( pFieldItem ) @@ -4132,7 +4228,7 @@ void ImpEditEngine::PaintOrStrip( OutputDevice& rOutDev, tools::Rectangle aClipR if ( rTextPortion.GetKind() == PortionKind::FIELD ) { // add a meta file comment if we record to a metafile - if( bMetafileValid ) + if( !pStripPortionsHelper && bMetafileValid ) { const EditCharAttrib* pAttr = rParaPortion.GetNode()->GetCharAttribs().FindFeature(nIndex); assert( pAttr && "Field not found" ); @@ -4311,7 +4407,7 @@ Point ImpEditEngine::CalculateTextPaintStartPosition(ImpEditView& rView) const return aStartPos; } -void ImpEditEngine::DrawText_ToEditView( ImpEditView* pView, const tools::Rectangle& rRect, OutputDevice* pTargetDevice ) +void ImpEditEngine::DrawText_ToEditView( TextHierarchyBreakup& rHelper, ImpEditView* pView, const tools::Rectangle& rRect, OutputDevice* pTargetDevice ) { if ( !IsUpdateLayout() || IsInUndo() ) return; @@ -4339,16 +4435,59 @@ void ImpEditEngine::DrawText_ToEditView( ImpEditView* pView, const tools::Rectan aClipRect.SetRight( nMaxX ); } - bool bClipRegion = rTarget.IsClipRegion(); - vcl::Region aOldRegion = rTarget.GetClipRegion(); - rTarget.IntersectClipRegion( aClipRect ); + static bool bUsePrimitives(nullptr == std::getenv("DISBALE_EDITENGINE_ON_PRIMITIVES")); - PaintOrStrip(rTarget, aClipRect, aStartPos); + if (bUsePrimitives) + { + // extract Primitives + PaintOrStrip(rTarget, aClipRect, aStartPos, 0_deg10, &rHelper); - if ( bClipRegion ) - rTarget.SetClipRegion( aOldRegion ); + if (rHelper.getTextPortionPrimitives().empty()) + // no Primitives, done + return; + + // 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); + + // get content and it's range + drawinglayer::primitive2d::Primitive2DContainer aContent(rHelper.getTextPortionPrimitives()); + const basegfx::B2DRange aContentRange(aContent.getB2DRange(aViewInformation2D)); + + if (!aContentRange.overlaps(aClipRange)) + // no overlap, nothing visible + return; + + 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))}; + } + + // create PrimitiveProcessor and render to target + std::unique_ptr xProcessor( + drawinglayer::processor2d::createProcessor2DFromOutputDevice(rTarget, aViewInformation2D)); + xProcessor->process(aContent); + } else - rTarget.SetClipRegion(); + { + bool bClipRegion = rTarget.IsClipRegion(); + vcl::Region aOldRegion = rTarget.GetClipRegion(); + rTarget.IntersectClipRegion( aClipRect ); + + PaintOrStrip(rTarget, aClipRect, aStartPos); + + if ( bClipRegion ) + rTarget.SetClipRegion( aOldRegion ); + else + rTarget.SetClipRegion(); + } pView->DrawSelectionXOR(pView->GetEditSelection(), nullptr, &rTarget); } diff --git a/editeng/source/outliner/outleeng.cxx b/editeng/source/outliner/outleeng.cxx index a4c193eb66ab..92dcbfb78fab 100644 --- a/editeng/source/outliner/outleeng.cxx +++ b/editeng/source/outliner/outleeng.cxx @@ -39,11 +39,11 @@ 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, const Point& rOrigin, Degree10 nOrientation, OutputDevice& rOutDev, StripPortionsHelper* pStripPortionsHelper) { if( GetControlWord() & EEControlBits::OUTLINER ) { - PaintFirstLineInfo aInfo(nPara, rStartPos, &rOutDev); + PaintFirstLineInfo aInfo(nPara, rStartPos, &rOutDev, pStripPortionsHelper); pOwner->maPaintFirstLineHdl.Call( &aInfo ); } diff --git a/editeng/source/outliner/outlvw.cxx b/editeng/source/outliner/outlvw.cxx index e1e28f04fcad..c7e772be9524 100644 --- a/editeng/source/outliner/outlvw.cxx +++ b/editeng/source/outliner/outlvw.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -66,7 +67,14 @@ void OutlinerView::DrawText_ToEditView( const tools::Rectangle& rRect, OutputDev if( rOwner.bFirstParaIsEmpty ) rOwner.Insert( OUString() ); - pEditView->DrawText_ToEditView( rRect, pTargetDevice ); + // use TextHierarchyBreakupOutliner to get all text embedded to the + // TextHierarchy.*Primitive2D groupings for better processing, plus + // the correct paragtaph countings + TextHierarchyBreakupOutliner aHelper(rOwner); + + // hand that Helper over to DrawText_ToEditView at the EditEngine + // for usage + pEditView->DrawText_ToEditView( aHelper, rRect, pTargetDevice ); } bool OutlinerView::PostKeyEvent( const KeyEvent& rKEvt, vcl::Window const * pFrameWin ) diff --git a/include/editeng/StripPortionsHelper.hxx b/include/editeng/StripPortionsHelper.hxx index 7da5cc88d516..dc235471eb37 100644 --- a/include/editeng/StripPortionsHelper.hxx +++ b/include/editeng/StripPortionsHelper.hxx @@ -38,6 +38,8 @@ namespace com::sun::star::lang struct Locale; } +class Outliner; + class EDITENG_DLLPUBLIC DrawPortionInfo { public: @@ -110,6 +112,8 @@ class EDITENG_DLLPUBLIC StripPortionsHelper public: virtual void processDrawPortionInfo(const DrawPortionInfo&) = 0; virtual void processDrawBulletInfo(const DrawBulletInfo&) = 0; + virtual void directlyAddB2DPrimitive(const drawinglayer::primitive2d::Primitive2DReference&) + = 0; }; class EDITENG_DLLPUBLIC TextHierarchyBreakup : public StripPortionsHelper @@ -127,8 +131,10 @@ protected: void flushLinePrimitivesToParagraphPrimitives(sal_Int32 nPara); public: - virtual void processDrawPortionInfo(const DrawPortionInfo& rDrawPortionInfo); - virtual void processDrawBulletInfo(const DrawBulletInfo& rDrawBulletInfo); + virtual void processDrawPortionInfo(const DrawPortionInfo& rDrawPortionInfo) override; + virtual void processDrawBulletInfo(const DrawBulletInfo& rDrawBulletInfo) override; + virtual void + directlyAddB2DPrimitive(const drawinglayer::primitive2d::Primitive2DReference&) override; TextHierarchyBreakup(); TextHierarchyBreakup(const basegfx::B2DHomMatrix& rNewTransformA, @@ -137,6 +143,20 @@ public: const drawinglayer::primitive2d::Primitive2DContainer& getTextPortionPrimitives(); }; +class EDITENG_DLLPUBLIC TextHierarchyBreakupOutliner : public TextHierarchyBreakup +{ + Outliner& mrOutliner; + +protected: + virtual sal_Int16 getOutlineLevelFromParagraph(sal_Int32 nPara) const override; + virtual sal_Int32 getParagraphCount() const override; + +public: + TextHierarchyBreakupOutliner(Outliner& rOutliner); + TextHierarchyBreakupOutliner(Outliner& rOutliner, const basegfx::B2DHomMatrix& rNewTransformA, + const basegfx::B2DHomMatrix& rNewTransformB); +}; + #endif // INCLUDED_EDITENG_STRIPPORTIONSHELPER_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/editeng/editview.hxx b/include/editeng/editview.hxx index c725cdbda71c..e77cea8c56b1 100644 --- a/include/editeng/editview.hxx +++ b/include/editeng/editview.hxx @@ -69,6 +69,7 @@ class InputContext; class OutputDevice; enum class TransliterationFlags; enum class PointerStyle; +class TextHierarchyBreakup; namespace com { namespace sun { @@ -204,6 +205,7 @@ public: Point CalculateTextPaintStartPosition() const; void DrawText_ToEditView( const tools::Rectangle& rRect, OutputDevice* pTargetDevice = nullptr ); + void DrawText_ToEditView( TextHierarchyBreakup& rHelper, const tools::Rectangle& rRect, OutputDevice* pTargetDevice = nullptr ); tools::Rectangle GetInvalidateRect() const; SAL_DLLPRIVATE void InvalidateWindow(const tools::Rectangle& rClipRect); void InvalidateOtherViewWindows( const tools::Rectangle& rInvRect ); diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx index df22cbe70fa3..a6f740d3ec36 100644 --- a/include/editeng/outliner.hxx +++ b/include/editeng/outliner.hxx @@ -407,9 +407,10 @@ struct EDITENG_DLLPUBLIC PaintFirstLineInfo sal_Int32 mnPara; const Point& mrStartPos; VclPtr mpOutDev; + StripPortionsHelper* mpStripPortionsHelper; - PaintFirstLineInfo( sal_Int32 nPara, const Point& rStartPos, OutputDevice* pOutDev ) - : mnPara( nPara ), mrStartPos( rStartPos ), mpOutDev( pOutDev ) + PaintFirstLineInfo( sal_Int32 nPara, const Point& rStartPos, OutputDevice* pOutDev, StripPortionsHelper* pStripPortionsHelper ) + : mnPara( nPara ), mrStartPos( rStartPos ), mpOutDev( pOutDev ), mpStripPortionsHelper( pStripPortionsHelper ) {} }; diff --git a/include/svx/svdoutl.hxx b/include/svx/svdoutl.hxx index 5ef5985ef26b..0af4f6804849 100644 --- a/include/svx/svdoutl.hxx +++ b/include/svx/svdoutl.hxx @@ -52,21 +52,6 @@ public: virtual std::optional GetCompatFlag(SdrCompatibilityFlag eFlag) const override; }; -class TextHierarchyBreakupOutliner : public TextHierarchyBreakup -{ - SdrOutliner& mrOutliner; - -protected: - virtual sal_Int16 getOutlineLevelFromParagraph(sal_Int32 nPara) const; - virtual sal_Int32 getParagraphCount() const; - -public: - TextHierarchyBreakupOutliner( - SdrOutliner& rOutliner, - const basegfx::B2DHomMatrix& rNewTransformA, - const basegfx::B2DHomMatrix& rNewTransformB); -}; - class TextHierarchyBreakupBlockText : public TextHierarchyBreakupOutliner { // ClipRange for BlockText decomposition; only text portions completely @@ -75,7 +60,7 @@ class TextHierarchyBreakupBlockText : public TextHierarchyBreakupOutliner const basegfx::B2DRange& mrClipRange; public: - virtual void processDrawPortionInfo(const DrawPortionInfo& rDrawPortionInfo); + virtual void processDrawPortionInfo(const DrawPortionInfo& rDrawPortionInfo) override; TextHierarchyBreakupBlockText( SdrOutliner& rOutliner, @@ -90,7 +75,7 @@ class TextHierarchyBreakupContourText : public TextHierarchyBreakupOutliner basegfx::B2DVector maScale; public: - virtual void processDrawPortionInfo(const DrawPortionInfo& rDrawPortionInfo); + virtual void processDrawPortionInfo(const DrawPortionInfo& rDrawPortionInfo) override; TextHierarchyBreakupContourText( SdrOutliner& rOutliner, diff --git a/sd/source/ui/view/outlview.cxx b/sd/source/ui/view/outlview.cxx index 768f32dff6d9..14c7ad84afe3 100644 --- a/sd/source/ui/view/outlview.cxx +++ b/sd/source/ui/view/outlview.cxx @@ -44,6 +44,13 @@ #include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -1576,8 +1583,23 @@ 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")); - pInfo->mpOutDev->DrawImage( aImagePos, aImageSize, maSlideImage ); + if (bUsePrimitives && pInfo->mpStripPortionsHelper) + { + // create BitmapPrimitive2D and add directly + const drawinglayer::primitive2d::Primitive2DReference xBitmap( + new drawinglayer::primitive2d::BitmapPrimitive2D( + maSlideImage.GetBitmapEx(), + basegfx::utils::createScaleTranslateB2DHomMatrix( + aImageSize.Width(), aImageSize.Height(), + aImagePos.X(), aImagePos.Y()))); + pInfo->mpStripPortionsHelper->directlyAddB2DPrimitive(xBitmap); + } + else + { + pInfo->mpOutDev->DrawImage( aImagePos, aImageSize, maSlideImage ); + } const bool bVertical = mrOutliner.IsVertical(); const bool bRightToLeftPara = rEditEngine.IsRightToLeft( pInfo->mnPara ); @@ -1612,7 +1634,38 @@ IMPL_LINK(OutlineView, PaintingFirstLineHdl, PaintFirstLineInfo*, pInfo, void) aTextPos.AdjustY( -(aTextSz.Width()) ); aTextPos.AdjustX(nBulletHeight / 2 ); } - pInfo->mpOutDev->DrawText( aTextPos, aPageText ); + + 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(), + {}, + std::move(aFontAttr), + css::lang::Locale(), + pInfo->mpOutDev->GetTextColor().getBColor())); + pInfo->mpStripPortionsHelper->directlyAddB2DPrimitive(xText); + } + else + { + pInfo->mpOutDev->DrawText( aTextPos, aPageText ); + } } void OutlineView::UpdateParagraph( sal_Int32 nPara ) diff --git a/svx/source/svdraw/svdotextpathdecomposition.cxx b/svx/source/svdraw/svdotextpathdecomposition.cxx index 14c9693b3d64..ec4017ba4350 100644 --- a/svx/source/svdraw/svdotextpathdecomposition.cxx +++ b/svx/source/svdraw/svdotextpathdecomposition.cxx @@ -154,17 +154,22 @@ namespace ::std::vector< impPathTextPortion > maPathTextPortions; public: - virtual void processDrawPortionInfo(const DrawPortionInfo& rDrawPortionInfo) + virtual void processDrawPortionInfo(const DrawPortionInfo& rDrawPortionInfo) override { // extract and add data for TextOnPath further processing maPathTextPortions.emplace_back(rDrawPortionInfo); } - virtual void processDrawBulletInfo(const DrawBulletInfo&) + virtual void processDrawBulletInfo(const DrawBulletInfo&) override { // nothing to do here, bullets are for now ignored for TextOnLine } + virtual void directlyAddB2DPrimitive(const drawinglayer::primitive2d::Primitive2DReference&) override + { + // nothing to do here, no support for directly adding Primitives + } + const ::std::vector< impPathTextPortion >& sortAndGetPathTextPortions() { if(!maPathTextPortions.empty()) diff --git a/svx/source/svdraw/svdoutl.cxx b/svx/source/svdraw/svdoutl.cxx index 7b4cf2499e36..da7bafc506c7 100644 --- a/svx/source/svdraw/svdoutl.cxx +++ b/svx/source/svdraw/svdoutl.cxx @@ -122,31 +122,6 @@ std::optional SdrOutliner::GetCompatFlag(SdrCompatibilityFlag eFlag) const return {}; } -sal_Int16 TextHierarchyBreakupOutliner::getOutlineLevelFromParagraph(sal_Int32 nPara) const -{ - sal_Int16 nDepth(mrOutliner.GetDepth(nPara)); - EBulletInfo eInfo(mrOutliner.GetBulletInfo(nPara)); - // Pass -1 to signal VclMetafileProcessor2D that there is no active - // bullets/numbering in this paragraph (i.e. this is normal text) - return eInfo.bVisible ? nDepth : -1; -} - -sal_Int32 TextHierarchyBreakupOutliner::getParagraphCount() const -{ - return mrOutliner.GetParagraphCount(); -} - -TextHierarchyBreakupOutliner::TextHierarchyBreakupOutliner( - SdrOutliner& rOutliner, - const basegfx::B2DHomMatrix& rNewTransformA, - const basegfx::B2DHomMatrix& rNewTransformB) -: TextHierarchyBreakup( - rNewTransformA, - rNewTransformB) -, mrOutliner(rOutliner) -{ -} - void TextHierarchyBreakupBlockText::processDrawPortionInfo(const DrawPortionInfo& rDrawPortionInfo) { // Is clipping wanted? This is text clipping; only accept a portion