sc: factor out some more code
[LibreOffice.git] / sw / source / core / doc / notxtfrm.cxx
blob6fee4477528190d9db90f68ddb7843e0eca3224b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <hintids.hxx>
21 #include <tools/urlobj.hxx>
22 #include <vcl/imapobj.hxx>
23 #include <vcl/imap.hxx>
24 #include <svl/urihelper.hxx>
25 #include <sfx2/progress.hxx>
26 #include <sfx2/printer.hxx>
27 #include <editeng/udlnitem.hxx>
28 #include <editeng/colritem.hxx>
29 #include <editeng/boxitem.hxx>
30 #include <fmturl.hxx>
31 #include <fmtsrnd.hxx>
32 #include <frmfmt.hxx>
33 #include <swrect.hxx>
34 #include <fesh.hxx>
35 #include <doc.hxx>
36 #include <IDocumentSettingAccess.hxx>
37 #include <IDocumentStylePoolAccess.hxx>
38 #include <IDocumentDeviceAccess.hxx>
39 #include <IDocumentLayoutAccess.hxx>
40 #include <flyfrm.hxx>
41 #include <flyfrms.hxx>
42 #include <frmtool.hxx>
43 #include <viewopt.hxx>
44 #include <viewimp.hxx>
45 #include <pam.hxx>
46 #include <hints.hxx>
47 #include <rootfrm.hxx>
48 #include <dflyobj.hxx>
49 #include <pagefrm.hxx>
50 #include <notxtfrm.hxx>
51 #include <grfatr.hxx>
52 #include <charatr.hxx>
53 #include <ndnotxt.hxx>
54 #include <ndgrf.hxx>
55 #include <ndole.hxx>
56 #include <swregion.hxx>
57 #include <poolfmt.hxx>
58 #include <strings.hrc>
59 #include <accessibilityoptions.hxx>
60 #include <com/sun/star/embed/EmbedMisc.hpp>
61 #include <com/sun/star/embed/EmbedStates.hpp>
62 #include <com/sun/star/embed/XEmbeddedObject.hpp>
63 #include <svtools/embedhlp.hxx>
64 #include <dview.hxx>
65 #include <basegfx/matrix/b2dhommatrix.hxx>
66 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
67 #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
68 #include <basegfx/matrix/b2dhommatrixtools.hxx>
69 #include <basegfx/utils/b2dclipstate.hxx>
70 #include <drawinglayer/processor2d/processor2dtools.hxx>
71 #include <txtfly.hxx>
72 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
73 #include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx>
74 #include <osl/diagnose.h>
76 // MM02 needed for VOC mechanism and getting the OC - may be moved to an own file
77 #include <svx/sdrpagewindow.hxx>
78 #include <svx/svdoutl.hxx>
79 #include <svx/svdpage.hxx>
80 #include <svx/svdpagv.hxx>
81 #include <svx/unopage.hxx>
82 #include <svx/sdr/contact/viewcontact.hxx>
83 #include <svx/sdr/contact/viewobjectcontact.hxx>
84 #include <svx/sdr/contact/objectcontact.hxx>
85 #include <svx/sdr/contact/displayinfo.hxx>
87 using namespace com::sun::star;
89 static bool GetRealURL( const SwGrfNode& rNd, OUString& rText )
91 bool bRet = rNd.GetFileFilterNms( &rText, nullptr );
92 if( bRet )
93 rText = URIHelper::removePassword( rText, INetURLObject::EncodeMechanism::WasEncoded,
94 INetURLObject::DecodeMechanism::Unambiguous);
95 if (rText.startsWith("data:image")) rText = "inline image";
97 return bRet;
100 static void lcl_PaintReplacement( const SwRect &rRect, const OUString &rText,
101 const SwViewShell &rSh, const SwNoTextFrame *pFrame,
102 bool bDefect )
104 static vcl::Font aFont = []()
106 vcl::Font tmp;
107 tmp.SetWeight( WEIGHT_BOLD );
108 tmp.SetStyleName( OUString() );
109 tmp.SetFamilyName(u"Noto Sans"_ustr);
110 tmp.SetFamily( FAMILY_SWISS );
111 tmp.SetTransparent( true );
112 return tmp;
113 }();
115 Color aCol( COL_RED );
116 FontLineStyle eUnderline = LINESTYLE_NONE;
117 const SwFormatURL &rURL = pFrame->FindFlyFrame()->GetFormat()->GetURL();
118 if( !rURL.GetURL().isEmpty() || rURL.GetMap() )
120 bool bVisited = false;
121 if ( rURL.GetMap() )
123 ImageMap *pMap = const_cast<ImageMap*>(rURL.GetMap());
124 for( size_t i = 0; i < pMap->GetIMapObjectCount(); ++i )
126 IMapObject *pObj = pMap->GetIMapObject( i );
127 if( rSh.GetDoc()->IsVisitedURL( pObj->GetURL() ) )
129 bVisited = true;
130 break;
134 else if ( !rURL.GetURL().isEmpty() )
135 bVisited = rSh.GetDoc()->IsVisitedURL( rURL.GetURL() );
137 SwFormat *pFormat = rSh.GetDoc()->getIDocumentStylePoolAccess().GetFormatFromPool( o3tl::narrowing<sal_uInt16>
138 (bVisited ? RES_POOLCHR_INET_VISIT : RES_POOLCHR_INET_NORMAL ) );
139 aCol = pFormat->GetColor().GetValue();
140 eUnderline = pFormat->GetUnderline().GetLineStyle();
143 aFont.SetUnderline( eUnderline );
144 aFont.SetColor( aCol );
146 const BitmapEx& rBmp = const_cast<SwViewShell&>(rSh).GetReplacementBitmap(bDefect);
147 Graphic::DrawEx(*rSh.GetOut(), rText, aFont, rBmp, rRect.Pos(), rRect.SSize());
150 SwNoTextFrame::SwNoTextFrame(SwNoTextNode * const pNode, SwFrame* pSib )
151 : SwContentFrame( pNode, pSib )
153 mnFrameType = SwFrameType::NoTxt;
156 SwContentFrame *SwNoTextNode::MakeFrame( SwFrame* pSib )
158 return new SwNoTextFrame(this, pSib);
161 void SwNoTextFrame::DestroyImpl()
163 StopAnimation();
165 SwContentFrame::DestroyImpl();
168 SwNoTextFrame::~SwNoTextFrame()
172 void SetOutDev( SwViewShell *pSh, OutputDevice *pOut )
174 pSh->mpOut = pOut;
177 static void lcl_ClearArea( const SwFrame &rFrame,
178 vcl::RenderContext &rOut, const SwRect& rPtArea,
179 const SwRect &rGrfArea )
181 SwRegionRects aRegion( rPtArea, 4 );
182 aRegion -= rGrfArea;
184 if ( aRegion.empty() )
185 return;
187 const SvxBrushItem *pItem;
188 std::optional<Color> xCol;
189 SwRect aOrigRect;
190 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes;
192 if ( rFrame.GetBackgroundBrush( aFillAttributes, pItem, xCol, aOrigRect, false, /*bConsiderTextBox=*/false ) )
194 SwRegionRects const region(rPtArea);
195 basegfx::utils::B2DClipState aClipState;
196 const bool bDone(::DrawFillAttributes(aFillAttributes, aOrigRect, region, aClipState, rOut));
198 if(!bDone)
200 for( const auto &rRegion : aRegion )
202 ::DrawGraphic(pItem, rOut, aOrigRect, rRegion);
206 else
208 rOut.Push( vcl::PushFlags::FILLCOLOR|vcl::PushFlags::LINECOLOR );
209 rOut.SetFillColor( rFrame.getRootFrame()->GetCurrShell()->Imp()->GetRetoucheColor());
210 rOut.SetLineColor();
211 for( const auto &rRegion : aRegion )
212 rOut.DrawRect( rRegion.SVRect() );
213 rOut.Pop();
217 void SwNoTextFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, PaintFrameMode) const
219 if ( getFrameArea().IsEmpty() )
220 return;
222 const SwViewShell* pSh = getRootFrame()->GetCurrShell();
223 if( !pSh->GetViewOptions()->IsGraphic() )
225 StopAnimation();
226 // #i6467# - no paint of placeholder for page preview
227 if ( pSh->GetWin() && !pSh->IsPreview() )
229 const SwNoTextNode* pNd = GetNode()->GetNoTextNode();
230 OUString aText( pNd->GetTitle() );
231 if ( aText.isEmpty() && pNd->IsGrfNode() )
232 GetRealURL( *static_cast<const SwGrfNode*>(pNd), aText );
233 if( aText.isEmpty() )
234 aText = FindFlyFrame()->GetFormat()->GetName();
235 lcl_PaintReplacement( getFrameArea(), aText, *pSh, this, false );
237 return;
240 if( pSh->GetAccessibilityOptions()->IsStopAnimatedGraphics() ||
241 // #i9684# Stop animation during printing/pdf export
242 !pSh->GetWin() )
243 StopAnimation();
245 SfxProgress::EnterLock(); // No progress reschedules in paint (SwapIn)
247 rRenderContext.Push();
248 bool bClip = true;
249 tools::PolyPolygon aPoly;
251 SwNoTextNode& rNoTNd = const_cast<SwNoTextNode&>(*static_cast<const SwNoTextNode*>(GetNode()));
252 SwGrfNode* pGrfNd = rNoTNd.GetGrfNode();
253 if( pGrfNd )
254 pGrfNd->SetFrameInPaint( true );
256 // #i13147# - add 2nd parameter with value <true> to
257 // method call <FindFlyFrame().GetContour(..)> to indicate that it is called
258 // for paint in order to avoid load of the intrinsic graphic.
259 if ( ( !rRenderContext.GetConnectMetaFile() ||
260 !pSh->GetWin() ) &&
261 FindFlyFrame()->GetContour( aPoly, true )
264 // don't clip if related compatibility flag is set
265 const IDocumentSettingAccess& rIDSA = pSh->GetDoc()->getIDocumentSettingAccess();
266 if (!rIDSA.get(DocumentSettingId::NO_CLIPPING_WITH_WRAP_POLYGON))
267 rRenderContext.SetClipRegion(vcl::Region(aPoly));
268 bClip = false;
271 SwRect aOrigPaint( rRect );
272 if ( HasAnimation() && pSh->GetWin() )
274 aOrigPaint = getFrameArea(); aOrigPaint += getFramePrintArea().Pos();
277 SwRect aGrfArea( getFrameArea() );
278 SwRect aPaintArea( aGrfArea );
280 // In case the picture fly frm was clipped, render it with the origin
281 // size instead of scaling it
282 if ( pGrfNd && rNoTNd.getIDocumentSettingAccess()->get( DocumentSettingId::CLIPPED_PICTURES ) )
284 auto pFindFly = FindFlyFrame();
285 if (pFindFly && pFindFly->IsFlyFreeFrame())
287 const SwFlyFreeFrame *pFly = static_cast< const SwFlyFreeFrame* >( pFindFly );
288 bool bGetUnclippedFrame=true;
289 const SvxBoxItem* pBoxItem;
290 if( pFly->GetFormat() && (pBoxItem = pFly->GetFormat()->GetItemIfSet(RES_BOX, false)) )
292 if( pBoxItem->HasBorder( /*bTreatPaddingAsBorder*/true) )
293 bGetUnclippedFrame = false;
296 if( bGetUnclippedFrame )
297 aGrfArea = SwRect( getFrameArea().Pos( ), pFly->GetUnclippedFrame( ).SSize( ) );
301 aPaintArea.Intersection_( aOrigPaint );
303 SwRect aNormal( getFrameArea().Pos() + getFramePrintArea().Pos(), getFramePrintArea().SSize() );
304 aNormal.Justify(); // Normalized rectangle for the comparisons
306 if( aPaintArea.Overlaps( aNormal ) )
308 // Calculate the four to-be-deleted rectangles
309 if( pSh->GetWin() )
310 ::lcl_ClearArea( *this, rRenderContext, aPaintArea, aNormal );
312 // The intersection of the PaintArea and the Bitmap contains the absolutely visible area of the Frame
313 aPaintArea.Intersection_( aNormal );
315 if ( bClip )
316 rRenderContext.IntersectClipRegion( aPaintArea.SVRect() );
317 /// delete unused 3rd parameter
318 PaintPicture( &rRenderContext, aGrfArea );
320 else
321 // If it's not visible, simply delete the given Area
322 lcl_ClearArea( *this, rRenderContext, aPaintArea, SwRect() );
323 if( pGrfNd )
324 pGrfNd->SetFrameInPaint( false );
326 rRenderContext.Pop();
327 SfxProgress::LeaveLock();
330 /** Calculate the position and the size of the graphic in the Frame,
331 corresponding to the current graphic attributes
333 @param Point the position in the Frame (also returned)
334 @param Size the graphic's size (also returned)
335 @param nMirror the current mirror attribute
337 static void lcl_CalcRect( Point& rPt, Size& rDim, MirrorGraph nMirror )
339 if( nMirror == MirrorGraph::Vertical || nMirror == MirrorGraph::Both )
341 rPt.setX(rPt.getX() + rDim.Width() -1);
342 rDim.setWidth( -rDim.Width() );
345 if( nMirror == MirrorGraph::Horizontal || nMirror == MirrorGraph::Both )
347 rPt.setY(rPt.getY() + rDim.Height() -1);
348 rDim.setHeight( -rDim.Height() );
352 /** Calculate the Bitmap's position and the size within the passed rectangle */
353 void SwNoTextFrame::GetGrfArea( SwRect &rRect, SwRect* pOrigRect ) const
355 // Currently only used for scaling, cropping and mirroring the contour of graphics!
356 // Everything else is handled by GraphicObject
357 // We put the graphic's visible rectangle into rRect.
358 // pOrigRect contains position and size of the whole graphic.
360 // RotateFlyFrame3: SwFrame may be transformed. Get untransformed
361 // SwRect(s) as base of calculation
362 const TransformableSwFrame* pTransformableSwFrame(getTransformableSwFrame());
363 const SwRect aFrameArea(pTransformableSwFrame ? pTransformableSwFrame->getUntransformedFrameArea() : getFrameArea());
364 const SwRect aFramePrintArea(pTransformableSwFrame ? pTransformableSwFrame->getUntransformedFramePrintArea() : getFramePrintArea());
366 const SwAttrSet& rAttrSet = GetNode()->GetSwAttrSet();
367 const SwCropGrf& rCrop = rAttrSet.GetCropGrf();
368 MirrorGraph nMirror = rAttrSet.GetMirrorGrf().GetValue();
370 if( rAttrSet.GetMirrorGrf().IsGrfToggle() )
372 if( !(FindPageFrame()->GetVirtPageNum() % 2) )
374 switch ( nMirror )
376 case MirrorGraph::Dont: nMirror = MirrorGraph::Vertical; break;
377 case MirrorGraph::Vertical: nMirror = MirrorGraph::Dont; break;
378 case MirrorGraph::Horizontal: nMirror = MirrorGraph::Both; break;
379 default: nMirror = MirrorGraph::Horizontal; break;
384 // We read graphic from the Node, if needed.
385 // It may fail, however.
386 tools::Long nLeftCrop, nRightCrop, nTopCrop, nBottomCrop;
387 Size aOrigSz( static_cast<const SwNoTextNode*>(GetNode())->GetTwipSize() );
388 if ( !aOrigSz.Width() )
390 aOrigSz.setWidth( aFramePrintArea.Width() );
391 nLeftCrop = -rCrop.GetLeft();
392 nRightCrop = -rCrop.GetRight();
394 else
396 nLeftCrop = std::max( aOrigSz.Width() -
397 (rCrop.GetRight() + rCrop.GetLeft()), tools::Long(1) );
398 const double nScale = double(aFramePrintArea.Width()) / double(nLeftCrop);
399 nLeftCrop = tools::Long(nScale * -rCrop.GetLeft() );
400 nRightCrop = tools::Long(nScale * -rCrop.GetRight() );
403 // crop values have to be mirrored too
404 if( nMirror == MirrorGraph::Vertical || nMirror == MirrorGraph::Both )
406 tools::Long nTmpCrop = nLeftCrop;
407 nLeftCrop = nRightCrop;
408 nRightCrop= nTmpCrop;
411 if( !aOrigSz.Height() )
413 aOrigSz.setHeight( aFramePrintArea.Height() );
414 nTopCrop = -rCrop.GetTop();
415 nBottomCrop= -rCrop.GetBottom();
417 else
419 nTopCrop = std::max( aOrigSz.Height() - (rCrop.GetTop() + rCrop.GetBottom()), tools::Long(1) );
420 const double nScale = double(aFramePrintArea.Height()) / double(nTopCrop);
421 nTopCrop = tools::Long(nScale * -rCrop.GetTop() );
422 nBottomCrop= tools::Long(nScale * -rCrop.GetBottom() );
425 // crop values have to be mirrored too
426 if( nMirror == MirrorGraph::Horizontal || nMirror == MirrorGraph::Both )
428 tools::Long nTmpCrop = nTopCrop;
429 nTopCrop = nBottomCrop;
430 nBottomCrop= nTmpCrop;
433 Size aVisSz( aFramePrintArea.SSize() );
434 Size aGrfSz( aVisSz );
435 Point aVisPt( aFrameArea.Pos() + aFramePrintArea.Pos() );
436 Point aGrfPt( aVisPt );
438 // Set the "visible" rectangle first
439 if ( nLeftCrop > 0 )
441 aVisPt.setX(aVisPt.getX() + nLeftCrop);
442 aVisSz.AdjustWidth( -nLeftCrop );
444 if ( nTopCrop > 0 )
446 aVisPt.setY(aVisPt.getY() + nTopCrop);
447 aVisSz.AdjustHeight( -nTopCrop );
449 if ( nRightCrop > 0 )
450 aVisSz.AdjustWidth( -nRightCrop );
451 if ( nBottomCrop > 0 )
452 aVisSz.AdjustHeight( -nBottomCrop );
454 rRect.Pos ( aVisPt );
455 rRect.SSize( aVisSz );
457 // Calculate the whole graphic if needed
458 if ( !pOrigRect )
459 return;
461 Size aTmpSz( aGrfSz );
462 aGrfPt.setX(aGrfPt.getX() + nLeftCrop);
463 aTmpSz.AdjustWidth( -(nLeftCrop + nRightCrop) );
464 aGrfPt.setY(aGrfPt.getY() + nTopCrop);
465 aTmpSz.AdjustHeight( -(nTopCrop + nBottomCrop) );
467 if( MirrorGraph::Dont != nMirror )
468 lcl_CalcRect( aGrfPt, aTmpSz, nMirror );
470 pOrigRect->Pos ( aGrfPt );
471 pOrigRect->SSize( aTmpSz );
474 /** By returning the surrounding Fly's size which equals the graphic's size */
475 const Size& SwNoTextFrame::GetSize() const
477 // Return the Frame's size
478 const SwFrame *pFly = FindFlyFrame();
479 if( !pFly )
480 pFly = this;
481 return pFly->getFramePrintArea().SSize();
484 void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
486 // RotateFlyFrame3 - inner frame. Get rotation and check if used
487 const double fRotation(getLocalFrameRotation());
488 const bool bRotated(!basegfx::fTools::equalZero(fRotation));
490 if(bRotated)
492 SwFlyFreeFrame* pUpperFly(dynamic_cast< SwFlyFreeFrame* >(GetUpper()));
494 if(pUpperFly)
496 if(!pUpperFly->isFrameAreaDefinitionValid())
498 // RotateFlyFrame3: outer frame *needs* to be layouted first, force this by calling
499 // it's ::Calc directly
500 pUpperFly->Calc(pRenderContext);
503 // Reset outer frame to unrotated state. This is necessary to make the
504 // layouting below work as currently implemented in Writer. As expected
505 // using Transformations allows to do this on the fly due to all information
506 // being included there.
507 // The full solution would be to adapt the whole layouting
508 // process of Writer to take care of Transformations, but that
509 // is currently beyond scope
510 if(pUpperFly->isTransformableSwFrame())
512 pUpperFly->getTransformableSwFrame()->restoreFrameAreas();
516 // Re-layout may be partially (see all isFrameAreaDefinitionValid() flags),
517 // so resetting the local SwFrame(s) in the local SwFrameAreaDefinition is also
518 // needed (e.g. for PrintPreview).
519 // Reset to BoundAreas will be done below automatically
520 if(isTransformableSwFrame())
522 getTransformableSwFrame()->restoreFrameAreas();
526 SwContentNotify aNotify( this );
527 SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
528 const SwBorderAttrs &rAttrs = *aAccess.Get();
530 while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
532 MakePos();
534 if ( !isFrameAreaSizeValid() )
536 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
537 aFrm.Width( GetUpper()->getFramePrintArea().Width() );
540 MakePrtArea( rAttrs );
542 if ( !isFrameAreaSizeValid() )
544 setFrameAreaSizeValid(true);
545 Format(getRootFrame()->GetCurrShell()->GetOut());
549 // RotateFlyFrame3 - inner frame
550 if(bRotated)
552 SwFlyFreeFrame* pUpperFly(dynamic_cast< SwFlyFreeFrame* >(GetUpper()));
554 if(pUpperFly)
556 // restore outer frame back to Transformed state, that means
557 // set the SwFrameAreaDefinition(s) back to BoundAreas of
558 // the transformed SwFrame. All needed information is part
559 // of the already correctly created Transformations of the
560 // upper frame, so it can be re-created on the fly
561 if(pUpperFly->isTransformableSwFrame())
563 pUpperFly->getTransformableSwFrame()->adaptFrameAreasToTransformations();
567 // After the unrotated layout is finished, apply possible set rotation to it
568 // get center from outer frame (layout frame) to be on the safe side
569 const Point aCenter(GetUpper() ? GetUpper()->getFrameArea().Center() : getFrameArea().Center());
570 const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y());
572 if(!mpTransformableSwFrame)
574 mpTransformableSwFrame.reset(new TransformableSwFrame(*this));
577 getTransformableSwFrame()->createFrameAreaTransformations(
578 fRotation,
579 aB2DCenter);
580 getTransformableSwFrame()->adaptFrameAreasToTransformations();
582 else
584 // reset transformations to show that they are not used
585 mpTransformableSwFrame.reset();
589 // RotateFlyFrame3 - Support for Transformations - outer frame
590 basegfx::B2DHomMatrix SwNoTextFrame::getFrameAreaTransformation() const
592 if(isTransformableSwFrame())
594 // use pre-created transformation
595 return getTransformableSwFrame()->getLocalFrameAreaTransformation();
598 // call parent
599 return SwContentFrame::getFrameAreaTransformation();
602 basegfx::B2DHomMatrix SwNoTextFrame::getFramePrintAreaTransformation() const
604 if(isTransformableSwFrame())
606 // use pre-created transformation
607 return getTransformableSwFrame()->getLocalFramePrintAreaTransformation();
610 // call parent
611 return SwContentFrame::getFramePrintAreaTransformation();
614 // RotateFlyFrame3 - Support for Transformations
615 void SwNoTextFrame::transform_translate(const Point& rOffset)
617 // call parent - this will do the basic transform for SwRect(s)
618 // in the SwFrameAreaDefinition
619 SwContentFrame::transform_translate(rOffset);
621 // check if the Transformations need to be adapted
622 if(isTransformableSwFrame())
624 const basegfx::B2DHomMatrix aTransform(
625 basegfx::utils::createTranslateB2DHomMatrix(
626 rOffset.X(), rOffset.Y()));
628 // transform using TransformableSwFrame
629 getTransformableSwFrame()->transform(aTransform);
633 // RotateFlyFrame3 - inner frame
634 // Check if we contain a SwGrfNode and get possible rotation from it
635 double SwNoTextFrame::getLocalFrameRotation() const
637 const SwNoTextNode* pSwNoTextNode(nullptr != GetNode() ? GetNode()->GetNoTextNode() : nullptr);
639 if(nullptr != pSwNoTextNode)
641 const SwGrfNode* pSwGrfNode(pSwNoTextNode->GetGrfNode());
643 if(nullptr != pSwGrfNode)
645 const SwAttrSet& rSwAttrSet(pSwGrfNode->GetSwAttrSet());
646 const SwRotationGrf& rSwRotationGrf(rSwAttrSet.GetRotationGrf());
647 const double fRotate = -toRadians(rSwRotationGrf.GetValue());
649 return basegfx::normalizeToRange(fRotate, 2 * M_PI);
653 // no rotation
654 return 0.0;
657 void SwNoTextFrame::dumpAsXml(xmlTextWriterPtr writer) const
659 (void)xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>("notxt"));
660 dumpAsXmlAttributes(writer);
662 (void)xmlTextWriterStartElement(writer, BAD_CAST("infos"));
663 dumpInfosAsXml(writer);
664 (void)xmlTextWriterEndElement(writer);
665 dumpChildrenAsXml(writer);
667 (void)xmlTextWriterEndElement(writer);
670 /** Calculate the Bitmap's site, if needed */
671 void SwNoTextFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs * )
673 const Size aNewSize( GetSize() );
675 // Did the height change?
676 SwTwips nChgHght = IsVertical() ?
677 static_cast<SwTwips>(aNewSize.Width() - getFramePrintArea().Width()) :
678 static_cast<SwTwips>(aNewSize.Height() - getFramePrintArea().Height());
679 if( nChgHght > 0)
680 Grow( nChgHght );
681 else if( nChgHght < 0)
682 Shrink( std::min(getFramePrintArea().Height(), tools::Long(-nChgHght)) );
685 bool SwNoTextFrame::GetCharRect( SwRect &rRect, const SwPosition& rPos,
686 SwCursorMoveState *pCMS, bool /*bAllowFarAway*/ ) const
688 if ( &rPos.GetNode() != static_cast<SwNode const *>(GetNode()) )
689 return false;
691 Calc(getRootFrame()->GetCurrShell()->GetOut());
692 SwRect aFrameRect( getFrameArea() );
693 rRect = aFrameRect;
694 rRect.Pos( getFrameArea().Pos() + getFramePrintArea().Pos() );
695 rRect.SSize( getFramePrintArea().SSize() );
697 rRect.Justify();
699 // Is the Bitmap in the visible area at all?
700 if( !aFrameRect.Overlaps( rRect ) )
702 // If not, then the Cursor is on the Frame
703 rRect = aFrameRect;
704 rRect.Width( 1 );
706 else
707 rRect.Intersection_( aFrameRect );
709 if ( pCMS && pCMS->m_bRealHeight )
711 pCMS->m_aRealHeight.setY(rRect.Height());
712 pCMS->m_aRealHeight.setX(0);
715 return true;
718 bool SwNoTextFrame::GetModelPositionForViewPoint(SwPosition* pPos, Point& ,
719 SwCursorMoveState*, bool ) const
721 pPos->Assign(*GetNode());
722 return true;
725 void SwNoTextFrame::ClearCache()
727 SwFlyFrame* pFly = FindFlyFrame();
728 if( pFly && pFly->GetFormat()->GetSurround().IsContour() )
730 ClrContourCache( pFly->GetVirtDrawObj() );
731 pFly->NotifyBackground( FindPageFrame(), getFramePrintArea(), PrepareHint::FlyFrameAttributesChanged );
735 void SwNoTextFrame::OnGraphicArrived()
737 if(GetNode()->GetNodeType() != SwNodeType::Grf)
739 InvalidatePrt();
740 SetCompletePaint();
741 return;
743 SwGrfNode* pNd = static_cast<SwGrfNode*>(GetNode());
744 ClearCache();
745 auto pVSh = pNd->GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell();
746 if(pVSh)
747 pVSh->OnGraphicArrived(getFrameArea());
750 void SwNoTextFrame::SwClientNotify(const SwModify& rModify, const SfxHint& rHint)
752 if(rHint.GetId() == SfxHintId::SwGrfRereadAndInCache)
754 if(SwNodeType::Grf != GetNode()->GetNodeType())
756 InvalidatePrt();
757 SetCompletePaint();
760 else if(rHint.GetId() == SfxHintId::SwPreGraphicArrived
761 || rHint.GetId() == SfxHintId::SwGraphicPieceArrived
762 || rHint.GetId() == SfxHintId::SwLinkedGraphicStreamArrived)
764 OnGraphicArrived();
766 else if (rHint.GetId() == SfxHintId::SwFormatChange)
768 ClearCache();
769 InvalidatePrt();
770 SetCompletePaint();
772 else if (rHint.GetId() == SfxHintId::SwAttrSetChange)
774 auto pChangeHint = static_cast<const sw::AttrSetChangeHint*>(&rHint);
775 SwContentFrame::SwClientNotify(rModify, rHint);
777 sal_uInt16 n;
778 for( n = RES_GRFATR_BEGIN; n < RES_GRFATR_END; ++n )
779 if( SfxItemState::SET == pChangeHint->m_pOld->GetChgSet()->
780 GetItemState( n, false ))
782 ClearCache();
784 if(RES_GRFATR_ROTATION == n)
786 // RotGrfFlyFrame: Update Handles in view, these may be rotation-dependent
787 // (e.g. crop handles) and need a visualisation update
788 if ( GetNode()->GetNodeType() == SwNodeType::Grf )
790 SwGrfNode* pNd = static_cast<SwGrfNode*>( GetNode());
791 SwViewShell *pVSh = pNd->GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell();
793 if(pVSh)
795 SdrView* pDrawView = pVSh->GetDrawView();
797 if(pDrawView)
799 pDrawView->AdjustMarkHdl(nullptr);
803 // RotateFlyFrame3 - invalidate needed for ContentFrame (inner, this)
804 // and LayoutFrame (outer, GetUpper). It is possible to only invalidate
805 // the outer frame, but that leads to an in-between state that gets
806 // potentially painted
807 if(GetUpper())
809 GetUpper()->InvalidateAll_();
812 InvalidateAll_();
815 break;
817 if( RES_GRFATR_END == n ) // not found
818 return ;
820 InvalidatePrt();
821 SetCompletePaint();
823 else if (rHint.GetId() == SfxHintId::SwObjectDying)
825 SwContentFrame::SwClientNotify(rModify, rHint);
826 InvalidatePrt();
827 SetCompletePaint();
829 else if (rHint.GetId() == SfxHintId::SwUpdateAttr)
831 SwContentFrame::SwClientNotify(rModify, rHint);
832 if (GetNode()->GetNodeType() == SwNodeType::Grf)
833 ClearCache();
834 InvalidatePrt();
835 SetCompletePaint();
837 else if (rHint.GetId() == SfxHintId::SwLegacyModify)
839 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
840 sal_uInt16 nWhich = pLegacy->GetWhich();
842 SwContentFrame::SwClientNotify(rModify, rHint);
844 if ( !pLegacy->m_pNew || !isGRFATR(nWhich) )
845 return;
847 InvalidatePrt();
848 SetCompletePaint();
852 static void lcl_correctlyAlignRect( SwRect& rAlignedGrfArea, const SwRect& rInArea, vcl::RenderContext const * pOut )
855 if(!pOut)
856 return;
857 tools::Rectangle aPxRect = pOut->LogicToPixel( rInArea.SVRect() );
858 tools::Rectangle aNewPxRect( aPxRect );
859 while( aNewPxRect.Left() < aPxRect.Left() )
861 rAlignedGrfArea.AddLeft( 1 );
862 aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() );
864 while( aNewPxRect.Top() < aPxRect.Top() )
866 rAlignedGrfArea.AddTop(+1);
867 aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() );
869 while( aNewPxRect.Bottom() > aPxRect.Bottom() )
871 rAlignedGrfArea.AddBottom( -1 );
872 aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() );
874 while( aNewPxRect.Right() > aPxRect.Right() )
876 rAlignedGrfArea.AddRight(-1);
877 aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() );
881 static bool paintUsingPrimitivesHelper(
882 vcl::RenderContext& rOutputDevice,
883 const drawinglayer::primitive2d::Primitive2DContainer& rSequence,
884 const basegfx::B2DRange& rSourceRange,
885 const basegfx::B2DRange& rTargetRange)
887 if(!rSequence.empty() && !basegfx::fTools::equalZero(rSourceRange.getWidth()) && !basegfx::fTools::equalZero(rSourceRange.getHeight()))
889 if(!basegfx::fTools::equalZero(rTargetRange.getWidth()) && !basegfx::fTools::equalZero(rTargetRange.getHeight()))
891 // map graphic range to target range. This will e.g. automatically include
892 // the mapping from 1/100th mm content to twips if needed when the target
893 // range is defined in twips
894 const basegfx::B2DHomMatrix aMappingTransform(
895 basegfx::utils::createSourceRangeTargetRangeTransform(
896 rSourceRange,
897 rTargetRange));
899 // Fill ViewInformation. Use MappingTransform here, so there is no need to
900 // embed the primitives to it. Use original TargetRange here so there is also
901 // no need to embed the primitives to a MaskPrimitive for cropping. This works
902 // only in this case where the graphic object cannot be rotated, though.
903 drawinglayer::geometry::ViewInformation2D aViewInformation2D;
904 aViewInformation2D.setObjectTransformation(aMappingTransform);
905 aViewInformation2D.setViewTransformation(rOutputDevice.GetViewTransformation());
906 aViewInformation2D.setViewport(rTargetRange);
908 // get a primitive processor for rendering
909 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
910 drawinglayer::processor2d::createProcessor2DFromOutputDevice(
911 rOutputDevice, aViewInformation2D) );
913 // render and cleanup
914 pProcessor2D->process(rSequence);
915 return true;
919 return false;
922 // MM02 original using fallback to VOC and primitive-based version
923 void paintGraphicUsingPrimitivesHelper(
924 vcl::RenderContext & rOutputDevice,
925 GraphicObject const& rGrfObj,
926 GraphicAttr const& rGraphicAttr,
927 const basegfx::B2DHomMatrix& rGraphicTransform,
928 const OUString& rName,
929 const OUString& rTitle,
930 const OUString& rDescription)
932 // RotGrfFlyFrame: unify using GraphicPrimitive2D
933 // -> the primitive handles all crop and mirror stuff
934 // -> the primitive renderer will create the needed pdf export data
935 // -> if bitmap content, it will be cached system-dependent
936 drawinglayer::primitive2d::Primitive2DContainer aContent {
937 new drawinglayer::primitive2d::GraphicPrimitive2D(
938 rGraphicTransform,
939 rGrfObj,
940 rGraphicAttr) };
942 // MM02 use primitive-based version for visualization
943 paintGraphicUsingPrimitivesHelper(
944 rOutputDevice,
945 aContent,
946 rGraphicTransform,
947 rName,
948 rTitle,
949 rDescription);
952 // MM02 new VOC and primitive-based version
953 void paintGraphicUsingPrimitivesHelper(
954 vcl::RenderContext & rOutputDevice,
955 drawinglayer::primitive2d::Primitive2DContainer& rContent,
956 const basegfx::B2DHomMatrix& rGraphicTransform,
957 const OUString& rName,
958 const OUString& rTitle,
959 const OUString& rDescription)
961 // RotateFlyFrame3: If ClipRegion is set at OutputDevice, we
962 // need to use that. Usually the renderer would be a VCL-based
963 // PrimitiveRenderer, but there are system-specific shortcuts that
964 // will *not* use the VCL-Paint of Bitmap and thus ignore this.
965 // Anyways, indirectly using a CLipRegion set at the target OutDev
966 // when using a PrimitiveRenderer is a non-valid implication.
967 // First tried only to use when HasPolyPolygonOrB2DPolyPolygon(),
968 // but there is an optimization at ClipRegion creation that detects
969 // a single Rectangle in a tools::PolyPolygon and forces to a simple
970 // RegionBand-based implementation, so cannot use it here.
971 if(rOutputDevice.IsClipRegion())
973 basegfx::B2DPolyPolygon aClip(rOutputDevice.GetClipRegion().GetAsB2DPolyPolygon());
975 if(0 != aClip.count())
977 rContent = drawinglayer::primitive2d::Primitive2DContainer {
978 new drawinglayer::primitive2d::MaskPrimitive2D(
979 std::move(aClip),
980 std::move(rContent)) };
984 if(!rName.isEmpty() || !rTitle.isEmpty() || !rDescription.isEmpty())
986 // Embed to ObjectInfoPrimitive2D when we have Name/Title/Description
987 // information available
988 rContent = drawinglayer::primitive2d::Primitive2DContainer {
989 new drawinglayer::primitive2d::ObjectInfoPrimitive2D(
990 std::move(rContent),
991 rName,
992 rTitle,
993 rDescription) };
996 basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0);
997 aTargetRange.transform(rGraphicTransform);
999 paintUsingPrimitivesHelper(
1000 rOutputDevice,
1001 rContent,
1002 aTargetRange,
1003 aTargetRange);
1006 // DrawContact section
1007 namespace { // anonymous namespace
1008 class ViewObjectContactOfSwNoTextFrame : public sdr::contact::ViewObjectContact
1010 protected:
1011 virtual void createPrimitive2DSequence(
1012 const sdr::contact::DisplayInfo& rDisplayInfo,
1013 drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
1015 // tdf#155190 disable this so superclass doesn't wrongly produce NonStruct
1016 virtual bool isExportPDFTags() const override { return false; }
1018 public:
1019 ViewObjectContactOfSwNoTextFrame(
1020 sdr::contact::ObjectContact& rObjectContact,
1021 sdr::contact::ViewContact& rViewContact);
1024 class ViewContactOfSwNoTextFrame : public sdr::contact::ViewContact
1026 private:
1027 // owner
1028 const SwNoTextFrame& mrSwNoTextFrame;
1030 protected:
1031 // Create an Object-Specific ViewObjectContact, set ViewContact and
1032 // ObjectContact. Always needs to return something.
1033 virtual sdr::contact::ViewObjectContact& CreateObjectSpecificViewObjectContact(
1034 sdr::contact::ObjectContact& rObjectContact) override;
1036 public:
1037 // read-access to owner
1038 const SwNoTextFrame& getSwNoTextFrame() const { return mrSwNoTextFrame; }
1040 // basic constructor, used from SwNoTextFrame.
1041 explicit ViewContactOfSwNoTextFrame(const SwNoTextFrame& rSwNoTextFrame);
1044 void ViewObjectContactOfSwNoTextFrame::createPrimitive2DSequence(
1045 const sdr::contact::DisplayInfo& /*rDisplayInfo*/,
1046 drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
1048 // MM02 get all the parameters formally used in paintGraphicUsingPrimitivesHelper
1049 ViewContactOfSwNoTextFrame& rVCOfNTF(static_cast<ViewContactOfSwNoTextFrame&>(GetViewContact()));
1050 const SwNoTextFrame& rSwNoTextFrame(rVCOfNTF.getSwNoTextFrame());
1051 SwNoTextNode& rNoTNd(const_cast<SwNoTextNode&>(*static_cast<const SwNoTextNode*>(rSwNoTextFrame.GetNode())));
1052 SwGrfNode* pGrfNd(rNoTNd.GetGrfNode());
1054 if(nullptr != pGrfNd)
1056 const bool bPrn(GetObjectContact().isOutputToPrinter() || GetObjectContact().isOutputToRecordingMetaFile());
1057 const GraphicObject& rGrfObj(pGrfNd->GetGrfObj(bPrn));
1058 GraphicAttr aGraphicAttr;
1059 pGrfNd->GetGraphicAttr(aGraphicAttr, &rSwNoTextFrame);
1060 const basegfx::B2DHomMatrix aGraphicTransform(rSwNoTextFrame.getFrameAreaTransformation());
1062 // MM02 this is the right place in the VOC-Mechanism to create
1063 // the primitives for visualization - these will be automatically
1064 // buffered and reused
1065 rVisitor.visit(new drawinglayer::primitive2d::GraphicPrimitive2D(
1066 aGraphicTransform,
1067 rGrfObj,
1068 aGraphicAttr));
1072 ViewObjectContactOfSwNoTextFrame::ViewObjectContactOfSwNoTextFrame(
1073 sdr::contact::ObjectContact& rObjectContact,
1074 sdr::contact::ViewContact& rViewContact)
1075 : sdr::contact::ViewObjectContact(rObjectContact, rViewContact)
1079 sdr::contact::ViewObjectContact& ViewContactOfSwNoTextFrame::CreateObjectSpecificViewObjectContact(
1080 sdr::contact::ObjectContact& rObjectContact)
1082 sdr::contact::ViewObjectContact* pRetval = new ViewObjectContactOfSwNoTextFrame(rObjectContact, *this);
1083 return *pRetval;
1086 ViewContactOfSwNoTextFrame::ViewContactOfSwNoTextFrame(
1087 const SwNoTextFrame& rSwNoTextFrame
1089 : mrSwNoTextFrame(rSwNoTextFrame)
1092 } // end of anonymous namespace
1094 sdr::contact::ViewContact& SwNoTextFrame::GetViewContact() const
1096 if(!mpViewContact)
1098 const_cast< SwNoTextFrame* >(this)->mpViewContact =
1099 std::make_unique<ViewContactOfSwNoTextFrame>(*this);
1102 return *mpViewContact;
1105 /** Paint the graphic.
1107 We require either a QuickDraw-Bitmap or a graphic here. If we do not have
1108 either, we return a replacement.
1110 @todo use aligned rectangle for drawing graphic.
1111 @todo pixel-align coordinations for drawing graphic. */
1112 void SwNoTextFrame::PaintPicture( vcl::RenderContext* pOut, const SwRect &rGrfArea ) const
1114 SwViewShell* pShell = getRootFrame()->GetCurrShell();
1116 SwNoTextNode& rNoTNd = const_cast<SwNoTextNode&>(*static_cast<const SwNoTextNode*>(GetNode()));
1117 SwGrfNode* pGrfNd = rNoTNd.GetGrfNode();
1118 SwOLENode* pOLENd = rNoTNd.GetOLENode();
1120 const bool bPrn = pOut == rNoTNd.getIDocumentDeviceAccess().getPrinter( false ) ||
1121 pOut->GetConnectMetaFile();
1123 const bool bIsChart = pOLENd && pOLENd->GetOLEObj().GetObject().IsChart();
1125 // calculate aligned rectangle from parameter <rGrfArea>.
1126 // Use aligned rectangle <aAlignedGrfArea> instead of <rGrfArea> in
1127 // the following code.
1128 SwRect aAlignedGrfArea = rGrfArea;
1129 ::SwAlignRect( aAlignedGrfArea, pShell, pOut );
1131 if( !bIsChart )
1133 // Because for drawing a graphic left-top-corner and size coordinations are
1134 // used, these coordinations have to be determined on pixel level.
1135 ::SwAlignGrfRect( &aAlignedGrfArea, *pOut );
1137 else //if( bIsChart )
1139 // #i78025# charts own borders are not completely visible
1140 // the above pixel correction is not correct - at least not for charts
1141 // so a different pixel correction is chosen here
1142 // this might be a good idea for all other OLE objects also,
1143 // but as I cannot oversee the consequences I fix it only for charts for now
1144 lcl_correctlyAlignRect( aAlignedGrfArea, rGrfArea, pOut );
1147 if( pGrfNd )
1149 // Fix for bug fdo#33781
1150 const AntialiasingFlags nFormerAntialiasingAtOutput( pOut->GetAntialiasing() );
1151 if (SwDrawView::IsAntiAliasing())
1152 pOut->SetAntialiasing( nFormerAntialiasingAtOutput | AntialiasingFlags::Enable );
1154 ImplPaintPictureGraphic( pOut, pGrfNd, bPrn, aAlignedGrfArea, pShell, rNoTNd );
1156 if ( SwDrawView::IsAntiAliasing() )
1157 pOut->SetAntialiasing( nFormerAntialiasingAtOutput );
1159 else // bIsChart || pOLENd
1161 // Fix for bug fdo#33781
1162 const AntialiasingFlags nFormerAntialiasingAtOutput( pOut->GetAntialiasing() );
1163 if (SwDrawView::IsAntiAliasing())
1165 AntialiasingFlags nNewAntialiasingAtOutput = nFormerAntialiasingAtOutput | AntialiasingFlags::Enable;
1167 // #i99665#
1168 // Adjust AntiAliasing mode at output device for chart OLE
1169 if (pOLENd && pOLENd->IsChart())
1170 nNewAntialiasingAtOutput |= AntialiasingFlags::PixelSnapHairline;
1172 pOut->SetAntialiasing( nNewAntialiasingAtOutput );
1175 ImplPaintPictureBitmap( pOut, pOLENd, bIsChart, bPrn, aAlignedGrfArea, pShell );
1177 // see #i99665#
1178 if (SwDrawView::IsAntiAliasing())
1180 pOut->SetAntialiasing( nFormerAntialiasingAtOutput );
1185 void SwNoTextFrame::ImplPaintPictureGraphic( vcl::RenderContext* pOut,
1186 SwGrfNode* pGrfNd, bool bPrn,
1187 const SwRect& rAlignedGrfArea, SwViewShell* pShell,
1188 SwNoTextNode& rNoTNd ) const
1190 bool bContinue = true;
1191 const GraphicObject& rGrfObj = pGrfNd->GetGrfObj(bPrn);
1193 GraphicAttr aGrfAttr;
1194 pGrfNd->GetGraphicAttr( aGrfAttr, this );
1196 if( !bPrn )
1198 // #i73788#
1199 if ( pGrfNd->IsLinkedInputStreamReady() )
1201 pGrfNd->UpdateLinkWithInputStream();
1203 // #i85717#, #i90395# - check, if asynchronous retrieval
1204 // if input stream for the graphic is possible
1205 else if ( ( rGrfObj.GetType() == GraphicType::Default ||
1206 rGrfObj.GetType() == GraphicType::NONE ) &&
1207 pGrfNd->IsLinkedFile() &&
1208 pGrfNd->IsAsyncRetrieveInputStreamPossible() )
1210 Size aTmpSz;
1211 ::sfx2::SvLinkSource* pGrfObj = pGrfNd->GetLink()->GetObj();
1212 if( !pGrfObj ||
1213 !pGrfObj->IsDataComplete() ||
1214 !(aTmpSz = pGrfNd->GetTwipSize()).Width() ||
1215 !aTmpSz.Height())
1217 pGrfNd->TriggerAsyncRetrieveInputStream(); // #i73788#
1219 OUString aText( pGrfNd->GetTitle() );
1220 if ( aText.isEmpty() )
1221 GetRealURL( *pGrfNd, aText );
1222 ::lcl_PaintReplacement( rAlignedGrfArea, aText, *pShell, this, false );
1223 bContinue = false;
1227 if( !bContinue )
1228 return;
1230 if( !rGrfObj.GetGraphic().IsSupportedGraphic())
1232 ImplPaintPictureReplacement(rGrfObj, pGrfNd, rAlignedGrfArea, pShell);
1233 return;
1236 const bool bAnimate = rGrfObj.IsAnimated() &&
1237 !pShell->IsPreview() &&
1238 !pShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() &&
1239 // #i9684# Stop animation during printing/pdf export
1240 pShell->GetWin();
1241 if( bAnimate &&
1242 FindFlyFrame() != ::GetFlyFromMarked( nullptr, pShell ))
1244 ImplPaintPictureAnimate(pOut, pShell, pGrfNd, rAlignedGrfArea);
1245 return;
1248 // MM02 To allow system-dependent buffering of the involved
1249 // bitmaps it is necessary to re-use the involved primitives
1250 // and their already executed decomposition (also for
1251 // performance reasons). This is usually done in DrawingLayer
1252 // by using the VOC-Mechanism (see descriptions elsewhere).
1253 // To get that here, make the involved SwNoTextFrame (this)
1254 // a sdr::contact::ViewContact supplier by supporting
1255 // a GetViewContact() - call. For ObjectContact we can use
1256 // the already existing ObjectContact from the involved
1257 // DrawingLayer. For this, the helper classes
1258 // ViewObjectContactOfSwNoTextFrame
1259 // ViewContactOfSwNoTextFrame
1260 // are created which support the VOC-mechanism in its minimal
1261 // form. This allows automatic and view-dependent (multiple edit
1262 // windows, print, etc.) re-use of the created primitives.
1263 // Also: Will be very useful when completely changing the Writer
1264 // repaint to VOC and Primitives, too.
1265 static const char* pDisableMM02Goodies(getenv("SAL_DISABLE_MM02_GOODIES"));
1266 static bool bUseViewObjectContactMechanism(nullptr == pDisableMM02Goodies);
1267 // tdf#130951 for safety reasons use fallback if ViewObjectContactMechanism
1268 // fails for some reason - usually could only be not to find the correct
1269 // SdrPageWindow
1270 bool bSucceeded(false);
1272 if(bUseViewObjectContactMechanism)
1274 // MM02 use VOC-mechanism and buffer primitives
1275 SwViewShellImp* pImp(pShell->Imp());
1276 SdrPageView* pPageView(nullptr != pImp
1277 ? pImp->GetPageView()
1278 : nullptr);
1279 // tdf#130951 caution - target may be Window, use the correct OutputDevice
1280 OutputDevice* pTarget((pShell->isOutputToWindow() && pShell->GetWin())
1281 ? pShell->GetWin()->GetOutDev()
1282 : pShell->GetOut());
1283 SdrPageWindow* pPageWindow(nullptr != pPageView && nullptr != pTarget
1284 ? pPageView->FindPageWindow(*pTarget)
1285 : nullptr);
1287 if(nullptr != pPageWindow)
1289 sdr::contact::ObjectContact& rOC(pPageWindow->GetObjectContact());
1290 sdr::contact::ViewContact& rVC(GetViewContact());
1291 sdr::contact::ViewObjectContact& rVOC(rVC.GetViewObjectContact(rOC));
1292 sdr::contact::DisplayInfo aDisplayInfo;
1294 drawinglayer::primitive2d::Primitive2DContainer aPrimitives(rVOC.getPrimitive2DSequence(aDisplayInfo));
1295 const basegfx::B2DHomMatrix aGraphicTransform(getFrameAreaTransformation());
1297 paintGraphicUsingPrimitivesHelper(
1298 *pOut,
1299 aPrimitives,
1300 aGraphicTransform,
1301 nullptr == pGrfNd->GetFlyFormat() ? OUString() : pGrfNd->GetFlyFormat()->GetName(),
1302 rNoTNd.GetTitle(),
1303 rNoTNd.GetDescription());
1304 bSucceeded = true;
1308 if(!bSucceeded)
1310 // MM02 fallback to direct paint with primitive-recreation
1311 // which will block reusage of system-dependent bitmap data
1312 const basegfx::B2DHomMatrix aGraphicTransform(getFrameAreaTransformation());
1314 paintGraphicUsingPrimitivesHelper(
1315 *pOut,
1316 rGrfObj,
1317 aGrfAttr,
1318 aGraphicTransform,
1319 nullptr == pGrfNd->GetFlyFormat() ? OUString() : pGrfNd->GetFlyFormat()->GetName(),
1320 rNoTNd.GetTitle(),
1321 rNoTNd.GetDescription());
1325 void SwNoTextFrame::ImplPaintPictureAnimate(vcl::RenderContext* pOut, SwViewShell* pShell,
1326 SwGrfNode* pGrfNd, const SwRect& rAlignedGrfArea) const
1328 OutputDevice* pVout;
1329 if( pOut == pShell->GetOut() && SwRootFrame::FlushVout() )
1331 pVout = pOut;
1332 pOut = pShell->GetOut();
1334 else if( pShell->GetWin() && pOut->IsVirtual() )
1336 pVout = pOut;
1337 pOut = pShell->GetWin()->GetOutDev();
1339 else
1340 pVout = nullptr;
1342 OSL_ENSURE( !pOut->IsVirtual() ||
1343 pShell->GetViewOptions()->IsPDFExport() || pShell->isOutputToWindow(),
1344 "pOut should not be a virtual device" );
1346 pGrfNd->StartGraphicAnimation(pOut, rAlignedGrfArea.Pos(),
1347 rAlignedGrfArea.SSize(), reinterpret_cast<sal_IntPtr>(this),
1348 pVout );
1351 void SwNoTextFrame::ImplPaintPictureReplacement(const GraphicObject& rGrfObj, SwGrfNode* pGrfNd,
1352 const SwRect& rAlignedGrfArea, SwViewShell* pShell) const
1354 TranslateId pResId;
1356 if( GraphicType::NONE == rGrfObj.GetType() )
1357 pResId = STR_COMCORE_READERROR;
1358 else if ( !rGrfObj.GetGraphic().IsSupportedGraphic() )
1359 pResId = STR_COMCORE_CANT_SHOW;
1361 OUString aText;
1362 if ( !pResId &&
1363 (aText = pGrfNd->GetTitle()).isEmpty() &&
1364 (!GetRealURL( *pGrfNd, aText ) || aText.isEmpty()))
1366 pResId = STR_COMCORE_READERROR;
1368 if (pResId)
1369 aText = SwResId(pResId);
1371 ::lcl_PaintReplacement( rAlignedGrfArea, aText, *pShell, this, true );
1374 void SwNoTextFrame::ImplPaintPictureBitmap( vcl::RenderContext* pOut,
1375 SwOLENode* pOLENd, bool bIsChart, bool bPrn, const SwRect& rAlignedGrfArea,
1376 SwViewShell* pShell ) const
1378 bool bDone(false);
1380 if(bIsChart)
1382 basegfx::B2DRange aSourceRange;
1383 const drawinglayer::primitive2d::Primitive2DContainer aSequence(
1384 pOLENd->GetOLEObj().tryToGetChartContentAsPrimitive2DSequence(
1385 aSourceRange,
1386 bPrn));
1388 if(!aSequence.empty() && !aSourceRange.isEmpty())
1390 const basegfx::B2DRange aTargetRange(
1391 rAlignedGrfArea.Left(), rAlignedGrfArea.Top(),
1392 rAlignedGrfArea.Right(), rAlignedGrfArea.Bottom());
1394 Color aOldBackColor;
1395 SvxDrawPage* pDrawPage = pOLENd->GetOLEObj().tryToGetChartDrawPage();
1396 SdrPage* pPage = pDrawPage ? pDrawPage->GetSdrPage() : nullptr;
1397 if (pPage)
1399 SdrModel& rModel = pPage->getSdrModelFromSdrPage();
1400 SdrOutliner& rOutl = rModel.GetDrawOutliner();
1401 aOldBackColor = rOutl.GetBackgroundColor();
1402 rOutl.SetBackgroundColor(pPage->GetPageBackgroundColor());
1405 bDone = paintUsingPrimitivesHelper(
1406 *pOut,
1407 aSequence,
1408 aSourceRange,
1409 aTargetRange);
1411 if (pPage)
1412 pPage->getSdrModelFromSdrPage().GetDrawOutliner().SetBackgroundColor(aOldBackColor);
1416 if(bDone || !pOLENd)
1417 return;
1419 // SwOLENode does not have a known GraphicObject, need to
1420 // work with Graphic instead
1421 const Graphic* pGraphic = pOLENd->GetGraphic();
1422 const Point aPosition(rAlignedGrfArea.Pos());
1423 const Size aSize(rAlignedGrfArea.SSize());
1425 uno::Reference<embed::XEmbeddedObject> xObj = pOLENd->GetOLEObj().GetOleRef();
1427 if ( pGraphic && pGraphic->GetType() != GraphicType::NONE )
1429 pGraphic->Draw(*pOut, aPosition, aSize);
1431 // shade the representation if the object is activated outplace
1432 if ( xObj.is() && xObj->getCurrentState() == embed::EmbedStates::ACTIVE )
1435 ::svt::EmbeddedObjectRef::DrawShading(
1436 tools::Rectangle(
1437 aPosition,
1438 aSize),
1439 pOut);
1442 else
1444 ::svt::EmbeddedObjectRef::DrawPaintReplacement(
1445 tools::Rectangle(aPosition, aSize),
1446 pOLENd->GetOLEObj().GetCurrentPersistName(),
1447 pOut);
1450 sal_Int64 nMiscStatus = xObj ? xObj->getStatus(pOLENd->GetAspect()) : 0;
1451 if ( !bPrn && dynamic_cast< const SwCursorShell *>( pShell ) != nullptr &&
1452 (nMiscStatus & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE))
1454 const SwFlyFrame *pFly = FindFlyFrame();
1455 assert( pFly != nullptr );
1456 static_cast<SwFEShell*>(pShell)->ConnectObj( pOLENd->GetOLEObj().GetObject(), pFly->getFramePrintArea(), pFly->getFrameArea());
1460 bool SwNoTextFrame::IsTransparent() const
1462 const SwViewShell* pSh = getRootFrame()->GetCurrShell();
1464 if ( !pSh || !pSh->GetViewOptions()->IsGraphic() )
1466 return true;
1469 const SwGrfNode *pNd;
1471 if( nullptr != (pNd = GetNode()->GetGrfNode()) )
1473 if(pNd->IsTransparent())
1475 return true;
1479 // RotateFlyFrame3: If we are transformed, there are 'free' areas between
1480 // the Graphic and the Border/Padding stuff - at least as long as those
1481 // (Border and Padding) are not transformed, too
1482 if(isTransformableSwFrame())
1484 // we can be more specific - rotations of multiples of
1485 // 90 degrees will leave no gaps. Go from [0.0 .. 2PI]
1486 // to [0 .. 360] and check modulo 90
1487 const tools::Long nRot(static_cast<tools::Long>(basegfx::rad2deg(getLocalFrameRotation())));
1488 const bool bMultipleOf90(0 == (nRot % 90));
1490 if(!bMultipleOf90)
1492 return true;
1496 //#29381# OLE are always transparent
1497 if(nullptr != GetNode()->GetOLENode())
1499 return true;
1502 // return false by default to avoid background paint
1503 return false;
1506 void SwNoTextFrame::StopAnimation( const OutputDevice* pOut ) const
1508 // Stop animated graphics
1509 const SwGrfNode* pGrfNd = GetNode()->GetGrfNode();
1511 if( pGrfNd && pGrfNd->IsAnimated() )
1513 const_cast< SwGrfNode* >(pGrfNd)->StopGraphicAnimation( pOut, reinterpret_cast<sal_IntPtr>(this) );
1517 bool SwNoTextFrame::HasAnimation() const
1519 const SwGrfNode* pGrfNd = GetNode()->GetGrfNode();
1520 return pGrfNd && pGrfNd->IsAnimated();
1523 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */