1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <config_wasm_strip.h>
22 #include <rootfrm.hxx>
23 #include <pagefrm.hxx>
24 #include <viewimp.hxx>
25 #include <viewopt.hxx>
29 #include <svx/svdpage.hxx>
32 #include <officecfg/Office/Common.hxx>
33 #include <pagepreviewlayout.hxx>
34 #include <comphelper/lok.hxx>
35 #include <comphelper/diagnose_ex.hxx>
36 #include <IDocumentLayoutAccess.hxx>
37 #include <IDocumentDrawModelAccess.hxx>
38 #include <drawdoc.hxx>
39 #include <prevwpage.hxx>
40 #include <sfx2/viewsh.hxx>
42 void SwViewShellImp::Init( const SwViewOption
*pNewOpt
)
44 OSL_ENSURE( m_pDrawView
, "SwViewShellImp::Init without DrawView" );
45 //Create PageView if it doesn't exist
46 SwRootFrame
*pRoot
= m_pShell
->GetLayout();
47 if ( !m_pSdrPageView
)
49 IDocumentDrawModelAccess
& rIDDMA
= m_pShell
->getIDocumentDrawModelAccess();
50 if ( !pRoot
->GetDrawPage() )
51 pRoot
->SetDrawPage( rIDDMA
.GetDrawModel()->GetPage( 0 ) );
53 if ( pRoot
->GetDrawPage()->GetSize() != pRoot
->getFrameArea().SSize() )
54 pRoot
->GetDrawPage()->SetSize( pRoot
->getFrameArea().SSize() );
56 m_pSdrPageView
= m_pDrawView
->ShowSdrPage( pRoot
->GetDrawPage());
57 // Notify drawing page view about invisible layers
58 rIDDMA
.NotifyInvisibleLayers( *m_pSdrPageView
);
60 m_pDrawView
->SetDragStripes( pNewOpt
->IsCrossHair() );
61 m_pDrawView
->SetGridSnap( pNewOpt
->IsSnap() );
62 m_pDrawView
->SetGridVisible( pNewOpt
->IsGridVisible() );
63 const Size
&rSz
= pNewOpt
->GetSnapSize();
64 m_pDrawView
->SetGridCoarse( rSz
);
66 ( rSz
.Width() ? rSz
.Width() /std::max(short(1),pNewOpt
->GetDivisionX()):0,
67 rSz
.Height()? rSz
.Height()/std::max(short(1),pNewOpt
->GetDivisionY()):0);
68 m_pDrawView
->SetGridFine( aFSize
);
69 Fraction
aSnGrWdtX(rSz
.Width(), pNewOpt
->GetDivisionX() + 1);
70 Fraction
aSnGrWdtY(rSz
.Height(), pNewOpt
->GetDivisionY() + 1);
71 m_pDrawView
->SetSnapGridWidth( aSnGrWdtX
, aSnGrWdtY
);
73 if ( pRoot
->getFrameArea().HasArea() )
74 m_pDrawView
->SetWorkArea( pRoot
->getFrameArea().SVRect() );
76 if ( GetShell()->IsPreview() )
77 m_pDrawView
->SetAnimationEnabled( false );
79 m_pDrawView
->SetUseIncompatiblePathCreateInterface( false );
81 // set handle size to 9 pixels, always
82 m_pDrawView
->SetMarkHdlSizePixel(9);
85 /// CTor for the core internals
86 SwViewShellImp::SwViewShellImp( SwViewShell
*pParent
) :
88 m_pSdrPageView( nullptr ),
89 m_pFirstVisiblePage( nullptr ),
90 m_pLayAction( nullptr ),
91 m_pIdleAct( nullptr ),
92 m_bFirstPageInvalid( true ),
93 m_bResetHdlHiddenPaint( false ),
94 m_bSmoothUpdate( false ),
95 m_bStopSmooth( false ),
96 m_nRestoreActions( 0 )
100 SwViewShellImp::~SwViewShellImp()
102 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
103 m_pAccessibleMap
.reset();
106 m_pPagePreviewLayout
.reset();
108 // Make sure HideSdrPage is also executed after ShowSdrPage.
110 m_pDrawView
->HideSdrPage();
116 OSL_ENSURE( !m_pLayAction
, "Have action for the rest of your life." );
117 OSL_ENSURE( !m_pIdleAct
,"Be idle for the rest of your life." );
120 bool SwViewShellImp::AddPaintRect( const SwRect
&rRect
)
122 // In case of tiled rendering the visual area is the last painted tile -> not interesting.
123 if ( rRect
.Overlaps( m_pShell
->VisArea() ) || comphelper::LibreOfficeKit::isActive() )
125 if ( !m_oPaintRegion
)
127 // In case of normal rendering, this makes sure only visible rectangles are painted.
128 // Otherwise get the rectangle of the full document, so all paint rectangles are invalidated.
129 const SwRect
& rArea
= comphelper::LibreOfficeKit::isActive() ? m_pShell
->GetLayout()->getFrameArea() : m_pShell
->VisArea();
130 m_oPaintRegion
.emplace();
131 m_oPaintRegion
->ChangeOrigin(rArea
);
133 if(!m_oPaintRegion
->empty())
135 // This function often gets called with rectangles that line up vertically.
136 // Try to extend the last one downwards to include the new one (use Union()
137 // in case the new one is actually already contained in the last one).
138 SwRect
& last
= m_oPaintRegion
->back();
139 if(last
.Left() == rRect
.Left() && last
.Width() == rRect
.Width()
140 && last
.Bottom() + 1 >= rRect
.Top() && last
.Bottom() <= rRect
.Bottom())
143 // And these rectangles lined up vertically often come up in groups
144 // that line up horizontally. Try to extend the previous rectangle
145 // to the right to include the last one.
146 if(m_oPaintRegion
->size() > 1)
148 SwRect
& last2
= (*m_oPaintRegion
)[m_oPaintRegion
->size() - 2];
149 if(last2
.Top() == last
.Top() && last2
.Height() == last
.Height()
150 && last2
.Right() + 1 >= last
.Left() && last2
.Right() <= last2
.Right())
153 m_oPaintRegion
->pop_back();
160 (*m_oPaintRegion
) += rRect
;
166 void SwViewShellImp::AddPendingLOKInvalidation( const SwRect
& rRect
)
168 std::vector
<SwRect
>& l
= m_pendingLOKInvalidations
;
169 if(l
.empty() && m_pShell
&& m_pShell
->GetSfxViewShell()) // Announce that these invalidations will need flushing.
170 m_pShell
->GetSfxViewShell()->libreOfficeKitViewAddPendingInvalidateTiles();
171 // These are often repeated, so check first for duplicates.
172 if( std::find( l
.begin(), l
.end(), rRect
) == l
.end())
173 l
.push_back( rRect
);
176 std::vector
<SwRect
> SwViewShellImp::TakePendingLOKInvalidations()
178 std::vector
<SwRect
> ret
;
179 std::swap(ret
, m_pendingLOKInvalidations
);
183 void SwViewShellImp::CheckWaitCursor()
186 m_pLayAction
->CheckWaitCursor();
189 bool SwViewShellImp::IsCalcLayoutProgress() const
191 return m_pLayAction
&& m_pLayAction
->IsCalcLayout();
194 bool SwViewShellImp::IsUpdateExpFields()
196 if ( m_pLayAction
&& m_pLayAction
->IsCalcLayout() )
198 m_pLayAction
->SetUpdateExpFields();
204 void SwViewShellImp::SetFirstVisPage(OutputDevice
const * pRenderContext
)
206 if ( m_pShell
->mbDocSizeChgd
&& m_pShell
->VisArea().Top() > m_pShell
->GetLayout()->getFrameArea().Height() )
208 //We are in an action and because of erase actions the VisArea is
209 //after the first visible page.
210 //To avoid excessive formatting, hand back the last page.
211 m_pFirstVisiblePage
= static_cast<SwPageFrame
*>(m_pShell
->GetLayout()->Lower());
212 while ( m_pFirstVisiblePage
&& m_pFirstVisiblePage
->GetNext() )
213 m_pFirstVisiblePage
= static_cast<SwPageFrame
*>(m_pFirstVisiblePage
->GetNext());
217 const SwViewOption
* pSwViewOption
= GetShell()->GetViewOptions();
218 const bool bBookMode
= pSwViewOption
->IsViewLayoutBookMode();
220 SwPageFrame
*pPage
= static_cast<SwPageFrame
*>(m_pShell
->GetLayout()->Lower());
221 SwRect aPageRect
= pPage
->GetBoundRect(pRenderContext
);
222 while ( pPage
&& !aPageRect
.Overlaps( m_pShell
->VisArea() ) )
224 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
227 aPageRect
= pPage
->GetBoundRect(pRenderContext
);
228 if ( bBookMode
&& pPage
->IsEmptyPage() )
230 const SwPageFrame
& rFormatPage
= pPage
->GetFormatPage();
231 aPageRect
.SSize( rFormatPage
.GetBoundRect(pRenderContext
).SSize() );
235 m_pFirstVisiblePage
= pPage
? pPage
: static_cast<SwPageFrame
*>(m_pShell
->GetLayout()->Lower());
237 m_bFirstPageInvalid
= false;
240 void SwViewShellImp::MakeDrawView()
242 IDocumentDrawModelAccess
& rIDDMA
= GetShell()->getIDocumentDrawModelAccess();
244 // the else here is not an error, MakeDrawModel_() calls this method again
245 // after the DrawModel is created to create DrawViews for all shells...
246 if( !rIDDMA
.GetDrawModel() )
248 rIDDMA
.MakeDrawModel_();
255 // Discussed with FME, he also thinks that the getPrinter is old and not correct. When i got
256 // him right, it anyways returns GetOut() when it's a printer, but NULL when not. He suggested
257 // to use GetOut() and check the existing cases.
258 // Check worked well. Took a look at viewing, printing, PDF export and print preview with a test
259 // document which has an empty 2nd page (right page, see bug)
260 auto pWin
= GetShell()->GetWin();
261 OutputDevice
* pOutDevForDrawView
= pWin
? pWin
->GetOutDev() : nullptr;
263 if(!pOutDevForDrawView
)
265 pOutDevForDrawView
= GetShell()->GetOut();
268 m_pDrawView
.reset( new SwDrawView(
270 *rIDDMA
.GetOrCreateDrawModel(),
271 pOutDevForDrawView
) );
274 GetDrawView()->SetActiveLayer("Heaven");
275 const SwViewOption
* pSwViewOption
= GetShell()->GetViewOptions();
278 // #i68597# If document is read-only, we will not profit from overlay,
280 if (m_pDrawView
->IsBufferedOverlayAllowed())
282 if(pSwViewOption
->IsReadonly())
284 m_pDrawView
->SetBufferedOverlayAllowed(false);
290 Color
SwViewShellImp::GetRetoucheColor() const
292 Color
aRet( COL_TRANSPARENT
);
293 const SwViewShell
&rSh
= *GetShell();
294 if (rSh
.GetWin() || rSh
.isOutputToWindow())
296 if ( rSh
.GetViewOptions()->getBrowseMode() &&
297 COL_TRANSPARENT
!= rSh
.GetViewOptions()->GetRetoucheColor() )
298 aRet
= rSh
.GetViewOptions()->GetRetoucheColor();
299 else if(rSh
.GetViewOptions()->IsPagePreview() &&
300 !officecfg::Office::Common::Accessibility::IsForPagePreviews::get())
303 aRet
= rSh
.GetViewOptions()->GetDocColor();
308 SwPageFrame
*SwViewShellImp::GetFirstVisPage(OutputDevice
const * pRenderContext
)
310 if ( m_bFirstPageInvalid
)
311 SetFirstVisPage(pRenderContext
);
312 return m_pFirstVisiblePage
;
315 const SwPageFrame
*SwViewShellImp::GetFirstVisPage(OutputDevice
const * pRenderContext
) const
317 if ( m_bFirstPageInvalid
)
318 const_cast<SwViewShellImp
*>(this)->SetFirstVisPage(pRenderContext
);
319 return m_pFirstVisiblePage
;
322 const SwPageFrame
* SwViewShellImp::GetLastVisPage(const OutputDevice
* pRenderContext
) const
324 const SwViewOption
* pSwViewOption
= m_pShell
->GetViewOptions();
325 const bool bBookMode
= pSwViewOption
->IsViewLayoutBookMode();
326 const SwPageFrame
* pPage
= GetFirstVisPage(pRenderContext
);
327 const SwPageFrame
* pLastVisPage
= pPage
;
328 SwRect aPageRect
= pPage
->GetBoundRect(pRenderContext
);
329 while (pPage
&& (pPage
->IsEmptyPage() || aPageRect
.Overlaps(m_pShell
->VisArea())))
331 pLastVisPage
= pPage
;
332 pPage
= static_cast<const SwPageFrame
*>(pPage
->GetNext());
335 aPageRect
= pPage
->GetBoundRect(pRenderContext
);
336 if (bBookMode
&& pPage
->IsEmptyPage())
338 const SwPageFrame
& rFormatPage
= pPage
->GetFormatPage();
339 aPageRect
.SSize(rFormatPage
.GetBoundRect(pRenderContext
).SSize());
346 // create page preview layout
347 void SwViewShellImp::InitPagePreviewLayout()
349 OSL_ENSURE( m_pShell
->GetLayout(), "no layout - page preview layout can not be created.");
350 if ( m_pShell
->GetLayout() )
351 m_pPagePreviewLayout
.reset( new SwPagePreviewLayout( *m_pShell
, *(m_pShell
->GetLayout()) ) );
354 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
355 void SwViewShellImp::UpdateAccessible()
357 // We require a layout and an XModel to be accessible.
358 IDocumentLayoutAccess
& rIDLA
= GetShell()->getIDocumentLayoutAccess();
359 vcl::Window
*pWin
= GetShell()->GetWin();
360 OSL_ENSURE( GetShell()->GetLayout(), "no layout, no access" );
361 OSL_ENSURE( pWin
, "no window, no access" );
363 if( IsAccessible() && rIDLA
.GetCurrentViewShell() && pWin
)
367 GetAccessibleMap().GetDocumentView();
369 catch (uno::Exception
const&)
371 TOOLS_WARN_EXCEPTION("sw.a11y", "");
372 assert(!"SwViewShellImp::UpdateAccessible: unhandled exception");
377 void SwViewShellImp::DisposeAccessible(const SwFrame
*pFrame
,
378 const SdrObject
*pObj
,
380 bool bCanSkipInvisible
)
382 OSL_ENSURE( !pFrame
|| pFrame
->IsAccessibleFrame(), "frame is not accessible" );
383 for(SwViewShell
& rTmp
: GetShell()->GetRingContainer())
385 if( rTmp
.Imp()->IsAccessible() )
386 rTmp
.Imp()->GetAccessibleMap().A11yDispose( pFrame
, pObj
, nullptr, bRecursive
, bCanSkipInvisible
);
390 void SwViewShellImp::MoveAccessible( const SwFrame
*pFrame
, const SdrObject
*pObj
,
391 const SwRect
& rOldFrame
)
393 OSL_ENSURE( !pFrame
|| pFrame
->IsAccessibleFrame(), "frame is not accessible" );
394 for(SwViewShell
& rTmp
: GetShell()->GetRingContainer())
396 if( rTmp
.Imp()->IsAccessible() )
397 rTmp
.Imp()->GetAccessibleMap().InvalidatePosOrSize( pFrame
, pObj
, nullptr,
402 void SwViewShellImp::InvalidateAccessibleFrameContent( const SwFrame
*pFrame
)
404 OSL_ENSURE( pFrame
->IsAccessibleFrame(), "frame is not accessible" );
405 for(SwViewShell
& rTmp
: GetShell()->GetRingContainer())
407 if( rTmp
.Imp()->IsAccessible() )
408 rTmp
.Imp()->GetAccessibleMap().InvalidateContent( pFrame
);
412 void SwViewShellImp::InvalidateAccessibleCursorPosition( const SwFrame
*pFrame
)
415 GetAccessibleMap().InvalidateCursorPosition( pFrame
);
418 void SwViewShellImp::InvalidateAccessibleEditableState( bool bAllShells
,
419 const SwFrame
*pFrame
)
423 for(SwViewShell
& rTmp
: GetShell()->GetRingContainer())
425 if( rTmp
.Imp()->IsAccessible() )
426 rTmp
.Imp()->GetAccessibleMap().InvalidateEditableStates( pFrame
);
429 else if( IsAccessible() )
431 GetAccessibleMap().InvalidateEditableStates( pFrame
);
435 void SwViewShellImp::InvalidateAccessibleRelationSet( const SwFlyFrame
*pMaster
,
436 const SwFlyFrame
*pFollow
)
438 for(SwViewShell
& rTmp
: GetShell()->GetRingContainer())
440 if( rTmp
.Imp()->IsAccessible() )
441 rTmp
.Imp()->GetAccessibleMap().InvalidateRelationSet( pMaster
,
446 /// invalidate CONTENT_FLOWS_FROM/_TO relation for paragraphs
447 void SwViewShellImp::InvalidateAccessibleParaFlowRelation_( const SwTextFrame
* _pFromTextFrame
,
448 const SwTextFrame
* _pToTextFrame
)
450 if ( !_pFromTextFrame
&& !_pToTextFrame
)
452 // No text frame provided. Thus, nothing to do.
456 for(SwViewShell
& rTmp
: GetShell()->GetRingContainer())
458 if ( rTmp
.Imp()->IsAccessible() )
460 if ( _pFromTextFrame
)
462 rTmp
.Imp()->GetAccessibleMap().
463 InvalidateParaFlowRelation( *_pFromTextFrame
, true );
467 rTmp
.Imp()->GetAccessibleMap().
468 InvalidateParaFlowRelation( *_pToTextFrame
, false );
474 /// invalidate text selection for paragraphs
475 void SwViewShellImp::InvalidateAccessibleParaTextSelection_()
477 for(SwViewShell
& rTmp
: GetShell()->GetRingContainer())
479 if ( rTmp
.Imp()->IsAccessible() )
481 rTmp
.Imp()->GetAccessibleMap().InvalidateTextSelectionOfAllParas();
486 /// invalidate attributes for paragraphs
487 void SwViewShellImp::InvalidateAccessibleParaAttrs_( const SwTextFrame
& rTextFrame
)
489 for(SwViewShell
& rTmp
: GetShell()->GetRingContainer())
491 if ( rTmp
.Imp()->IsAccessible() )
493 rTmp
.Imp()->GetAccessibleMap().InvalidateAttr( rTextFrame
);
498 void SwViewShellImp::UpdateAccessiblePreview( const std::vector
<std::unique_ptr
<PreviewPage
>>& _rPreviewPages
,
499 const Fraction
& _rScale
,
500 const SwPageFrame
* _pSelectedPageFrame
,
501 const Size
& _rPreviewWinSize
)
504 GetAccessibleMap().UpdatePreview( _rPreviewPages
, _rScale
,
505 _pSelectedPageFrame
, _rPreviewWinSize
);
508 void SwViewShellImp::InvalidateAccessiblePreviewSelection( sal_uInt16 nSelPage
)
511 GetAccessibleMap().InvalidatePreviewSelection( nSelPage
);
514 SwAccessibleMap
*SwViewShellImp::CreateAccessibleMap()
516 assert(!m_pAccessibleMap
);
517 m_pAccessibleMap
= std::make_shared
<SwAccessibleMap
>(GetShell());
518 return m_pAccessibleMap
.get();
521 void SwViewShellImp::FireAccessibleEvents()
524 GetAccessibleMap().FireEvents();
526 #endif // ENABLE_WASM_STRIP_ACCESSIBILITY
528 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */