xref: /core/sw/source/core/view/pagepreviewlayout.cxx (revision d884c4be)
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 <config_wasm_strip.h>
21 
22 #include <pagepreviewlayout.hxx>
23 #include <prevwpage.hxx>
24 
25 #include <algorithm>
26 #include <osl/diagnose.h>
27 #include <tools/fract.hxx>
28 #include <vcl/settings.hxx>
29 
30 #include <rootfrm.hxx>
31 #include <pagefrm.hxx>
32 #include <viewsh.hxx>
33 #include <viewimp.hxx>
34 #include <viewopt.hxx>
35 #include <swregion.hxx>
36 #include <strings.hrc>
37 #include <frmtool.hxx>
38 #include <sfx2/zoomitem.hxx>
39 #include <printdata.hxx>
40 #include <paintfrm.hxx>
41 
42 #include <IDocumentDeviceAccess.hxx>
43 
44 // methods to initialize page preview layout
45 
SwPagePreviewLayout(SwViewShell & _rParentViewShell,const SwRootFrame & _rLayoutRootFrame)46 SwPagePreviewLayout::SwPagePreviewLayout( SwViewShell& _rParentViewShell,
47                                           const SwRootFrame& _rLayoutRootFrame )
48     : mrParentViewShell( _rParentViewShell ),
49       mrLayoutRootFrame ( _rLayoutRootFrame )
50 {
51     Clear_();
52 
53     mbBookPreview = false;
54     mbBookPreviewModeToggled = false;
55 
56     mbPrintEmptyPages = mrParentViewShell.getIDocumentDeviceAccess().getPrintData().IsPrintEmptyPages();
57 }
58 
Clear_()59 void SwPagePreviewLayout::Clear_()
60 {
61     mbLayoutInfoValid = mbLayoutSizesValid = mbPaintInfoValid = false;
62 
63     maWinSize.setWidth( 0 );
64     maWinSize.setHeight( 0 );
65     mnCols = mnRows = 0;
66 
67     ClearPreviewLayoutSizes();
68 
69     mbDoesLayoutRowsFitIntoWindow = false;
70     mbDoesLayoutColsFitIntoWindow = false;
71 
72     mnPaintPhyStartPageNum = 0;
73     mnPaintStartCol = mnPaintStartRow = 0;
74     mbNoPageVisible = false;
75     maPaintStartPageOffset.setX( 0 );
76     maPaintStartPageOffset.setY( 0 );
77     maPaintPreviewDocOffset.setX( 0 );
78     maPaintPreviewDocOffset.setY( 0 );
79     maAdditionalPaintOffset.setX( 0 );
80     maAdditionalPaintOffset.setY( 0 );
81     maPaintedPreviewDocRect.SetLeft( 0 );
82     maPaintedPreviewDocRect.SetTop( 0 );
83     maPaintedPreviewDocRect.SetRight( 0 );
84     maPaintedPreviewDocRect.SetBottom( 0 );
85     mnSelectedPageNum = 0;
86     ClearPreviewPageData();
87 
88     mbInPaint = false;
89     mbNewLayoutDuringPaint = false;
90 }
91 
ClearPreviewLayoutSizes()92 void SwPagePreviewLayout::ClearPreviewLayoutSizes()
93 {
94     mnPages = 0;
95 
96     maMaxPageSize.setWidth( 0 );
97     maMaxPageSize.setHeight( 0 );
98     maPreviewDocRect.SetLeft( 0 );
99     maPreviewDocRect.SetTop( 0 );
100     maPreviewDocRect.SetRight( 0 );
101     maPreviewDocRect.SetBottom( 0 );
102     mnColWidth = mnRowHeight = 0;
103     mnPreviewLayoutWidth = mnPreviewLayoutHeight = 0;
104 }
105 
ClearPreviewPageData()106 void SwPagePreviewLayout::ClearPreviewPageData()
107 {
108     maPreviewPages.clear();
109 }
110 
111 /** calculate page preview layout sizes
112 
113 */
CalcPreviewLayoutSizes()114 void SwPagePreviewLayout::CalcPreviewLayoutSizes()
115 {
116     vcl::RenderContext* pRenderContext = mrParentViewShell.GetOut();
117     // calculate maximal page size; calculate also number of pages
118 
119     const SwPageFrame* pPage = static_cast<const SwPageFrame*>(mrLayoutRootFrame.Lower());
120     while ( pPage )
121     {
122         if ( !mbBookPreview && !mbPrintEmptyPages && pPage->IsEmptyPage() )
123         {
124             pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
125             continue;
126         }
127 
128         ++mnPages;
129         pPage->Calc(pRenderContext);
130         const Size& rPageSize = pPage->getFrameArea().SSize();
131         if ( rPageSize.Width() > maMaxPageSize.Width() )
132             maMaxPageSize.setWidth( rPageSize.Width() );
133         if ( rPageSize.Height() > maMaxPageSize.Height() )
134             maMaxPageSize.setHeight( rPageSize.Height() );
135         pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
136     }
137     // calculate and set column width and row height
138     mnColWidth = maMaxPageSize.Width() + gnXFree;
139     mnRowHeight = maMaxPageSize.Height() + gnYFree;
140 
141     // calculate and set preview layout width and height
142     mnPreviewLayoutWidth = mnCols * mnColWidth + gnXFree;
143     mnPreviewLayoutHeight = mnRows * mnRowHeight + gnYFree;
144 
145     // calculate document rectangle in preview layout
146     {
147         Size aDocSize;
148         // document width
149         aDocSize.setWidth( mnPreviewLayoutWidth );
150 
151         // document height
152         // determine number of rows needed for <nPages> in preview layout
153         // use method <GetRowOfPage(..)>.
154         const sal_uInt16 nDocRows = GetRowOfPage( mnPages );
155         aDocSize.setHeight( nDocRows * maMaxPageSize.Height() +
156                             (nDocRows+1) * gnYFree );
157         maPreviewDocRect.SetPos( Point( 0, 0 ) );
158         maPreviewDocRect.SetSize( aDocSize );
159     }
160 }
161 
162 /** init page preview layout
163 
164     initialize the page preview settings for a given layout.
165 
166     side effects:
167     (1) If parameter <_bCalcScale> is true, mapping mode with calculated
168     scaling is set at the output device and the zoom at the view options of
169     the given view shell is set with the calculated scaling.
170 */
Init(const sal_uInt16 _nCols,const sal_uInt16 _nRows,const Size & _rPxWinSize)171 void SwPagePreviewLayout::Init( const sal_uInt16 _nCols,
172                                 const sal_uInt16 _nRows,
173                                 const Size&      _rPxWinSize
174                               )
175 {
176     // check environment and parameters
177     {
178         bool bColsRowsValid = (_nCols != 0) && (_nRows != 0);
179         OSL_ENSURE( bColsRowsValid, "preview layout parameters not correct - preview layout can *not* be initialized" );
180         if ( !bColsRowsValid )
181             return;
182 
183         bool bPxWinSizeValid = (_rPxWinSize.Width() >= 0) &&
184                                (_rPxWinSize.Height() >= 0);
185         OSL_ENSURE( bPxWinSizeValid, "no window size - preview layout can *not* be initialized" );
186         if ( !bPxWinSizeValid )
187             return;
188     }
189 
190     // environment and parameters ok
191 
192     // clear existing preview settings
193     Clear_();
194 
195     // set layout information columns and rows
196     mnCols = _nCols;
197     mnRows = _nRows;
198 
199     CalcPreviewLayoutSizes();
200 
201     // validate layout information
202     mbLayoutInfoValid = true;
203 
204     // calculate scaling
205     MapMode aMapMode( MapUnit::MapTwip );
206     Size aWinSize = mrParentViewShell.GetOut()->PixelToLogic( _rPxWinSize, aMapMode );
207     Fraction aXScale( aWinSize.Width(), mnPreviewLayoutWidth );
208     Fraction aYScale( aWinSize.Height(), mnPreviewLayoutHeight );
209     if( aXScale < aYScale )
210         aYScale = aXScale;
211     {
212         // adjust scaling for Drawing layer.
213         aYScale *= Fraction( 1000, 1 );
214         tools::Long nNewNuminator = aYScale.operator long();
215         if( nNewNuminator < 1 )
216             nNewNuminator = 1;
217         aYScale = Fraction( nNewNuminator, 1000 );
218         // propagate scaling as zoom percentage to view options for font cache
219         ApplyNewZoomAtViewShell( static_cast<sal_uInt8>(nNewNuminator/10) );
220 
221         aMapMode.SetScaleY( aYScale );
222         aMapMode.SetScaleX( aYScale );
223         // set created mapping mode with calculated scaling at output device.
224         mrParentViewShell.GetOut()->SetMapMode( aMapMode );
225         // update statics for paint.
226         ::SwCalcPixStatics( mrParentViewShell.GetOut() );
227     }
228 
229     // set window size in twips
230     maWinSize = mrParentViewShell.GetOut()->PixelToLogic( _rPxWinSize );
231     // validate layout sizes
232     mbLayoutSizesValid = true;
233 }
234 
235 /** apply new zoom at given view shell */
ApplyNewZoomAtViewShell(sal_uInt8 _aNewZoom)236 void SwPagePreviewLayout::ApplyNewZoomAtViewShell( sal_uInt8 _aNewZoom )
237 {
238     SwViewOption aNewViewOptions = *(mrParentViewShell.GetViewOptions());
239     if ( aNewViewOptions.GetZoom() != _aNewZoom )
240     {
241         aNewViewOptions.SetZoom( _aNewZoom );
242         //#i19975# - consider zoom type.
243         aNewViewOptions.SetZoomType( SvxZoomType::PERCENT );
244         mrParentViewShell.ApplyViewOptions( aNewViewOptions );
245     }
246 }
247 
248 /** method to adjust page preview layout to document changes
249 
250 */
ReInit()251 void SwPagePreviewLayout::ReInit()
252 {
253     // check environment and parameters
254     {
255         bool bLayoutSettingsValid = mbLayoutInfoValid && mbLayoutSizesValid;
256         OSL_ENSURE( bLayoutSettingsValid,
257                 "no valid preview layout info/sizes - no re-init of page preview layout");
258         if ( !bLayoutSettingsValid )
259             return;
260     }
261 
262     ClearPreviewLayoutSizes();
263     CalcPreviewLayoutSizes();
264 }
265 
266 // methods to prepare paint of page preview
267 
268 /** prepare paint of page preview
269 
270     delete parameter _onStartPageVirtNum
271 
272     @note _nProposedStartPageNum, _onStartPageNum are absolute
273 */
Prepare(const sal_uInt16 _nProposedStartPageNum,const Point & rProposedStartPos,const Size & _rPxWinSize,sal_uInt16 & _onStartPageNum,tools::Rectangle & _orDocPreviewPaintRect,const bool _bStartWithPageAtFirstCol)274 bool SwPagePreviewLayout::Prepare( const sal_uInt16 _nProposedStartPageNum,
275                                    const Point&      rProposedStartPos,
276                                    const Size&      _rPxWinSize,
277                                    sal_uInt16&      _onStartPageNum,
278                                    tools::Rectangle&       _orDocPreviewPaintRect,
279                                    const bool       _bStartWithPageAtFirstCol
280                                  )
281 {
282     sal_uInt16 nProposedStartPageNum = ConvertAbsoluteToRelativePageNum( _nProposedStartPageNum );
283     // check environment and parameters
284     {
285         bool bLayoutSettingsValid = mbLayoutInfoValid && mbLayoutSizesValid;
286         OSL_ENSURE( bLayoutSettingsValid,
287                 "no valid preview layout info/sizes - no prepare of preview paint");
288         if ( !bLayoutSettingsValid )
289             return false;
290 
291         bool bStartPageRangeValid = nProposedStartPageNum <= mnPages;
292         OSL_ENSURE( bStartPageRangeValid,
293                 "proposed start page not existing - no prepare of preview paint");
294         if ( !bStartPageRangeValid )
295             return false;
296 
297         bool bStartPosRangeValid =
298                 rProposedStartPos.X() >= 0 && rProposedStartPos.Y() >= 0 &&
299                 rProposedStartPos.X() <= maPreviewDocRect.Right() &&
300                 rProposedStartPos.Y() <= maPreviewDocRect.Bottom();
301         OSL_ENSURE( bStartPosRangeValid,
302                 "proposed start position out of range - no prepare of preview paint");
303         if ( !bStartPosRangeValid )
304             return false;
305 
306         bool bWinSizeValid = !_rPxWinSize.IsEmpty();
307         OSL_ENSURE( bWinSizeValid, "no window size - no prepare of preview paint");
308         if ( !bWinSizeValid )
309             return false;
310 
311         bool bStartInfoValid = _nProposedStartPageNum > 0 ||
312                                rProposedStartPos != Point(0,0);
313         if ( !bStartInfoValid )
314             nProposedStartPageNum = 1;
315     }
316 
317     // environment and parameter ok
318 
319     // update window size at preview setting data
320     maWinSize = mrParentViewShell.GetOut()->PixelToLogic( _rPxWinSize );
321 
322     mbNoPageVisible = false;
323     if ( nProposedStartPageNum > 0 )
324     {
325         // determine column and row of proposed start page in virtual preview layout
326         const sal_uInt16 nColOfProposed = GetColOfPage( nProposedStartPageNum );
327         const sal_uInt16 nRowOfProposed = GetRowOfPage( nProposedStartPageNum );
328         // determine start page
329         if ( _bStartWithPageAtFirstCol )
330         {
331             // leaving left-top-corner blank is
332             // controlled by <mbBookPreview>.
333             if ( mbBookPreview &&
334                  ( nProposedStartPageNum == 1 || nRowOfProposed == 1 )
335                )
336                 mnPaintPhyStartPageNum = 1;
337             else
338                 mnPaintPhyStartPageNum = nProposedStartPageNum - (nColOfProposed-1);
339         }
340         else
341             mnPaintPhyStartPageNum = nProposedStartPageNum;
342 
343         mnPaintPhyStartPageNum = ConvertRelativeToAbsolutePageNum( mnPaintPhyStartPageNum );
344 
345         // set starting column
346         if ( _bStartWithPageAtFirstCol )
347             mnPaintStartCol = 1;
348         else
349             mnPaintStartCol = nColOfProposed;
350         // set starting row
351         mnPaintStartRow = nRowOfProposed;
352         // page offset == (-1,-1), indicating no offset and paint of free space.
353         maPaintStartPageOffset.setX( -1 );
354         maPaintStartPageOffset.setY( -1 );
355         // virtual preview document offset.
356         if ( _bStartWithPageAtFirstCol )
357             maPaintPreviewDocOffset.setX( 0 );
358         else
359             maPaintPreviewDocOffset.setX( (nColOfProposed-1) * mnColWidth );
360         maPaintPreviewDocOffset.setY( (nRowOfProposed-1) * mnRowHeight );
361     }
362     else
363     {
364         // determine column and row of proposed start position.
365         // Note: paint starts at point (0,0)
366         const sal_uInt16 nColOfProposed =
367                 o3tl::narrowing<sal_uInt16>(rProposedStartPos.X() / mnColWidth) + 1;
368         const sal_uInt16 nRowOfProposed =
369                 o3tl::narrowing<sal_uInt16>(rProposedStartPos.Y() / mnRowHeight) + 1;
370         // determine start page == page at proposed start position
371         // leaving left-top-corner blank is
372         // controlled by <mbBookPreview>.
373         if ( mbBookPreview &&
374              ( nRowOfProposed == 1 && nColOfProposed == 1 )
375            )
376             mnPaintPhyStartPageNum = 1;
377         else
378         {
379             // leaving left-top-corner blank is
380             // controlled by <mbBookPreview>.
381             mnPaintPhyStartPageNum = (nRowOfProposed-1) * mnCols + nColOfProposed;
382             if ( mbBookPreview )
383                 --mnPaintPhyStartPageNum;
384             if ( mnPaintPhyStartPageNum > mnPages )
385             {
386                 // no page will be visible, because shown part of document
387                 // preview is the last row to the right of the last page
388                 mnPaintPhyStartPageNum = mnPages;
389                 mbNoPageVisible = true;
390             }
391         }
392         // set starting column and starting row
393         mnPaintStartCol = nColOfProposed;
394         mnPaintStartRow = nRowOfProposed;
395         // page offset
396         maPaintStartPageOffset.setX(
397                 (rProposedStartPos.X() % mnColWidth) - gnXFree );
398         maPaintStartPageOffset.setY(
399                 (rProposedStartPos.Y() % mnRowHeight) - gnYFree );
400         // virtual preview document offset.
401         maPaintPreviewDocOffset = rProposedStartPos;
402     }
403 
404     // determine additional paint offset, if preview layout fits into window.
405     CalcAdditionalPaintOffset();
406 
407     // determine rectangle to be painted from document preview
408     CalcDocPreviewPaintRect();
409     _orDocPreviewPaintRect = maPaintedPreviewDocRect;
410 
411     // shift visible preview document area to the left,
412     // if on the right is an area left blank.
413     if ( !mbDoesLayoutColsFitIntoWindow &&
414          maPaintedPreviewDocRect.GetWidth() < maWinSize.Width() )
415     {
416         maPaintedPreviewDocRect.Move(
417                 -(maWinSize.Width() - maPaintedPreviewDocRect.GetWidth()), 0 );
418         Prepare( 0, maPaintedPreviewDocRect.TopLeft(),
419                  _rPxWinSize, _onStartPageNum,
420                  _orDocPreviewPaintRect, _bStartWithPageAtFirstCol );
421     }
422 
423     // shift visible preview document area to the top,
424     // if on the bottom is an area left blank.
425     if ( mbBookPreviewModeToggled &&
426          maPaintedPreviewDocRect.Bottom() == maPreviewDocRect.Bottom() &&
427          maPaintedPreviewDocRect.GetHeight() < maWinSize.Height() )
428     {
429         if ( mbDoesLayoutRowsFitIntoWindow )
430         {
431             if ( maPaintedPreviewDocRect.GetHeight() < mnPreviewLayoutHeight)
432             {
433                 maPaintedPreviewDocRect.Move(
434                         0, -(mnPreviewLayoutHeight - maPaintedPreviewDocRect.GetHeight()) );
435                 Prepare( 0, maPaintedPreviewDocRect.TopLeft(),
436                          _rPxWinSize, _onStartPageNum,
437                          _orDocPreviewPaintRect, _bStartWithPageAtFirstCol );
438             }
439         }
440         else
441         {
442             maPaintedPreviewDocRect.Move(
443                     0, -(maWinSize.Height() - maPaintedPreviewDocRect.GetHeight()) );
444             Prepare( 0, maPaintedPreviewDocRect.TopLeft(),
445                      _rPxWinSize, _onStartPageNum,
446                      _orDocPreviewPaintRect, _bStartWithPageAtFirstCol );
447         }
448     }
449 
450     // determine preview pages - visible pages with needed data for paint and
451     // accessible pages with needed data.
452     CalcPreviewPages();
453 
454     // OD 07.11.2003 #i22014# - indicate new layout, if print preview is in paint
455     if ( mbInPaint )
456     {
457         mbNewLayoutDuringPaint = true;
458     }
459 
460     // validate paint data
461     mbPaintInfoValid = true;
462 
463     // return start page
464     _onStartPageNum = mnPaintPhyStartPageNum;
465 
466     return true;
467 }
468 
469 /** calculate additional paint offset
470 
471 */
CalcAdditionalPaintOffset()472 void SwPagePreviewLayout::CalcAdditionalPaintOffset()
473 {
474     if ( mnPreviewLayoutWidth <= maWinSize.Width() &&
475          maPaintStartPageOffset.X() <= 0 )
476     {
477         mbDoesLayoutColsFitIntoWindow = true;
478         maAdditionalPaintOffset.setX( (maWinSize.Width() - mnPreviewLayoutWidth) / 2 );
479     }
480     else
481     {
482         mbDoesLayoutColsFitIntoWindow = false;
483         maAdditionalPaintOffset.setX( 0 );
484     }
485 
486     if ( mnPreviewLayoutHeight <= maWinSize.Height() &&
487          maPaintStartPageOffset.Y() <= 0 )
488     {
489         mbDoesLayoutRowsFitIntoWindow = true;
490         maAdditionalPaintOffset.setY( (maWinSize.Height() - mnPreviewLayoutHeight) / 2 );
491     }
492     else
493     {
494         mbDoesLayoutRowsFitIntoWindow = false;
495         maAdditionalPaintOffset.setY( 0 );
496     }
497 }
498 
499 /** calculate painted preview document rectangle
500 
501 */
CalcDocPreviewPaintRect()502 void SwPagePreviewLayout::CalcDocPreviewPaintRect()
503 {
504     Point aTopLeftPos = maPaintPreviewDocOffset;
505     maPaintedPreviewDocRect.SetPos( aTopLeftPos );
506 
507     Size aSize;
508     if ( mbDoesLayoutColsFitIntoWindow )
509         aSize.setWidth( std::min( tools::Long(mnPreviewLayoutWidth),
510                              maPreviewDocRect.GetWidth() - aTopLeftPos.X() ) );
511     else
512         aSize.setWidth( std::min( maPreviewDocRect.GetWidth() - aTopLeftPos.X(),
513                              maWinSize.Width() - maAdditionalPaintOffset.X() ) );
514     if ( mbDoesLayoutRowsFitIntoWindow )
515         aSize.setHeight( std::min( tools::Long(mnPreviewLayoutHeight),
516                               maPreviewDocRect.GetHeight() - aTopLeftPos.Y() ) );
517     else
518         aSize.setHeight( std::min( maPreviewDocRect.GetHeight() - aTopLeftPos.Y(),
519                               maWinSize.Height() - maAdditionalPaintOffset.Y() ) );
520     maPaintedPreviewDocRect.SetSize( aSize );
521 }
522 
523 /** calculate preview pages
524 
525 */
CalcPreviewPages()526 void SwPagePreviewLayout::CalcPreviewPages()
527 {
528     vcl::RenderContext* pRenderContext = mrParentViewShell.GetOut();
529     ClearPreviewPageData();
530 
531     if ( mbNoPageVisible )
532         return;
533 
534     // determine start page frame
535     const SwPageFrame* pStartPage = mrLayoutRootFrame.GetPageByPageNum( mnPaintPhyStartPageNum );
536 
537     // calculate initial paint offset
538     Point aInitialPaintOffset;
539     /// check whether RTL interface or not
540     if(!AllSettings::GetLayoutRTL()){
541         if ( maPaintStartPageOffset != Point( -1, -1 ) )
542             aInitialPaintOffset = Point(0,0) - maPaintStartPageOffset;
543         else
544             aInitialPaintOffset = Point( gnXFree, gnYFree );
545     }
546     else {
547         if ( maPaintStartPageOffset != Point( -1, -1 ) )
548             aInitialPaintOffset = Point(0 + ((SwPagePreviewLayout::mnCols-1)*mnColWidth),0) - maPaintStartPageOffset;
549         else
550             aInitialPaintOffset = Point( gnXFree + ((SwPagePreviewLayout::mnCols-1)*mnColWidth), gnYFree );
551     }
552     aInitialPaintOffset += maAdditionalPaintOffset;
553 
554     // prepare loop data
555     const SwPageFrame* pPage = pStartPage;
556     sal_uInt16 nCurrCol = mnPaintStartCol;
557     sal_uInt16 nConsideredRows = 0;
558     Point aCurrPaintOffset = aInitialPaintOffset;
559     // loop on pages to determine preview background rectangles
560     while ( pPage &&
561             (!mbDoesLayoutRowsFitIntoWindow || nConsideredRows < mnRows) &&
562             aCurrPaintOffset.Y() < maWinSize.Height()
563           )
564     {
565         if ( !mbBookPreview && !mbPrintEmptyPages && pPage->IsEmptyPage() )
566         {
567             pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
568             continue;
569         }
570 
571         pPage->Calc(pRenderContext);
572 
573         // consider only pages, which have to be painted.
574         if ( nCurrCol < mnPaintStartCol )
575         {
576             // calculate data of unvisible page needed for accessibility
577             std::unique_ptr<PreviewPage> pPreviewPage(new PreviewPage);
578             Point aCurrAccOffset = aCurrPaintOffset -
579                            Point( (mnPaintStartCol-nCurrCol) * mnColWidth, 0 );
580             CalcPreviewDataForPage( *pPage, aCurrAccOffset, pPreviewPage.get() );
581             pPreviewPage->bVisible = false;
582             maPreviewPages.push_back( std::move(pPreviewPage) );
583             // continue with next page and next column
584             pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
585             ++nCurrCol;
586             continue;
587         }
588         if ( aCurrPaintOffset.X() < maWinSize.Width() )
589         {
590             // leaving left-top-corner blank is
591             // controlled by <mbBookPreview>.
592             if ( mbBookPreview && pPage->GetPhyPageNum() == 1 && mnCols != 1 && nCurrCol == 1
593                )
594             {
595                 // first page in 2nd column
596                 // --> continue with increased paint offset and next column
597                 /// check whether RTL interface or not
598                 if(!AllSettings::GetLayoutRTL())
599                     aCurrPaintOffset.AdjustX(mnColWidth );
600                 else aCurrPaintOffset.AdjustX( -mnColWidth );
601                 ++nCurrCol;
602                 continue;
603             }
604 
605             // calculate data of visible page
606             std::unique_ptr<PreviewPage> pPreviewPage(new PreviewPage);
607             CalcPreviewDataForPage( *pPage, aCurrPaintOffset, pPreviewPage.get() );
608             pPreviewPage->bVisible = true;
609             maPreviewPages.push_back( std::move(pPreviewPage) );
610         }
611         else
612         {
613             // calculate data of unvisible page needed for accessibility
614             std::unique_ptr<PreviewPage> pPreviewPage(new PreviewPage);
615             CalcPreviewDataForPage( *pPage, aCurrPaintOffset, pPreviewPage.get() );
616             pPreviewPage->bVisible = false;
617             maPreviewPages.push_back( std::move(pPreviewPage) );
618         }
619 
620         // prepare data for next loop
621         pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
622 
623         /// check whether RTL interface or not
624         if(!AllSettings::GetLayoutRTL())
625             aCurrPaintOffset.AdjustX(mnColWidth );
626         else aCurrPaintOffset.AdjustX( -mnColWidth );
627         ++nCurrCol;
628         if ( nCurrCol > mnCols )
629         {
630             ++nConsideredRows;
631             aCurrPaintOffset.setX( aInitialPaintOffset.X() );
632             nCurrCol = 1;
633             aCurrPaintOffset.AdjustY(mnRowHeight );
634         }
635     }
636 }
637 
638 /** determines preview data for a given page and a given preview offset
639 
640     OD 13.12.2002 #103492#
641 */
CalcPreviewDataForPage(const SwPageFrame & _rPage,const Point & _rPreviewOffset,PreviewPage * _opPreviewPage)642 void SwPagePreviewLayout::CalcPreviewDataForPage( const SwPageFrame& _rPage,
643                                                    const Point& _rPreviewOffset,
644                                                    PreviewPage* _opPreviewPage )
645 {
646     // page frame
647     _opPreviewPage->pPage = &_rPage;
648     // size of page frame
649     if ( _rPage.IsEmptyPage() )
650     {
651         if ( _rPage.GetPhyPageNum() % 2 == 0 )
652             _opPreviewPage->aPageSize = _rPage.GetPrev()->getFrameArea().SSize();
653         else
654             _opPreviewPage->aPageSize = _rPage.GetNext()->getFrameArea().SSize();
655     }
656     else
657         _opPreviewPage->aPageSize = _rPage.getFrameArea().SSize();
658     // position of page in preview window
659     Point aPreviewWinOffset( _rPreviewOffset );
660     if ( _opPreviewPage->aPageSize.Width() < maMaxPageSize.Width() )
661         aPreviewWinOffset.AdjustX(( maMaxPageSize.Width() - _opPreviewPage->aPageSize.Width() ) / 2 );
662     if ( _opPreviewPage->aPageSize.Height() < maMaxPageSize.Height() )
663         aPreviewWinOffset.AdjustY(( maMaxPageSize.Height() - _opPreviewPage->aPageSize.Height() ) / 2 );
664     _opPreviewPage->aPreviewWinPos = aPreviewWinOffset;
665     // logic position of page and mapping offset for paint
666     if ( _rPage.IsEmptyPage() )
667     {
668         _opPreviewPage->aLogicPos = _opPreviewPage->aPreviewWinPos;
669         _opPreviewPage->aMapOffset = Point( 0, 0 );
670     }
671     else
672     {
673         _opPreviewPage->aLogicPos = _rPage.getFrameArea().Pos();
674         _opPreviewPage->aMapOffset = _opPreviewPage->aPreviewWinPos - _opPreviewPage->aLogicPos;
675     }
676 }
677 
678 /** enable/disable book preview
679 
680     OD 2004-03-04 #i18143#
681 */
SetBookPreviewMode(const bool _bEnableBookPreview,sal_uInt16 & _onStartPageNum,tools::Rectangle & _orDocPreviewPaintRect)682 bool SwPagePreviewLayout::SetBookPreviewMode( const bool _bEnableBookPreview,
683                                               sal_uInt16& _onStartPageNum,
684                                               tools::Rectangle&  _orDocPreviewPaintRect )
685 {
686     if ( mbBookPreview != _bEnableBookPreview)
687     {
688         mbBookPreview = _bEnableBookPreview;
689         // re-initialize page preview layout
690         ReInit();
691         // re-prepare page preview layout
692         {
693             mbBookPreviewModeToggled = true;
694             Point aProposedStartPos( maPaintPreviewDocOffset );
695             // if proposed start position is below virtual preview document
696             // bottom, adjust it to the virtual preview document bottom
697             if ( aProposedStartPos.Y() > maPreviewDocRect.Bottom() )
698             {
699                 aProposedStartPos.setY( maPreviewDocRect.Bottom() );
700             }
701             Prepare( 0, aProposedStartPos,
702                      mrParentViewShell.GetOut()->LogicToPixel( maWinSize ),
703                      _onStartPageNum, _orDocPreviewPaintRect );
704             mbBookPreviewModeToggled = false;
705         }
706 
707         return true;
708     }
709 
710     return false;
711 }
712 
713 // methods to determine new data for changing the current shown part of the
714 // document preview.
715 
716 /** calculate start position for new scale
717 
718 */
GetPreviewStartPosForNewScale(const Fraction & _aNewScale,const Fraction & _aOldScale,const Size & _aNewWinSize) const719 Point SwPagePreviewLayout::GetPreviewStartPosForNewScale(
720                           const Fraction& _aNewScale,
721                           const Fraction& _aOldScale,
722                           const Size&     _aNewWinSize ) const
723 {
724     Point aNewPaintStartPos = maPaintedPreviewDocRect.TopLeft();
725     if ( _aNewScale < _aOldScale )
726     {
727         // increase paint width by moving start point to left.
728         if ( mnPreviewLayoutWidth < _aNewWinSize.Width() )
729             aNewPaintStartPos.setX( 0 );
730         else if ( maPaintedPreviewDocRect.GetWidth() < _aNewWinSize.Width() )
731         {
732             aNewPaintStartPos.AdjustX( -(
733                 (_aNewWinSize.Width() - maPaintedPreviewDocRect.GetWidth()) / 2) );
734             if ( aNewPaintStartPos.X() < 0)
735                 aNewPaintStartPos.setX( 0 );
736         }
737 
738         if ( !mbDoesLayoutRowsFitIntoWindow )
739         {
740             // increase paint height by moving start point to top.
741             if ( mnPreviewLayoutHeight < _aNewWinSize.Height() )
742             {
743                 aNewPaintStartPos.setY(
744                     (mnPaintStartRow - 1) * mnRowHeight );
745             }
746             else if ( maPaintedPreviewDocRect.GetHeight() < _aNewWinSize.Height() )
747             {
748                 aNewPaintStartPos.AdjustY( -(
749                     (_aNewWinSize.Height() - maPaintedPreviewDocRect.GetHeight()) / 2) );
750                 if ( aNewPaintStartPos.Y() < 0)
751                     aNewPaintStartPos.setY( 0 );
752             }
753         }
754     }
755     else
756     {
757         // decrease paint width by moving start point to right
758         if ( maPaintedPreviewDocRect.GetWidth() > _aNewWinSize.Width() )
759             aNewPaintStartPos.AdjustX(
760                 (maPaintedPreviewDocRect.GetWidth() - _aNewWinSize.Width()) / 2 );
761         // decrease paint height by moving start point to bottom
762         if ( maPaintedPreviewDocRect.GetHeight() > _aNewWinSize.Height() )
763         {
764             aNewPaintStartPos.AdjustY(
765                 (maPaintedPreviewDocRect.GetHeight() - _aNewWinSize.Height()) / 2 );
766             // check, if new y-position is outside document preview
767             if ( aNewPaintStartPos.Y() > maPreviewDocRect.Bottom() )
768                 aNewPaintStartPos.setY(
769                         std::max( tools::Long(0), maPreviewDocRect.Bottom() - mnPreviewLayoutHeight ) );
770         }
771     }
772 
773     return aNewPaintStartPos;
774 }
775 
776 /** determines, if page with given page number is visible in preview
777 
778     @note _nPageNum is absolute
779 */
IsPageVisible(const sal_uInt16 _nPageNum) const780 bool SwPagePreviewLayout::IsPageVisible( const sal_uInt16 _nPageNum ) const
781 {
782     const PreviewPage* pPreviewPage = GetPreviewPageByPageNum( _nPageNum );
783     return pPreviewPage && pPreviewPage->bVisible;
784 }
785 
786 /** calculate data to bring new selected page into view.
787 
788     @note IN/OUT parameters are absolute page numbers!!!
789 */
CalcStartValuesForSelectedPageMove(const sal_Int16 _nHoriMove,const sal_Int16 _nVertMove,sal_uInt16 & _orNewSelectedPage,sal_uInt16 & _orNewStartPage,Point & _orNewStartPos) const790 void SwPagePreviewLayout::CalcStartValuesForSelectedPageMove(
791                                 const sal_Int16  _nHoriMove,
792                                 const sal_Int16  _nVertMove,
793                                 sal_uInt16&      _orNewSelectedPage,
794                                 sal_uInt16&      _orNewStartPage,
795                                 Point&           _orNewStartPos ) const
796 {
797     // determine position of current selected page
798     sal_uInt16 nTmpRelSelPageNum = ConvertAbsoluteToRelativePageNum( mnSelectedPageNum );
799     sal_uInt16 nNewRelSelectedPageNum = nTmpRelSelPageNum;
800 
801     const sal_uInt16 nCurrRow = GetRowOfPage(nTmpRelSelPageNum);
802 
803     // determine new selected page number
804     {
805         if ( _nHoriMove != 0 )
806         {
807             if ( (nNewRelSelectedPageNum + _nHoriMove) < 1 )
808                 nNewRelSelectedPageNum = 1;
809             else if ( (nNewRelSelectedPageNum + _nHoriMove) > mnPages )
810                 nNewRelSelectedPageNum = mnPages;
811             else
812                 nNewRelSelectedPageNum = nNewRelSelectedPageNum + _nHoriMove;
813         }
814         if ( _nVertMove != 0 )
815         {
816             if ( (nNewRelSelectedPageNum + (_nVertMove * mnCols)) < 1 )
817                 nNewRelSelectedPageNum = 1;
818             else if ( (nNewRelSelectedPageNum + (_nVertMove * mnCols)) > mnPages )
819                 nNewRelSelectedPageNum = mnPages;
820             else
821                 nNewRelSelectedPageNum += ( _nVertMove * mnCols );
822         }
823     }
824 
825     sal_uInt16 nNewStartPage = mnPaintPhyStartPageNum;
826     Point aNewStartPos(0,0);
827 
828     const sal_uInt16 nNewAbsSelectedPageNum = ConvertRelativeToAbsolutePageNum( nNewRelSelectedPageNum );
829     if ( !IsPageVisible( nNewAbsSelectedPageNum ) )
830     {
831         if ( _nHoriMove != 0 && _nVertMove != 0 )
832         {
833             OSL_FAIL( "missing implementation for moving preview selected page horizontal AND vertical");
834             return;
835         }
836 
837         // new selected page has to be brought into view considering current
838         // visible preview.
839         const sal_uInt16 nTotalRows = GetRowOfPage( mnPages );
840         if ( (_nHoriMove > 0 || _nVertMove > 0) &&
841              mbDoesLayoutRowsFitIntoWindow &&
842              mbDoesLayoutColsFitIntoWindow &&
843              nCurrRow > nTotalRows - mnRows )
844         {
845             // new proposed start page = left-top-corner of last possible
846             // preview page.
847             nNewStartPage = (nTotalRows - mnRows) * mnCols + 1;
848             // leaving left-top-corner blank is controlled
849             // by <mbBookPreview>.
850             if ( mbBookPreview )
851             {
852                 // Note: decrease new proposed start page number by one,
853                 // because of blank left-top-corner
854                 --nNewStartPage;
855             }
856             nNewStartPage = ConvertRelativeToAbsolutePageNum( nNewStartPage );
857         }
858         else
859         {
860             // new proposed start page = new selected page.
861             nNewStartPage = ConvertRelativeToAbsolutePageNum( nNewRelSelectedPageNum );
862         }
863     }
864 
865     _orNewSelectedPage = nNewAbsSelectedPageNum;
866     _orNewStartPage = nNewStartPage;
867     _orNewStartPos = aNewStartPos;
868 }
869 
870 namespace {
871 
872 /** checks, if given position is inside a shown document page */
873 struct PreviewPosInsidePagePred
874 {
875     const Point mnPreviewPos;
PreviewPosInsidePagePred__anon519dd74e0111::PreviewPosInsidePagePred876     explicit PreviewPosInsidePagePred(const Point& rPreviewPos)
877         : mnPreviewPos( rPreviewPos )
878     {}
operator ()__anon519dd74e0111::PreviewPosInsidePagePred879     bool operator() ( const std::unique_ptr<PreviewPage> & _pPreviewPage )
880     {
881         if ( _pPreviewPage->bVisible )
882         {
883             tools::Rectangle aPreviewPageRect( _pPreviewPage->aPreviewWinPos, _pPreviewPage->aPageSize );
884             return aPreviewPageRect.Contains( mnPreviewPos );
885         }
886         return false;
887     }
888 };
889 
890 }
891 
IsPreviewPosInDocPreviewPage(const Point & rPreviewPos,Point & _orDocPos,bool & _obPosInEmptyPage,sal_uInt16 & _onPageNum) const892 bool SwPagePreviewLayout::IsPreviewPosInDocPreviewPage( const Point&  rPreviewPos,
893                                                     Point&       _orDocPos,
894                                                     bool&        _obPosInEmptyPage,
895                                                     sal_uInt16&  _onPageNum ) const
896 {
897     // initialize variable parameter values.
898     _orDocPos.setX( 0 );
899     _orDocPos.setY( 0 );
900     _obPosInEmptyPage = false;
901     _onPageNum = 0;
902 
903     auto aFoundPreviewPageIter =
904             std::find_if( maPreviewPages.begin(), maPreviewPages.end(),
905                           PreviewPosInsidePagePred( rPreviewPos ) );
906 
907     if ( aFoundPreviewPageIter != maPreviewPages.end() )
908     {
909         // given preview position is inside a document page.
910         _onPageNum = (*aFoundPreviewPageIter)->pPage->GetPhyPageNum();
911         _obPosInEmptyPage = (*aFoundPreviewPageIter)->pPage->IsEmptyPage();
912         if ( !_obPosInEmptyPage )
913         {
914             // given preview position inside a normal page
915             _orDocPos = rPreviewPos -
916                         (*aFoundPreviewPageIter)->aPreviewWinPos +
917                         (*aFoundPreviewPageIter)->aLogicPos;
918             return true;
919         }
920     }
921 
922     return false;
923 }
924 
925 /** determine window page scroll amount */
GetWinPagesScrollAmount(const sal_Int16 _nWinPagesToScroll) const926 SwTwips SwPagePreviewLayout::GetWinPagesScrollAmount(
927                                 const sal_Int16 _nWinPagesToScroll ) const
928 {
929     SwTwips nScrollAmount;
930     if ( mbDoesLayoutRowsFitIntoWindow )
931     {
932         nScrollAmount = (mnPreviewLayoutHeight - gnYFree) * _nWinPagesToScroll;
933     }
934     else
935         nScrollAmount = _nWinPagesToScroll * maPaintedPreviewDocRect.GetHeight();
936 
937     // check, if preview layout size values are valid.
938     // If not, the checks for an adjustment of the scroll amount aren't useful.
939     if ( mbLayoutSizesValid )
940     {
941         if ( (maPaintedPreviewDocRect.Top() + nScrollAmount) <= 0 )
942             nScrollAmount = -maPaintedPreviewDocRect.Top();
943 
944         // correct scroll amount
945         if ( nScrollAmount > 0 &&
946              maPaintedPreviewDocRect.Bottom() == maPreviewDocRect.Bottom()
947            )
948         {
949             nScrollAmount = 0;
950         }
951         else
952         {
953             while ( (maPaintedPreviewDocRect.Top() + nScrollAmount + gnYFree) >= maPreviewDocRect.GetHeight() )
954             {
955                 nScrollAmount -= mnRowHeight;
956             }
957         }
958     }
959 
960     return nScrollAmount;
961 }
962 
963 // methods to paint page preview layout
964 
965 namespace
966 {
967 /// Similar to RenderContextGuard, but does not touch the draw view.
968 class PreviewRenderContextGuard
969 {
970     VclPtr<vcl::RenderContext> m_pOriginalValue;
971     SwViewShell& m_rShell;
972 
973 public:
PreviewRenderContextGuard(SwViewShell & rShell,vcl::RenderContext * pValue)974     PreviewRenderContextGuard(SwViewShell& rShell, vcl::RenderContext* pValue)
975         : m_pOriginalValue(rShell.GetOut()),
976         m_rShell(rShell)
977     {
978         m_rShell.SetOut(pValue);
979     }
980 
~PreviewRenderContextGuard()981     ~PreviewRenderContextGuard()
982     {
983         m_rShell.SetOut(m_pOriginalValue);
984     }
985 };
986 }
987 
988 /** paint prepared preview
989 
990 */
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle & rOutRect) const991 bool SwPagePreviewLayout::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rOutRect) const
992 {
993     PreviewRenderContextGuard aGuard(mrParentViewShell, &rRenderContext);
994     // check environment and parameters
995     {
996         if (!mrParentViewShell.GetWin() && !mrParentViewShell.GetOut()->GetConnectMetaFile())
997         {
998             return false;
999         }
1000 
1001         OSL_ENSURE(mbPaintInfoValid, "invalid preview settings - no paint of preview");
1002         if (!mbPaintInfoValid)
1003             return false;
1004     }
1005 
1006     // OD 17.11.2003 #i22014# - no paint, if <superfluous> flag is set at layout
1007     if (mrLayoutRootFrame.IsSuperfluous())
1008     {
1009         return true;
1010     }
1011 
1012     // environment and parameter ok
1013 
1014     if (mbInPaint)
1015     {
1016         return false;
1017     }
1018     mbInPaint = true;
1019 
1020     OutputDevice* pOutputDev = &rRenderContext;
1021 
1022     // prepare paint
1023     if ( !maPreviewPages.empty() )
1024     {
1025         mrParentViewShell.Imp()->m_bFirstPageInvalid = false;
1026         mrParentViewShell.Imp()->m_pFirstVisiblePage =
1027                 const_cast<SwPageFrame*>(maPreviewPages[0]->pPage);
1028     }
1029 
1030     // paint preview background
1031     {
1032         SwRegionRects aPreviewBackgrdRegion((SwRect(rOutRect)));
1033         // calculate preview background rectangles
1034         for ( auto & rpPreviewPage : maPreviewPages )
1035         {
1036             if ( rpPreviewPage->bVisible )
1037             {
1038                 aPreviewBackgrdRegion -=
1039                         SwRect( rpPreviewPage->aPreviewWinPos, rpPreviewPage->aPageSize );
1040             }
1041         }
1042         // paint preview background rectangles
1043         mrParentViewShell.PaintDesktop_(aPreviewBackgrdRegion);
1044     }
1045 
1046     // prepare data for paint of pages
1047     const tools::Rectangle aPxOutRect( pOutputDev->LogicToPixel(rOutRect) );
1048 
1049     MapMode aMapMode( pOutputDev->GetMapMode() );
1050     MapMode aSavedMapMode = aMapMode;
1051 
1052     const vcl::Font& rEmptyPgFont = SwPageFrame::GetEmptyPageFont();
1053 
1054     for ( auto & rpPreviewPage : maPreviewPages )
1055     {
1056         if ( !rpPreviewPage->bVisible )
1057             continue;
1058 
1059         tools::Rectangle aPageRect( rpPreviewPage->aLogicPos, rpPreviewPage->aPageSize );
1060         aMapMode.SetOrigin( rpPreviewPage->aMapOffset );
1061         pOutputDev->SetMapMode( aMapMode );
1062         tools::Rectangle aPxPaintRect = pOutputDev->LogicToPixel( aPageRect );
1063         if ( aPxOutRect.Overlaps( aPxPaintRect) )
1064         {
1065             const SwPageFrame* pPage = rpPreviewPage->pPage;
1066 
1067             if (pPage->IsEmptyPage())
1068             {
1069                 const Color aRetouche( mrParentViewShell.Imp()->GetRetoucheColor() );
1070                 if( pOutputDev->GetFillColor() != aRetouche )
1071                     pOutputDev->SetFillColor( aRetouche );
1072                 pOutputDev->SetLineColor(); // no line color
1073                 // use aligned page rectangle
1074                 {
1075                     SwRect aTmpPageRect( aPageRect );
1076                     ::SwAlignRect( aTmpPageRect, &mrParentViewShell, &rRenderContext );
1077                     aPageRect = aTmpPageRect.SVRect();
1078                 }
1079                 pOutputDev->DrawRect( aPageRect );
1080 
1081                 // paint empty page text
1082                 vcl::Font aOldFont( pOutputDev->GetFont() );
1083                 pOutputDev->SetFont( rEmptyPgFont );
1084                 pOutputDev->DrawText( aPageRect, SwResId( STR_EMPTYPAGE ),
1085                                     DrawTextFlags::VCenter |
1086                                     DrawTextFlags::Center |
1087                                     DrawTextFlags::Clip );
1088                 pOutputDev->SetFont( aOldFont );
1089                 // paint shadow and border for empty page
1090                 // use new method to paint page border and shadow
1091                 SwPageFrame::PaintBorderAndShadow( SwRect(aPageRect), &mrParentViewShell, true, false, true );
1092             }
1093             else
1094             {
1095                 const bool bIsLeftShadowed = pPage->IsLeftShadowNeeded();
1096                 const bool bIsRightShadowed = pPage->IsRightShadowNeeded();
1097 
1098                 mrParentViewShell.maVisArea = SwRect(aPageRect);
1099                 aPxPaintRect.Intersection( aPxOutRect );
1100                 tools::Rectangle aPaintRect = pOutputDev->PixelToLogic( aPxPaintRect );
1101                 mrParentViewShell.Paint(rRenderContext, aPaintRect);
1102 
1103                 // --> OD 2007-08-15 #i80691#
1104                 // paint page border and shadow
1105                 {
1106                     SwRect aPageBorderRect;
1107                     SwPageFrame::GetBorderAndShadowBoundRect( SwRect( aPageRect ), &mrParentViewShell, &rRenderContext, aPageBorderRect,
1108                         bIsLeftShadowed, bIsRightShadowed, true );
1109                     const vcl::Region aDLRegion(aPageBorderRect.SVRect());
1110                     mrParentViewShell.DLPrePaint2(aDLRegion);
1111                     SwPageFrame::PaintBorderAndShadow( SwRect(aPageRect), &mrParentViewShell, true, false, true );
1112                     mrParentViewShell.DLPostPaint2(true);
1113                 }
1114                 // <--
1115             }
1116             // OD 07.11.2003 #i22014# - stop painting, because new print
1117             // preview layout is created during paint.
1118             if ( mbNewLayoutDuringPaint )
1119             {
1120                 break;
1121             }
1122 
1123             if (pPage->GetPhyPageNum() == mnSelectedPageNum)
1124             {
1125                 PaintSelectMarkAtPage(rRenderContext, rpPreviewPage.get());
1126             }
1127         }
1128     }
1129 
1130     // OD 17.11.2003 #i22014# - no update of accessible preview, if a new
1131     // print preview layout is created during paint.
1132 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1133     if ( !mbNewLayoutDuringPaint )
1134     {
1135         // update at accessibility interface
1136         mrParentViewShell.Imp()->UpdateAccessiblePreview(
1137                         maPreviewPages,
1138                         aMapMode.GetScaleX(),
1139                         mrLayoutRootFrame.GetPageByPageNum( mnSelectedPageNum ),
1140                         maWinSize );
1141     }
1142 #endif
1143 
1144     pOutputDev->SetMapMode( aSavedMapMode );
1145     mrParentViewShell.maVisArea.Clear();
1146 
1147     // OD 07.11.2003 #i22014#
1148     mbInPaint = false;
1149     mbNewLayoutDuringPaint = false;
1150 
1151     return true;
1152 }
1153 
1154 /** repaint pages on page preview
1155 
1156     OD 18.12.2002 #103492#
1157 */
Repaint(const tools::Rectangle & rInvalidCoreRect) const1158 void SwPagePreviewLayout::Repaint( const tools::Rectangle& rInvalidCoreRect ) const
1159 {
1160     // check environment and parameters
1161     {
1162         if ( !mrParentViewShell.GetWin() &&
1163              !mrParentViewShell.GetOut()->GetConnectMetaFile() )
1164             return;
1165 
1166         OSL_ENSURE( mbPaintInfoValid,
1167                 "invalid preview settings - no paint of preview" );
1168         if ( !mbPaintInfoValid )
1169             return;
1170     }
1171 
1172     // environment and parameter ok
1173 
1174     // prepare paint
1175     if ( !maPreviewPages.empty() )
1176     {
1177         mrParentViewShell.Imp()->m_bFirstPageInvalid = false;
1178         mrParentViewShell.Imp()->m_pFirstVisiblePage =
1179                 const_cast<SwPageFrame*>(maPreviewPages[0]->pPage);
1180     }
1181 
1182     // invalidate visible pages, which overlap the invalid core rectangle
1183     for ( auto & rpPreviewPage : maPreviewPages )
1184     {
1185         if ( !rpPreviewPage->bVisible )
1186             continue;
1187 
1188         tools::Rectangle aPageRect( rpPreviewPage->aLogicPos, rpPreviewPage->aPageSize );
1189         if ( rInvalidCoreRect.Overlaps( aPageRect ) )
1190         {
1191             aPageRect.Intersection(rInvalidCoreRect);
1192             tools::Rectangle aInvalidPreviewRect = aPageRect;
1193             aInvalidPreviewRect.SetPos( aInvalidPreviewRect.TopLeft() -
1194                                       rpPreviewPage->aLogicPos +
1195                                       rpPreviewPage->aPreviewWinPos );
1196             mrParentViewShell.GetWin()->Invalidate( aInvalidPreviewRect );
1197         }
1198     }
1199 }
1200 
1201 /** paint selection mark at page
1202 
1203     OD 17.12.2002 #103492#
1204 */
PaintSelectMarkAtPage(vcl::RenderContext & rRenderContext,const PreviewPage * _aSelectedPreviewPage) const1205 void SwPagePreviewLayout::PaintSelectMarkAtPage(vcl::RenderContext& rRenderContext,
1206                                     const PreviewPage* _aSelectedPreviewPage ) const
1207 {
1208     OutputDevice* pOutputDev = &rRenderContext;
1209     MapMode aMapMode( pOutputDev->GetMapMode() );
1210     // save mapping mode of output device
1211     MapMode aSavedMapMode = aMapMode;
1212     // save fill and line color of output device
1213     Color aFill( pOutputDev->GetFillColor() );
1214     Color aLine( pOutputDev->GetLineColor() );
1215 
1216     // determine selection mark color
1217     Color aSelPgLineColor(117, 114, 106);
1218     const StyleSettings& rSettings =
1219         mrParentViewShell.GetWin()->GetSettings().GetStyleSettings();
1220     if ( rSettings.GetHighContrastMode() )
1221         aSelPgLineColor = rSettings.GetHighlightTextColor();
1222 
1223     // set needed mapping mode at output device
1224     aMapMode.SetOrigin( _aSelectedPreviewPage->aMapOffset );
1225     pOutputDev->SetMapMode( aMapMode );
1226 
1227     // calculate page rectangle in pixel coordinates
1228     SwRect aPageRect( _aSelectedPreviewPage->aLogicPos,
1229                          _aSelectedPreviewPage->aPageSize );
1230     // OD 19.02.2003 #107369# - use aligned page rectangle, as it is used for
1231     // page border and shadow paint - see <SwPageFrame::PaintBorderAndShadow(..)>
1232     ::SwAlignRect( aPageRect, &mrParentViewShell, pOutputDev );
1233     tools::Rectangle aPxPageRect = pOutputDev->LogicToPixel( aPageRect.SVRect() );
1234 
1235     // draw two rectangle
1236     // OD 19.02.2003 #107369# - adjust position of select mark rectangle
1237     tools::Rectangle aRect( aPxPageRect.Left(), aPxPageRect.Top(),
1238                        aPxPageRect.Right(), aPxPageRect.Bottom() );
1239     aRect = pOutputDev->PixelToLogic( aRect );
1240     pOutputDev->SetFillColor(); // OD 20.02.2003 #107369# - no fill color
1241     pOutputDev->SetLineColor( aSelPgLineColor );
1242     pOutputDev->DrawRect( aRect );
1243     // OD 19.02.2003 #107369# - adjust position of select mark rectangle
1244     aRect = tools::Rectangle( aPxPageRect.Left()+1, aPxPageRect.Top()+1,
1245                        aPxPageRect.Right()-1, aPxPageRect.Bottom()-1 );
1246     aRect = pOutputDev->PixelToLogic( aRect );
1247     pOutputDev->DrawRect( aRect );
1248 
1249     // reset fill and line color of output device
1250     pOutputDev->SetFillColor( aFill );
1251     pOutputDev->SetLineColor( aLine );
1252 
1253     // reset mapping mode of output device
1254     pOutputDev->SetMapMode( aSavedMapMode );
1255 }
1256 
1257 /** paint to mark new selected page
1258 
1259     OD 17.12.2002 #103492#
1260     Perform paint for current selected page in order to unmark it.
1261     Set new selected page and perform paint to mark this page.
1262 
1263     @note _nSelectedPage, mnSelectedPage are absolute
1264 */
MarkNewSelectedPage(const sal_uInt16 _nSelectedPage)1265 void SwPagePreviewLayout::MarkNewSelectedPage( const sal_uInt16 _nSelectedPage )
1266 {
1267     const sal_uInt16 nOldSelectedPageNum = mnSelectedPageNum;
1268     mnSelectedPageNum = _nSelectedPage;
1269 
1270     // re-paint for current selected page in order to unmark it.
1271     const PreviewPage* pOldSelectedPreviewPage = GetPreviewPageByPageNum( nOldSelectedPageNum );
1272     OutputDevice* pOutputDev = mrParentViewShell.GetOut();
1273     if ( pOldSelectedPreviewPage && pOldSelectedPreviewPage->bVisible )
1274     {
1275         // OD 20.02.2003 #107369# - invalidate only areas of selection mark.
1276         SwRect aPageRect( pOldSelectedPreviewPage->aPreviewWinPos,
1277                               pOldSelectedPreviewPage->aPageSize );
1278         ::SwAlignRect( aPageRect, &mrParentViewShell, pOutputDev );
1279         tools::Rectangle aPxPageRect = pOutputDev->LogicToPixel( aPageRect.SVRect() );
1280         // invalidate top mark line
1281         tools::Rectangle aInvalPxRect( aPxPageRect.Left(), aPxPageRect.Top(),
1282                                 aPxPageRect.Right(), aPxPageRect.Top()+1 );
1283         mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
1284         // invalidate right mark line
1285         aInvalPxRect = tools::Rectangle( aPxPageRect.Right()-1, aPxPageRect.Top(),
1286                                   aPxPageRect.Right(), aPxPageRect.Bottom() );
1287         mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
1288         // invalidate bottom mark line
1289         aInvalPxRect = tools::Rectangle( aPxPageRect.Left(), aPxPageRect.Bottom()-1,
1290                                   aPxPageRect.Right(), aPxPageRect.Bottom() );
1291         mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
1292         // invalidate left mark line
1293         aInvalPxRect = tools::Rectangle( aPxPageRect.Left(), aPxPageRect.Top(),
1294                                   aPxPageRect.Left()+1, aPxPageRect.Bottom() );
1295         mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
1296     }
1297 
1298     // re-paint for new selected page in order to mark it.
1299     const PreviewPage* pNewSelectedPreviewPage = GetPreviewPageByPageNum( _nSelectedPage );
1300     if ( pNewSelectedPreviewPage && pNewSelectedPreviewPage->bVisible )
1301     {
1302         const PreviewPage* pSelectedPreviewPage = GetPreviewPageByPageNum(mnSelectedPageNum);
1303         SwRect aPageRect(pSelectedPreviewPage->aPreviewWinPos, pSelectedPreviewPage->aPageSize);
1304         ::SwAlignRect(aPageRect, &mrParentViewShell, pOutputDev);
1305         mrParentViewShell.GetWin()->Invalidate(aPageRect.SVRect());
1306     }
1307 }
1308 
1309 // helper methods
1310 
1311 namespace {
1312 
1313 /** get preview page by physical page number
1314 
1315     OD 17.12.2002 #103492#
1316 */
1317 struct EqualsPageNumPred
1318 {
1319     const sal_uInt16 mnPageNum;
EqualsPageNumPred__anon519dd74e0311::EqualsPageNumPred1320     explicit EqualsPageNumPred(const sal_uInt16 _nPageNum)
1321         : mnPageNum( _nPageNum )
1322     {}
operator ()__anon519dd74e0311::EqualsPageNumPred1323     bool operator() ( const std::unique_ptr<PreviewPage> & _pPreviewPage )
1324     {
1325         return _pPreviewPage->pPage->GetPhyPageNum() == mnPageNum;
1326     }
1327 };
1328 
1329 }
1330 
GetPreviewPageByPageNum(const sal_uInt16 _nPageNum) const1331 const PreviewPage* SwPagePreviewLayout::GetPreviewPageByPageNum( const sal_uInt16 _nPageNum ) const
1332 {
1333     auto aFoundPreviewPageIter =
1334             std::find_if( maPreviewPages.begin(), maPreviewPages.end(),
1335                           EqualsPageNumPred( _nPageNum ) );
1336 
1337     if ( aFoundPreviewPageIter == maPreviewPages.end() )
1338         return nullptr;
1339 
1340     return aFoundPreviewPageIter->get();
1341 }
1342 
1343 /** determine row the page with the given number is in
1344 
1345     OD 17.01.2003 #103492#
1346 
1347     @note _nPageNum is relative
1348 */
GetRowOfPage(sal_uInt16 _nPageNum) const1349 sal_uInt16 SwPagePreviewLayout::GetRowOfPage( sal_uInt16 _nPageNum ) const
1350 {
1351     // OD 19.02.2003 #107369# - leaving left-top-corner blank is controlled
1352     // by <mbBookPreview>.
1353     if ( mbBookPreview )
1354     {
1355         // Note: increase given physical page number by one, because left-top-corner
1356         //       in the preview layout is left blank.
1357         ++_nPageNum;
1358     }
1359 
1360     return _nPageNum / mnCols + ((_nPageNum % mnCols)>0 ? 1 : 0);
1361 }
1362 
1363 /** determine column the page with the given number is in
1364 
1365     OD 17.01.2003 #103492#
1366 
1367     @note _nPageNum is relative
1368 */
GetColOfPage(sal_uInt16 _nPageNum) const1369 sal_uInt16 SwPagePreviewLayout::GetColOfPage( sal_uInt16 _nPageNum ) const
1370 {
1371     // OD 19.02.2003 #107369# - leaving left-top-corner blank is controlled
1372     // by <mbBookPreview>.
1373     if ( mbBookPreview )
1374     {
1375         // Note: increase given physical page number by one, because left-top-corner
1376         //       in the preview layout is left blank.
1377         ++_nPageNum;
1378     }
1379 
1380     const sal_uInt16 nCol = _nPageNum % mnCols;
1381     return nCol ? nCol : mnCols;
1382 }
1383 
GetPreviewDocSize() const1384 Size SwPagePreviewLayout::GetPreviewDocSize() const
1385 {
1386     OSL_ENSURE( PreviewLayoutValid(), "PagePreviewLayout not valid" );
1387     return maPreviewDocRect.GetSize();
1388 }
1389 
1390 /** get size of a preview page by its physical page number
1391 
1392     OD 15.01.2003 #103492#
1393 */
GetPreviewPageSizeByPageNum(sal_uInt16 _nPageNum) const1394 Size SwPagePreviewLayout::GetPreviewPageSizeByPageNum( sal_uInt16 _nPageNum ) const
1395 {
1396     const PreviewPage* pPreviewPage = GetPreviewPageByPageNum( _nPageNum );
1397     if ( pPreviewPage )
1398     {
1399         return pPreviewPage->aPageSize;
1400     }
1401     return Size( 0, 0 );
1402 }
1403 
1404 /** get virtual page number by its physical page number
1405 
1406     OD 21.03.2003 #108282#
1407 */
GetVirtPageNumByPageNum(sal_uInt16 _nPageNum) const1408 sal_uInt16 SwPagePreviewLayout::GetVirtPageNumByPageNum( sal_uInt16 _nPageNum ) const
1409 {
1410     const PreviewPage* pPreviewPage = GetPreviewPageByPageNum( _nPageNum );
1411     if ( pPreviewPage )
1412     {
1413         return pPreviewPage->pPage->GetVirtPageNum();
1414     }
1415     return 0;
1416 }
1417 
1418 /** Convert absolute to relative page numbers (see PrintEmptyPages) */
ConvertAbsoluteToRelativePageNum(sal_uInt16 _nAbsPageNum) const1419 sal_uInt16 SwPagePreviewLayout::ConvertAbsoluteToRelativePageNum( sal_uInt16 _nAbsPageNum ) const
1420 {
1421     if ( mbBookPreview || mbPrintEmptyPages || !_nAbsPageNum )
1422     {
1423         return _nAbsPageNum;
1424     }
1425 
1426     const SwPageFrame* pTmpPage = static_cast<const SwPageFrame*>(mrLayoutRootFrame.Lower());
1427 
1428     sal_uInt16 nRet = 1;
1429 
1430     while ( pTmpPage && pTmpPage->GetPhyPageNum() != _nAbsPageNum )
1431     {
1432         if ( !pTmpPage->IsEmptyPage() )
1433             ++nRet;
1434 
1435         pTmpPage = static_cast<const SwPageFrame*>( pTmpPage->GetNext() );
1436     }
1437 
1438     return nRet;
1439 }
1440 
1441 /** Convert relative to absolute page numbers (see PrintEmptyPages) */
ConvertRelativeToAbsolutePageNum(sal_uInt16 _nRelPageNum) const1442 sal_uInt16 SwPagePreviewLayout::ConvertRelativeToAbsolutePageNum( sal_uInt16 _nRelPageNum ) const
1443 {
1444     if ( mbBookPreview || mbPrintEmptyPages || !_nRelPageNum )
1445     {
1446         return _nRelPageNum;
1447     }
1448 
1449     const SwPageFrame* pTmpPage = static_cast<const SwPageFrame*>(mrLayoutRootFrame.Lower());
1450     const SwPageFrame* pRet = nullptr;
1451 
1452     sal_uInt16 i = 0;
1453     while( pTmpPage && i != _nRelPageNum )
1454     {
1455         if ( !pTmpPage->IsEmptyPage() )
1456             ++i;
1457 
1458         pRet = pTmpPage;
1459         pTmpPage = static_cast<const SwPageFrame*>( pTmpPage->GetNext() );
1460     }
1461 
1462     assert(pRet);
1463 
1464     return pRet->GetPhyPageNum();
1465 }
1466 
1467 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1468