android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / doc / notxtfrm.cxx
blobccf60904585d6e6aa2ad8da58b04d06d682ec43d
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/svdpagv.hxx>
79 #include <svx/sdr/contact/viewcontact.hxx>
80 #include <svx/sdr/contact/viewobjectcontact.hxx>
81 #include <svx/sdr/contact/objectcontact.hxx>
82 #include <svx/sdr/contact/displayinfo.hxx>
84 using namespace com::sun::star;
86 static bool GetRealURL( const SwGrfNode& rNd, OUString& rText )
88 bool bRet = rNd.GetFileFilterNms( &rText, nullptr );
89 if( bRet )
90 rText = URIHelper::removePassword( rText, INetURLObject::EncodeMechanism::WasEncoded,
91 INetURLObject::DecodeMechanism::Unambiguous);
92 if (rText.startsWith("data:image")) rText = "inline image";
94 return bRet;
97 static void lcl_PaintReplacement( const SwRect &rRect, const OUString &rText,
98 const SwViewShell &rSh, const SwNoTextFrame *pFrame,
99 bool bDefect )
101 static vcl::Font aFont = []()
103 vcl::Font tmp;
104 tmp.SetWeight( WEIGHT_BOLD );
105 tmp.SetStyleName( OUString() );
106 tmp.SetFamilyName("Noto Sans");
107 tmp.SetFamily( FAMILY_SWISS );
108 tmp.SetTransparent( true );
109 return tmp;
110 }();
112 Color aCol( COL_RED );
113 FontLineStyle eUnderline = LINESTYLE_NONE;
114 const SwFormatURL &rURL = pFrame->FindFlyFrame()->GetFormat()->GetURL();
115 if( !rURL.GetURL().isEmpty() || rURL.GetMap() )
117 bool bVisited = false;
118 if ( rURL.GetMap() )
120 ImageMap *pMap = const_cast<ImageMap*>(rURL.GetMap());
121 for( size_t i = 0; i < pMap->GetIMapObjectCount(); ++i )
123 IMapObject *pObj = pMap->GetIMapObject( i );
124 if( rSh.GetDoc()->IsVisitedURL( pObj->GetURL() ) )
126 bVisited = true;
127 break;
131 else if ( !rURL.GetURL().isEmpty() )
132 bVisited = rSh.GetDoc()->IsVisitedURL( rURL.GetURL() );
134 SwFormat *pFormat = rSh.GetDoc()->getIDocumentStylePoolAccess().GetFormatFromPool( o3tl::narrowing<sal_uInt16>
135 (bVisited ? RES_POOLCHR_INET_VISIT : RES_POOLCHR_INET_NORMAL ) );
136 aCol = pFormat->GetColor().GetValue();
137 eUnderline = pFormat->GetUnderline().GetLineStyle();
140 aFont.SetUnderline( eUnderline );
141 aFont.SetColor( aCol );
143 const BitmapEx& rBmp = const_cast<SwViewShell&>(rSh).GetReplacementBitmap(bDefect);
144 Graphic::DrawEx(*rSh.GetOut(), rText, aFont, rBmp, rRect.Pos(), rRect.SSize());
147 SwNoTextFrame::SwNoTextFrame(SwNoTextNode * const pNode, SwFrame* pSib )
148 : SwContentFrame( pNode, pSib )
150 mnFrameType = SwFrameType::NoTxt;
153 SwContentFrame *SwNoTextNode::MakeFrame( SwFrame* pSib )
155 return new SwNoTextFrame(this, pSib);
158 void SwNoTextFrame::DestroyImpl()
160 StopAnimation();
162 SwContentFrame::DestroyImpl();
165 SwNoTextFrame::~SwNoTextFrame()
169 void SetOutDev( SwViewShell *pSh, OutputDevice *pOut )
171 pSh->mpOut = pOut;
174 static void lcl_ClearArea( const SwFrame &rFrame,
175 vcl::RenderContext &rOut, const SwRect& rPtArea,
176 const SwRect &rGrfArea )
178 SwRegionRects aRegion( rPtArea, 4 );
179 aRegion -= rGrfArea;
181 if ( aRegion.empty() )
182 return;
184 const SvxBrushItem *pItem;
185 std::optional<Color> xCol;
186 SwRect aOrigRect;
187 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes;
189 if ( rFrame.GetBackgroundBrush( aFillAttributes, pItem, xCol, aOrigRect, false, /*bConsiderTextBox=*/false ) )
191 SwRegionRects const region(rPtArea);
192 basegfx::utils::B2DClipState aClipState;
193 const bool bDone(::DrawFillAttributes(aFillAttributes, aOrigRect, region, aClipState, rOut));
195 if(!bDone)
197 for( const auto &rRegion : aRegion )
199 ::DrawGraphic(pItem, rOut, aOrigRect, rRegion);
203 else
205 rOut.Push( vcl::PushFlags::FILLCOLOR|vcl::PushFlags::LINECOLOR );
206 rOut.SetFillColor( rFrame.getRootFrame()->GetCurrShell()->Imp()->GetRetoucheColor());
207 rOut.SetLineColor();
208 for( const auto &rRegion : aRegion )
209 rOut.DrawRect( rRegion.SVRect() );
210 rOut.Pop();
214 void SwNoTextFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
216 if ( getFrameArea().IsEmpty() )
217 return;
219 const SwViewShell* pSh = getRootFrame()->GetCurrShell();
220 if( !pSh->GetViewOptions()->IsGraphic() )
222 StopAnimation();
223 // #i6467# - no paint of placeholder for page preview
224 if ( pSh->GetWin() && !pSh->IsPreview() )
226 const SwNoTextNode* pNd = GetNode()->GetNoTextNode();
227 OUString aText( pNd->GetTitle() );
228 if ( aText.isEmpty() && pNd->IsGrfNode() )
229 GetRealURL( *static_cast<const SwGrfNode*>(pNd), aText );
230 if( aText.isEmpty() )
231 aText = FindFlyFrame()->GetFormat()->GetName();
232 lcl_PaintReplacement( getFrameArea(), aText, *pSh, this, false );
234 return;
237 if( pSh->GetAccessibilityOptions()->IsStopAnimatedGraphics() ||
238 // #i9684# Stop animation during printing/pdf export
239 !pSh->GetWin() )
240 StopAnimation();
242 SfxProgress::EnterLock(); // No progress reschedules in paint (SwapIn)
244 rRenderContext.Push();
245 bool bClip = true;
246 tools::PolyPolygon aPoly;
248 SwNoTextNode& rNoTNd = const_cast<SwNoTextNode&>(*static_cast<const SwNoTextNode*>(GetNode()));
249 SwGrfNode* pGrfNd = rNoTNd.GetGrfNode();
250 if( pGrfNd )
251 pGrfNd->SetFrameInPaint( true );
253 // #i13147# - add 2nd parameter with value <true> to
254 // method call <FindFlyFrame().GetContour(..)> to indicate that it is called
255 // for paint in order to avoid load of the intrinsic graphic.
256 if ( ( !rRenderContext.GetConnectMetaFile() ||
257 !pSh->GetWin() ) &&
258 FindFlyFrame()->GetContour( aPoly, true )
261 rRenderContext.SetClipRegion(vcl::Region(aPoly));
262 bClip = false;
265 SwRect aOrigPaint( rRect );
266 if ( HasAnimation() && pSh->GetWin() )
268 aOrigPaint = getFrameArea(); aOrigPaint += getFramePrintArea().Pos();
271 SwRect aGrfArea( getFrameArea() );
272 SwRect aPaintArea( aGrfArea );
274 // In case the picture fly frm was clipped, render it with the origin
275 // size instead of scaling it
276 if ( pGrfNd && rNoTNd.getIDocumentSettingAccess()->get( DocumentSettingId::CLIPPED_PICTURES ) )
278 auto pFindFly = FindFlyFrame();
279 if (pFindFly && pFindFly->IsFlyFreeFrame())
281 const SwFlyFreeFrame *pFly = static_cast< const SwFlyFreeFrame* >( pFindFly );
282 bool bGetUnclippedFrame=true;
283 const SvxBoxItem* pBoxItem;
284 if( pFly->GetFormat() && (pBoxItem = pFly->GetFormat()->GetItemIfSet(RES_BOX, false)) )
286 if( pBoxItem->HasBorder( /*bTreatPaddingAsBorder*/true) )
287 bGetUnclippedFrame = false;
290 if( bGetUnclippedFrame )
291 aGrfArea = SwRect( getFrameArea().Pos( ), pFly->GetUnclippedFrame( ).SSize( ) );
295 aPaintArea.Intersection_( aOrigPaint );
297 SwRect aNormal( getFrameArea().Pos() + getFramePrintArea().Pos(), getFramePrintArea().SSize() );
298 aNormal.Justify(); // Normalized rectangle for the comparisons
300 if( aPaintArea.Overlaps( aNormal ) )
302 // Calculate the four to-be-deleted rectangles
303 if( pSh->GetWin() )
304 ::lcl_ClearArea( *this, rRenderContext, aPaintArea, aNormal );
306 // The intersection of the PaintArea and the Bitmap contains the absolutely visible area of the Frame
307 aPaintArea.Intersection_( aNormal );
309 if ( bClip )
310 rRenderContext.IntersectClipRegion( aPaintArea.SVRect() );
311 /// delete unused 3rd parameter
312 PaintPicture( &rRenderContext, aGrfArea );
314 else
315 // If it's not visible, simply delete the given Area
316 lcl_ClearArea( *this, rRenderContext, aPaintArea, SwRect() );
317 if( pGrfNd )
318 pGrfNd->SetFrameInPaint( false );
320 rRenderContext.Pop();
321 SfxProgress::LeaveLock();
324 /** Calculate the position and the size of the graphic in the Frame,
325 corresponding to the current graphic attributes
327 @param Point the position in the Frame (also returned)
328 @param Size the graphic's size (also returned)
329 @param nMirror the current mirror attribute
331 static void lcl_CalcRect( Point& rPt, Size& rDim, MirrorGraph nMirror )
333 if( nMirror == MirrorGraph::Vertical || nMirror == MirrorGraph::Both )
335 rPt.setX(rPt.getX() + rDim.Width() -1);
336 rDim.setWidth( -rDim.Width() );
339 if( nMirror == MirrorGraph::Horizontal || nMirror == MirrorGraph::Both )
341 rPt.setY(rPt.getY() + rDim.Height() -1);
342 rDim.setHeight( -rDim.Height() );
346 /** Calculate the Bitmap's position and the size within the passed rectangle */
347 void SwNoTextFrame::GetGrfArea( SwRect &rRect, SwRect* pOrigRect ) const
349 // Currently only used for scaling, cropping and mirroring the contour of graphics!
350 // Everything else is handled by GraphicObject
351 // We put the graphic's visible rectangle into rRect.
352 // pOrigRect contains position and size of the whole graphic.
354 // RotateFlyFrame3: SwFrame may be transformed. Get untransformed
355 // SwRect(s) as base of calculation
356 const TransformableSwFrame* pTransformableSwFrame(getTransformableSwFrame());
357 const SwRect aFrameArea(pTransformableSwFrame ? pTransformableSwFrame->getUntransformedFrameArea() : getFrameArea());
358 const SwRect aFramePrintArea(pTransformableSwFrame ? pTransformableSwFrame->getUntransformedFramePrintArea() : getFramePrintArea());
360 const SwAttrSet& rAttrSet = GetNode()->GetSwAttrSet();
361 const SwCropGrf& rCrop = rAttrSet.GetCropGrf();
362 MirrorGraph nMirror = rAttrSet.GetMirrorGrf().GetValue();
364 if( rAttrSet.GetMirrorGrf().IsGrfToggle() )
366 if( !(FindPageFrame()->GetVirtPageNum() % 2) )
368 switch ( nMirror )
370 case MirrorGraph::Dont: nMirror = MirrorGraph::Vertical; break;
371 case MirrorGraph::Vertical: nMirror = MirrorGraph::Dont; break;
372 case MirrorGraph::Horizontal: nMirror = MirrorGraph::Both; break;
373 default: nMirror = MirrorGraph::Horizontal; break;
378 // We read graphic from the Node, if needed.
379 // It may fail, however.
380 tools::Long nLeftCrop, nRightCrop, nTopCrop, nBottomCrop;
381 Size aOrigSz( static_cast<const SwNoTextNode*>(GetNode())->GetTwipSize() );
382 if ( !aOrigSz.Width() )
384 aOrigSz.setWidth( aFramePrintArea.Width() );
385 nLeftCrop = -rCrop.GetLeft();
386 nRightCrop = -rCrop.GetRight();
388 else
390 nLeftCrop = std::max( aOrigSz.Width() -
391 (rCrop.GetRight() + rCrop.GetLeft()), tools::Long(1) );
392 const double nScale = double(aFramePrintArea.Width()) / double(nLeftCrop);
393 nLeftCrop = tools::Long(nScale * -rCrop.GetLeft() );
394 nRightCrop = tools::Long(nScale * -rCrop.GetRight() );
397 // crop values have to be mirrored too
398 if( nMirror == MirrorGraph::Vertical || nMirror == MirrorGraph::Both )
400 tools::Long nTmpCrop = nLeftCrop;
401 nLeftCrop = nRightCrop;
402 nRightCrop= nTmpCrop;
405 if( !aOrigSz.Height() )
407 aOrigSz.setHeight( aFramePrintArea.Height() );
408 nTopCrop = -rCrop.GetTop();
409 nBottomCrop= -rCrop.GetBottom();
411 else
413 nTopCrop = std::max( aOrigSz.Height() - (rCrop.GetTop() + rCrop.GetBottom()), tools::Long(1) );
414 const double nScale = double(aFramePrintArea.Height()) / double(nTopCrop);
415 nTopCrop = tools::Long(nScale * -rCrop.GetTop() );
416 nBottomCrop= tools::Long(nScale * -rCrop.GetBottom() );
419 // crop values have to be mirrored too
420 if( nMirror == MirrorGraph::Horizontal || nMirror == MirrorGraph::Both )
422 tools::Long nTmpCrop = nTopCrop;
423 nTopCrop = nBottomCrop;
424 nBottomCrop= nTmpCrop;
427 Size aVisSz( aFramePrintArea.SSize() );
428 Size aGrfSz( aVisSz );
429 Point aVisPt( aFrameArea.Pos() + aFramePrintArea.Pos() );
430 Point aGrfPt( aVisPt );
432 // Set the "visible" rectangle first
433 if ( nLeftCrop > 0 )
435 aVisPt.setX(aVisPt.getX() + nLeftCrop);
436 aVisSz.AdjustWidth( -nLeftCrop );
438 if ( nTopCrop > 0 )
440 aVisPt.setY(aVisPt.getY() + nTopCrop);
441 aVisSz.AdjustHeight( -nTopCrop );
443 if ( nRightCrop > 0 )
444 aVisSz.AdjustWidth( -nRightCrop );
445 if ( nBottomCrop > 0 )
446 aVisSz.AdjustHeight( -nBottomCrop );
448 rRect.Pos ( aVisPt );
449 rRect.SSize( aVisSz );
451 // Calculate the whole graphic if needed
452 if ( !pOrigRect )
453 return;
455 Size aTmpSz( aGrfSz );
456 aGrfPt.setX(aGrfPt.getX() + nLeftCrop);
457 aTmpSz.AdjustWidth( -(nLeftCrop + nRightCrop) );
458 aGrfPt.setY(aGrfPt.getY() + nTopCrop);
459 aTmpSz.AdjustHeight( -(nTopCrop + nBottomCrop) );
461 if( MirrorGraph::Dont != nMirror )
462 lcl_CalcRect( aGrfPt, aTmpSz, nMirror );
464 pOrigRect->Pos ( aGrfPt );
465 pOrigRect->SSize( aTmpSz );
468 /** By returning the surrounding Fly's size which equals the graphic's size */
469 const Size& SwNoTextFrame::GetSize() const
471 // Return the Frame's size
472 const SwFrame *pFly = FindFlyFrame();
473 if( !pFly )
474 pFly = this;
475 return pFly->getFramePrintArea().SSize();
478 void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
480 // RotateFlyFrame3 - inner frame. Get rotation and check if used
481 const double fRotation(getLocalFrameRotation());
482 const bool bRotated(!basegfx::fTools::equalZero(fRotation));
484 if(bRotated)
486 SwFlyFreeFrame* pUpperFly(dynamic_cast< SwFlyFreeFrame* >(GetUpper()));
488 if(pUpperFly)
490 if(!pUpperFly->isFrameAreaDefinitionValid())
492 // RotateFlyFrame3: outer frame *needs* to be layouted first, force this by calling
493 // it's ::Calc directly
494 pUpperFly->Calc(pRenderContext);
497 // Reset outer frame to unrotated state. This is necessary to make the
498 // layouting below work as currently implemented in Writer. As expected
499 // using Transformations allows to do this on the fly due to all information
500 // being included there.
501 // The full solution would be to adapt the whole layouting
502 // process of Writer to take care of Transformations, but that
503 // is currently beyond scope
504 if(pUpperFly->isTransformableSwFrame())
506 pUpperFly->getTransformableSwFrame()->restoreFrameAreas();
510 // Re-layout may be partially (see all isFrameAreaDefinitionValid() flags),
511 // so resetting the local SwFrame(s) in the local SwFrameAreaDefinition is also
512 // needed (e.g. for PrintPreview).
513 // Reset to BoundAreas will be done below automatically
514 if(isTransformableSwFrame())
516 getTransformableSwFrame()->restoreFrameAreas();
520 SwContentNotify aNotify( this );
521 SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
522 const SwBorderAttrs &rAttrs = *aAccess.Get();
524 while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
526 MakePos();
528 if ( !isFrameAreaSizeValid() )
530 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
531 aFrm.Width( GetUpper()->getFramePrintArea().Width() );
534 MakePrtArea( rAttrs );
536 if ( !isFrameAreaSizeValid() )
538 setFrameAreaSizeValid(true);
539 Format(getRootFrame()->GetCurrShell()->GetOut());
543 // RotateFlyFrame3 - inner frame
544 if(bRotated)
546 SwFlyFreeFrame* pUpperFly(dynamic_cast< SwFlyFreeFrame* >(GetUpper()));
548 if(pUpperFly)
550 // restore outer frame back to Transformed state, that means
551 // set the SwFrameAreaDefinition(s) back to BoundAreas of
552 // the transformed SwFrame. All needed information is part
553 // of the already correctly created Transformations of the
554 // upper frame, so it can be re-created on the fly
555 if(pUpperFly->isTransformableSwFrame())
557 pUpperFly->getTransformableSwFrame()->adaptFrameAreasToTransformations();
561 // After the unrotated layout is finished, apply possible set rotation to it
562 // get center from outer frame (layout frame) to be on the safe side
563 const Point aCenter(GetUpper() ? GetUpper()->getFrameArea().Center() : getFrameArea().Center());
564 const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y());
566 if(!mpTransformableSwFrame)
568 mpTransformableSwFrame.reset(new TransformableSwFrame(*this));
571 getTransformableSwFrame()->createFrameAreaTransformations(
572 fRotation,
573 aB2DCenter);
574 getTransformableSwFrame()->adaptFrameAreasToTransformations();
576 else
578 // reset transformations to show that they are not used
579 mpTransformableSwFrame.reset();
583 // RotateFlyFrame3 - Support for Transformations - outer frame
584 basegfx::B2DHomMatrix SwNoTextFrame::getFrameAreaTransformation() const
586 if(isTransformableSwFrame())
588 // use pre-created transformation
589 return getTransformableSwFrame()->getLocalFrameAreaTransformation();
592 // call parent
593 return SwContentFrame::getFrameAreaTransformation();
596 basegfx::B2DHomMatrix SwNoTextFrame::getFramePrintAreaTransformation() const
598 if(isTransformableSwFrame())
600 // use pre-created transformation
601 return getTransformableSwFrame()->getLocalFramePrintAreaTransformation();
604 // call parent
605 return SwContentFrame::getFramePrintAreaTransformation();
608 // RotateFlyFrame3 - Support for Transformations
609 void SwNoTextFrame::transform_translate(const Point& rOffset)
611 // call parent - this will do the basic transform for SwRect(s)
612 // in the SwFrameAreaDefinition
613 SwContentFrame::transform_translate(rOffset);
615 // check if the Transformations need to be adapted
616 if(isTransformableSwFrame())
618 const basegfx::B2DHomMatrix aTransform(
619 basegfx::utils::createTranslateB2DHomMatrix(
620 rOffset.X(), rOffset.Y()));
622 // transform using TransformableSwFrame
623 getTransformableSwFrame()->transform(aTransform);
627 // RotateFlyFrame3 - inner frame
628 // Check if we contain a SwGrfNode and get possible rotation from it
629 double SwNoTextFrame::getLocalFrameRotation() const
631 const SwNoTextNode* pSwNoTextNode(nullptr != GetNode() ? GetNode()->GetNoTextNode() : nullptr);
633 if(nullptr != pSwNoTextNode)
635 const SwGrfNode* pSwGrfNode(pSwNoTextNode->GetGrfNode());
637 if(nullptr != pSwGrfNode)
639 const SwAttrSet& rSwAttrSet(pSwGrfNode->GetSwAttrSet());
640 const SwRotationGrf& rSwRotationGrf(rSwAttrSet.GetRotationGrf());
641 const double fRotate = -toRadians(rSwRotationGrf.GetValue());
643 return basegfx::normalizeToRange(fRotate, 2 * M_PI);
647 // no rotation
648 return 0.0;
651 /** Calculate the Bitmap's site, if needed */
652 void SwNoTextFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs * )
654 const Size aNewSize( GetSize() );
656 // Did the height change?
657 SwTwips nChgHght = IsVertical() ?
658 static_cast<SwTwips>(aNewSize.Width() - getFramePrintArea().Width()) :
659 static_cast<SwTwips>(aNewSize.Height() - getFramePrintArea().Height());
660 if( nChgHght > 0)
661 Grow( nChgHght );
662 else if( nChgHght < 0)
663 Shrink( std::min(getFramePrintArea().Height(), tools::Long(-nChgHght)) );
666 bool SwNoTextFrame::GetCharRect( SwRect &rRect, const SwPosition& rPos,
667 SwCursorMoveState *pCMS, bool /*bAllowFarAway*/ ) const
669 if ( &rPos.GetNode() != static_cast<SwNode const *>(GetNode()) )
670 return false;
672 Calc(getRootFrame()->GetCurrShell()->GetOut());
673 SwRect aFrameRect( getFrameArea() );
674 rRect = aFrameRect;
675 rRect.Pos( getFrameArea().Pos() + getFramePrintArea().Pos() );
676 rRect.SSize( getFramePrintArea().SSize() );
678 rRect.Justify();
680 // Is the Bitmap in the visible area at all?
681 if( !aFrameRect.Overlaps( rRect ) )
683 // If not, then the Cursor is on the Frame
684 rRect = aFrameRect;
685 rRect.Width( 1 );
687 else
688 rRect.Intersection_( aFrameRect );
690 if ( pCMS && pCMS->m_bRealHeight )
692 pCMS->m_aRealHeight.setY(rRect.Height());
693 pCMS->m_aRealHeight.setX(0);
696 return true;
699 bool SwNoTextFrame::GetModelPositionForViewPoint(SwPosition* pPos, Point& ,
700 SwCursorMoveState*, bool ) const
702 pPos->Assign(*GetNode());
703 return true;
706 void SwNoTextFrame::ClearCache()
708 SwFlyFrame* pFly = FindFlyFrame();
709 if( pFly && pFly->GetFormat()->GetSurround().IsContour() )
711 ClrContourCache( pFly->GetVirtDrawObj() );
712 pFly->NotifyBackground( FindPageFrame(), getFramePrintArea(), PrepareHint::FlyFrameAttributesChanged );
716 void SwNoTextFrame::OnGraphicArrived()
718 if(GetNode()->GetNodeType() != SwNodeType::Grf)
720 InvalidatePrt();
721 SetCompletePaint();
722 return;
724 SwGrfNode* pNd = static_cast<SwGrfNode*>(GetNode());
725 ClearCache();
726 auto pVSh = pNd->GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell();
727 if(pVSh)
728 pVSh->OnGraphicArrived(getFrameArea());
731 void SwNoTextFrame::SwClientNotify(const SwModify& rModify, const SfxHint& rHint)
733 if(dynamic_cast<const sw::GrfRereadAndInCacheHint*>(&rHint))
735 if(SwNodeType::Grf != GetNode()->GetNodeType())
737 InvalidatePrt();
738 SetCompletePaint();
740 return;
742 if(rHint.GetId() == SfxHintId::SwPreGraphicArrived
743 || rHint.GetId() == SfxHintId::SwGraphicPieceArrived
744 || rHint.GetId() == SfxHintId::SwLinkedGraphicStreamArrived)
746 OnGraphicArrived();
747 return;
749 else if (rHint.GetId() != SfxHintId::SwLegacyModify)
750 return;
751 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
752 sal_uInt16 nWhich = pLegacy->GetWhich();
754 SwContentFrame::SwClientNotify(rModify, rHint);
756 bool bComplete = true;
758 switch( nWhich )
760 case RES_OBJECTDYING:
761 break;
763 case RES_UPDATE_ATTR:
764 if (GetNode()->GetNodeType() != SwNodeType::Grf) {
765 break;
767 [[fallthrough]];
768 case RES_FMT_CHG:
769 ClearCache();
770 break;
772 case RES_ATTRSET_CHG:
774 sal_uInt16 n;
775 for( n = RES_GRFATR_BEGIN; n < RES_GRFATR_END; ++n )
776 if( SfxItemState::SET == static_cast<const SwAttrSetChg*>(pLegacy->m_pOld)->GetChgSet()->
777 GetItemState( n, false ))
779 ClearCache();
781 if(RES_GRFATR_ROTATION == n)
783 // RotGrfFlyFrame: Update Handles in view, these may be rotation-dependent
784 // (e.g. crop handles) and need a visualisation update
785 if ( GetNode()->GetNodeType() == SwNodeType::Grf )
787 SwGrfNode* pNd = static_cast<SwGrfNode*>( GetNode());
788 SwViewShell *pVSh = pNd->GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell();
790 if(pVSh)
792 SdrView* pDrawView = pVSh->GetDrawView();
794 if(pDrawView)
796 pDrawView->AdjustMarkHdl(nullptr);
800 // RotateFlyFrame3 - invalidate needed for ContentFrame (inner, this)
801 // and LayoutFrame (outer, GetUpper). It is possible to only invalidate
802 // the outer frame, but that leads to an in-between state that gets
803 // potentially painted
804 if(GetUpper())
806 GetUpper()->InvalidateAll_();
809 InvalidateAll_();
812 break;
814 if( RES_GRFATR_END == n ) // not found
815 return ;
817 break;
819 default:
820 if ( !pLegacy->m_pNew || !isGRFATR(nWhich) )
821 return;
824 if( bComplete )
826 InvalidatePrt();
827 SetCompletePaint();
831 static void lcl_correctlyAlignRect( SwRect& rAlignedGrfArea, const SwRect& rInArea, vcl::RenderContext const * pOut )
834 if(!pOut)
835 return;
836 tools::Rectangle aPxRect = pOut->LogicToPixel( rInArea.SVRect() );
837 tools::Rectangle aNewPxRect( aPxRect );
838 while( aNewPxRect.Left() < aPxRect.Left() )
840 rAlignedGrfArea.AddLeft( 1 );
841 aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() );
843 while( aNewPxRect.Top() < aPxRect.Top() )
845 rAlignedGrfArea.AddTop(+1);
846 aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() );
848 while( aNewPxRect.Bottom() > aPxRect.Bottom() )
850 rAlignedGrfArea.AddBottom( -1 );
851 aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() );
853 while( aNewPxRect.Right() > aPxRect.Right() )
855 rAlignedGrfArea.AddRight(-1);
856 aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() );
860 static bool paintUsingPrimitivesHelper(
861 vcl::RenderContext& rOutputDevice,
862 const drawinglayer::primitive2d::Primitive2DContainer& rSequence,
863 const basegfx::B2DRange& rSourceRange,
864 const basegfx::B2DRange& rTargetRange)
866 if(!rSequence.empty() && !basegfx::fTools::equalZero(rSourceRange.getWidth()) && !basegfx::fTools::equalZero(rSourceRange.getHeight()))
868 if(!basegfx::fTools::equalZero(rTargetRange.getWidth()) && !basegfx::fTools::equalZero(rTargetRange.getHeight()))
870 // map graphic range to target range. This will e.g. automatically include
871 // the mapping from 1/100th mm content to twips if needed when the target
872 // range is defined in twips
873 const basegfx::B2DHomMatrix aMappingTransform(
874 basegfx::utils::createSourceRangeTargetRangeTransform(
875 rSourceRange,
876 rTargetRange));
878 // Fill ViewInformation. Use MappingTransform here, so there is no need to
879 // embed the primitives to it. Use original TargetRange here so there is also
880 // no need to embed the primitives to a MaskPrimitive for cropping. This works
881 // only in this case where the graphic object cannot be rotated, though.
882 drawinglayer::geometry::ViewInformation2D aViewInformation2D;
883 aViewInformation2D.setObjectTransformation(aMappingTransform);
884 aViewInformation2D.setViewTransformation(rOutputDevice.GetViewTransformation());
885 aViewInformation2D.setViewport(rTargetRange);
887 // get a primitive processor for rendering
888 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
889 drawinglayer::processor2d::createProcessor2DFromOutputDevice(
890 rOutputDevice, aViewInformation2D) );
892 // render and cleanup
893 pProcessor2D->process(rSequence);
894 return true;
898 return false;
901 // MM02 original using fallback to VOC and primitive-based version
902 void paintGraphicUsingPrimitivesHelper(
903 vcl::RenderContext & rOutputDevice,
904 GraphicObject const& rGrfObj,
905 GraphicAttr const& rGraphicAttr,
906 const basegfx::B2DHomMatrix& rGraphicTransform,
907 const OUString& rName,
908 const OUString& rTitle,
909 const OUString& rDescription)
911 // RotGrfFlyFrame: unify using GraphicPrimitive2D
912 // -> the primitive handles all crop and mirror stuff
913 // -> the primitive renderer will create the needed pdf export data
914 // -> if bitmap content, it will be cached system-dependent
915 drawinglayer::primitive2d::Primitive2DContainer aContent(1);
916 aContent[0] = new drawinglayer::primitive2d::GraphicPrimitive2D(
917 rGraphicTransform,
918 rGrfObj,
919 rGraphicAttr);
921 // MM02 use primitive-based version for visualization
922 paintGraphicUsingPrimitivesHelper(
923 rOutputDevice,
924 aContent,
925 rGraphicTransform,
926 rName,
927 rTitle,
928 rDescription);
931 // MM02 new VOC and primitive-based version
932 void paintGraphicUsingPrimitivesHelper(
933 vcl::RenderContext & rOutputDevice,
934 drawinglayer::primitive2d::Primitive2DContainer& rContent,
935 const basegfx::B2DHomMatrix& rGraphicTransform,
936 const OUString& rName,
937 const OUString& rTitle,
938 const OUString& rDescription)
940 // RotateFlyFrame3: If ClipRegion is set at OutputDevice, we
941 // need to use that. Usually the renderer would be a VCL-based
942 // PrimitiveRenderer, but there are system-specific shortcuts that
943 // will *not* use the VCL-Paint of Bitmap and thus ignore this.
944 // Anyways, indirectly using a CLipRegion set at the target OutDev
945 // when using a PrimitiveRenderer is a non-valid implication.
946 // First tried only to use when HasPolyPolygonOrB2DPolyPolygon(),
947 // but there is an optimization at ClipRegion creation that detects
948 // a single Rectangle in a tools::PolyPolygon and forces to a simple
949 // RegionBand-based implementation, so cannot use it here.
950 if(rOutputDevice.IsClipRegion())
952 basegfx::B2DPolyPolygon aClip(rOutputDevice.GetClipRegion().GetAsB2DPolyPolygon());
954 if(0 != aClip.count())
956 rContent.resize(1);
957 rContent[0] =
958 new drawinglayer::primitive2d::MaskPrimitive2D(
959 std::move(aClip),
960 drawinglayer::primitive2d::Primitive2DContainer(rContent));
964 if(!rName.isEmpty() || !rTitle.isEmpty() || !rDescription.isEmpty())
966 // Embed to ObjectInfoPrimitive2D when we have Name/Title/Description
967 // information available
968 rContent.resize(1);
969 rContent[0] =
970 new drawinglayer::primitive2d::ObjectInfoPrimitive2D(
971 drawinglayer::primitive2d::Primitive2DContainer(rContent),
972 rName,
973 rTitle,
974 rDescription);
977 basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0);
978 aTargetRange.transform(rGraphicTransform);
980 paintUsingPrimitivesHelper(
981 rOutputDevice,
982 rContent,
983 aTargetRange,
984 aTargetRange);
987 // DrawContact section
988 namespace { // anonymous namespace
989 class ViewObjectContactOfSwNoTextFrame : public sdr::contact::ViewObjectContact
991 protected:
992 virtual void createPrimitive2DSequence(
993 const sdr::contact::DisplayInfo& rDisplayInfo,
994 drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
996 // tdf#155190 disable this so superclass doesn't wrongly produce NonStruct
997 virtual bool isExportPDFTags() const override { return false; }
999 public:
1000 ViewObjectContactOfSwNoTextFrame(
1001 sdr::contact::ObjectContact& rObjectContact,
1002 sdr::contact::ViewContact& rViewContact);
1005 class ViewContactOfSwNoTextFrame : public sdr::contact::ViewContact
1007 private:
1008 // owner
1009 const SwNoTextFrame& mrSwNoTextFrame;
1011 protected:
1012 // Create an Object-Specific ViewObjectContact, set ViewContact and
1013 // ObjectContact. Always needs to return something.
1014 virtual sdr::contact::ViewObjectContact& CreateObjectSpecificViewObjectContact(
1015 sdr::contact::ObjectContact& rObjectContact) override;
1017 public:
1018 // read-access to owner
1019 const SwNoTextFrame& getSwNoTextFrame() const { return mrSwNoTextFrame; }
1021 // basic constructor, used from SwNoTextFrame.
1022 explicit ViewContactOfSwNoTextFrame(const SwNoTextFrame& rSwNoTextFrame);
1025 void ViewObjectContactOfSwNoTextFrame::createPrimitive2DSequence(
1026 const sdr::contact::DisplayInfo& /*rDisplayInfo*/,
1027 drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
1029 // MM02 get all the parameters formally used in paintGraphicUsingPrimitivesHelper
1030 ViewContactOfSwNoTextFrame& rVCOfNTF(static_cast<ViewContactOfSwNoTextFrame&>(GetViewContact()));
1031 const SwNoTextFrame& rSwNoTextFrame(rVCOfNTF.getSwNoTextFrame());
1032 SwNoTextNode& rNoTNd(const_cast<SwNoTextNode&>(*static_cast<const SwNoTextNode*>(rSwNoTextFrame.GetNode())));
1033 SwGrfNode* pGrfNd(rNoTNd.GetGrfNode());
1035 if(nullptr != pGrfNd)
1037 const bool bPrn(GetObjectContact().isOutputToPrinter() || GetObjectContact().isOutputToRecordingMetaFile());
1038 const GraphicObject& rGrfObj(pGrfNd->GetGrfObj(bPrn));
1039 GraphicAttr aGraphicAttr;
1040 pGrfNd->GetGraphicAttr(aGraphicAttr, &rSwNoTextFrame);
1041 const basegfx::B2DHomMatrix aGraphicTransform(rSwNoTextFrame.getFrameAreaTransformation());
1043 // MM02 this is the right place in the VOC-Mechanism to create
1044 // the primitives for visualization - these will be automatically
1045 // buffered and reused
1046 rVisitor.visit(new drawinglayer::primitive2d::GraphicPrimitive2D(
1047 aGraphicTransform,
1048 rGrfObj,
1049 aGraphicAttr));
1053 ViewObjectContactOfSwNoTextFrame::ViewObjectContactOfSwNoTextFrame(
1054 sdr::contact::ObjectContact& rObjectContact,
1055 sdr::contact::ViewContact& rViewContact)
1056 : sdr::contact::ViewObjectContact(rObjectContact, rViewContact)
1060 sdr::contact::ViewObjectContact& ViewContactOfSwNoTextFrame::CreateObjectSpecificViewObjectContact(
1061 sdr::contact::ObjectContact& rObjectContact)
1063 sdr::contact::ViewObjectContact* pRetval = new ViewObjectContactOfSwNoTextFrame(rObjectContact, *this);
1064 return *pRetval;
1067 ViewContactOfSwNoTextFrame::ViewContactOfSwNoTextFrame(
1068 const SwNoTextFrame& rSwNoTextFrame
1070 : mrSwNoTextFrame(rSwNoTextFrame)
1073 } // end of anonymous namespace
1075 sdr::contact::ViewContact& SwNoTextFrame::GetViewContact() const
1077 if(!mpViewContact)
1079 const_cast< SwNoTextFrame* >(this)->mpViewContact =
1080 std::make_unique<ViewContactOfSwNoTextFrame>(*this);
1083 return *mpViewContact;
1086 /** Paint the graphic.
1088 We require either a QuickDraw-Bitmap or a graphic here. If we do not have
1089 either, we return a replacement.
1091 @todo use aligned rectangle for drawing graphic.
1092 @todo pixel-align coordinations for drawing graphic. */
1093 void SwNoTextFrame::PaintPicture( vcl::RenderContext* pOut, const SwRect &rGrfArea ) const
1095 SwViewShell* pShell = getRootFrame()->GetCurrShell();
1097 SwNoTextNode& rNoTNd = const_cast<SwNoTextNode&>(*static_cast<const SwNoTextNode*>(GetNode()));
1098 SwGrfNode* pGrfNd = rNoTNd.GetGrfNode();
1099 SwOLENode* pOLENd = rNoTNd.GetOLENode();
1101 const bool bPrn = pOut == rNoTNd.getIDocumentDeviceAccess().getPrinter( false ) ||
1102 pOut->GetConnectMetaFile();
1104 const bool bIsChart = pOLENd && pOLENd->GetOLEObj().GetObject().IsChart();
1106 // calculate aligned rectangle from parameter <rGrfArea>.
1107 // Use aligned rectangle <aAlignedGrfArea> instead of <rGrfArea> in
1108 // the following code.
1109 SwRect aAlignedGrfArea = rGrfArea;
1110 ::SwAlignRect( aAlignedGrfArea, pShell, pOut );
1112 if( !bIsChart )
1114 // Because for drawing a graphic left-top-corner and size coordinations are
1115 // used, these coordinations have to be determined on pixel level.
1116 ::SwAlignGrfRect( &aAlignedGrfArea, *pOut );
1118 else //if( bIsChart )
1120 // #i78025# charts own borders are not completely visible
1121 // the above pixel correction is not correct - at least not for charts
1122 // so a different pixel correction is chosen here
1123 // this might be a good idea for all other OLE objects also,
1124 // but as I cannot oversee the consequences I fix it only for charts for now
1125 lcl_correctlyAlignRect( aAlignedGrfArea, rGrfArea, pOut );
1128 if( pGrfNd )
1130 // Fix for bug fdo#33781
1131 const AntialiasingFlags nFormerAntialiasingAtOutput( pOut->GetAntialiasing() );
1132 if (SwDrawView::IsAntiAliasing())
1133 pOut->SetAntialiasing( nFormerAntialiasingAtOutput | AntialiasingFlags::Enable );
1135 ImplPaintPictureGraphic( pOut, pGrfNd, bPrn, aAlignedGrfArea, pShell, rNoTNd );
1137 if ( SwDrawView::IsAntiAliasing() )
1138 pOut->SetAntialiasing( nFormerAntialiasingAtOutput );
1140 else // bIsChart || pOLENd
1142 // Fix for bug fdo#33781
1143 const AntialiasingFlags nFormerAntialiasingAtOutput( pOut->GetAntialiasing() );
1144 if (SwDrawView::IsAntiAliasing())
1146 AntialiasingFlags nNewAntialiasingAtOutput = nFormerAntialiasingAtOutput | AntialiasingFlags::Enable;
1148 // #i99665#
1149 // Adjust AntiAliasing mode at output device for chart OLE
1150 if ( pOLENd->IsChart() )
1151 nNewAntialiasingAtOutput |= AntialiasingFlags::PixelSnapHairline;
1153 pOut->SetAntialiasing( nNewAntialiasingAtOutput );
1156 ImplPaintPictureBitmap( pOut, pOLENd, bIsChart, bPrn, aAlignedGrfArea, pShell );
1158 // see #i99665#
1159 if (SwDrawView::IsAntiAliasing())
1161 pOut->SetAntialiasing( nFormerAntialiasingAtOutput );
1166 void SwNoTextFrame::ImplPaintPictureGraphic( vcl::RenderContext* pOut,
1167 SwGrfNode* pGrfNd, bool bPrn,
1168 const SwRect& rAlignedGrfArea, SwViewShell* pShell,
1169 SwNoTextNode& rNoTNd ) const
1171 bool bContinue = true;
1172 const GraphicObject& rGrfObj = pGrfNd->GetGrfObj(bPrn);
1174 GraphicAttr aGrfAttr;
1175 pGrfNd->GetGraphicAttr( aGrfAttr, this );
1177 if( !bPrn )
1179 // #i73788#
1180 if ( pGrfNd->IsLinkedInputStreamReady() )
1182 pGrfNd->UpdateLinkWithInputStream();
1184 // #i85717#, #i90395# - check, if asynchronous retrieval
1185 // if input stream for the graphic is possible
1186 else if ( ( rGrfObj.GetType() == GraphicType::Default ||
1187 rGrfObj.GetType() == GraphicType::NONE ) &&
1188 pGrfNd->IsLinkedFile() &&
1189 pGrfNd->IsAsyncRetrieveInputStreamPossible() )
1191 Size aTmpSz;
1192 ::sfx2::SvLinkSource* pGrfObj = pGrfNd->GetLink()->GetObj();
1193 if( !pGrfObj ||
1194 !pGrfObj->IsDataComplete() ||
1195 !(aTmpSz = pGrfNd->GetTwipSize()).Width() ||
1196 !aTmpSz.Height())
1198 pGrfNd->TriggerAsyncRetrieveInputStream(); // #i73788#
1200 OUString aText( pGrfNd->GetTitle() );
1201 if ( aText.isEmpty() )
1202 GetRealURL( *pGrfNd, aText );
1203 ::lcl_PaintReplacement( rAlignedGrfArea, aText, *pShell, this, false );
1204 bContinue = false;
1208 if( !bContinue )
1209 return;
1211 if( !rGrfObj.GetGraphic().IsSupportedGraphic())
1213 ImplPaintPictureReplacement(rGrfObj, pGrfNd, rAlignedGrfArea, pShell);
1214 return;
1217 const bool bAnimate = rGrfObj.IsAnimated() &&
1218 !pShell->IsPreview() &&
1219 !pShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() &&
1220 // #i9684# Stop animation during printing/pdf export
1221 pShell->GetWin();
1222 if( bAnimate &&
1223 FindFlyFrame() != ::GetFlyFromMarked( nullptr, pShell ))
1225 ImplPaintPictureAnimate(pOut, pShell, pGrfNd, rAlignedGrfArea);
1226 return;
1229 // MM02 To allow system-dependent buffering of the involved
1230 // bitmaps it is necessary to re-use the involved primitives
1231 // and their already executed decomposition (also for
1232 // performance reasons). This is usually done in DrawingLayer
1233 // by using the VOC-Mechanism (see descriptions elsewhere).
1234 // To get that here, make the involved SwNoTextFrame (this)
1235 // a sdr::contact::ViewContact supplier by supporting
1236 // a GetViewContact() - call. For ObjectContact we can use
1237 // the already existing ObjectContact from the involved
1238 // DrawingLayer. For this, the helper classes
1239 // ViewObjectContactOfSwNoTextFrame
1240 // ViewContactOfSwNoTextFrame
1241 // are created which support the VOC-mechanism in its minimal
1242 // form. This allows automatic and view-dependent (multiple edit
1243 // windows, print, etc.) re-use of the created primitives.
1244 // Also: Will be very useful when completely changing the Writer
1245 // repaint to VOC and Primitives, too.
1246 static const char* pDisableMM02Goodies(getenv("SAL_DISABLE_MM02_GOODIES"));
1247 static bool bUseViewObjectContactMechanism(nullptr == pDisableMM02Goodies);
1248 // tdf#130951 for safety reasons use fallback if ViewObjectContactMechanism
1249 // fails for some reason - usually could only be not to find the correct
1250 // SdrPageWindow
1251 bool bSucceeded(false);
1253 if(bUseViewObjectContactMechanism)
1255 // MM02 use VOC-mechanism and buffer primitives
1256 SwViewShellImp* pImp(pShell->Imp());
1257 SdrPageView* pPageView(nullptr != pImp
1258 ? pImp->GetPageView()
1259 : nullptr);
1260 // tdf#130951 caution - target may be Window, use the correct OutputDevice
1261 OutputDevice* pTarget((pShell->isOutputToWindow() && pShell->GetWin())
1262 ? pShell->GetWin()->GetOutDev()
1263 : pShell->GetOut());
1264 SdrPageWindow* pPageWindow(nullptr != pPageView && nullptr != pTarget
1265 ? pPageView->FindPageWindow(*pTarget)
1266 : nullptr);
1268 if(nullptr != pPageWindow)
1270 sdr::contact::ObjectContact& rOC(pPageWindow->GetObjectContact());
1271 sdr::contact::ViewContact& rVC(GetViewContact());
1272 sdr::contact::ViewObjectContact& rVOC(rVC.GetViewObjectContact(rOC));
1273 sdr::contact::DisplayInfo aDisplayInfo;
1275 drawinglayer::primitive2d::Primitive2DContainer aPrimitives(rVOC.getPrimitive2DSequence(aDisplayInfo));
1276 const basegfx::B2DHomMatrix aGraphicTransform(getFrameAreaTransformation());
1278 paintGraphicUsingPrimitivesHelper(
1279 *pOut,
1280 aPrimitives,
1281 aGraphicTransform,
1282 nullptr == pGrfNd->GetFlyFormat() ? OUString() : pGrfNd->GetFlyFormat()->GetName(),
1283 rNoTNd.GetTitle(),
1284 rNoTNd.GetDescription());
1285 bSucceeded = true;
1289 if(!bSucceeded)
1291 // MM02 fallback to direct paint with primitive-recreation
1292 // which will block reusage of system-dependent bitmap data
1293 const basegfx::B2DHomMatrix aGraphicTransform(getFrameAreaTransformation());
1295 paintGraphicUsingPrimitivesHelper(
1296 *pOut,
1297 rGrfObj,
1298 aGrfAttr,
1299 aGraphicTransform,
1300 nullptr == pGrfNd->GetFlyFormat() ? OUString() : pGrfNd->GetFlyFormat()->GetName(),
1301 rNoTNd.GetTitle(),
1302 rNoTNd.GetDescription());
1306 void SwNoTextFrame::ImplPaintPictureAnimate(vcl::RenderContext* pOut, SwViewShell* pShell,
1307 SwGrfNode* pGrfNd, const SwRect& rAlignedGrfArea) const
1309 OutputDevice* pVout;
1310 if( pOut == pShell->GetOut() && SwRootFrame::FlushVout() )
1312 pVout = pOut;
1313 pOut = pShell->GetOut();
1315 else if( pShell->GetWin() && pOut->IsVirtual() )
1317 pVout = pOut;
1318 pOut = pShell->GetWin()->GetOutDev();
1320 else
1321 pVout = nullptr;
1323 OSL_ENSURE( !pOut->IsVirtual() ||
1324 pShell->GetViewOptions()->IsPDFExport() || pShell->isOutputToWindow(),
1325 "pOut should not be a virtual device" );
1327 pGrfNd->StartGraphicAnimation(pOut, rAlignedGrfArea.Pos(),
1328 rAlignedGrfArea.SSize(), reinterpret_cast<sal_IntPtr>(this),
1329 pVout );
1332 void SwNoTextFrame::ImplPaintPictureReplacement(const GraphicObject& rGrfObj, SwGrfNode* pGrfNd,
1333 const SwRect& rAlignedGrfArea, SwViewShell* pShell) const
1335 TranslateId pResId;
1337 if( GraphicType::NONE == rGrfObj.GetType() )
1338 pResId = STR_COMCORE_READERROR;
1339 else if ( !rGrfObj.GetGraphic().IsSupportedGraphic() )
1340 pResId = STR_COMCORE_CANT_SHOW;
1342 OUString aText;
1343 if ( !pResId &&
1344 (aText = pGrfNd->GetTitle()).isEmpty() &&
1345 (!GetRealURL( *pGrfNd, aText ) || aText.isEmpty()))
1347 pResId = STR_COMCORE_READERROR;
1349 if (pResId)
1350 aText = SwResId(pResId);
1352 ::lcl_PaintReplacement( rAlignedGrfArea, aText, *pShell, this, true );
1355 void SwNoTextFrame::ImplPaintPictureBitmap( vcl::RenderContext* pOut,
1356 SwOLENode* pOLENd, bool bIsChart, bool bPrn, const SwRect& rAlignedGrfArea,
1357 SwViewShell* pShell ) const
1359 bool bDone(false);
1361 if(bIsChart)
1363 basegfx::B2DRange aSourceRange;
1364 const drawinglayer::primitive2d::Primitive2DContainer aSequence(
1365 pOLENd->GetOLEObj().tryToGetChartContentAsPrimitive2DSequence(
1366 aSourceRange,
1367 bPrn));
1369 if(!aSequence.empty() && !aSourceRange.isEmpty())
1371 const basegfx::B2DRange aTargetRange(
1372 rAlignedGrfArea.Left(), rAlignedGrfArea.Top(),
1373 rAlignedGrfArea.Right(), rAlignedGrfArea.Bottom());
1375 bDone = paintUsingPrimitivesHelper(
1376 *pOut,
1377 aSequence,
1378 aSourceRange,
1379 aTargetRange);
1383 if(bDone || !pOLENd)
1384 return;
1386 // SwOLENode does not have a known GraphicObject, need to
1387 // work with Graphic instead
1388 const Graphic* pGraphic = pOLENd->GetGraphic();
1389 const Point aPosition(rAlignedGrfArea.Pos());
1390 const Size aSize(rAlignedGrfArea.SSize());
1392 if ( pGraphic && pGraphic->GetType() != GraphicType::NONE )
1394 pGraphic->Draw(*pOut, aPosition, aSize);
1396 // shade the representation if the object is activated outplace
1397 uno::Reference < embed::XEmbeddedObject > xObj = pOLENd->GetOLEObj().GetOleRef();
1398 if ( xObj.is() && xObj->getCurrentState() == embed::EmbedStates::ACTIVE )
1401 ::svt::EmbeddedObjectRef::DrawShading(
1402 tools::Rectangle(
1403 aPosition,
1404 aSize),
1405 pOut);
1408 else
1410 ::svt::EmbeddedObjectRef::DrawPaintReplacement(
1411 tools::Rectangle(aPosition, aSize),
1412 pOLENd->GetOLEObj().GetCurrentPersistName(),
1413 pOut);
1416 sal_Int64 nMiscStatus = pOLENd->GetOLEObj().GetOleRef()->getStatus( pOLENd->GetAspect() );
1417 if ( !bPrn && dynamic_cast< const SwCursorShell *>( pShell ) != nullptr &&
1418 (nMiscStatus & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE))
1420 const SwFlyFrame *pFly = FindFlyFrame();
1421 assert( pFly != nullptr );
1422 static_cast<SwFEShell*>(pShell)->ConnectObj( pOLENd->GetOLEObj().GetObject(), pFly->getFramePrintArea(), pFly->getFrameArea());
1426 bool SwNoTextFrame::IsTransparent() const
1428 const SwViewShell* pSh = getRootFrame()->GetCurrShell();
1430 if ( !pSh || !pSh->GetViewOptions()->IsGraphic() )
1432 return true;
1435 const SwGrfNode *pNd;
1437 if( nullptr != (pNd = GetNode()->GetGrfNode()) )
1439 if(pNd->IsTransparent())
1441 return true;
1445 // RotateFlyFrame3: If we are transformed, there are 'free' areas between
1446 // the Graphic and the Border/Padding stuff - at least as long as those
1447 // (Border and Padding) are not transformed, too
1448 if(isTransformableSwFrame())
1450 // we can be more specific - rotations of multiples of
1451 // 90 degrees will leave no gaps. Go from [0.0 .. 2PI]
1452 // to [0 .. 360] and check modulo 90
1453 const tools::Long nRot(static_cast<tools::Long>(basegfx::rad2deg(getLocalFrameRotation())));
1454 const bool bMultipleOf90(0 == (nRot % 90));
1456 if(!bMultipleOf90)
1458 return true;
1462 //#29381# OLE are always transparent
1463 if(nullptr != GetNode()->GetOLENode())
1465 return true;
1468 // return false by default to avoid background paint
1469 return false;
1472 void SwNoTextFrame::StopAnimation( const OutputDevice* pOut ) const
1474 // Stop animated graphics
1475 const SwGrfNode* pGrfNd = GetNode()->GetGrfNode();
1477 if( pGrfNd && pGrfNd->IsAnimated() )
1479 const_cast< SwGrfNode* >(pGrfNd)->StopGraphicAnimation( pOut, reinterpret_cast<sal_IntPtr>(this) );
1483 bool SwNoTextFrame::HasAnimation() const
1485 const SwGrfNode* pGrfNd = GetNode()->GetGrfNode();
1486 return pGrfNd && pGrfNd->IsAnimated();
1489 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */