Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <hintids.hxx>
21 : #include <tools/urlobj.hxx>
22 : #include <vcl/print.hxx>
23 : #include <vcl/virdev.hxx>
24 : #include <vcl/svapp.hxx>
25 : #include <svtools/imapobj.hxx>
26 : #include <svtools/imap.hxx>
27 : #include <svl/urihelper.hxx>
28 : #include <svtools/soerr.hxx>
29 : #include <sfx2/progress.hxx>
30 : #include <sfx2/docfile.hxx>
31 : #include <sfx2/printer.hxx>
32 : #include <editeng/udlnitem.hxx>
33 : #include <editeng/colritem.hxx>
34 : #include <svx/xoutbmp.hxx>
35 : #include <vcl/window.hxx>
36 : #include <fmturl.hxx>
37 : #include <fmtsrnd.hxx>
38 : #include <frmfmt.hxx>
39 : #include <swrect.hxx>
40 : #include <fesh.hxx>
41 : #include <doc.hxx>
42 : #include <flyfrm.hxx>
43 : #include <flyfrms.hxx>
44 : #include <frmtool.hxx>
45 : #include <viewopt.hxx>
46 : #include <viewimp.hxx>
47 : #include <pam.hxx>
48 : #include <hints.hxx>
49 : #include <rootfrm.hxx>
50 : #include <dflyobj.hxx>
51 : #include <pagefrm.hxx>
52 : #include <notxtfrm.hxx>
53 : #include <grfatr.hxx>
54 : #include <charatr.hxx>
55 : #include <fmtornt.hxx>
56 : #include <ndnotxt.hxx>
57 : #include <ndgrf.hxx>
58 : #include <ndole.hxx>
59 : #include <swregion.hxx>
60 : #include <poolfmt.hxx>
61 : #include <mdiexp.hxx>
62 : #include <swwait.hxx>
63 : #include <comcore.hrc>
64 : #include <accessibilityoptions.hxx>
65 : #include <com/sun/star/embed/EmbedMisc.hpp>
66 : #include <com/sun/star/embed/EmbedStates.hpp>
67 : #include <svtools/embedhlp.hxx>
68 : #include <svx/charthelper.hxx>
69 : #include <dview.hxx>
70 : #include <basegfx/matrix/b2dhommatrix.hxx>
71 : #include <drawinglayer/processor2d/baseprocessor2d.hxx>
72 : #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
73 : #include <basegfx/matrix/b2dhommatrixtools.hxx>
74 : #include <drawinglayer/processor2d/processor2dtools.hxx>
75 :
76 : using namespace com::sun::star;
77 :
78 : extern void ClrContourCache( const SdrObject *pObj ); // TxtFly.Cxx
79 :
80 0 : inline bool GetRealURL( const SwGrfNode& rNd, OUString& rTxt )
81 : {
82 0 : bool bRet = rNd.GetFileFilterNms( &rTxt, 0 );
83 0 : if( bRet )
84 0 : rTxt = URIHelper::removePassword( rTxt, INetURLObject::WAS_ENCODED,
85 0 : INetURLObject::DECODE_UNAMBIGUOUS);
86 0 : if (rTxt.startsWith("data:image")) rTxt = "inline image";
87 :
88 0 : return bRet;
89 : }
90 :
91 0 : static void lcl_PaintReplacement( const SwRect &rRect, const OUString &rText,
92 : const SwViewShell &rSh, const SwNoTxtFrm *pFrm,
93 : bool bDefect )
94 : {
95 : static Font *pFont = 0;
96 0 : if ( !pFont )
97 : {
98 0 : pFont = new Font();
99 0 : pFont->SetWeight( WEIGHT_BOLD );
100 0 : pFont->SetStyleName( OUString() );
101 0 : pFont->SetName(OUString("Arial Unicode"));
102 0 : pFont->SetFamily( FAMILY_SWISS );
103 0 : pFont->SetTransparent( true );
104 : }
105 :
106 0 : Color aCol( COL_RED );
107 0 : FontUnderline eUnderline = UNDERLINE_NONE;
108 0 : const SwFmtURL &rURL = pFrm->FindFlyFrm()->GetFmt()->GetURL();
109 0 : if( !rURL.GetURL().isEmpty() || rURL.GetMap() )
110 : {
111 0 : bool bVisited = false;
112 0 : if ( rURL.GetMap() )
113 : {
114 0 : ImageMap *pMap = (ImageMap*)rURL.GetMap();
115 0 : for( sal_uInt16 i = 0; i < pMap->GetIMapObjectCount(); i++ )
116 : {
117 0 : IMapObject *pObj = pMap->GetIMapObject( i );
118 0 : if( rSh.GetDoc()->IsVisitedURL( pObj->GetURL() ) )
119 : {
120 0 : bVisited = true;
121 0 : break;
122 : }
123 : }
124 : }
125 0 : else if ( !rURL.GetURL().isEmpty() )
126 0 : bVisited = rSh.GetDoc()->IsVisitedURL( rURL.GetURL() );
127 :
128 0 : SwFmt *pFmt = rSh.GetDoc()->GetFmtFromPool( static_cast<sal_uInt16>
129 0 : (bVisited ? RES_POOLCHR_INET_VISIT : RES_POOLCHR_INET_NORMAL ) );
130 0 : aCol = pFmt->GetColor().GetValue();
131 0 : eUnderline = pFmt->GetUnderline().GetLineStyle();
132 : }
133 :
134 0 : pFont->SetUnderline( eUnderline );
135 0 : pFont->SetColor( aCol );
136 :
137 0 : const BitmapEx& rBmp = SwViewShell::GetReplacementBitmap( bDefect );
138 0 : Graphic::DrawEx( rSh.GetOut(), rText, *pFont, rBmp, rRect.Pos(), rRect.SSize() );
139 0 : }
140 :
141 0 : SwNoTxtFrm::SwNoTxtFrm(SwNoTxtNode * const pNode, SwFrm* pSib )
142 0 : : SwCntntFrm( pNode, pSib )
143 : {
144 0 : InitCtor();
145 0 : }
146 :
147 : /// Initialization: Currently add the Frame to the Cache
148 0 : void SwNoTxtFrm::InitCtor()
149 : {
150 0 : mnType = FRMC_NOTXT;
151 : // The graphic's weight is 0 if it has not been read,
152 : // < 0 if we had a read error and we needed to use the replacement and
153 : // > 0 if it is available
154 0 : nWeight = 0;
155 0 : }
156 :
157 0 : SwCntntFrm *SwNoTxtNode::MakeFrm( SwFrm* pSib )
158 : {
159 0 : return new SwNoTxtFrm(this, pSib);
160 : }
161 :
162 0 : SwNoTxtFrm::~SwNoTxtFrm()
163 : {
164 0 : StopAnimation();
165 0 : }
166 :
167 0 : void SetOutDev( SwViewShell *pSh, OutputDevice *pOut )
168 : {
169 0 : pSh->mpOut = pOut;
170 0 : }
171 :
172 0 : static void lcl_ClearArea( const SwFrm &rFrm,
173 : OutputDevice &rOut, const SwRect& rPtArea,
174 : const SwRect &rGrfArea )
175 : {
176 0 : SwRegionRects aRegion( rPtArea, 4 );
177 0 : aRegion -= rGrfArea;
178 :
179 0 : if ( !aRegion.empty() )
180 : {
181 0 : const SvxBrushItem *pItem; const Color *pCol; SwRect aOrigRect;
182 :
183 : //UUUU
184 0 : FillAttributesPtr aFillAttributes;
185 :
186 0 : if ( rFrm.GetBackgroundBrush( aFillAttributes, pItem, pCol, aOrigRect, sal_False ) )
187 : {
188 0 : const bool bDone(::DrawFillAttributes(aFillAttributes, aOrigRect, rPtArea, rOut));
189 :
190 0 : if(!bDone)
191 : {
192 0 : for( sal_uInt16 i = 0; i < aRegion.size(); ++i )
193 : {
194 0 : ::DrawGraphic( pItem, &rOut, aOrigRect, aRegion[i] );
195 : }
196 : }
197 : }
198 : else
199 : {
200 0 : rOut.Push( PUSH_FILLCOLOR|PUSH_LINECOLOR );
201 0 : rOut.SetFillColor( rFrm.getRootFrm()->GetCurrShell()->Imp()->GetRetoucheColor());
202 0 : rOut.SetLineColor();
203 0 : for( sal_uInt16 i = 0; i < aRegion.size(); ++i )
204 0 : rOut.DrawRect( aRegion[i].SVRect() );
205 0 : rOut.Pop();
206 0 : }
207 0 : }
208 0 : }
209 :
210 0 : void SwNoTxtFrm::Paint(SwRect const& rRect, SwPrintData const*const) const
211 : {
212 0 : if ( Frm().IsEmpty() )
213 0 : return;
214 :
215 0 : const SwViewShell* pSh = getRootFrm()->GetCurrShell();
216 0 : if( !pSh->GetViewOptions()->IsGraphic() )
217 : {
218 0 : StopAnimation();
219 : // #i6467# - no paint of placeholder for page preview
220 0 : if ( pSh->GetWin() && !pSh->IsPreview() )
221 : {
222 0 : const SwNoTxtNode* pNd = GetNode()->GetNoTxtNode();
223 0 : OUString aTxt( pNd->GetTitle() );
224 0 : if ( aTxt.isEmpty() && pNd->IsGrfNode() )
225 0 : GetRealURL( *(SwGrfNode*)pNd, aTxt );
226 0 : if( aTxt.isEmpty() )
227 0 : aTxt = FindFlyFrm()->GetFmt()->GetName();
228 0 : lcl_PaintReplacement( Frm(), aTxt, *pSh, this, false );
229 : }
230 0 : return;
231 : }
232 :
233 0 : if( pSh->GetAccessibilityOptions()->IsStopAnimatedGraphics() ||
234 : // #i9684# Stop animation during printing/pdf export
235 0 : !pSh->GetWin() )
236 0 : StopAnimation();
237 :
238 0 : SfxProgress::EnterLock(); // No progress reschedules in paint (SwapIn)
239 :
240 0 : OutputDevice *pOut = pSh->GetOut();
241 0 : pOut->Push();
242 0 : bool bClip = true;
243 0 : PolyPolygon aPoly;
244 :
245 0 : SwNoTxtNode& rNoTNd = *(SwNoTxtNode*)GetNode();
246 0 : SwGrfNode* pGrfNd = rNoTNd.GetGrfNode();
247 0 : if( pGrfNd )
248 0 : pGrfNd->SetFrameInPaint( true );
249 :
250 : // #i13147# - add 2nd parameter with value <sal_True> to
251 : // method call <FindFlyFrm().GetContour(..)> to indicate that it is called
252 : // for paint in order to avoid load of the intrinsic graphic.
253 0 : if ( ( !pOut->GetConnectMetaFile() ||
254 0 : !pSh->GetWin() ) &&
255 0 : FindFlyFrm()->GetContour( aPoly, sal_True )
256 : )
257 : {
258 0 : pOut->SetClipRegion(Region(aPoly));
259 0 : bClip = false;
260 : }
261 :
262 0 : SwRect aOrigPaint( rRect );
263 0 : if ( HasAnimation() && pSh->GetWin() )
264 : {
265 0 : aOrigPaint = Frm(); aOrigPaint += Prt().Pos();
266 : }
267 :
268 0 : SwRect aGrfArea( Frm() );
269 0 : SwRect aPaintArea( aGrfArea );
270 :
271 : // In case the picture fly frm was clipped, render it with the origin
272 : // size instead of scaling it
273 0 : if ( rNoTNd.getIDocumentSettingAccess()->get( IDocumentSettingAccess::CLIPPED_PICTURES ) )
274 : {
275 0 : const SwFlyFreeFrm *pFly = dynamic_cast< const SwFlyFreeFrm* >( FindFlyFrm() );
276 0 : if( pFly )
277 0 : aGrfArea = SwRect( Frm().Pos( ), pFly->GetUnclippedFrm( ).SSize( ) );
278 : }
279 :
280 0 : aPaintArea._Intersection( aOrigPaint );
281 :
282 0 : SwRect aNormal( Frm().Pos() + Prt().Pos(), Prt().SSize() );
283 0 : aNormal.Justify(); // Normalized rectangle for the comparisons
284 :
285 0 : if( aPaintArea.IsOver( aNormal ) )
286 : {
287 : // Calculate the four to-be-deleted rectangles
288 0 : if( pSh->GetWin() )
289 0 : ::lcl_ClearArea( *this, *pSh->GetOut(), aPaintArea, aNormal );
290 :
291 : // The intersection of the PaintArea and the Bitmap contains the absolutely visible area of the Frame
292 0 : aPaintArea._Intersection( aNormal );
293 :
294 0 : if ( bClip )
295 0 : pOut->IntersectClipRegion( aPaintArea.SVRect() );
296 : /// delete unused 3rd parameter
297 0 : PaintPicture( pOut, aGrfArea );
298 : }
299 : else
300 : // If it's not visible, simply delete the given Area
301 0 : lcl_ClearArea( *this, *pSh->GetOut(), aPaintArea, SwRect() );
302 0 : if( pGrfNd )
303 0 : pGrfNd->SetFrameInPaint( false );
304 :
305 0 : pOut->Pop();
306 0 : SfxProgress::LeaveLock();
307 : }
308 :
309 : /** Calculate the position and the size of the graphic in the Frame,
310 : corresponding to the current graphic attributes
311 :
312 : @param Point the position in the Frame (also returned)
313 : @param Size the graphic's size (also returned)
314 : @param nMirror the current mirror attribute
315 : */
316 0 : static void lcl_CalcRect( Point& rPt, Size& rDim, sal_uInt16 nMirror )
317 : {
318 0 : if( nMirror == RES_MIRROR_GRAPH_VERT || nMirror == RES_MIRROR_GRAPH_BOTH )
319 : {
320 0 : rPt.setX(rPt.getX() + rDim.Width() -1);
321 0 : rDim.Width() = -rDim.Width();
322 : }
323 :
324 0 : if( nMirror == RES_MIRROR_GRAPH_HOR || nMirror == RES_MIRROR_GRAPH_BOTH )
325 : {
326 0 : rPt.setY(rPt.getY() + rDim.Height() -1);
327 0 : rDim.Height() = -rDim.Height();
328 : }
329 0 : }
330 :
331 : /** Calculate the Bitmap's position and the size within the passed rectangle */
332 0 : void SwNoTxtFrm::GetGrfArea( SwRect &rRect, SwRect* pOrigRect,
333 : bool ) const
334 : {
335 : // Currently only used for scaling, cropping and mirroring the contour of graphics!
336 : // Everything else is handled by GraphicObject
337 :
338 : // We put the graphic's visible rectangle into rRect.
339 : // pOrigRect contains position and size of the whole graphic.
340 :
341 0 : const SwAttrSet& rAttrSet = GetNode()->GetSwAttrSet();
342 0 : const SwCropGrf& rCrop = rAttrSet.GetCropGrf();
343 0 : sal_uInt16 nMirror = rAttrSet.GetMirrorGrf().GetValue();
344 :
345 0 : if( rAttrSet.GetMirrorGrf().IsGrfToggle() )
346 : {
347 0 : if( !(FindPageFrm()->GetVirtPageNum() % 2) )
348 : {
349 0 : switch ( nMirror )
350 : {
351 0 : case RES_MIRROR_GRAPH_DONT: nMirror = RES_MIRROR_GRAPH_VERT; break;
352 0 : case RES_MIRROR_GRAPH_VERT: nMirror = RES_MIRROR_GRAPH_DONT; break;
353 0 : case RES_MIRROR_GRAPH_HOR: nMirror = RES_MIRROR_GRAPH_BOTH; break;
354 0 : default: nMirror = RES_MIRROR_GRAPH_HOR; break;
355 : }
356 : }
357 : }
358 :
359 : // We read graphic from the Node, if needed.
360 : // It may fail, however.
361 : long nLeftCrop, nRightCrop, nTopCrop, nBottomCrop;
362 0 : Size aOrigSz( ((SwNoTxtNode*)GetNode())->GetTwipSize() );
363 0 : if ( !aOrigSz.Width() )
364 : {
365 0 : aOrigSz.Width() = Prt().Width();
366 0 : nLeftCrop = -rCrop.GetLeft();
367 0 : nRightCrop = -rCrop.GetRight();
368 : }
369 : else
370 : {
371 0 : nLeftCrop = std::max( aOrigSz.Width() -
372 0 : (rCrop.GetRight() + rCrop.GetLeft()), long(1) );
373 0 : const double nScale = double(Prt().Width()) / double(nLeftCrop);
374 0 : nLeftCrop = long(nScale * -rCrop.GetLeft() );
375 0 : nRightCrop = long(nScale * -rCrop.GetRight() );
376 : }
377 :
378 : // crop values have to be mirrored too
379 0 : if( nMirror == RES_MIRROR_GRAPH_VERT || nMirror == RES_MIRROR_GRAPH_BOTH )
380 : {
381 0 : long nTmpCrop = nLeftCrop;
382 0 : nLeftCrop = nRightCrop;
383 0 : nRightCrop= nTmpCrop;
384 : }
385 :
386 0 : if( !aOrigSz.Height() )
387 : {
388 0 : aOrigSz.Height() = Prt().Height();
389 0 : nTopCrop = -rCrop.GetTop();
390 0 : nBottomCrop= -rCrop.GetBottom();
391 : }
392 : else
393 : {
394 0 : nTopCrop = std::max( aOrigSz.Height() - (rCrop.GetTop() + rCrop.GetBottom()), long(1) );
395 0 : const double nScale = double(Prt().Height()) / double(nTopCrop);
396 0 : nTopCrop = long(nScale * -rCrop.GetTop() );
397 0 : nBottomCrop= long(nScale * -rCrop.GetBottom() );
398 : }
399 :
400 : // crop values have to be mirrored too
401 0 : if( nMirror == RES_MIRROR_GRAPH_HOR || nMirror == RES_MIRROR_GRAPH_BOTH )
402 : {
403 0 : long nTmpCrop = nTopCrop;
404 0 : nTopCrop = nBottomCrop;
405 0 : nBottomCrop= nTmpCrop;
406 : }
407 :
408 0 : Size aVisSz( Prt().SSize() );
409 0 : Size aGrfSz( aVisSz );
410 0 : Point aVisPt( Frm().Pos() + Prt().Pos() );
411 0 : Point aGrfPt( aVisPt );
412 :
413 : // Set the "visible" rectangle first
414 0 : if ( nLeftCrop > 0 )
415 : {
416 0 : aVisPt.setX(aVisPt.getX() + nLeftCrop);
417 0 : aVisSz.Width() -= nLeftCrop;
418 : }
419 0 : if ( nTopCrop > 0 )
420 : {
421 0 : aVisPt.setY(aVisPt.getY() + nTopCrop);
422 0 : aVisSz.Height() -= nTopCrop;
423 : }
424 0 : if ( nRightCrop > 0 )
425 0 : aVisSz.Width() -= nRightCrop;
426 0 : if ( nBottomCrop > 0 )
427 0 : aVisSz.Height() -= nBottomCrop;
428 :
429 0 : rRect.Pos ( aVisPt );
430 0 : rRect.SSize( aVisSz );
431 :
432 : // Calculate the whole graphic if needed
433 0 : if ( pOrigRect )
434 : {
435 0 : Size aTmpSz( aGrfSz );
436 0 : aGrfPt.setX(aGrfPt.getX() + nLeftCrop);
437 0 : aTmpSz.Width() -= nLeftCrop + nRightCrop;
438 0 : aGrfPt.setY(aGrfPt.getY() + nTopCrop);
439 0 : aTmpSz.Height()-= nTopCrop + nBottomCrop;
440 :
441 0 : if( RES_MIRROR_GRAPH_DONT != nMirror )
442 0 : lcl_CalcRect( aGrfPt, aTmpSz, nMirror );
443 :
444 0 : pOrigRect->Pos ( aGrfPt );
445 0 : pOrigRect->SSize( aTmpSz );
446 : }
447 0 : }
448 :
449 : /** By returning the surrounding Fly's size which equals the graphic's size */
450 0 : const Size& SwNoTxtFrm::GetSize() const
451 : {
452 : // Return the Frame's size
453 0 : const SwFrm *pFly = FindFlyFrm();
454 0 : if( !pFly )
455 0 : pFly = this;
456 0 : return pFly->Prt().SSize();
457 : }
458 :
459 0 : void SwNoTxtFrm::MakeAll()
460 : {
461 0 : SwCntntNotify aNotify( this );
462 0 : SwBorderAttrAccess aAccess( SwFrm::GetCache(), this );
463 0 : const SwBorderAttrs &rAttrs = *aAccess.Get();
464 :
465 0 : while ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
466 : {
467 0 : MakePos();
468 :
469 0 : if ( !mbValidSize )
470 0 : Frm().Width( GetUpper()->Prt().Width() );
471 :
472 0 : MakePrtArea( rAttrs );
473 :
474 0 : if ( !mbValidSize )
475 0 : { mbValidSize = sal_True;
476 0 : Format();
477 : }
478 0 : }
479 0 : }
480 :
481 : /** Calculate the Bitmap's site, if needed */
482 0 : void SwNoTxtFrm::Format( const SwBorderAttrs * )
483 : {
484 0 : const Size aNewSize( GetSize() );
485 :
486 : // Did the height change?
487 0 : SwTwips nChgHght = IsVertical() ?
488 0 : (SwTwips)(aNewSize.Width() - Prt().Width()) :
489 0 : (SwTwips)(aNewSize.Height() - Prt().Height());
490 0 : if( nChgHght > 0)
491 0 : Grow( nChgHght );
492 0 : else if( nChgHght < 0)
493 0 : Shrink( std::min(Prt().Height(), -nChgHght) );
494 0 : }
495 :
496 0 : bool SwNoTxtFrm::GetCharRect( SwRect &rRect, const SwPosition& rPos,
497 : SwCrsrMoveState *pCMS ) const
498 : {
499 0 : if ( &rPos.nNode.GetNode() != (SwNode*)GetNode() )
500 0 : return false;
501 :
502 0 : Calc();
503 0 : SwRect aFrameRect( Frm() );
504 0 : rRect = aFrameRect;
505 0 : rRect.Pos( Frm().Pos() + Prt().Pos() );
506 0 : rRect.SSize( Prt().SSize() );
507 :
508 0 : rRect.Justify();
509 :
510 : // Is the Bitmap in the visible area at all?
511 0 : if( !aFrameRect.IsOver( rRect ) )
512 : {
513 : // If not, then the Cursor is on the Frame
514 0 : rRect = aFrameRect;
515 0 : rRect.Width( 1 );
516 : }
517 : else
518 0 : rRect._Intersection( aFrameRect );
519 :
520 0 : if ( pCMS )
521 : {
522 0 : if ( pCMS->bRealHeight )
523 : {
524 0 : pCMS->aRealHeight.setY(rRect.Height());
525 0 : pCMS->aRealHeight.setX(0);
526 : }
527 : }
528 :
529 0 : return true;
530 : }
531 :
532 0 : bool SwNoTxtFrm::GetCrsrOfst(SwPosition* pPos, Point& ,
533 : SwCrsrMoveState*, bool ) const
534 : {
535 0 : SwCntntNode* pCNd = (SwCntntNode*)GetNode();
536 0 : pPos->nNode = *pCNd;
537 0 : pPos->nContent.Assign( pCNd, 0 );
538 0 : return true;
539 : }
540 :
541 : #define CLEARCACHE( pNd ) {\
542 : (pNd)->ReleaseGraphicFromCache();\
543 : SwFlyFrm* pFly = FindFlyFrm();\
544 : if( pFly && pFly->GetFmt()->GetSurround().IsContour() )\
545 : {\
546 : ClrContourCache( pFly->GetVirtDrawObj() );\
547 : pFly->NotifyBackground( FindPageFrm(), Prt(), PREP_FLY_ATTR_CHG );\
548 : }\
549 : }
550 :
551 0 : void SwNoTxtFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
552 : {
553 0 : sal_uInt16 nWhich = pNew ? pNew->Which() : pOld ? pOld->Which() : 0;
554 :
555 : // #i73788#
556 : // no <SwCntntFrm::Modify(..)> for RES_LINKED_GRAPHIC_STREAM_ARRIVED
557 0 : if ( RES_GRAPHIC_PIECE_ARRIVED != nWhich &&
558 0 : RES_GRAPHIC_ARRIVED != nWhich &&
559 0 : RES_GRF_REREAD_AND_INCACHE != nWhich &&
560 : RES_LINKED_GRAPHIC_STREAM_ARRIVED != nWhich )
561 : {
562 0 : SwCntntFrm::Modify( pOld, pNew );
563 : }
564 :
565 0 : bool bComplete = true;
566 :
567 0 : switch( nWhich )
568 : {
569 : case RES_OBJECTDYING:
570 0 : break;
571 :
572 : case RES_GRF_REREAD_AND_INCACHE:
573 0 : if( ND_GRFNODE == GetNode()->GetNodeType() )
574 : {
575 0 : bComplete = false;
576 0 : SwGrfNode* pNd = (SwGrfNode*) GetNode();
577 :
578 0 : SwViewShell *pVSh = 0;
579 0 : pNd->GetDoc()->GetEditShell( &pVSh );
580 0 : if( pVSh )
581 : {
582 0 : GraphicAttr aAttr;
583 0 : if( pNd->GetGrfObj().IsCached( pVSh->GetOut(), Point(),
584 0 : Prt().SSize(), &pNd->GetGraphicAttr( aAttr, this ) ))
585 : {
586 0 : SwViewShell *pSh = pVSh;
587 0 : do {
588 0 : SET_CURR_SHELL( pSh );
589 0 : if( pSh->GetWin() )
590 : {
591 0 : if( pSh->IsPreview() )
592 0 : ::RepaintPagePreview( pSh, Frm().SVRect() );
593 : else
594 0 : pSh->GetWin()->Invalidate( Frm().SVRect() );
595 0 : }
596 0 : } while( pVSh != (pSh = (SwViewShell*)pSh->GetNext() ));
597 : }
598 : else
599 0 : pNd->SwapIn();
600 : }
601 : }
602 0 : break;
603 :
604 : case RES_UPDATE_ATTR:
605 : case RES_FMT_CHG:
606 0 : CLEARCACHE( (SwGrfNode*) GetNode() )
607 0 : break;
608 :
609 : case RES_ATTRSET_CHG:
610 : {
611 : sal_uInt16 n;
612 0 : for( n = RES_GRFATR_BEGIN; n < RES_GRFATR_END; ++n )
613 0 : if( SFX_ITEM_SET == ((SwAttrSetChg*)pOld)->GetChgSet()->
614 0 : GetItemState( n, false ))
615 : {
616 0 : CLEARCACHE( (SwGrfNode*) GetNode() )
617 0 : break;
618 : }
619 0 : if( RES_GRFATR_END == n ) // not found
620 0 : return ;
621 : }
622 0 : break;
623 :
624 : case RES_GRAPHIC_PIECE_ARRIVED:
625 : case RES_GRAPHIC_ARRIVED:
626 : // i73788# - handle RES_LINKED_GRAPHIC_STREAM_ARRIVED as RES_GRAPHIC_ARRIVED
627 : case RES_LINKED_GRAPHIC_STREAM_ARRIVED:
628 0 : if ( GetNode()->GetNodeType() == ND_GRFNODE )
629 : {
630 0 : bComplete = false;
631 0 : SwGrfNode* pNd = (SwGrfNode*) GetNode();
632 :
633 0 : CLEARCACHE( pNd )
634 :
635 0 : SwRect aRect( Frm() );
636 :
637 0 : SwViewShell *pVSh = 0;
638 0 : pNd->GetDoc()->GetEditShell( &pVSh );
639 0 : if( !pVSh )
640 0 : break;
641 :
642 0 : SwViewShell *pSh = pVSh;
643 0 : do {
644 0 : SET_CURR_SHELL( pSh );
645 0 : if( pSh->IsPreview() )
646 : {
647 0 : if( pSh->GetWin() )
648 0 : ::RepaintPagePreview( pSh, aRect );
649 : }
650 0 : else if ( pSh->VisArea().IsOver( aRect ) &&
651 0 : OUTDEV_WINDOW == pSh->GetOut()->GetOutDevType() )
652 : {
653 : // invalidate instead of painting
654 0 : pSh->GetWin()->Invalidate( aRect.SVRect() );
655 : }
656 :
657 0 : pSh = (SwViewShell *)pSh->GetNext();
658 0 : } while( pSh != pVSh );
659 : }
660 0 : break;
661 :
662 : default:
663 0 : if ( !pNew || !isGRFATR(nWhich) )
664 0 : return;
665 : }
666 :
667 0 : if( bComplete )
668 : {
669 0 : InvalidatePrt();
670 0 : SetCompletePaint();
671 : }
672 : }
673 :
674 0 : static void lcl_correctlyAlignRect( SwRect& rAlignedGrfArea, const SwRect& rInArea, OutputDevice* pOut )
675 : {
676 :
677 0 : if(!pOut)
678 0 : return;
679 0 : Rectangle aPxRect = pOut->LogicToPixel( rInArea.SVRect() );
680 0 : Rectangle aNewPxRect( aPxRect );
681 0 : while( aNewPxRect.Left() < aPxRect.Left() )
682 : {
683 0 : rAlignedGrfArea.Left( rAlignedGrfArea.Left()+1 );
684 0 : aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() );
685 : }
686 0 : while( aNewPxRect.Top() < aPxRect.Top() )
687 : {
688 0 : rAlignedGrfArea.Top( rAlignedGrfArea.Top()+1 );
689 0 : aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() );
690 : }
691 0 : while( aNewPxRect.Bottom() > aPxRect.Bottom() )
692 : {
693 0 : rAlignedGrfArea.Bottom( rAlignedGrfArea.Bottom()-1 );
694 0 : aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() );
695 : }
696 0 : while( aNewPxRect.Right() > aPxRect.Right() )
697 : {
698 0 : rAlignedGrfArea.Right( rAlignedGrfArea.Right()-1 );
699 0 : aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() );
700 : }
701 : }
702 :
703 0 : bool paintUsingPrimitivesHelper(
704 : OutputDevice& rOutputDevice,
705 : const drawinglayer::primitive2d::Primitive2DSequence& rSequence,
706 : const basegfx::B2DRange& rSourceRange,
707 : const basegfx::B2DRange& rTargetRange)
708 : {
709 0 : if(rSequence.hasElements() && !basegfx::fTools::equalZero(rSourceRange.getWidth()) && !basegfx::fTools::equalZero(rSourceRange.getHeight()))
710 : {
711 0 : if(!basegfx::fTools::equalZero(rTargetRange.getWidth()) && !basegfx::fTools::equalZero(rTargetRange.getHeight()))
712 : {
713 : // map graphic range to target range. This will e.g. automatically include
714 : // tme mapping from 1/100th mm content to twips if needed when the target
715 : // range is defined in twips
716 : const basegfx::B2DHomMatrix aMappingTransform(
717 : basegfx::tools::createSourceRangeTargetRangeTransform(
718 : rSourceRange,
719 0 : rTargetRange));
720 :
721 : // Fill ViewInformation. Use MappingTransform here, so there is no need to
722 : // embed the primitives to it. Use original TargetRange here so there is also
723 : // no need to embed the primitives to a MaskPrimitive for cropping. This works
724 : // only in this case where the graphic object cannot be rotated, though.
725 : const drawinglayer::geometry::ViewInformation2D aViewInformation2D(
726 : aMappingTransform,
727 : rOutputDevice.GetViewTransformation(),
728 : rTargetRange,
729 : 0,
730 : 0.0,
731 0 : uno::Sequence< beans::PropertyValue >());
732 :
733 : // get a primitive processor for rendering
734 : drawinglayer::processor2d::BaseProcessor2D* pProcessor2D =
735 : drawinglayer::processor2d::createProcessor2DFromOutputDevice(
736 0 : rOutputDevice, aViewInformation2D);
737 :
738 0 : if(pProcessor2D)
739 : {
740 : // render and cleanup
741 0 : pProcessor2D->process(rSequence);
742 0 : delete pProcessor2D;
743 0 : return true;
744 0 : }
745 : }
746 : }
747 :
748 0 : return false;
749 : }
750 :
751 0 : void paintGraphicUsingPrimitivesHelper(OutputDevice & rOutputDevice,
752 : Graphic const& rGraphic, GraphicAttr const& rGraphicAttr,
753 : SwRect const& rAlignedGrfArea)
754 : {
755 : // unify using GraphicPrimitive2D
756 : // -> the primitive handles all crop and mirror stuff
757 : // -> the primitive renderer will create the needed pdf export data
758 : // -> if bitmap content, it will be cached system-dependent
759 : const basegfx::B2DRange aTargetRange(
760 0 : rAlignedGrfArea.Left(), rAlignedGrfArea.Top(),
761 0 : rAlignedGrfArea.Right(), rAlignedGrfArea.Bottom());
762 : const basegfx::B2DHomMatrix aTargetTransform(
763 : basegfx::tools::createScaleTranslateB2DHomMatrix(
764 : aTargetRange.getRange(),
765 0 : aTargetRange.getMinimum()));
766 0 : drawinglayer::primitive2d::Primitive2DSequence aContent(1);
767 :
768 0 : aContent[0] = new drawinglayer::primitive2d::GraphicPrimitive2D(
769 : aTargetTransform,
770 : rGraphic,
771 0 : rGraphicAttr);
772 :
773 : paintUsingPrimitivesHelper(
774 : rOutputDevice,
775 : aContent,
776 : aTargetRange,
777 0 : aTargetRange);
778 0 : }
779 :
780 : /** Paint the graphic.
781 :
782 : We require either a QuickDraw-Bitmap or a graphic here. If we do not have
783 : either, we return a replacement.
784 :
785 : @todo use aligned rectangle for drawing graphic.
786 : @todo pixel-align coordinations for drawing graphic. */
787 0 : void SwNoTxtFrm::PaintPicture( OutputDevice* pOut, const SwRect &rGrfArea ) const
788 : {
789 0 : SwViewShell* pShell = getRootFrm()->GetCurrShell();
790 :
791 0 : SwNoTxtNode& rNoTNd = *(SwNoTxtNode*)GetNode();
792 0 : SwGrfNode* pGrfNd = rNoTNd.GetGrfNode();
793 0 : SwOLENode* pOLENd = rNoTNd.GetOLENode();
794 :
795 0 : const sal_Bool bPrn = pOut == rNoTNd.getIDocumentDeviceAccess()->getPrinter( false ) ||
796 0 : pOut->GetConnectMetaFile();
797 :
798 0 : const bool bIsChart = pOLENd && ChartHelper::IsChart( pOLENd->GetOLEObj().GetObject() );
799 :
800 : // calculate aligned rectangle from parameter <rGrfArea>.
801 : // Use aligned rectangle <aAlignedGrfArea> instead of <rGrfArea> in
802 : // the following code.
803 0 : SwRect aAlignedGrfArea = rGrfArea;
804 0 : ::SwAlignRect( aAlignedGrfArea, pShell );
805 :
806 0 : if( !bIsChart )
807 : {
808 : // Because for drawing a graphic left-top-corner and size coordinations are
809 : // used, these coordinations have to be determined on pixel level.
810 0 : ::SwAlignGrfRect( &aAlignedGrfArea, *pOut );
811 : }
812 : else //if( bIsChart )
813 : {
814 : // #i78025# charts own borders are not completely visible
815 : // the above pixel correction is not correct - at least not for charts
816 : // so a different pixel correction is chosen here
817 : // this might be a good idea for all other OLE objects also,
818 : // but as I cannot oversee the consequences I fix it only for charts for now
819 0 : lcl_correctlyAlignRect( aAlignedGrfArea, rGrfArea, pOut );
820 : }
821 :
822 0 : if( pGrfNd )
823 : {
824 : // Fix for bug fdo#33781
825 0 : const sal_uInt16 nFormerAntialiasingAtOutput( pOut->GetAntialiasing() );
826 0 : if (pShell->Imp()->GetDrawView()->IsAntiAliasing())
827 : {
828 0 : pOut->SetAntialiasing( nFormerAntialiasingAtOutput | ANTIALIASING_ENABLE_B2DDRAW );
829 : }
830 :
831 0 : bool bForceSwap = false, bContinue = true;
832 0 : const GraphicObject& rGrfObj = pGrfNd->GetGrfObj();
833 :
834 0 : GraphicAttr aGrfAttr;
835 0 : pGrfNd->GetGraphicAttr( aGrfAttr, this );
836 :
837 0 : if( !bPrn )
838 : {
839 : // #i73788#
840 0 : if ( pGrfNd->IsLinkedInputStreamReady() )
841 : {
842 0 : pGrfNd->UpdateLinkWithInputStream();
843 : }
844 : // #i85717#, #i90395# - check, if asynchronous retrieval
845 : // if input stream for the graphic is possible
846 0 : else if ( ( rGrfObj.GetType() == GRAPHIC_DEFAULT ||
847 0 : rGrfObj.GetType() == GRAPHIC_NONE ) &&
848 0 : pGrfNd->IsLinkedFile() &&
849 0 : pGrfNd->IsAsyncRetrieveInputStreamPossible() )
850 : {
851 0 : Size aTmpSz;
852 0 : ::sfx2::SvLinkSource* pGrfObj = pGrfNd->GetLink()->GetObj();
853 0 : if( !pGrfObj ||
854 0 : !pGrfObj->IsDataComplete() ||
855 0 : !(aTmpSz = pGrfNd->GetTwipSize()).Width() ||
856 0 : !aTmpSz.Height() || !pGrfNd->GetAutoFmtLvl() )
857 : {
858 0 : pGrfNd->TriggerAsyncRetrieveInputStream(); // #i73788#
859 : }
860 0 : OUString aTxt( pGrfNd->GetTitle() );
861 0 : if ( aTxt.isEmpty() )
862 0 : GetRealURL( *pGrfNd, aTxt );
863 0 : ::lcl_PaintReplacement( aAlignedGrfArea, aTxt, *pShell, this, false );
864 0 : bContinue = false;
865 : }
866 : }
867 :
868 0 : if( bContinue )
869 : {
870 0 : const sal_Bool bSwapped = rGrfObj.IsSwappedOut();
871 0 : const bool bSwappedIn = pGrfNd->SwapIn( bPrn );
872 0 : if( bSwappedIn && rGrfObj.GetGraphic().IsSupportedGraphic())
873 : {
874 0 : const bool bAnimate = rGrfObj.IsAnimated() &&
875 0 : !pShell->IsPreview() &&
876 0 : !pShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() &&
877 : // #i9684# Stop animation during printing/pdf export
878 0 : pShell->GetWin();
879 :
880 0 : if( bAnimate &&
881 0 : FindFlyFrm() != ::GetFlyFromMarked( 0, pShell ))
882 : {
883 : OutputDevice* pVout;
884 0 : if( pOut == pShell->GetOut() && SwRootFrm::FlushVout() )
885 0 : pVout = pOut, pOut = pShell->GetOut();
886 0 : else if( pShell->GetWin() &&
887 0 : OUTDEV_VIRDEV == pOut->GetOutDevType() )
888 0 : pVout = pOut, pOut = pShell->GetWin();
889 : else
890 0 : pVout = 0;
891 :
892 : OSL_ENSURE( OUTDEV_VIRDEV != pOut->GetOutDevType() ||
893 : pShell->GetViewOptions()->IsPDFExport(),
894 : "pOut should not be a virtual device" );
895 :
896 0 : pGrfNd->StartGraphicAnimation(pOut, aAlignedGrfArea.Pos(),
897 0 : aAlignedGrfArea.SSize(), sal_IntPtr(this),
898 0 : 0, GRFMGR_DRAW_STANDARD, pVout );
899 : }
900 : else
901 : {
902 : paintGraphicUsingPrimitivesHelper(*pOut,
903 0 : rGrfObj.GetGraphic(), aGrfAttr, aAlignedGrfArea);
904 : }
905 : }
906 : else
907 : {
908 0 : sal_uInt16 nResId = 0;
909 0 : if( bSwappedIn )
910 : {
911 0 : if( GRAPHIC_NONE == rGrfObj.GetType() )
912 0 : nResId = STR_COMCORE_READERROR;
913 0 : else if ( !rGrfObj.GetGraphic().IsSupportedGraphic() )
914 0 : nResId = STR_COMCORE_CANT_SHOW;
915 : }
916 0 : ((SwNoTxtFrm*)this)->nWeight = -1;
917 0 : OUString aText;
918 0 : if ( !nResId &&
919 0 : (aText = pGrfNd->GetTitle()).isEmpty() &&
920 0 : (!GetRealURL( *pGrfNd, aText ) || aText.isEmpty()))
921 : {
922 0 : nResId = STR_COMCORE_READERROR;
923 : }
924 0 : if ( nResId )
925 0 : aText = SW_RESSTR( nResId );
926 :
927 0 : ::lcl_PaintReplacement( aAlignedGrfArea, aText, *pShell, this, true );
928 : }
929 :
930 : // When printing, we must not collect the graphics
931 0 : if( bSwapped && bPrn )
932 0 : bForceSwap = true;
933 : }
934 :
935 0 : if( bForceSwap )
936 0 : pGrfNd->SwapOut();
937 :
938 0 : if ( pShell->Imp()->GetDrawView()->IsAntiAliasing() )
939 0 : pOut->SetAntialiasing( nFormerAntialiasingAtOutput );
940 : }
941 : else // bIsChart || pOLENd
942 : {
943 : // Fix for bug fdo#33781
944 0 : const sal_uInt16 nFormerAntialiasingAtOutput( pOut->GetAntialiasing() );
945 0 : if (pShell->Imp()->GetDrawView()->IsAntiAliasing())
946 : {
947 0 : sal_uInt16 nNewAntialiasingAtOutput = nFormerAntialiasingAtOutput | ANTIALIASING_ENABLE_B2DDRAW;
948 :
949 : // #i99665#
950 : // Adjust AntiAliasing mode at output device for chart OLE
951 0 : if ( pOLENd->IsChart() )
952 0 : nNewAntialiasingAtOutput |= ANTIALIASING_PIXELSNAPHAIRLINE;
953 :
954 0 : pOut->SetAntialiasing( nNewAntialiasingAtOutput );
955 : }
956 :
957 0 : bool bDone(false);
958 :
959 0 : if(bIsChart)
960 : {
961 0 : const uno::Reference< frame::XModel > aXModel(pOLENd->GetOLEObj().GetOleRef()->getComponent(), uno::UNO_QUERY);
962 :
963 0 : if(aXModel.is())
964 : {
965 0 : basegfx::B2DRange aSourceRange;
966 :
967 : const drawinglayer::primitive2d::Primitive2DSequence aSequence(
968 : ChartHelper::tryToGetChartContentAsPrimitive2DSequence(
969 : aXModel,
970 0 : aSourceRange));
971 :
972 0 : if(aSequence.hasElements() && !aSourceRange.isEmpty())
973 : {
974 : const basegfx::B2DRange aTargetRange(
975 0 : aAlignedGrfArea.Left(), aAlignedGrfArea.Top(),
976 0 : aAlignedGrfArea.Right(), aAlignedGrfArea.Bottom());
977 :
978 : bDone = paintUsingPrimitivesHelper(
979 : *pOut,
980 : aSequence,
981 : aSourceRange,
982 0 : aTargetRange);
983 0 : }
984 0 : }
985 : }
986 :
987 0 : if(!bDone && pOLENd)
988 : {
989 0 : Point aPosition(aAlignedGrfArea.Pos());
990 0 : Size aSize(aAlignedGrfArea.SSize());
991 :
992 0 : const Graphic* pGraphic = pOLENd->GetGraphic();
993 0 : if ( pGraphic && pGraphic->GetType() != GRAPHIC_NONE )
994 : {
995 0 : pGraphic->Draw( pOut, aPosition, aSize );
996 :
997 : // shade the representation if the object is activated outplace
998 0 : uno::Reference < embed::XEmbeddedObject > xObj = pOLENd->GetOLEObj().GetOleRef();
999 0 : if ( xObj.is() && xObj->getCurrentState() == embed::EmbedStates::ACTIVE )
1000 : {
1001 0 : ::svt::EmbeddedObjectRef::DrawShading( Rectangle( aPosition, aSize ), pOut );
1002 0 : }
1003 : }
1004 : else
1005 0 : ::svt::EmbeddedObjectRef::DrawPaintReplacement( Rectangle( aPosition, aSize ), pOLENd->GetOLEObj().GetCurrentPersistName(), pOut );
1006 :
1007 0 : sal_Int64 nMiscStatus = pOLENd->GetOLEObj().GetOleRef()->getStatus( pOLENd->GetAspect() );
1008 0 : if ( !bPrn && pShell->ISA( SwCrsrShell ) &&
1009 0 : nMiscStatus & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE )
1010 : {
1011 0 : const SwFlyFrm *pFly = FindFlyFrm();
1012 : assert( pFly != NULL );
1013 0 : ((SwFEShell*)pShell)->ConnectObj( pOLENd->GetOLEObj().GetObject(), pFly->Prt(), pFly->Frm());
1014 : }
1015 : }
1016 :
1017 : // see #i99665#
1018 0 : if (pShell->Imp()->GetDrawView()->IsAntiAliasing())
1019 : {
1020 0 : pOut->SetAntialiasing( nFormerAntialiasingAtOutput );
1021 : }
1022 : }
1023 0 : }
1024 :
1025 0 : sal_Bool SwNoTxtFrm::IsTransparent() const
1026 : {
1027 0 : const SwViewShell* pSh = getRootFrm()->GetCurrShell();
1028 0 : if ( !pSh || !pSh->GetViewOptions()->IsGraphic() )
1029 0 : return sal_True;
1030 :
1031 : const SwGrfNode *pNd;
1032 0 : if( 0 != (pNd = GetNode()->GetGrfNode()) )
1033 0 : return pNd->IsTransparent();
1034 :
1035 : //#29381# OLE are always transparent
1036 0 : return sal_True;
1037 : }
1038 :
1039 0 : void SwNoTxtFrm::StopAnimation( OutputDevice* pOut ) const
1040 : {
1041 : // Stop animated graphics
1042 0 : const SwGrfNode* pGrfNd = dynamic_cast< const SwGrfNode* >(GetNode()->GetGrfNode());
1043 :
1044 0 : if( pGrfNd && pGrfNd->IsAnimated() )
1045 : {
1046 0 : const_cast< SwGrfNode* >(pGrfNd)->StopGraphicAnimation( pOut, sal_IntPtr(this) );
1047 : }
1048 0 : }
1049 :
1050 0 : sal_Bool SwNoTxtFrm::HasAnimation() const
1051 : {
1052 0 : const SwGrfNode* pGrfNd = GetNode()->GetGrfNode();
1053 0 : return pGrfNd && pGrfNd->IsAnimated();
1054 : }
1055 :
1056 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|