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 <scitems.hxx>
21 #include <editeng/eeitem.hxx>
22 
23 #include <printfun.hxx>
24 
25 #include <editeng/adjustitem.hxx>
26 #include <editeng/borderline.hxx>
27 #include <editeng/boxitem.hxx>
28 #include <editeng/brushitem.hxx>
29 #include <svtools/colorcfg.hxx>
30 #include <editeng/editstat.hxx>
31 #include <svx/fmview.hxx>
32 #include <editeng/frmdiritem.hxx>
33 #include <editeng/lrspitem.hxx>
34 #include <editeng/paperinf.hxx>
35 #include <editeng/pbinitem.hxx>
36 #include <editeng/shaditem.hxx>
37 #include <editeng/sizeitem.hxx>
38 #include <editeng/fhgtitem.hxx>
39 #include <editeng/ulspitem.hxx>
40 #include <sfx2/printer.hxx>
41 #include <tools/multisel.hxx>
42 #include <sfx2/docfile.hxx>
43 #include <tools/urlobj.hxx>
44 #include <osl/diagnose.h>
45 
46 #include <editutil.hxx>
47 #include <docsh.hxx>
48 #include <output.hxx>
49 #include <viewdata.hxx>
50 #include <viewopti.hxx>
51 #include <stlpool.hxx>
52 #include <pagepar.hxx>
53 #include <attrib.hxx>
54 #include <patattr.hxx>
55 #include <docpool.hxx>
56 #include <dociter.hxx>
57 #include <globstr.hrc>
58 #include <scresid.hxx>
59 #include <pagedata.hxx>
60 #include <printopt.hxx>
61 #include <prevloc.hxx>
62 #include <scmod.hxx>
63 #include <drwlayer.hxx>
64 #include <fillinfo.hxx>
65 #include <postit.hxx>
66 
67 #include <memory>
68 #include <com/sun/star/document/XDocumentProperties.hpp>
69 
70 #define ZOOM_MIN    10
71 
72 namespace{
73 
lcl_GetBool(const SfxItemSet * pSet,sal_uInt16 nWhich)74 bool lcl_GetBool(const SfxItemSet* pSet, sal_uInt16 nWhich)
75 {
76     return static_cast<const SfxBoolItem&>(pSet->Get(nWhich)).GetValue();
77 }
78 
lcl_GetUShort(const SfxItemSet * pSet,sal_uInt16 nWhich)79 sal_uInt16 lcl_GetUShort(const SfxItemSet* pSet, sal_uInt16 nWhich)
80 {
81     return static_cast<const SfxUInt16Item&>(pSet->Get(nWhich)).GetValue();
82 }
83 
lcl_GetShow(const SfxItemSet * pSet,sal_uInt16 nWhich)84 bool lcl_GetShow(const SfxItemSet* pSet, sal_uInt16 nWhich)
85 {
86     return ScVObjMode::VOBJ_MODE_SHOW == static_cast<const ScViewObjectModeItem&>(pSet->Get(nWhich)).GetValue();
87 }
88 
89 
90 } // namespace
91 
ScPageRowEntry(const ScPageRowEntry & r)92 ScPageRowEntry::ScPageRowEntry(const ScPageRowEntry& r)
93 {
94     nStartRow = r.nStartRow;
95     nEndRow   = r.nEndRow;
96     nPagesX   = r.nPagesX;
97     aHidden   = r.aHidden;
98     aHidden.resize(nPagesX, false);
99 }
100 
operator =(const ScPageRowEntry & r)101 ScPageRowEntry& ScPageRowEntry::operator=(const ScPageRowEntry& r)
102 {
103     nStartRow = r.nStartRow;
104     nEndRow   = r.nEndRow;
105     nPagesX   = r.nPagesX;
106     aHidden   = r.aHidden;
107     aHidden.resize(nPagesX, false);
108     return *this;
109 }
110 
SetPagesX(size_t nNew)111 void ScPageRowEntry::SetPagesX(size_t nNew)
112 {
113     nPagesX = nNew;
114     aHidden.resize(nPagesX, false);
115 }
116 
SetHidden(size_t nX)117 void ScPageRowEntry::SetHidden(size_t nX)
118 {
119     if ( nX < nPagesX )
120     {
121         if ( nX+1 == nPagesX )  // last page?
122             --nPagesX;
123         else
124         {
125             aHidden.resize(nPagesX, false);
126             aHidden[nX] = true;
127         }
128     }
129 }
130 
IsHidden(size_t nX) const131 bool ScPageRowEntry::IsHidden(size_t nX) const
132 {
133     return nX >= nPagesX || aHidden[nX];       //! inline?
134 }
135 
CountVisible() const136 size_t ScPageRowEntry::CountVisible() const
137 {
138     if (!aHidden.empty())
139     {
140         size_t nVis = 0;
141         for (size_t i=0; i<nPagesX; i++)
142             if (!aHidden[i])
143                 ++nVis;
144         return nVis;
145     }
146     else
147         return nPagesX;
148 }
149 
lcl_LineTotal(const::editeng::SvxBorderLine * pLine)150 static tools::Long lcl_LineTotal(const ::editeng::SvxBorderLine* pLine)
151 {
152     return pLine ? ( pLine->GetScaledWidth() ) : 0;
153 }
154 
Construct(const ScPrintOptions * pOptions)155 void ScPrintFunc::Construct( const ScPrintOptions* pOptions )
156 {
157     pDocShell->UpdatePendingRowHeights( nPrintTab );
158 
159     SfxPrinter* pDocPrinter = rDoc.GetPrinter();   // use the printer, even for preview
160     if (pDocPrinter)
161         aOldPrinterMode = pDocPrinter->GetMapMode();
162 
163     //  unified MapMode for all calls (e.g. Repaint!!!)
164     //  else, EditEngine outputs different text heights
165     pDev->SetMapMode(MapMode(MapUnit::MapPixel));
166 
167     pBorderItem = nullptr;
168     pBackgroundItem = nullptr;
169     pShadowItem = nullptr;
170 
171     pEditEngine = nullptr;
172     pEditDefaults = nullptr;
173 
174     ScStyleSheetPool* pStylePool    = rDoc.GetStyleSheetPool();
175     SfxStyleSheetBase* pStyleSheet  = pStylePool->Find(
176                                             rDoc.GetPageStyle( nPrintTab ),
177                                             SfxStyleFamily::Page );
178     if (pStyleSheet)
179         pParamSet = &pStyleSheet->GetItemSet();
180     else
181     {
182         OSL_FAIL("Template not found" );
183         pParamSet = nullptr;
184     }
185 
186     if (!bFromPrintState)
187         nZoom = 100;
188     nManualZoom = 100;
189     bClearWin = false;
190     bUseStyleColor = false;
191     bIsRender = false;
192 
193     InitParam(pOptions);
194 
195     pPageData = nullptr;       // is only needed for initialisation
196 }
197 
ScPrintFunc(ScDocShell * pShell,SfxPrinter * pNewPrinter,SCTAB nTab,tools::Long nPage,tools::Long nDocP,const ScRange * pArea,const ScPrintOptions * pOptions,ScPageBreakData * pData)198 ScPrintFunc::ScPrintFunc( ScDocShell* pShell, SfxPrinter* pNewPrinter, SCTAB nTab,
199                             tools::Long nPage, tools::Long nDocP, const ScRange* pArea,
200                             const ScPrintOptions* pOptions,
201                             ScPageBreakData* pData )
202     :   pDocShell           ( pShell ),
203         rDoc(pDocShell->GetDocument()),
204         pPrinter            ( pNewPrinter ),
205         pDrawView           ( nullptr ),
206         nPrintTab           ( nTab ),
207         nPageStart          ( nPage ),
208         nDocPages           ( nDocP ),
209         pUserArea           ( pArea ),
210         bFromPrintState     ( false ),
211         bSourceRangeValid   ( false ),
212         bPrintCurrentTable  ( false ),
213         bMultiArea          ( false ),
214         mbHasPrintRange(true),
215         nTabPages           ( 0 ),
216         nTotalPages         ( 0 ),
217         bPrintAreaValid     ( false ),
218         pPageData           ( pData )
219 {
220     pDev = pPrinter.get();
221     aSrcOffset = pPrinter->PixelToLogic(pPrinter->GetPageOffsetPixel(), MapMode(MapUnit::Map100thMM));
222     m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
223     m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
224     m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
225     Construct( pOptions );
226 }
227 
ScPrintFunc(ScDocShell * pShell,SfxPrinter * pNewPrinter,const ScPrintState & rState,const ScPrintOptions * pOptions)228 ScPrintFunc::ScPrintFunc(ScDocShell* pShell, SfxPrinter* pNewPrinter,
229                          const ScPrintState& rState, const ScPrintOptions* pOptions)
230     :   pDocShell           ( pShell ),
231         rDoc(pDocShell->GetDocument()),
232         pPrinter            ( pNewPrinter ),
233         pDrawView           ( nullptr ),
234         pUserArea           ( nullptr ),
235         bSourceRangeValid   ( false ),
236         bPrintCurrentTable  ( false ),
237         bMultiArea          ( false ),
238         mbHasPrintRange(true),
239         pPageData           ( nullptr )
240 {
241     pDev = pPrinter.get();
242 
243     nPrintTab   = rState.nPrintTab;
244     nStartCol   = rState.nStartCol;
245     nStartRow   = rState.nStartRow;
246     nEndCol     = rState.nEndCol;
247     nEndRow     = rState.nEndRow;
248     bPrintAreaValid = rState.bPrintAreaValid;
249     nZoom       = rState.nZoom;
250     m_aRanges.m_nPagesX = rState.nPagesX;
251     m_aRanges.m_nPagesY = rState.nPagesY;
252     nTabPages   = rState.nTabPages;
253     nTotalPages = rState.nTotalPages;
254     nPageStart  = rState.nPageStart;
255     nDocPages   = rState.nDocPages;
256     bFromPrintState = true;
257 
258     if (rState.bSavedStateRanges)
259     {
260         m_aRanges.m_nTotalY = rState.nTotalY;
261         m_aRanges.m_xPageEndX = rState.xPageEndX;
262         m_aRanges.m_xPageEndY = rState.xPageEndY;
263         m_aRanges.m_xPageRows = rState.xPageRows;
264         m_aRanges.m_aInput = rState.aPrintPageRangesInput;
265     }
266     else
267     {
268         m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
269         m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
270         m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
271     }
272 
273     aSrcOffset = pPrinter->PixelToLogic(pPrinter->GetPageOffsetPixel(), MapMode(MapUnit::Map100thMM));
274     Construct( pOptions );
275 }
276 
ScPrintFunc(OutputDevice * pOutDev,ScDocShell * pShell,SCTAB nTab,tools::Long nPage,tools::Long nDocP,const ScRange * pArea,const ScPrintOptions * pOptions)277 ScPrintFunc::ScPrintFunc( OutputDevice* pOutDev, ScDocShell* pShell, SCTAB nTab,
278                             tools::Long nPage, tools::Long nDocP, const ScRange* pArea,
279                             const ScPrintOptions* pOptions )
280     :   pDocShell           ( pShell ),
281         rDoc(pDocShell->GetDocument()),
282         pPrinter            ( nullptr ),
283         pDrawView           ( nullptr ),
284         nPrintTab           ( nTab ),
285         nPageStart          ( nPage ),
286         nDocPages           ( nDocP ),
287         pUserArea           ( pArea ),
288         bFromPrintState     ( false ),
289         bSourceRangeValid   ( false ),
290         bPrintCurrentTable  ( false ),
291         bMultiArea          ( false ),
292         mbHasPrintRange(true),
293         nTabPages           ( 0 ),
294         nTotalPages         ( 0 ),
295         bPrintAreaValid     ( false ),
296         pPageData           ( nullptr )
297 {
298     pDev = pOutDev;
299     m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
300     m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
301     m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
302     Construct( pOptions );
303 }
304 
ScPrintFunc(OutputDevice * pOutDev,ScDocShell * pShell,const ScPrintState & rState,const ScPrintOptions * pOptions)305 ScPrintFunc::ScPrintFunc( OutputDevice* pOutDev, ScDocShell* pShell,
306                              const ScPrintState& rState, const ScPrintOptions* pOptions )
307     :   pDocShell           ( pShell ),
308         rDoc(pDocShell->GetDocument()),
309         pPrinter            ( nullptr ),
310         pDrawView           ( nullptr ),
311         pUserArea           ( nullptr ),
312         bSourceRangeValid   ( false ),
313         bPrintCurrentTable  ( false ),
314         bMultiArea          ( false ),
315         mbHasPrintRange(true),
316         pPageData           ( nullptr )
317 {
318     pDev = pOutDev;
319 
320     nPrintTab   = rState.nPrintTab;
321     nStartCol   = rState.nStartCol;
322     nStartRow   = rState.nStartRow;
323     nEndCol     = rState.nEndCol;
324     nEndRow     = rState.nEndRow;
325     bPrintAreaValid = rState.bPrintAreaValid;
326     nZoom       = rState.nZoom;
327     m_aRanges.m_nPagesX = rState.nPagesX;
328     m_aRanges.m_nPagesY = rState.nPagesY;
329     nTabPages   = rState.nTabPages;
330     nTotalPages = rState.nTotalPages;
331     nPageStart  = rState.nPageStart;
332     nDocPages   = rState.nDocPages;
333     bFromPrintState = true;
334 
335     if (rState.bSavedStateRanges)
336     {
337         m_aRanges.m_nTotalY = rState.nTotalY;
338         m_aRanges.m_xPageEndX = rState.xPageEndX;
339         m_aRanges.m_xPageEndY = rState.xPageEndY;
340         m_aRanges.m_xPageRows = rState.xPageRows;
341         m_aRanges.m_aInput = rState.aPrintPageRangesInput;
342     }
343     else
344     {
345         m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
346         m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
347         m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
348     }
349 
350     Construct( pOptions );
351 }
352 
GetPrintState(ScPrintState & rState,bool bSavePageRanges)353 void ScPrintFunc::GetPrintState(ScPrintState& rState,  bool bSavePageRanges)
354 {
355     rState.nPrintTab    = nPrintTab;
356     rState.nStartCol    = nStartCol;
357     rState.nStartRow    = nStartRow;
358     rState.nEndCol      = nEndCol;
359     rState.nEndRow      = nEndRow;
360     rState.bPrintAreaValid = bPrintAreaValid;
361     rState.nZoom        = nZoom;
362     rState.nPagesX      = m_aRanges.m_nPagesX;
363     rState.nPagesY      = m_aRanges.m_nPagesY;
364     rState.nTabPages    = nTabPages;
365     rState.nTotalPages  = nTotalPages;
366     rState.nPageStart   = nPageStart;
367     rState.nDocPages    = nDocPages;
368     if (bSavePageRanges)
369     {
370         rState.bSavedStateRanges = true;
371         rState.nTotalY = m_aRanges.m_nTotalY;
372         rState.xPageEndX = m_aRanges.m_xPageEndX;
373         rState.xPageEndY = m_aRanges.m_xPageEndY;
374         rState.xPageRows = m_aRanges.m_xPageRows;
375         rState.aPrintPageRangesInput = m_aRanges.m_aInput;
376     }
377 }
378 
GetLastSourceRange(ScRange & rRange) const379 bool ScPrintFunc::GetLastSourceRange( ScRange& rRange ) const
380 {
381     rRange = aLastSourceRange;
382     return bSourceRangeValid;
383 }
384 
FillPageData()385 void ScPrintFunc::FillPageData()
386 {
387     if (!pPageData)
388         return;
389 
390     sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( pPageData->GetCount() );
391     ScPrintRangeData& rData = pPageData->GetData(nCount);       // count up
392 
393     assert( bPrintAreaValid );
394     rData.SetPrintRange( ScRange( nStartCol, nStartRow, nPrintTab,
395                                     nEndCol, nEndRow, nPrintTab ) );
396     // #i123672#
397     if(m_aRanges.m_xPageEndX->empty())
398     {
399         OSL_ENSURE(false, "vector access error for maPageEndX (!)");
400     }
401     else
402     {
403         rData.SetPagesX( m_aRanges.m_nPagesX, m_aRanges.m_xPageEndX->data());
404     }
405 
406     // #i123672#
407     if(m_aRanges.m_xPageEndY->empty())
408     {
409         OSL_ENSURE(false, "vector access error for maPageEndY (!)");
410     }
411     else
412     {
413         rData.SetPagesY( m_aRanges.m_nTotalY, m_aRanges.m_xPageEndY->data());
414     }
415 
416     //  Settings
417     rData.SetTopDown( aTableParam.bTopDown );
418     rData.SetAutomatic( !aAreaParam.bPrintArea );
419 }
420 
~ScPrintFunc()421 ScPrintFunc::~ScPrintFunc()
422 {
423     pEditDefaults.reset();
424     pEditEngine.reset();
425 
426     //  Printer settings are now restored from outside
427 
428     //  For DrawingLayer/Charts, the MapMode of the printer (RefDevice) must always be correct
429     SfxPrinter* pDocPrinter = rDoc.GetPrinter();   // use Preview also for the printer
430     if (pDocPrinter)
431         pDocPrinter->SetMapMode(aOldPrinterMode);
432 }
433 
SetDrawView(FmFormView * pNew)434 void ScPrintFunc::SetDrawView( FmFormView* pNew )
435 {
436     pDrawView = pNew;
437 }
438 
lcl_HidePrint(const ScTableInfo & rTabInfo,SCCOL nX1,SCCOL nX2)439 static void lcl_HidePrint( const ScTableInfo& rTabInfo, SCCOL nX1, SCCOL nX2 )
440 {
441     for (SCSIZE nArrY=1; nArrY+1<rTabInfo.mnArrCount; nArrY++)
442     {
443         RowInfo* pThisRowInfo = &rTabInfo.mpRowInfo[nArrY];
444         for (SCCOL nX=nX1; nX<=nX2; nX++)
445         {
446             CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nX+1];
447             if (!rCellInfo.bEmptyCellText)
448                 if (rCellInfo.pPatternAttr->
449                             GetItem(ATTR_PROTECTION, rCellInfo.pConditionSet).GetHidePrint())
450                 {
451                     rCellInfo.maCell.clear();
452                     rCellInfo.bEmptyCellText = true;
453                 }
454         }
455     }
456 }
457 
458 //          output to Device (static)
459 //
460 //      us used for:
461 //      -   Clipboard/Bitmap
462 //      -   Ole-Object (DocShell::Draw)
463 //      -   Preview of templates
464 
DrawToDev(ScDocument & rDoc,OutputDevice * pDev,double,const tools::Rectangle & rBound,ScViewData * pViewData,bool bMetaFile)465 void ScPrintFunc::DrawToDev(ScDocument& rDoc, OutputDevice* pDev, double /* nPrintFactor */,
466                             const tools::Rectangle& rBound, ScViewData* pViewData, bool bMetaFile)
467 {
468     //! evaluate nPrintFactor !!!
469 
470     SCTAB nTab = 0;
471     if (pViewData)
472         nTab = pViewData->GetTabNo();
473 
474     bool bDoGrid, bNullVal, bFormula;
475     ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
476     SfxStyleSheetBase* pStyleSheet = pStylePool->Find( rDoc.GetPageStyle( nTab ), SfxStyleFamily::Page );
477     if (pStyleSheet)
478     {
479         SfxItemSet& rSet = pStyleSheet->GetItemSet();
480         bDoGrid  = rSet.Get(ATTR_PAGE_GRID).GetValue();
481         bNullVal = rSet.Get(ATTR_PAGE_NULLVALS).GetValue();
482         bFormula = rSet.Get(ATTR_PAGE_FORMULAS).GetValue();
483     }
484     else
485     {
486         const ScViewOptions& rOpt = rDoc.GetViewOptions();
487         bDoGrid  = rOpt.GetOption(VOPT_GRID);
488         bNullVal = rOpt.GetOption(VOPT_NULLVALS);
489         bFormula = rOpt.GetOption(VOPT_FORMULAS);
490     }
491 
492     MapMode aMode = pDev->GetMapMode();
493 
494     tools::Rectangle aRect = rBound;
495 
496     if (aRect.Right() < aRect.Left() || aRect.Bottom() < aRect.Top())
497         aRect = tools::Rectangle( Point(), pDev->GetOutputSize() );
498 
499     SCCOL nX1 = 0;
500     SCROW nY1 = 0;
501     SCCOL nX2 = OLE_STD_CELLS_X - 1;
502     SCROW nY2 = OLE_STD_CELLS_Y - 1;
503     if (bMetaFile)
504     {
505         ScRange aRange = rDoc.GetRange( nTab, rBound );
506         nX1 = aRange.aStart.Col();
507         nY1 = aRange.aStart.Row();
508         nX2 = aRange.aEnd.Col();
509         nY2 = aRange.aEnd.Row();
510     }
511     else if (pViewData)
512     {
513         ScSplitPos eWhich = pViewData->GetActivePart();
514         ScHSplitPos eHWhich = WhichH(eWhich);
515         ScVSplitPos eVWhich = WhichV(eWhich);
516         nX1 = pViewData->GetPosX(eHWhich);
517         nY1 = pViewData->GetPosY(eVWhich);
518         nX2 = nX1 + pViewData->VisibleCellsX(eHWhich);
519         if (nX2>nX1) --nX2;
520         nY2 = nY1 + pViewData->VisibleCellsY(eVWhich);
521         if (nY2>nY1) --nY2;
522     }
523 
524     if (nX1 > rDoc.MaxCol()) nX1 = rDoc.MaxCol();
525     if (nX2 > rDoc.MaxCol()) nX2 = rDoc.MaxCol();
526     if (nY1 > rDoc.MaxRow()) nY1 = rDoc.MaxRow();
527     if (nY2 > rDoc.MaxRow()) nY2 = rDoc.MaxRow();
528 
529     tools::Long nDevSizeX = aRect.Right()-aRect.Left()+1;
530     tools::Long nDevSizeY = aRect.Bottom()-aRect.Top()+1;
531 
532     tools::Long nTwipsSizeX = 0;
533     for (SCCOL i=nX1; i<=nX2; i++)
534         nTwipsSizeX += rDoc.GetColWidth( i, nTab );
535     tools::Long nTwipsSizeY = static_cast<tools::Long>(rDoc.GetRowHeight( nY1, nY2, nTab ));
536 
537     //  if no lines, still space for the outline frame (20 Twips = 1pt)
538     //  (HasLines initializes aLines to 0,0,0,0)
539     nTwipsSizeX += 20;
540     nTwipsSizeY += 20;
541 
542     double nScaleX = static_cast<double>(nDevSizeX) / nTwipsSizeX;
543     double nScaleY = static_cast<double>(nDevSizeY) / nTwipsSizeY;
544 
545                             //!     hand over Flag at FillInfo !!!!!
546     ScRange aERange;
547     bool bEmbed = rDoc.IsEmbedded();
548     if (bEmbed)
549     {
550         rDoc.GetEmbedded(aERange);
551         rDoc.ResetEmbedded();
552     }
553 
554     //  Assemble data
555 
556     ScTableInfo aTabInfo;
557     rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nTab,
558                    nScaleX, nScaleY, false, bFormula );
559     lcl_HidePrint( aTabInfo, nX1, nX2 );
560 
561     if (bEmbed)
562         rDoc.SetEmbedded(aERange);
563 
564     tools::Long nScrX = aRect.Left();
565     tools::Long nScrY = aRect.Top();
566 
567     //  If no lines, still leave space for grid lines
568     //  (would be elseways cut away)
569     nScrX += 1;
570     nScrY += 1;
571 
572     ScOutputData aOutputData( pDev, OUTTYPE_PRINTER, aTabInfo, &rDoc, nTab,
573                                 nScrX, nScrY, nX1, nY1, nX2, nY2, nScaleX, nScaleY );
574     aOutputData.SetMetaFileMode(bMetaFile);
575     aOutputData.SetShowNullValues(bNullVal);
576     aOutputData.SetShowFormulas(bFormula);
577 
578     ScDrawLayer* pModel = rDoc.GetDrawLayer();
579     std::unique_ptr<FmFormView> pDrawView;
580 
581     if( pModel )
582     {
583         pDrawView.reset(
584             new FmFormView(
585                 *pModel,
586                 pDev));
587         pDrawView->ShowSdrPage(pDrawView->GetModel()->GetPage(nTab));
588         pDrawView->SetPrintPreview();
589         aOutputData.SetDrawView( pDrawView.get() );
590     }
591 
592     //! SetUseStyleColor ??
593 
594     if ( bMetaFile && pDev->IsVirtual() )
595         aOutputData.SetSnapPixel();
596 
597     Point aLogStart = pDev->PixelToLogic(Point(nScrX, nScrY), MapMode(MapUnit::Map100thMM));
598     tools::Long nLogStX = aLogStart.X();
599     tools::Long nLogStY = aLogStart.Y();
600 
601     //!     nZoom for GetFont in OutputData ???
602 
603     if (!bMetaFile && pViewData)
604         pDev->SetMapMode(pViewData->GetLogicMode(pViewData->GetActivePart()));
605 
606     // #i72502#
607     const Point aMMOffset(aOutputData.PrePrintDrawingLayer(nLogStX, nLogStY));
608     aOutputData.PrintDrawingLayer(SC_LAYER_BACK, aMMOffset);
609 
610     if (!bMetaFile && pViewData)
611         pDev->SetMapMode(aMode);
612 
613     aOutputData.DrawBackground(*pDev);
614 
615     aOutputData.DrawShadow();
616     aOutputData.DrawFrame(*pDev);
617     aOutputData.DrawStrings();
618 
619     if (!bMetaFile && pViewData)
620         pDev->SetMapMode(pViewData->GetLogicMode(pViewData->GetActivePart()));
621 
622     aOutputData.DrawEdit(!bMetaFile);
623 
624     if (bDoGrid)
625     {
626         if (!bMetaFile && pViewData)
627             pDev->SetMapMode(aMode);
628 
629         aOutputData.DrawGrid(*pDev, true, false);    // no page breaks
630 
631         pDev->SetLineColor( COL_BLACK );
632 
633         Size aOne = pDev->PixelToLogic( Size(1,1) );
634         if (bMetaFile)
635             aOne = Size(1,1);   // compatible with DrawGrid
636         tools::Long nRight = nScrX + aOutputData.GetScrW() - aOne.Width();
637         tools::Long nBottom = nScrY + aOutputData.GetScrH() - aOne.Height();
638 
639         bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
640 
641         // extra line at the left edge for left-to-right, right for right-to-left
642         if ( bLayoutRTL )
643             pDev->DrawLine( Point(nRight,nScrY), Point(nRight,nBottom) );
644         else
645             pDev->DrawLine( Point(nScrX,nScrY), Point(nScrX,nBottom) );
646         // extra line at the top in both cases
647         pDev->DrawLine( Point(nScrX,nScrY), Point(nRight,nScrY) );
648     }
649 
650     // #i72502#
651     aOutputData.PrintDrawingLayer(SC_LAYER_FRONT, aMMOffset);
652     aOutputData.PrintDrawingLayer(SC_LAYER_INTERN, aMMOffset);
653     aOutputData.PostPrintDrawingLayer(aMMOffset); // #i74768#
654 }
655 
656 //          Printing
657 
lcl_FillHFParam(ScPrintHFParam & rParam,const SfxItemSet * pHFSet)658 static void lcl_FillHFParam( ScPrintHFParam& rParam, const SfxItemSet* pHFSet )
659 {
660     //  nDistance must be initialized differently before
661 
662     if ( pHFSet == nullptr )
663     {
664         rParam.bEnable  = false;
665         rParam.pBorder  = nullptr;
666         rParam.pBack    = nullptr;
667         rParam.pShadow  = nullptr;
668     }
669     else
670     {
671         rParam.bEnable  = pHFSet->Get(ATTR_PAGE_ON).GetValue();
672         rParam.bDynamic = pHFSet->Get(ATTR_PAGE_DYNAMIC).GetValue();
673         rParam.bShared  = pHFSet->Get(ATTR_PAGE_SHARED).GetValue();
674         rParam.bSharedFirst = pHFSet->Get(ATTR_PAGE_SHARED_FIRST).GetValue();
675         rParam.nHeight  = pHFSet->Get(ATTR_PAGE_SIZE).GetSize().Height();
676         const SvxLRSpaceItem* pHFLR = &pHFSet->Get(ATTR_LRSPACE);
677         tools::Long nTmp;
678         nTmp = pHFLR->GetLeft();
679         rParam.nLeft = nTmp < 0 ? 0 : sal_uInt16(nTmp);
680         nTmp = pHFLR->GetRight();
681         rParam.nRight = nTmp < 0 ? 0 : sal_uInt16(nTmp);
682         rParam.pBorder  = &pHFSet->Get(ATTR_BORDER);
683         rParam.pBack    = &pHFSet->Get(ATTR_BACKGROUND);
684         rParam.pShadow  = &pHFSet->Get(ATTR_SHADOW);
685 
686 //   now back in the dialog:
687 //      rParam.nHeight += rParam.nDistance;             // not in the dialog any more ???
688 
689         rParam.nHeight += lcl_LineTotal( rParam.pBorder->GetTop() ) +
690                           lcl_LineTotal( rParam.pBorder->GetBottom() );
691 
692         rParam.nManHeight = rParam.nHeight;
693     }
694 
695     if (!rParam.bEnable)
696         rParam.nHeight = 0;
697 }
698 
699 //  bNew = TRUE:    search for used part of the document
700 //  bNew = FALSE:   only limit whole lines/columns
701 
AdjustPrintArea(bool bNew)702 bool ScPrintFunc::AdjustPrintArea( bool bNew )
703 {
704     SCCOL nOldEndCol = nEndCol; // only important for !bNew
705     SCROW nOldEndRow = nEndRow;
706     bool bChangeCol = true;         // at bNew both are being adjusted
707     bool bChangeRow = true;
708 
709     bool bNotes = aTableParam.bNotes;
710     if ( bNew )
711     {
712         nStartCol = 0;
713         nStartRow = 0;
714         if (!rDoc.GetPrintArea( nPrintTab, nEndCol, nEndRow, bNotes ))
715             return false;   // nothing
716         bPrintAreaValid = true;
717     }
718     else
719     {
720         bool bFound = true;
721         bChangeCol = ( nStartCol == 0 && nEndCol == rDoc.MaxCol() );
722         bChangeRow = ( nStartRow == 0 && nEndRow == rDoc.MaxRow() );
723         bool bForcedChangeRow = false;
724 
725         // #i53558# Crop entire column of old row limit to real print area with
726         // some fuzzyness.
727         if (!bChangeRow && nStartRow == 0)
728         {
729             SCROW nPAEndRow;
730             bFound = rDoc.GetPrintAreaVer( nPrintTab, nStartCol, nEndCol, nPAEndRow, bNotes );
731             // Say we don't want to print more than ~1000 empty rows, which are
732             // about 14 pages intentionally left blank...
733             const SCROW nFuzzy = 23*42;
734             if (nPAEndRow + nFuzzy < nEndRow)
735             {
736                 bForcedChangeRow = true;
737                 nEndRow = nPAEndRow;
738             }
739             else
740                 bFound = true;  // user seems to _want_ to print some empty rows
741         }
742         // TODO: in case we extend the number of columns we may have to do the
743         // same for horizontal cropping.
744 
745         if ( bChangeCol && bChangeRow )
746             bFound = rDoc.GetPrintArea( nPrintTab, nEndCol, nEndRow, bNotes );
747         else if ( bChangeCol )
748             bFound = rDoc.GetPrintAreaHor( nPrintTab, nStartRow, nEndRow, nEndCol );
749         else if ( bChangeRow )
750             bFound = rDoc.GetPrintAreaVer( nPrintTab, nStartCol, nEndCol, nEndRow, bNotes );
751 
752         if (!bFound)
753             return false;   // empty
754 
755         bPrintAreaValid = true;
756         if (bForcedChangeRow)
757             bChangeRow = true;
758     }
759 
760     assert( bPrintAreaValid );
761     rDoc.ExtendMerge( nStartCol,nStartRow, nEndCol,nEndRow, nPrintTab );  // no Refresh, incl. Attrs
762 
763     if ( bChangeCol )
764     {
765         OutputDevice* pRefDev = rDoc.GetPrinter();     // use the printer also for Preview
766         pRefDev->SetMapMode(MapMode(MapUnit::MapPixel)); // important for GetNeededSize
767 
768         rDoc.ExtendPrintArea( pRefDev,
769                             nPrintTab, nStartCol, nStartRow, nEndCol, nEndRow );
770         //  changing nEndCol
771     }
772 
773     if ( nEndCol < rDoc.MaxCol() && rDoc.HasAttrib(
774                     nEndCol,nStartRow,nPrintTab, nEndCol,nEndRow,nPrintTab, HasAttrFlags::ShadowRight ) )
775         ++nEndCol;
776     if ( nEndRow < rDoc.MaxRow() && rDoc.HasAttrib(
777                     nStartCol,nEndRow,nPrintTab, nEndCol,nEndRow,nPrintTab, HasAttrFlags::ShadowDown ) )
778         ++nEndRow;
779 
780     if (!bChangeCol) nEndCol = nOldEndCol;
781     if (!bChangeRow) nEndRow = nOldEndRow;
782 
783     return true;
784 }
785 
TextHeight(const EditTextObject * pObject)786 tools::Long ScPrintFunc::TextHeight( const EditTextObject* pObject )
787 {
788     if (!pObject)
789         return 0;
790 
791     pEditEngine->SetTextNewDefaults( *pObject, *pEditDefaults, false );
792 
793     return static_cast<tools::Long>(pEditEngine->GetTextHeight());
794 }
795 
796 //  nZoom must be set !!!
797 //  and the respective Twip-MapMode configured
798 
UpdateHFHeight(ScPrintHFParam & rParam)799 void ScPrintFunc::UpdateHFHeight( ScPrintHFParam& rParam )
800 {
801     OSL_ENSURE( aPageSize.Width(), "UpdateHFHeight without aPageSize");
802 
803     if (!(rParam.bEnable && rParam.bDynamic))
804         return;
805 
806     //  calculate nHeight from content
807 
808     MakeEditEngine();
809     tools::Long nPaperWidth = ( aPageSize.Width() - nLeftMargin - nRightMargin -
810                             rParam.nLeft - rParam.nRight ) * 100 / nZoom;
811     if (rParam.pBorder)
812         nPaperWidth -= ( rParam.pBorder->GetDistance(SvxBoxItemLine::LEFT) +
813                          rParam.pBorder->GetDistance(SvxBoxItemLine::RIGHT) +
814                          lcl_LineTotal(rParam.pBorder->GetLeft()) +
815                          lcl_LineTotal(rParam.pBorder->GetRight()) ) * 100 / nZoom;
816 
817     if (rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE)
818         nPaperWidth -= ( rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::LEFT) +
819                          rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::RIGHT) ) * 100 / nZoom;
820 
821     pEditEngine->SetPaperSize( Size( nPaperWidth, 10000 ) );
822 
823     tools::Long nMaxHeight = 0;
824     if ( rParam.pLeft )
825     {
826         nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pLeft->GetLeftArea() ) );
827         nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pLeft->GetCenterArea() ) );
828         nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pLeft->GetRightArea() ) );
829     }
830     if ( rParam.pRight )
831     {
832         nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pRight->GetLeftArea() ) );
833         nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pRight->GetCenterArea() ) );
834         nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pRight->GetRightArea() ) );
835     }
836     if ( rParam.pFirst )
837     {
838         nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pFirst->GetLeftArea() ) );
839         nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pFirst->GetCenterArea() ) );
840         nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pFirst->GetRightArea() ) );
841     }
842 
843     rParam.nHeight = nMaxHeight + rParam.nDistance;
844     if (rParam.pBorder)
845         rParam.nHeight += rParam.pBorder->GetDistance(SvxBoxItemLine::TOP) +
846                           rParam.pBorder->GetDistance(SvxBoxItemLine::BOTTOM) +
847                           lcl_LineTotal( rParam.pBorder->GetTop() ) +
848                           lcl_LineTotal( rParam.pBorder->GetBottom() );
849     if (rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE)
850         rParam.nHeight += rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::TOP) +
851                           rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM);
852 
853     if (rParam.nHeight < rParam.nManHeight)
854         rParam.nHeight = rParam.nManHeight;         // configured minimum
855 }
856 
InitParam(const ScPrintOptions * pOptions)857 void ScPrintFunc::InitParam( const ScPrintOptions* pOptions )
858 {
859     if (!pParamSet)
860         return;
861 
862                                 // TabPage "Page"
863     const SvxLRSpaceItem* pLRItem = &pParamSet->Get( ATTR_LRSPACE );
864     tools::Long nTmp;
865     nTmp = pLRItem->GetLeft();
866     nLeftMargin = nTmp < 0 ? 0 : sal_uInt16(nTmp);
867     nTmp = pLRItem->GetRight();
868     nRightMargin = nTmp < 0 ? 0 : sal_uInt16(nTmp);
869     const SvxULSpaceItem* pULItem = &pParamSet->Get( ATTR_ULSPACE );
870     nTopMargin    = pULItem->GetUpper();
871     nBottomMargin = pULItem->GetLower();
872 
873     const SvxPageItem* pPageItem = &pParamSet->Get( ATTR_PAGE );
874     nPageUsage          = pPageItem->GetPageUsage();
875     bLandscape          = pPageItem->IsLandscape();
876     aFieldData.eNumType = pPageItem->GetNumType();
877 
878     bCenterHor = pParamSet->Get(ATTR_PAGE_HORCENTER).GetValue();
879     bCenterVer = pParamSet->Get(ATTR_PAGE_VERCENTER).GetValue();
880 
881     aPageSize = pParamSet->Get(ATTR_PAGE_SIZE).GetSize();
882     if ( !aPageSize.Width() || !aPageSize.Height() )
883     {
884         OSL_FAIL("PageSize Null ?!?!?");
885         aPageSize = SvxPaperInfo::GetPaperSize( PAPER_A4 );
886     }
887 
888     pBorderItem     = &pParamSet->Get(ATTR_BORDER);
889     pBackgroundItem = &pParamSet->Get(ATTR_BACKGROUND);
890     pShadowItem     = &pParamSet->Get(ATTR_SHADOW);
891 
892                                 // TabPage "Headline"
893 
894     aHdr.pLeft      = &pParamSet->Get(ATTR_PAGE_HEADERLEFT);      // Content
895     aHdr.pRight     = &pParamSet->Get(ATTR_PAGE_HEADERRIGHT);
896     aHdr.pFirst     = &pParamSet->Get(ATTR_PAGE_HEADERFIRST);
897 
898     const SvxSetItem* pHeaderSetItem;
899     const SfxItemSet* pHeaderSet = nullptr;
900     if ( pParamSet->GetItemState( ATTR_PAGE_HEADERSET, false,
901                             reinterpret_cast<const SfxPoolItem**>(&pHeaderSetItem) ) == SfxItemState::SET )
902     {
903         pHeaderSet = &pHeaderSetItem->GetItemSet();
904                                                         // Headline has space below
905         aHdr.nDistance  = pHeaderSet->Get(ATTR_ULSPACE).GetLower();
906     }
907     lcl_FillHFParam( aHdr, pHeaderSet );
908 
909                                 // TabPage "Footline"
910 
911     aFtr.pLeft      = &pParamSet->Get(ATTR_PAGE_FOOTERLEFT);      // Content
912     aFtr.pRight     = &pParamSet->Get(ATTR_PAGE_FOOTERRIGHT);
913     aFtr.pFirst     = &pParamSet->Get(ATTR_PAGE_FOOTERFIRST);
914 
915     const SvxSetItem* pFooterSetItem;
916     const SfxItemSet* pFooterSet = nullptr;
917     if ( pParamSet->GetItemState( ATTR_PAGE_FOOTERSET, false,
918                             reinterpret_cast<const SfxPoolItem**>(&pFooterSetItem) ) == SfxItemState::SET )
919     {
920         pFooterSet = &pFooterSetItem->GetItemSet();
921                                                         // Footline has space above
922         aFtr.nDistance  = pFooterSet->Get(ATTR_ULSPACE).GetUpper();
923     }
924     lcl_FillHFParam( aFtr, pFooterSet );
925 
926     // Compile Table-/Area-Params from single Items
927 
928     // TabPage "Table"
929 
930     const SfxUInt16Item*     pScaleItem          = nullptr;
931     const ScPageScaleToItem* pScaleToItem        = nullptr;
932     const SfxUInt16Item*     pScaleToPagesItem   = nullptr;
933     SfxItemState             eState;
934 
935     eState = pParamSet->GetItemState( ATTR_PAGE_SCALE, false,
936                                       reinterpret_cast<const SfxPoolItem**>(&pScaleItem) );
937     if ( SfxItemState::DEFAULT == eState )
938         pScaleItem = &pParamSet->GetPool()->GetDefaultItem( ATTR_PAGE_SCALE );
939 
940     eState = pParamSet->GetItemState( ATTR_PAGE_SCALETO, false,
941                                       reinterpret_cast<const SfxPoolItem**>(&pScaleToItem) );
942     if ( SfxItemState::DEFAULT == eState )
943         pScaleToItem = &pParamSet->GetPool()->GetDefaultItem( ATTR_PAGE_SCALETO );
944 
945     eState = pParamSet->GetItemState( ATTR_PAGE_SCALETOPAGES, false,
946                                       reinterpret_cast<const SfxPoolItem**>(&pScaleToPagesItem) );
947     if ( SfxItemState::DEFAULT == eState )
948         pScaleToPagesItem = &pParamSet->GetPool()->GetDefaultItem( ATTR_PAGE_SCALETOPAGES );
949 
950     OSL_ENSURE( pScaleItem && pScaleToItem && pScaleToPagesItem, "Missing ScaleItem! :-/" );
951 
952     aTableParam.bCellContent    = true;
953     aTableParam.bNotes          = lcl_GetBool(pParamSet,ATTR_PAGE_NOTES);
954     aTableParam.bGrid           = lcl_GetBool(pParamSet,ATTR_PAGE_GRID);
955     aTableParam.bHeaders        = lcl_GetBool(pParamSet,ATTR_PAGE_HEADERS);
956     aTableParam.bFormulas       = lcl_GetBool(pParamSet,ATTR_PAGE_FORMULAS);
957     aTableParam.bNullVals       = lcl_GetBool(pParamSet,ATTR_PAGE_NULLVALS);
958     aTableParam.bCharts         = lcl_GetShow(pParamSet,ATTR_PAGE_CHARTS);
959     aTableParam.bObjects        = lcl_GetShow(pParamSet,ATTR_PAGE_OBJECTS);
960     aTableParam.bDrawings       = lcl_GetShow(pParamSet,ATTR_PAGE_DRAWINGS);
961     aTableParam.bTopDown        = lcl_GetBool(pParamSet,ATTR_PAGE_TOPDOWN);
962     aTableParam.bLeftRight      = !aTableParam.bLeftRight;
963     aTableParam.nFirstPageNo    = lcl_GetUShort(pParamSet,ATTR_PAGE_FIRSTPAGENO);
964     if (!aTableParam.nFirstPageNo)
965         aTableParam.nFirstPageNo = static_cast<sal_uInt16>(nPageStart);     // from previous table
966 
967     if ( pScaleItem && pScaleToItem && pScaleToPagesItem )
968     {
969         sal_uInt16  nScaleAll     = pScaleItem->GetValue();
970         sal_uInt16  nScaleToPages = pScaleToPagesItem->GetValue();
971 
972         aTableParam.bScaleNone      = (nScaleAll     == 100);
973         aTableParam.bScaleAll       = (nScaleAll      > 0  );
974         aTableParam.bScaleTo        = pScaleToItem->IsValid();
975         aTableParam.bScalePageNum   = (nScaleToPages  > 0  );
976         aTableParam.nScaleAll       = nScaleAll;
977         aTableParam.nScaleWidth     = pScaleToItem->GetWidth();
978         aTableParam.nScaleHeight    = pScaleToItem->GetHeight();
979         aTableParam.nScalePageNum   = nScaleToPages;
980     }
981     else
982     {
983         aTableParam.bScaleNone      = true;
984         aTableParam.bScaleAll       = false;
985         aTableParam.bScaleTo        = false;
986         aTableParam.bScalePageNum   = false;
987         aTableParam.nScaleAll       = 0;
988         aTableParam.nScaleWidth     = 0;
989         aTableParam.nScaleHeight    = 0;
990         aTableParam.nScalePageNum   = 0;
991     }
992 
993     //  skip empty pages only if options with that flag are passed
994     aTableParam.bSkipEmpty = pOptions && pOptions->GetSkipEmpty();
995     if ( pPageData )
996         aTableParam.bSkipEmpty = false;
997     // If pPageData is set, only the breaks are interesting for the
998     // pagebreak preview, empty pages are not addressed separately.
999 
1000     aTableParam.bForceBreaks = pOptions && pOptions->GetForceBreaks();
1001 
1002     // TabPage "Parts":
1003 
1004     //! walk through all PrintAreas of the table !!!
1005     const ScRange*  pPrintArea = rDoc.GetPrintRange( nPrintTab, 0 );
1006     const ScRange*  pRepeatCol = rDoc.GetRepeatColRange( nPrintTab );
1007     const ScRange*  pRepeatRow = rDoc.GetRepeatRowRange( nPrintTab );
1008 
1009     //  ignoring ATTR_PAGE_PRINTTABLES
1010 
1011     bool bHasPrintRange = rDoc.HasPrintRange();
1012     sal_uInt16 nPrintRangeCount = rDoc.GetPrintRangeCount(nPrintTab);
1013     bool bPrintEntireSheet = rDoc.IsPrintEntireSheet(nPrintTab);
1014 
1015     if (!bPrintEntireSheet && !nPrintRangeCount)
1016         mbHasPrintRange = false;
1017 
1018     if ( pUserArea )                // UserArea (selection) has priority
1019     {
1020         bPrintCurrentTable    =
1021         aAreaParam.bPrintArea = true;                   // Selection
1022         aAreaParam.aPrintArea = *pUserArea;
1023 
1024         //  The table-query is already in DocShell::Print, here always
1025         aAreaParam.aPrintArea.aStart.SetTab(nPrintTab);
1026         aAreaParam.aPrintArea.aEnd.SetTab(nPrintTab);
1027     }
1028     else if (bHasPrintRange)
1029     {
1030         if ( pPrintArea )                               // at least one set?
1031         {
1032             bPrintCurrentTable    =
1033             aAreaParam.bPrintArea = true;
1034             aAreaParam.aPrintArea = *pPrintArea;
1035 
1036             bMultiArea = nPrintRangeCount > 1;
1037         }
1038         else
1039         {
1040             // do not print hidden sheets with "Print entire sheet" flag
1041             bPrintCurrentTable = rDoc.IsPrintEntireSheet( nPrintTab ) && rDoc.IsVisible( nPrintTab );
1042             aAreaParam.bPrintArea = !bPrintCurrentTable;    // otherwise the table is always counted
1043         }
1044     }
1045     else
1046     {
1047         //  don't print hidden tables if there's no print range defined there
1048         if ( rDoc.IsVisible( nPrintTab ) )
1049         {
1050             aAreaParam.bPrintArea = false;
1051             bPrintCurrentTable = true;
1052         }
1053         else
1054         {
1055             aAreaParam.bPrintArea = true;   // otherwise the table is always counted
1056             bPrintCurrentTable = false;
1057         }
1058     }
1059 
1060     if ( pRepeatCol )
1061     {
1062         aAreaParam.bRepeatCol = true;
1063         nRepeatStartCol = pRepeatCol->aStart.Col();
1064         nRepeatEndCol   = pRepeatCol->aEnd  .Col();
1065     }
1066     else
1067     {
1068         aAreaParam.bRepeatCol = false;
1069         nRepeatStartCol = nRepeatEndCol = SCCOL_REPEAT_NONE;
1070     }
1071 
1072     if ( pRepeatRow )
1073     {
1074         aAreaParam.bRepeatRow = true;
1075         nRepeatStartRow = pRepeatRow->aStart.Row();
1076         nRepeatEndRow   = pRepeatRow->aEnd  .Row();
1077     }
1078     else
1079     {
1080         aAreaParam.bRepeatRow = false;
1081         nRepeatStartRow = nRepeatEndRow = SCROW_REPEAT_NONE;
1082     }
1083 
1084             //  Split pages
1085 
1086     if (!bPrintAreaValid)
1087     {
1088         nTabPages = CountPages();                                   // also calculates zoom
1089         nTotalPages = nTabPages;
1090         nTotalPages += CountNotePages();
1091     }
1092     else
1093     {
1094         CalcPages();            // search breaks only
1095         CountNotePages();       // Count notes, even if number of pages is already known
1096     }
1097 
1098     if (nDocPages)
1099         aFieldData.nTotalPages = nDocPages;
1100     else
1101         aFieldData.nTotalPages = nTotalPages;
1102 
1103     SetDateTime( DateTime( DateTime::SYSTEM ) );
1104 
1105     if( pDocShell->getDocProperties()->getTitle().getLength() != 0 )
1106         aFieldData.aTitle = pDocShell->getDocProperties()->getTitle();
1107     else
1108         aFieldData.aTitle = pDocShell->GetTitle();
1109 
1110     const INetURLObject& rURLObj = pDocShell->GetMedium()->GetURLObject();
1111     aFieldData.aLongDocName = rURLObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
1112     if ( !aFieldData.aLongDocName.isEmpty() )
1113         aFieldData.aShortDocName = rURLObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
1114     else
1115         aFieldData.aShortDocName = aFieldData.aLongDocName = aFieldData.aTitle;
1116 
1117     //  Printer settings (Orientation, Paper) at DoPrint
1118 }
1119 
GetDataSize() const1120 Size ScPrintFunc::GetDataSize() const
1121 {
1122     Size aSize = aPageSize;
1123     aSize.AdjustWidth( -(nLeftMargin + nRightMargin) );
1124     aSize.AdjustHeight( -(nTopMargin + nBottomMargin) );
1125     aSize.AdjustHeight( -(aHdr.nHeight + aFtr.nHeight) );
1126     return aSize;
1127 }
1128 
GetScaleData(Size & rPhysSize,tools::Long & rDocHdr,tools::Long & rDocFtr)1129 void ScPrintFunc::GetScaleData( Size& rPhysSize, tools::Long& rDocHdr, tools::Long& rDocFtr )
1130 {
1131     rPhysSize = aPageSize;
1132     rPhysSize.AdjustWidth( -(nLeftMargin + nRightMargin) );
1133     rPhysSize.AdjustHeight( -(nTopMargin + nBottomMargin) );
1134 
1135     rDocHdr = aHdr.nHeight;
1136     rDocFtr = aFtr.nHeight;
1137 }
1138 
SetDateTime(const DateTime & rDateTime)1139 void ScPrintFunc::SetDateTime( const DateTime& rDateTime )
1140 {
1141     aFieldData.aDateTime = rDateTime;
1142 }
1143 
lcl_DrawGraphic(const Graphic & rGraphic,vcl::RenderContext & rOutDev,const tools::Rectangle & rGrf,const tools::Rectangle & rOut)1144 static void lcl_DrawGraphic( const Graphic &rGraphic, vcl::RenderContext& rOutDev,
1145                       const tools::Rectangle &rGrf, const tools::Rectangle &rOut )
1146 {
1147     const bool bNotInside = !rOut.IsInside( rGrf );
1148     if ( bNotInside )
1149     {
1150         rOutDev.Push();
1151         rOutDev.IntersectClipRegion( rOut );
1152     }
1153 
1154     rGraphic.Draw(rOutDev, rGrf.TopLeft(), rGrf.GetSize());
1155 
1156     if ( bNotInside )
1157         rOutDev.Pop();
1158 }
1159 
lcl_DrawGraphic(const SvxBrushItem & rBrush,vcl::RenderContext & rOutDev,const OutputDevice * pRefDev,const tools::Rectangle & rOrg,const tools::Rectangle & rOut,OUString const & referer)1160 static void lcl_DrawGraphic( const SvxBrushItem &rBrush, vcl::RenderContext& rOutDev, const OutputDevice* pRefDev,
1161                         const tools::Rectangle &rOrg, const tools::Rectangle &rOut,
1162                         OUString const & referer )
1163 {
1164     Size aGrfSize(0,0);
1165     const Graphic *pGraphic = rBrush.GetGraphic(referer);
1166     SvxGraphicPosition ePos;
1167     if ( pGraphic && pGraphic->IsSupportedGraphic() )
1168     {
1169         const MapMode aMapMM( MapUnit::Map100thMM );
1170         if ( pGraphic->GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
1171             aGrfSize = pRefDev->PixelToLogic( pGraphic->GetPrefSize(), aMapMM );
1172         else
1173             aGrfSize = OutputDevice::LogicToLogic( pGraphic->GetPrefSize(),
1174                                     pGraphic->GetPrefMapMode(), aMapMM );
1175         ePos = rBrush.GetGraphicPos();
1176     }
1177     else
1178         ePos = GPOS_NONE;
1179 
1180     Point aPos;
1181     Size aDrawSize = aGrfSize;
1182 
1183     bool bDraw = true;
1184     switch ( ePos )
1185     {
1186         case GPOS_LT: aPos = rOrg.TopLeft();
1187                       break;
1188         case GPOS_MT: aPos.setY( rOrg.Top() );
1189                       aPos.setX( rOrg.Left() + rOrg.GetSize().Width()/2 - aGrfSize.Width()/2 );
1190                       break;
1191         case GPOS_RT: aPos.setY( rOrg.Top() );
1192                       aPos.setX( rOrg.Right() - aGrfSize.Width() );
1193                       break;
1194 
1195         case GPOS_LM: aPos.setY( rOrg.Top() + rOrg.GetSize().Height()/2 - aGrfSize.Height()/2 );
1196                       aPos.setX( rOrg.Left() );
1197                       break;
1198         case GPOS_MM: aPos.setY( rOrg.Top() + rOrg.GetSize().Height()/2 - aGrfSize.Height()/2 );
1199                       aPos.setX( rOrg.Left() + rOrg.GetSize().Width()/2 - aGrfSize.Width()/2 );
1200                       break;
1201         case GPOS_RM: aPos.setY( rOrg.Top() + rOrg.GetSize().Height()/2 - aGrfSize.Height()/2 );
1202                       aPos.setX( rOrg.Right() - aGrfSize.Width() );
1203                       break;
1204 
1205         case GPOS_LB: aPos.setY( rOrg.Bottom() - aGrfSize.Height() );
1206                       aPos.setX( rOrg.Left() );
1207                       break;
1208         case GPOS_MB: aPos.setY( rOrg.Bottom() - aGrfSize.Height() );
1209                       aPos.setX( rOrg.Left() + rOrg.GetSize().Width()/2 - aGrfSize.Width()/2 );
1210                       break;
1211         case GPOS_RB: aPos.setY( rOrg.Bottom() - aGrfSize.Height() );
1212                       aPos.setX( rOrg.Right() - aGrfSize.Width() );
1213                       break;
1214 
1215         case GPOS_AREA:
1216                       aPos = rOrg.TopLeft();
1217                       aDrawSize = rOrg.GetSize();
1218                       break;
1219         case GPOS_TILED:
1220                     {
1221                         //  use GraphicObject::DrawTiled instead of an own loop
1222                         //  (pixel rounding is handled correctly, and a very small bitmap
1223                         //  is duplicated into a bigger one for better performance)
1224 
1225                         GraphicObject aObject( *pGraphic );
1226 
1227                         if( rOutDev.GetOutDevType() == OUTDEV_PDF &&
1228                             (aObject.GetType() == GraphicType::Bitmap || aObject.GetType() == GraphicType::Default) )
1229                         {
1230                             // For PDF export, every draw
1231                             // operation for bitmaps takes a noticeable
1232                             // amount of place (~50 characters). Thus,
1233                             // optimize between tile bitmap size and
1234                             // number of drawing operations here.
1235                             //
1236                             //                  A_out
1237                             // n_chars = k1 *  ---------- + k2 * A_bitmap
1238                             //                  A_bitmap
1239                             //
1240                             // minimum n_chars is obtained for (derive for
1241                             // A_bitmap, set to 0, take positive
1242                             // solution):
1243                             //                   k1
1244                             // A_bitmap = Sqrt( ---- A_out )
1245                             //                   k2
1246                             //
1247                             // where k1 is the number of chars per draw
1248                             // operation, and k2 is the number of chars
1249                             // per bitmap pixel. This is approximately 50
1250                             // and 7 for current PDF writer, respectively.
1251 
1252                             const double    k1( 50 );
1253                             const double    k2( 7 );
1254                             const Size      aSize( rOrg.GetSize() );
1255                             const double    Abitmap( k1/k2 * aSize.Width()*aSize.Height() );
1256 
1257                             aObject.DrawTiled( rOutDev, rOrg, aGrfSize, Size(0,0),
1258                                                ::std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap)) + .5 ) ) );
1259                         }
1260                         else
1261                         {
1262                             aObject.DrawTiled( rOutDev, rOrg, aGrfSize, Size(0,0) );
1263                         }
1264 
1265                         bDraw = false;
1266                     }
1267                     break;
1268 
1269         case GPOS_NONE:
1270                       bDraw = false;
1271                       break;
1272 
1273         default: OSL_ENSURE( false, "new Graphic position?" );
1274     }
1275     tools::Rectangle aGrf( aPos,aDrawSize );
1276     if ( bDraw && aGrf.IsOver( rOut ) )
1277     {
1278         lcl_DrawGraphic( *pGraphic, rOutDev, aGrf, rOut );
1279     }
1280 }
1281 
1282 // The frame is drawn inwards
1283 
DrawBorder(tools::Long nScrX,tools::Long nScrY,tools::Long nScrW,tools::Long nScrH,const SvxBoxItem * pBorderData,const SvxBrushItem * pBackground,const SvxShadowItem * pShadow)1284 void ScPrintFunc::DrawBorder( tools::Long nScrX, tools::Long nScrY, tools::Long nScrW, tools::Long nScrH,
1285                                 const SvxBoxItem* pBorderData, const SvxBrushItem* pBackground,
1286                                 const SvxShadowItem* pShadow )
1287 {
1288     //!     direct output from SvxBoxItem !!!
1289 
1290     if (pBorderData)
1291         if ( !pBorderData->GetTop() && !pBorderData->GetBottom() && !pBorderData->GetLeft() &&
1292                                         !pBorderData->GetRight() )
1293             pBorderData = nullptr;
1294 
1295     if (!pBorderData && !pBackground && !pShadow)
1296         return;                                     // nothing to do
1297 
1298     tools::Long nLeft   = 0;
1299     tools::Long nRight  = 0;
1300     tools::Long nTop    = 0;
1301     tools::Long nBottom = 0;
1302 
1303     //  aFrameRect - outside around frame, without shadow
1304     if ( pShadow && pShadow->GetLocation() != SvxShadowLocation::NONE )
1305     {
1306         nLeft   += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::LEFT)   * nScaleX );
1307         nRight  += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::RIGHT)  * nScaleX );
1308         nTop    += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::TOP)    * nScaleY );
1309         nBottom += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM) * nScaleY );
1310     }
1311     tools::Rectangle aFrameRect( Point(nScrX+nLeft, nScrY+nTop),
1312                           Size(nScrW-nLeft-nRight, nScrH-nTop-nBottom) );
1313 
1314     //  center of frame, to paint lines through OutputData
1315     if (pBorderData)
1316     {
1317         nLeft   += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetLeft())   * nScaleX / 2 );
1318         nRight  += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetRight())  * nScaleX / 2 );
1319         nTop    += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetTop())    * nScaleY / 2 );
1320         nBottom += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetBottom()) * nScaleY / 2 );
1321     }
1322     tools::Long nEffHeight = nScrH - nTop - nBottom;
1323     tools::Long nEffWidth = nScrW - nLeft - nRight;
1324     if (nEffHeight<=0 || nEffWidth<=0)
1325         return;                                         // empty
1326 
1327     if ( pBackground )
1328     {
1329         if (pBackground->GetGraphicPos() != GPOS_NONE)
1330         {
1331             OutputDevice* pRefDev;
1332             if ( bIsRender )
1333                 pRefDev = pDev;                 // don't use printer for PDF
1334             else
1335                 pRefDev = rDoc.GetPrinter();   // use printer also for preview
1336             OUString referer;
1337             if (pDocShell->HasName()) {
1338                 referer = pDocShell->GetMedium()->GetName();
1339             }
1340             lcl_DrawGraphic(*pBackground, *pDev, pRefDev, aFrameRect, aFrameRect, referer);
1341         }
1342         else
1343         {
1344             pDev->SetFillColor(pBackground->GetColor());
1345             pDev->SetLineColor();
1346             pDev->DrawRect(aFrameRect);
1347         }
1348     }
1349 
1350     if ( pShadow && pShadow->GetLocation() != SvxShadowLocation::NONE )
1351     {
1352         pDev->SetFillColor(pShadow->GetColor());
1353         pDev->SetLineColor();
1354         tools::Long nShadowX = static_cast<tools::Long>( pShadow->GetWidth() * nScaleX );
1355         tools::Long nShadowY = static_cast<tools::Long>( pShadow->GetWidth() * nScaleY );
1356         switch (pShadow->GetLocation())
1357         {
1358             case SvxShadowLocation::TopLeft:
1359                 pDev->DrawRect( tools::Rectangle(
1360                         aFrameRect.Left()-nShadowX, aFrameRect.Top()-nShadowY,
1361                         aFrameRect.Right()-nShadowX, aFrameRect.Top() ) );
1362                 pDev->DrawRect( tools::Rectangle(
1363                         aFrameRect.Left()-nShadowX, aFrameRect.Top()-nShadowY,
1364                         aFrameRect.Left(), aFrameRect.Bottom()-nShadowY ) );
1365                 break;
1366             case SvxShadowLocation::TopRight:
1367                 pDev->DrawRect( tools::Rectangle(
1368                         aFrameRect.Left()+nShadowX, aFrameRect.Top()-nShadowY,
1369                         aFrameRect.Right()+nShadowX, aFrameRect.Top() ) );
1370                 pDev->DrawRect( tools::Rectangle(
1371                         aFrameRect.Right(), aFrameRect.Top()-nShadowY,
1372                         aFrameRect.Right()+nShadowX, aFrameRect.Bottom()-nShadowY ) );
1373                 break;
1374             case SvxShadowLocation::BottomLeft:
1375                 pDev->DrawRect( tools::Rectangle(
1376                         aFrameRect.Left()-nShadowX, aFrameRect.Bottom(),
1377                         aFrameRect.Right()-nShadowX, aFrameRect.Bottom()+nShadowY ) );
1378                 pDev->DrawRect( tools::Rectangle(
1379                         aFrameRect.Left()-nShadowX, aFrameRect.Top()+nShadowY,
1380                         aFrameRect.Left(), aFrameRect.Bottom()+nShadowY ) );
1381                 break;
1382             case SvxShadowLocation::BottomRight:
1383                 pDev->DrawRect( tools::Rectangle(
1384                         aFrameRect.Left()+nShadowX, aFrameRect.Bottom(),
1385                         aFrameRect.Right()+nShadowX, aFrameRect.Bottom()+nShadowY ) );
1386                 pDev->DrawRect( tools::Rectangle(
1387                         aFrameRect.Right(), aFrameRect.Top()+nShadowY,
1388                         aFrameRect.Right()+nShadowX, aFrameRect.Bottom()+nShadowY ) );
1389                 break;
1390             default:
1391             {
1392                 // added to avoid warnings
1393             }
1394         }
1395     }
1396 
1397     if (!pBorderData)
1398         return;
1399 
1400     ScDocumentUniquePtr pBorderDoc(new ScDocument( SCDOCMODE_UNDO ));
1401     pBorderDoc->InitUndo( rDoc, 0,0, true,true );
1402     pBorderDoc->ApplyAttr( 0,0,0, *pBorderData );
1403 
1404     ScTableInfo aTabInfo;
1405     pBorderDoc->FillInfo( aTabInfo, 0,0, 0,0, 0,
1406                                         nScaleX, nScaleY, false, false );
1407     OSL_ENSURE(aTabInfo.mnArrCount,"nArrCount == 0");
1408 
1409     aTabInfo.mpRowInfo[1].nHeight = static_cast<sal_uInt16>(nEffHeight);
1410     aTabInfo.mpRowInfo[0].pCellInfo[1].nWidth =
1411         aTabInfo.mpRowInfo[1].pCellInfo[1].nWidth = static_cast<sal_uInt16>(nEffWidth);
1412 
1413     ScOutputData aOutputData( pDev, OUTTYPE_PRINTER, aTabInfo, pBorderDoc.get(), 0,
1414                                 nScrX+nLeft, nScrY+nTop, 0,0, 0,0, nScaleX, nScaleY );
1415     aOutputData.SetUseStyleColor( bUseStyleColor );
1416 
1417     aOutputData.DrawFrame(*pDev);
1418 }
1419 
PrintColHdr(SCCOL nX1,SCCOL nX2,tools::Long nScrX,tools::Long nScrY)1420 void ScPrintFunc::PrintColHdr( SCCOL nX1, SCCOL nX2, tools::Long nScrX, tools::Long nScrY )
1421 {
1422     bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
1423     tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
1424 
1425     Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1426     tools::Long nOneX = aOnePixel.Width();
1427     tools::Long nOneY = aOnePixel.Height();
1428     SCCOL nCol;
1429 
1430     tools::Long nHeight = static_cast<tools::Long>(PRINT_HEADER_HEIGHT * nScaleY);
1431     tools::Long nEndY = nScrY + nHeight - nOneY;
1432 
1433     tools::Long nPosX = nScrX;
1434     if ( bLayoutRTL )
1435     {
1436         for (nCol=nX1; nCol<=nX2; nCol++)
1437             nPosX += static_cast<tools::Long>( rDoc.GetColWidth( nCol, nPrintTab ) * nScaleX );
1438     }
1439     else
1440         nPosX -= nOneX;
1441     tools::Long nPosY = nScrY - nOneY;
1442     OUString aText;
1443 
1444     for (nCol=nX1; nCol<=nX2; nCol++)
1445     {
1446         sal_uInt16 nDocW = rDoc.GetColWidth( nCol, nPrintTab );
1447         if (nDocW)
1448         {
1449             tools::Long nWidth = static_cast<tools::Long>(nDocW * nScaleX);
1450             tools::Long nEndX = nPosX + nWidth * nLayoutSign;
1451 
1452             pDev->DrawRect( tools::Rectangle( nPosX,nPosY,nEndX,nEndY ) );
1453 
1454             aText = ::ScColToAlpha( nCol);
1455             tools::Long nTextWidth = pDev->GetTextWidth(aText);
1456             tools::Long nTextHeight = pDev->GetTextHeight();
1457             tools::Long nAddX = ( nWidth  - nTextWidth  ) / 2;
1458             tools::Long nAddY = ( nHeight - nTextHeight ) / 2;
1459             tools::Long nTextPosX = nPosX+nAddX;
1460             if ( bLayoutRTL )
1461                 nTextPosX -= nWidth;
1462             pDev->DrawText( Point( nTextPosX,nPosY+nAddY ), aText );
1463 
1464             nPosX = nEndX;
1465         }
1466     }
1467 }
1468 
PrintRowHdr(SCROW nY1,SCROW nY2,tools::Long nScrX,tools::Long nScrY)1469 void ScPrintFunc::PrintRowHdr( SCROW nY1, SCROW nY2, tools::Long nScrX, tools::Long nScrY )
1470 {
1471     Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1472     tools::Long nOneX = aOnePixel.Width();
1473     tools::Long nOneY = aOnePixel.Height();
1474 
1475     bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
1476 
1477     tools::Long nWidth = static_cast<tools::Long>(PRINT_HEADER_WIDTH * nScaleX);
1478     tools::Long nEndX = nScrX + nWidth;
1479     tools::Long nPosX = nScrX;
1480     if ( !bLayoutRTL )
1481     {
1482         nEndX -= nOneX;
1483         nPosX -= nOneX;
1484     }
1485     tools::Long nPosY = nScrY - nOneY;
1486     OUString aText;
1487 
1488     for (SCROW nRow=nY1; nRow<=nY2; nRow++)
1489     {
1490         sal_uInt16 nDocH = rDoc.GetRowHeight( nRow, nPrintTab );
1491         if (nDocH)
1492         {
1493             tools::Long nHeight = static_cast<tools::Long>(nDocH * nScaleY);
1494             tools::Long nEndY = nPosY + nHeight;
1495 
1496             pDev->DrawRect( tools::Rectangle( nPosX,nPosY,nEndX,nEndY ) );
1497 
1498             aText = OUString::number( nRow+1 );
1499             tools::Long nTextWidth = pDev->GetTextWidth(aText);
1500             tools::Long nTextHeight = pDev->GetTextHeight();
1501             tools::Long nAddX = ( nWidth  - nTextWidth  ) / 2;
1502             tools::Long nAddY = ( nHeight - nTextHeight ) / 2;
1503             pDev->DrawText( Point( nPosX+nAddX,nPosY+nAddY ), aText );
1504 
1505             nPosY = nEndY;
1506         }
1507     }
1508 }
1509 
LocateColHdr(SCCOL nX1,SCCOL nX2,tools::Long nScrX,tools::Long nScrY,bool bRepCol,ScPreviewLocationData & rLocationData)1510 void ScPrintFunc::LocateColHdr( SCCOL nX1, SCCOL nX2, tools::Long nScrX, tools::Long nScrY,
1511                                 bool bRepCol, ScPreviewLocationData& rLocationData )
1512 {
1513     Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1514     tools::Long nOneX = aOnePixel.Width();
1515     tools::Long nOneY = aOnePixel.Height();
1516 
1517     tools::Long nHeight = static_cast<tools::Long>(PRINT_HEADER_HEIGHT * nScaleY);
1518     tools::Long nEndY = nScrY + nHeight - nOneY;
1519 
1520     tools::Long nPosX = nScrX - nOneX;
1521     for (SCCOL nCol=nX1; nCol<=nX2; nCol++)
1522     {
1523         sal_uInt16 nDocW = rDoc.GetColWidth( nCol, nPrintTab );
1524         if (nDocW)
1525             nPosX += static_cast<tools::Long>(nDocW * nScaleX);
1526     }
1527     tools::Rectangle aCellRect( nScrX, nScrY, nPosX, nEndY );
1528     rLocationData.AddColHeaders( aCellRect, nX1, nX2, bRepCol );
1529 }
1530 
LocateRowHdr(SCROW nY1,SCROW nY2,tools::Long nScrX,tools::Long nScrY,bool bRepRow,ScPreviewLocationData & rLocationData)1531 void ScPrintFunc::LocateRowHdr( SCROW nY1, SCROW nY2, tools::Long nScrX, tools::Long nScrY,
1532                                 bool bRepRow, ScPreviewLocationData& rLocationData )
1533 {
1534     Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1535     tools::Long nOneX = aOnePixel.Width();
1536     tools::Long nOneY = aOnePixel.Height();
1537 
1538     bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
1539 
1540     tools::Long nWidth = static_cast<tools::Long>(PRINT_HEADER_WIDTH * nScaleX);
1541     tools::Long nEndX = nScrX + nWidth;
1542     if ( !bLayoutRTL )
1543         nEndX -= nOneX;
1544 
1545     tools::Long nPosY = nScrY - nOneY;
1546     nPosY += rDoc.GetScaledRowHeight( nY1, nY2, nPrintTab, nScaleY);
1547     tools::Rectangle aCellRect( nScrX, nScrY, nEndX, nPosY );
1548     rLocationData.AddRowHeaders( aCellRect, nY1, nY2, bRepRow );
1549 }
1550 
LocateArea(SCCOL nX1,SCROW nY1,SCCOL nX2,SCROW nY2,tools::Long nScrX,tools::Long nScrY,bool bRepCol,bool bRepRow,ScPreviewLocationData & rLocationData)1551 void ScPrintFunc::LocateArea( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
1552                                 tools::Long nScrX, tools::Long nScrY, bool bRepCol, bool bRepRow,
1553                                 ScPreviewLocationData& rLocationData )
1554 {
1555     //  get MapMode for drawing objects (same MapMode as in ScOutputData::PrintDrawingLayer)
1556 
1557     Point aLogPos = OutputDevice::LogicToLogic(Point(nScrX,nScrY), aOffsetMode, aLogicMode);
1558     tools::Long nLogStX = aLogPos.X();
1559     tools::Long nLogStY = aLogPos.Y();
1560 
1561     SCCOL nCol;
1562     Point aTwipOffset;
1563     for (nCol=0; nCol<nX1; nCol++)
1564         aTwipOffset.AdjustX( -(rDoc.GetColWidth( nCol, nPrintTab )) );
1565     aTwipOffset.AdjustY( -sal_Int32(rDoc.GetRowHeight( 0, nY1-1, nPrintTab )) );
1566 
1567     Point aMMOffset( aTwipOffset );
1568     aMMOffset.setX( static_cast<tools::Long>(aMMOffset.X() * HMM_PER_TWIPS) );
1569     aMMOffset.setY( static_cast<tools::Long>(aMMOffset.Y() * HMM_PER_TWIPS) );
1570     aMMOffset += Point( nLogStX, nLogStY );
1571     MapMode aDrawMapMode( MapUnit::Map100thMM, aMMOffset, aLogicMode.GetScaleX(), aLogicMode.GetScaleY() );
1572 
1573     //  get pixel rectangle
1574 
1575     Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1576     tools::Long nOneX = aOnePixel.Width();
1577     tools::Long nOneY = aOnePixel.Height();
1578 
1579     tools::Long nPosX = nScrX - nOneX;
1580     for (nCol=nX1; nCol<=nX2; nCol++)
1581     {
1582         sal_uInt16 nDocW = rDoc.GetColWidth( nCol, nPrintTab );
1583         if (nDocW)
1584             nPosX += static_cast<tools::Long>(nDocW * nScaleX);
1585     }
1586 
1587     tools::Long nPosY = nScrY - nOneY;
1588     nPosY += rDoc.GetScaledRowHeight( nY1, nY2, nPrintTab, nScaleY);
1589     tools::Rectangle aCellRect( nScrX, nScrY, nPosX, nPosY );
1590     rLocationData.AddCellRange( aCellRect, ScRange( nX1,nY1,nPrintTab, nX2,nY2,nPrintTab ),
1591                                 bRepCol, bRepRow, aDrawMapMode );
1592 }
1593 
PrintArea(SCCOL nX1,SCROW nY1,SCCOL nX2,SCROW nY2,tools::Long nScrX,tools::Long nScrY,bool bShLeft,bool bShTop,bool bShRight,bool bShBottom)1594 void ScPrintFunc::PrintArea( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
1595                                 tools::Long nScrX, tools::Long nScrY,
1596                                 bool bShLeft, bool bShTop, bool bShRight, bool bShBottom )
1597 {
1598     // #i47547# nothing to do if the end of the print area is before the end of
1599     // the repeat columns/rows (don't use negative size for ScOutputData)
1600     if ( nX2 < nX1 || nY2 < nY1 )
1601         return;
1602 
1603                             //!     hand over Flag at FillInfo  !!!!!
1604     ScRange aERange;
1605     bool bEmbed = rDoc.IsEmbedded();
1606     if (bEmbed)
1607     {
1608         rDoc.GetEmbedded(aERange);
1609         rDoc.ResetEmbedded();
1610     }
1611 
1612     Point aPos = OutputDevice::LogicToLogic(Point(nScrX,nScrY), aOffsetMode, aLogicMode);
1613     tools::Long nLogStX = aPos.X();
1614     tools::Long nLogStY = aPos.Y();
1615 
1616                     //  Assemble data
1617 
1618     ScTableInfo aTabInfo;
1619     rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nPrintTab,
1620                                         nScaleX, nScaleY, true, aTableParam.bFormulas );
1621     lcl_HidePrint( aTabInfo, nX1, nX2 );
1622 
1623     if (bEmbed)
1624         rDoc.SetEmbedded(aERange);
1625 
1626     ScOutputData aOutputData( pDev, OUTTYPE_PRINTER, aTabInfo, &rDoc, nPrintTab,
1627                                 nScrX, nScrY, nX1, nY1, nX2, nY2, nScaleX, nScaleY );
1628 
1629     aOutputData.SetDrawView( pDrawView );
1630 
1631     // test if all paint parts are hidden, then a paint is not necessary at all
1632     const Point aMMOffset(aOutputData.PrePrintDrawingLayer(nLogStX, nLogStY));
1633     const bool bHideAllDrawingLayer( pDrawView && pDrawView->getHideOle() && pDrawView->getHideChart()
1634             && pDrawView->getHideDraw() && pDrawView->getHideFormControl() );
1635 
1636     if(!bHideAllDrawingLayer)
1637     {
1638         pDev->SetMapMode(aLogicMode);
1639         //  don's set Clipping here (Mapmode is being moved)
1640 
1641         // #i72502#
1642         aOutputData.PrintDrawingLayer(SC_LAYER_BACK, aMMOffset);
1643     }
1644 
1645     pDev->SetMapMode(aOffsetMode);
1646 
1647     aOutputData.SetShowFormulas( aTableParam.bFormulas );
1648     aOutputData.SetShowNullValues( aTableParam.bNullVals );
1649     aOutputData.SetUseStyleColor( bUseStyleColor );
1650 
1651     Color aGridColor( COL_BLACK );
1652     if ( bUseStyleColor )
1653         aGridColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
1654     aOutputData.SetGridColor( aGridColor );
1655 
1656     if ( !pPrinter )
1657     {
1658         OutputDevice* pRefDev = rDoc.GetPrinter();     // use the printer also for Preview
1659         Fraction aPrintFrac( nZoom, 100 );              // without nManualZoom
1660         //  MapMode, as it would arrive at the printer:
1661         pRefDev->SetMapMode( MapMode( MapUnit::Map100thMM, Point(), aPrintFrac, aPrintFrac ) );
1662 
1663         //  when rendering (PDF), don't use printer as ref device, but printer's MapMode
1664         //  has to be set anyway, as charts still use it (#106409#)
1665         if ( !bIsRender )
1666             aOutputData.SetRefDevice( pRefDev );
1667     }
1668 
1669     if( aTableParam.bCellContent )
1670         aOutputData.DrawBackground(*pDev);
1671 
1672     pDev->SetClipRegion(vcl::Region(tools::Rectangle(
1673                 aPos, Size(aOutputData.GetScrW(), aOutputData.GetScrH()))));
1674     pDev->SetClipRegion();
1675 
1676     if( aTableParam.bCellContent )
1677     {
1678         aOutputData.DrawExtraShadow( bShLeft, bShTop, bShRight, bShBottom );
1679         aOutputData.DrawFrame(*pDev);
1680         aOutputData.DrawStrings();
1681         aOutputData.DrawEdit(false);
1682     }
1683 
1684     if (aTableParam.bGrid)
1685         aOutputData.DrawGrid(*pDev, true, false);    // no page breaks
1686 
1687     aOutputData.AddPDFNotes();      // has no effect if not rendering PDF with notes enabled
1688 
1689     // test if all paint parts are hidden, then a paint is not necessary at all
1690     if(!bHideAllDrawingLayer)
1691     {
1692         // #i72502#
1693         aOutputData.PrintDrawingLayer(SC_LAYER_FRONT, aMMOffset);
1694     }
1695 
1696     // #i72502#
1697     aOutputData.PrintDrawingLayer(SC_LAYER_INTERN, aMMOffset);
1698     aOutputData.PostPrintDrawingLayer(aMMOffset); // #i74768#
1699 }
1700 
IsMirror(tools::Long nPageNo)1701 bool ScPrintFunc::IsMirror( tools::Long nPageNo )          // Mirror margins?
1702 {
1703     return nPageUsage == SvxPageUsage::Mirror && (nPageNo & 1);
1704 }
1705 
IsLeft(tools::Long nPageNo)1706 bool ScPrintFunc::IsLeft( tools::Long nPageNo )            // left foot notes?
1707 {
1708     bool bLeft;
1709     if (nPageUsage == SvxPageUsage::Left)
1710         bLeft = true;
1711     else if (nPageUsage == SvxPageUsage::Right)
1712         bLeft = false;
1713     else
1714         bLeft = (nPageNo & 1) != 0;
1715     return bLeft;
1716 }
1717 
MakeTableString()1718 void ScPrintFunc::MakeTableString()
1719 {
1720     OUString aTmp;
1721     rDoc.GetName(nPrintTab, aTmp);
1722     aFieldData.aTabName = aTmp;
1723 }
1724 
MakeEditEngine()1725 void ScPrintFunc::MakeEditEngine()
1726 {
1727     if (!pEditEngine)
1728     {
1729         //  can't use document's edit engine pool here,
1730         //  because pool must have twips as default metric
1731         pEditEngine.reset( new ScHeaderEditEngine( EditEngine::CreatePool().get() ) );
1732 
1733         pEditEngine->EnableUndo(false);
1734         //fdo#45869 we want text to be positioned as it would be for the
1735         //high dpi printed output, not as would be ideal for the 96dpi preview
1736         //window itself
1737         pEditEngine->SetRefDevice(pPrinter ? pPrinter : rDoc.GetRefDevice());
1738         pEditEngine->SetWordDelimiters(
1739                 ScEditUtil::ModifyDelimiters( pEditEngine->GetWordDelimiters() ) );
1740         pEditEngine->SetControlWord( pEditEngine->GetControlWord() & ~EEControlBits::RTFSTYLESHEETS );
1741         rDoc.ApplyAsianEditSettings( *pEditEngine );
1742         pEditEngine->EnableAutoColor( bUseStyleColor );
1743 
1744         //  Default-Set for alignment
1745         pEditDefaults.reset( new SfxItemSet( pEditEngine->GetEmptyItemSet() ) );
1746 
1747         const ScPatternAttr& rPattern = rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN);
1748         rPattern.FillEditItemSet( pEditDefaults.get() );
1749         //  FillEditItemSet adjusts font height to 1/100th mm,
1750         //  but for header/footer twips is needed, as in the PatternAttr:
1751         pEditDefaults->Put( rPattern.GetItem(ATTR_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT) );
1752         pEditDefaults->Put( rPattern.GetItem(ATTR_CJK_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CJK) );
1753         pEditDefaults->Put( rPattern.GetItem(ATTR_CTL_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CTL) );
1754         //  don't use font color, because background color is not used
1755         //! there's no way to set the background for note pages
1756         pEditDefaults->ClearItem( EE_CHAR_COLOR );
1757         if (ScGlobal::IsSystemRTL())
1758             pEditDefaults->Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
1759     }
1760 
1761     pEditEngine->SetData( aFieldData );     // Set page count etc.
1762 }
1763 
1764 //  nStartY = logic
PrintHF(tools::Long nPageNo,bool bHeader,tools::Long nStartY,bool bDoPrint,ScPreviewLocationData * pLocationData)1765 void ScPrintFunc::PrintHF( tools::Long nPageNo, bool bHeader, tools::Long nStartY,
1766                             bool bDoPrint, ScPreviewLocationData* pLocationData )
1767 {
1768     const ScPrintHFParam& rParam = bHeader ? aHdr : aFtr;
1769 
1770     pDev->SetMapMode( aTwipMode );          // Head-/Footlines in Twips
1771 
1772     bool bFirst = 0 == nPageNo && !rParam.bSharedFirst;
1773     bool bLeft = IsLeft(nPageNo) && !rParam.bShared;
1774     const ScPageHFItem* pHFItem = bFirst ? rParam.pFirst : (bLeft ? rParam.pLeft : rParam.pRight);
1775 
1776     tools::Long nLineStartX = aPageRect.Left()  + rParam.nLeft;
1777     tools::Long nLineEndX   = aPageRect.Right() - rParam.nRight;
1778     tools::Long nLineWidth  = nLineEndX - nLineStartX + 1;
1779 
1780     //  Edit-Engine
1781 
1782     Point aStart( nLineStartX, nStartY );
1783     Size aPaperSize( nLineWidth, rParam.nHeight-rParam.nDistance );
1784     if ( rParam.pBorder )
1785     {
1786         tools::Long nLeft = lcl_LineTotal( rParam.pBorder->GetLeft() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::LEFT);
1787         tools::Long nTop = lcl_LineTotal( rParam.pBorder->GetTop() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::TOP);
1788         aStart.AdjustX(nLeft );
1789         aStart.AdjustY(nTop );
1790         aPaperSize.AdjustWidth( -(nLeft + lcl_LineTotal( rParam.pBorder->GetRight() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::RIGHT)) );
1791         aPaperSize.AdjustHeight( -(nTop + lcl_LineTotal( rParam.pBorder->GetBottom() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::BOTTOM)) );
1792     }
1793 
1794     if ( rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE )
1795     {
1796         tools::Long nLeft  = rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::LEFT);
1797         tools::Long nTop   = rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::TOP);
1798         aStart.AdjustX(nLeft );
1799         aStart.AdjustY(nTop );
1800         aPaperSize.AdjustWidth( -(nLeft + rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::RIGHT)) );
1801         aPaperSize.AdjustHeight( -(nTop + rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM)) );
1802     }
1803 
1804     aFieldData.nPageNo = nPageNo+aTableParam.nFirstPageNo;
1805     MakeEditEngine();
1806 
1807     pEditEngine->SetPaperSize(aPaperSize);
1808 
1809     //  Frame / Background
1810 
1811     Point aBorderStart( nLineStartX, nStartY );
1812     Size aBorderSize( nLineWidth, rParam.nHeight-rParam.nDistance );
1813     if ( rParam.bDynamic )
1814     {
1815         //  adjust here again, for even/odd head-/footlines
1816         //  and probably other breaks by variable (page number etc.)
1817 
1818         tools::Long nMaxHeight = 0;
1819         nMaxHeight = std::max( nMaxHeight, TextHeight( pHFItem->GetLeftArea() ) );
1820         nMaxHeight = std::max( nMaxHeight, TextHeight( pHFItem->GetCenterArea() ) );
1821         nMaxHeight = std::max( nMaxHeight, TextHeight( pHFItem->GetRightArea() ) );
1822         if (rParam.pBorder)
1823             nMaxHeight += lcl_LineTotal( rParam.pBorder->GetTop() ) +
1824                           lcl_LineTotal( rParam.pBorder->GetBottom() ) +
1825                                     rParam.pBorder->GetDistance(SvxBoxItemLine::TOP) +
1826                                     rParam.pBorder->GetDistance(SvxBoxItemLine::BOTTOM);
1827         if (rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE)
1828             nMaxHeight += rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::TOP) +
1829                           rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM);
1830 
1831         if (nMaxHeight < rParam.nManHeight-rParam.nDistance)
1832             nMaxHeight = rParam.nManHeight-rParam.nDistance;        // configured Minimum
1833 
1834         aBorderSize.setHeight( nMaxHeight );
1835     }
1836 
1837     if ( bDoPrint )
1838     {
1839         double nOldScaleX = nScaleX;
1840         double nOldScaleY = nScaleY;
1841         nScaleX = nScaleY = 1.0;            // output directly in Twips
1842         DrawBorder( aBorderStart.X(), aBorderStart.Y(), aBorderSize.Width(), aBorderSize.Height(),
1843                         rParam.pBorder, rParam.pBack, rParam.pShadow );
1844         nScaleX = nOldScaleX;
1845         nScaleY = nOldScaleY;
1846 
1847         //  Clipping for Text
1848 
1849         pDev->SetClipRegion(vcl::Region(tools::Rectangle(aStart, aPaperSize)));
1850 
1851         //  left
1852 
1853         const EditTextObject* pObject = pHFItem->GetLeftArea();
1854         if (pObject)
1855         {
1856             pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
1857             pEditEngine->SetTextNewDefaults( *pObject, *pEditDefaults, false );
1858             Point aDraw = aStart;
1859             tools::Long nDif = aPaperSize.Height() - static_cast<tools::Long>(pEditEngine->GetTextHeight());
1860             if (nDif > 0)
1861                 aDraw.AdjustY(nDif / 2 );
1862             pEditEngine->Draw(*pDev, aDraw);
1863         }
1864 
1865         //  center
1866 
1867         pObject = pHFItem->GetCenterArea();
1868         if (pObject)
1869         {
1870             pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) );
1871             pEditEngine->SetTextNewDefaults( *pObject, *pEditDefaults, false );
1872             Point aDraw = aStart;
1873             tools::Long nDif = aPaperSize.Height() - static_cast<tools::Long>(pEditEngine->GetTextHeight());
1874             if (nDif > 0)
1875                 aDraw.AdjustY(nDif / 2 );
1876             pEditEngine->Draw(*pDev, aDraw);
1877         }
1878 
1879         //  right
1880 
1881         pObject = pHFItem->GetRightArea();
1882         if (pObject)
1883         {
1884             pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
1885             pEditEngine->SetTextNewDefaults( *pObject, *pEditDefaults, false );
1886             Point aDraw = aStart;
1887             tools::Long nDif = aPaperSize.Height() - static_cast<tools::Long>(pEditEngine->GetTextHeight());
1888             if (nDif > 0)
1889                 aDraw.AdjustY(nDif / 2 );
1890             pEditEngine->Draw(*pDev, aDraw);
1891         }
1892 
1893         pDev->SetClipRegion();
1894     }
1895 
1896     if ( pLocationData )
1897     {
1898         tools::Rectangle aHeaderRect( aBorderStart, aBorderSize );
1899         pLocationData->AddHeaderFooter( aHeaderRect, bHeader, bLeft );
1900     }
1901 }
1902 
DoNotes(tools::Long nNoteStart,bool bDoPrint,ScPreviewLocationData * pLocationData)1903 tools::Long ScPrintFunc::DoNotes( tools::Long nNoteStart, bool bDoPrint, ScPreviewLocationData* pLocationData )
1904 {
1905     if (bDoPrint)
1906         pDev->SetMapMode(aTwipMode);
1907 
1908     MakeEditEngine();
1909     pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
1910     pEditEngine->SetDefaults( *pEditDefaults );
1911 
1912     vcl::Font aMarkFont;
1913     ScAutoFontColorMode eColorMode = bUseStyleColor ? SC_AUTOCOL_DISPLAY : SC_AUTOCOL_PRINT;
1914     rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN).GetFont( aMarkFont, eColorMode );
1915     pDev->SetFont( aMarkFont );
1916     tools::Long nMarkLen = pDev->GetTextWidth("GW99999:");
1917     // without Space-Char, because it rarely arrives there
1918 
1919     Size aDataSize = aPageRect.GetSize();
1920     if ( nMarkLen > aDataSize.Width() / 2 )     // everything much too small?
1921         nMarkLen = aDataSize.Width() / 2;       // split the page appropriately
1922     aDataSize.AdjustWidth( -nMarkLen );
1923 
1924     pEditEngine->SetPaperSize( aDataSize );
1925     tools::Long nPosX = aPageRect.Left() + nMarkLen;
1926     tools::Long nPosY = aPageRect.Top();
1927 
1928     tools::Long nCount = 0;
1929     tools::Long nSize = aNotePosList.size();
1930     bool bOk;
1931     do
1932     {
1933         bOk = false;
1934         if ( nNoteStart + nCount < nSize)
1935         {
1936             ScAddress &rPos = aNotePosList[ nNoteStart + nCount ];
1937 
1938             if( const ScPostIt* pNote = rDoc.GetNote( rPos ) )
1939             {
1940                 if(const EditTextObject *pEditText = pNote->GetEditTextObject())
1941                     pEditEngine->SetTextCurrentDefaults(*pEditText);
1942                 tools::Long nTextHeight = pEditEngine->GetTextHeight();
1943                 if ( nPosY + nTextHeight < aPageRect.Bottom() )
1944                 {
1945                     if (bDoPrint)
1946                     {
1947                         pEditEngine->Draw(*pDev, Point(nPosX, nPosY));
1948 
1949                         OUString aMarkStr(rPos.Format(ScRefFlags::VALID, &rDoc, rDoc.GetAddressConvention()) + ":");
1950 
1951                         //  cell position also via EditEngine, for correct positioning
1952                         pEditEngine->SetTextCurrentDefaults(aMarkStr);
1953                         pEditEngine->Draw(*pDev, Point(aPageRect.Left(), nPosY));
1954                     }
1955 
1956                     if ( pLocationData )
1957                     {
1958                         tools::Rectangle aTextRect( Point( nPosX, nPosY ), Size( aDataSize.Width(), nTextHeight ) );
1959                         pLocationData->AddNoteText( aTextRect, rPos );
1960                         tools::Rectangle aMarkRect( Point( aPageRect.Left(), nPosY ), Size( nMarkLen, nTextHeight ) );
1961                         pLocationData->AddNoteMark( aMarkRect, rPos );
1962                     }
1963 
1964                     nPosY += nTextHeight;
1965                     nPosY += 200;                   // Distance
1966                     ++nCount;
1967                     bOk = true;
1968                 }
1969             }
1970         }
1971     }
1972     while (bOk);
1973 
1974     return nCount;
1975 }
1976 
PrintNotes(tools::Long nPageNo,tools::Long nNoteStart,bool bDoPrint,ScPreviewLocationData * pLocationData)1977 tools::Long ScPrintFunc::PrintNotes( tools::Long nPageNo, tools::Long nNoteStart, bool bDoPrint, ScPreviewLocationData* pLocationData )
1978 {
1979     if ( nNoteStart >= static_cast<tools::Long>(aNotePosList.size()) || !aTableParam.bNotes )
1980         return 0;
1981 
1982     if ( bDoPrint && bClearWin )
1983     {
1984         //!  aggregate PrintPage !!!
1985 
1986         Color aBackgroundColor( COL_WHITE );
1987         if ( bUseStyleColor )
1988             aBackgroundColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
1989 
1990         pDev->SetMapMode(aOffsetMode);
1991         pDev->SetLineColor();
1992         pDev->SetFillColor(aBackgroundColor);
1993         pDev->DrawRect(tools::Rectangle(Point(),
1994                 Size(static_cast<tools::Long>(aPageSize.Width() * nScaleX * 100 / nZoom),
1995                      static_cast<tools::Long>(aPageSize.Height() * nScaleY * 100 / nZoom))));
1996     }
1997 
1998     //      adjust aPageRect for left/right page
1999 
2000     tools::Rectangle aTempRect( Point(), aPageSize );
2001     if (IsMirror(nPageNo))
2002     {
2003         aPageRect.SetLeft( ( aTempRect.Left()  + nRightMargin ) * 100 / nZoom );
2004         aPageRect.SetRight( ( aTempRect.Right() - nLeftMargin  ) * 100 / nZoom );
2005     }
2006     else
2007     {
2008         aPageRect.SetLeft( ( aTempRect.Left()  + nLeftMargin  ) * 100 / nZoom );
2009         aPageRect.SetRight( ( aTempRect.Right() - nRightMargin ) * 100 / nZoom );
2010     }
2011 
2012     if ( pPrinter && bDoPrint )
2013     {
2014         OSL_FAIL( "StartPage does not exist anymore" );
2015     }
2016 
2017     if ( bDoPrint || pLocationData )
2018     {
2019         //  Head and foot lines
2020 
2021         if (aHdr.bEnable)
2022         {
2023             tools::Long nHeaderY = aPageRect.Top()-aHdr.nHeight;
2024             PrintHF( nPageNo, true, nHeaderY, bDoPrint, pLocationData );
2025         }
2026         if (aFtr.bEnable)
2027         {
2028             tools::Long nFooterY = aPageRect.Bottom()+aFtr.nDistance;
2029             PrintHF( nPageNo, false, nFooterY, bDoPrint, pLocationData );
2030         }
2031     }
2032 
2033     tools::Long nCount = DoNotes( nNoteStart, bDoPrint, pLocationData );
2034 
2035     if ( pPrinter && bDoPrint )
2036     {
2037         OSL_FAIL( "EndPage does not exist anymore" );
2038     }
2039 
2040     return nCount;
2041 }
2042 
PrintPage(tools::Long nPageNo,SCCOL nX1,SCROW nY1,SCCOL nX2,SCROW nY2,bool bDoPrint,ScPreviewLocationData * pLocationData)2043 void ScPrintFunc::PrintPage( tools::Long nPageNo, SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
2044                                 bool bDoPrint, ScPreviewLocationData* pLocationData )
2045 {
2046     bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
2047     tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
2048 
2049     //  nPageNo is the page number within all sheets of one "start page" setting
2050 
2051     if ( bClearWin && bDoPrint )
2052     {
2053         //  must exactly fit to painting the frame in preview.cxx !!!
2054 
2055         Color aBackgroundColor( COL_WHITE );
2056         if ( bUseStyleColor )
2057             aBackgroundColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
2058 
2059         pDev->SetMapMode(aOffsetMode);
2060         pDev->SetLineColor();
2061         pDev->SetFillColor(aBackgroundColor);
2062         pDev->DrawRect(tools::Rectangle(Point(),
2063                 Size(static_cast<tools::Long>(aPageSize.Width() * nScaleX * 100 / nZoom),
2064                      static_cast<tools::Long>(aPageSize.Height() * nScaleY * 100 / nZoom))));
2065     }
2066 
2067     //      adjust aPageRect for left/right page
2068 
2069     tools::Rectangle aTempRect( Point(), aPageSize );
2070     if (IsMirror(nPageNo))
2071     {
2072         aPageRect.SetLeft( ( aTempRect.Left()  + nRightMargin ) * 100 / nZoom );
2073         aPageRect.SetRight( ( aTempRect.Right() - nLeftMargin  ) * 100 / nZoom );
2074     }
2075     else
2076     {
2077         aPageRect.SetLeft( ( aTempRect.Left()  + nLeftMargin  ) * 100 / nZoom );
2078         aPageRect.SetRight( ( aTempRect.Right() - nRightMargin ) * 100 / nZoom );
2079     }
2080 
2081     if ( aAreaParam.bRepeatCol )
2082         if ( nX1 > nRepeatStartCol && nX1 <= nRepeatEndCol )
2083             nX1 = nRepeatEndCol + 1;
2084     bool bDoRepCol = (aAreaParam.bRepeatCol && nX1 > nRepeatEndCol);
2085     if ( aAreaParam.bRepeatRow )
2086         if ( nY1 > nRepeatStartRow && nY1 <= nRepeatEndRow )
2087             nY1 = nRepeatEndRow + 1;
2088     bool bDoRepRow = (aAreaParam.bRepeatRow && nY1 > nRepeatEndRow);
2089 
2090     // use new object hide flags in SdrPaintView
2091     if(pDrawView)
2092     {
2093         pDrawView->setHideOle(!aTableParam.bObjects);
2094         pDrawView->setHideChart(!aTableParam.bCharts);
2095         pDrawView->setHideDraw(!aTableParam.bDrawings);
2096         pDrawView->setHideFormControl(!aTableParam.bDrawings);
2097     }
2098 
2099     if ( pPrinter && bDoPrint )
2100     {
2101         OSL_FAIL( "StartPage does not exist anymore" );
2102     }
2103 
2104     //  head and foot lines (without centering)
2105 
2106     if (aHdr.bEnable)
2107     {
2108         tools::Long nHeaderY = aPageRect.Top()-aHdr.nHeight;
2109         PrintHF( nPageNo, true, nHeaderY, bDoPrint, pLocationData );
2110     }
2111     if (aFtr.bEnable)
2112     {
2113         tools::Long nFooterY = aPageRect.Bottom()+aFtr.nDistance;
2114         PrintHF( nPageNo, false, nFooterY, bDoPrint, pLocationData );
2115     }
2116 
2117     //  Position ( margins / centering )
2118 
2119     tools::Long nLeftSpace = aPageRect.Left();     // Document-Twips
2120     tools::Long nTopSpace  = aPageRect.Top();
2121     if ( bCenterHor || bLayoutRTL )
2122     {
2123         tools::Long nDataWidth = 0;
2124         SCCOL i;
2125         for (i=nX1; i<=nX2; i++)
2126             nDataWidth += rDoc.GetColWidth( i,nPrintTab );
2127         if (bDoRepCol)
2128             for (i=nRepeatStartCol; i<=nRepeatEndCol; i++)
2129                 nDataWidth += rDoc.GetColWidth( i,nPrintTab );
2130         if (aTableParam.bHeaders)
2131             nDataWidth += tools::Long(PRINT_HEADER_WIDTH);
2132         if (pBorderItem)
2133             nDataWidth += pBorderItem->GetDistance(SvxBoxItemLine::LEFT) +
2134                            pBorderItem->GetDistance(SvxBoxItemLine::RIGHT);        //! Line width?
2135         if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
2136             nDataWidth += pShadowItem->CalcShadowSpace(SvxShadowItemSide::LEFT) +
2137                            pShadowItem->CalcShadowSpace(SvxShadowItemSide::RIGHT);
2138         if ( bCenterHor )
2139         {
2140             nLeftSpace += ( aPageRect.GetWidth() - nDataWidth ) / 2;        // LTR or RTL
2141             if (pBorderItem)
2142                 nLeftSpace -= lcl_LineTotal(pBorderItem->GetLeft());
2143         }
2144         else if ( bLayoutRTL )
2145             nLeftSpace += aPageRect.GetWidth() - nDataWidth;                // align to the right edge of the page
2146     }
2147     if ( bCenterVer )
2148     {
2149         tools::Long nDataHeight = rDoc.GetRowHeight( nY1, nY2, nPrintTab);
2150         if (bDoRepRow)
2151             nDataHeight += rDoc.GetRowHeight( nRepeatStartRow,
2152                     nRepeatEndRow, nPrintTab);
2153         if (aTableParam.bHeaders)
2154             nDataHeight += tools::Long(PRINT_HEADER_HEIGHT);
2155         if (pBorderItem)
2156             nDataHeight += pBorderItem->GetDistance(SvxBoxItemLine::TOP) +
2157                            pBorderItem->GetDistance(SvxBoxItemLine::BOTTOM);       //! Line width?
2158         if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
2159             nDataHeight += pShadowItem->CalcShadowSpace(SvxShadowItemSide::TOP) +
2160                            pShadowItem->CalcShadowSpace(SvxShadowItemSide::BOTTOM);
2161         nTopSpace += ( aPageRect.GetHeight() - nDataHeight ) / 2;
2162         if (pBorderItem)
2163             nTopSpace -= lcl_LineTotal(pBorderItem->GetTop());
2164     }
2165 
2166     //  calculate sizes of the elements for partitioning
2167     //  (header, repeat, data)
2168 
2169     tools::Long nHeaderWidth   = 0;
2170     tools::Long nHeaderHeight  = 0;
2171     tools::Long nRepeatWidth   = 0;
2172     tools::Long nRepeatHeight  = 0;
2173     tools::Long nContentWidth  = 0;        // scaled - not the same as nDataWidth above
2174     tools::Long nContentHeight = 0;
2175     if (aTableParam.bHeaders)
2176     {
2177         nHeaderWidth  = static_cast<tools::Long>(PRINT_HEADER_WIDTH * nScaleX);
2178         nHeaderHeight = static_cast<tools::Long>(PRINT_HEADER_HEIGHT * nScaleY);
2179     }
2180     if (bDoRepCol)
2181         for (SCCOL i=nRepeatStartCol; i<=nRepeatEndCol; i++)
2182             nRepeatWidth += static_cast<tools::Long>(rDoc.GetColWidth(i,nPrintTab) * nScaleX);
2183     if (bDoRepRow)
2184         nRepeatHeight += rDoc.GetScaledRowHeight( nRepeatStartRow,
2185                 nRepeatEndRow, nPrintTab, nScaleY);
2186     for (SCCOL i=nX1; i<=nX2; i++)
2187         nContentWidth += static_cast<tools::Long>(rDoc.GetColWidth(i,nPrintTab) * nScaleX);
2188     nContentHeight += rDoc.GetScaledRowHeight( nY1, nY2, nPrintTab,
2189             nScaleY);
2190 
2191     //  partition the page
2192 
2193     tools::Long nStartX = static_cast<tools::Long>( nLeftSpace * nScaleX );
2194     tools::Long nStartY = static_cast<tools::Long>( nTopSpace  * nScaleY );
2195     tools::Long nInnerStartX = nStartX;
2196     tools::Long nInnerStartY = nStartY;
2197     if (pBorderItem)
2198     {
2199         nInnerStartX += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetLeft()) +
2200                                     pBorderItem->GetDistance(SvxBoxItemLine::LEFT) ) * nScaleX );
2201         nInnerStartY += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetTop()) +
2202                                     pBorderItem->GetDistance(SvxBoxItemLine::TOP) ) * nScaleY );
2203     }
2204     if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
2205     {
2206         nInnerStartX += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::LEFT) * nScaleX );
2207         nInnerStartY += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::TOP) * nScaleY );
2208     }
2209 
2210     if ( bLayoutRTL )
2211     {
2212         //  arrange elements starting from the right edge
2213         nInnerStartX += nHeaderWidth + nRepeatWidth + nContentWidth;
2214 
2215         //  make rounding easier so the elements are really next to each other in preview
2216         Size aOffsetOnePixel = pDev->PixelToLogic( Size(1,1), aOffsetMode );
2217         tools::Long nOffsetOneX = aOffsetOnePixel.Width();
2218         nInnerStartX += nOffsetOneX / 2;
2219     }
2220 
2221     tools::Long nFrameStartX = nInnerStartX;
2222     tools::Long nFrameStartY = nInnerStartY;
2223 
2224     tools::Long nRepStartX = nInnerStartX + nHeaderWidth * nLayoutSign;    // widths/heights are 0 if not used
2225     tools::Long nRepStartY = nInnerStartY + nHeaderHeight;
2226     tools::Long nDataX = nRepStartX + nRepeatWidth * nLayoutSign;
2227     tools::Long nDataY = nRepStartY + nRepeatHeight;
2228     tools::Long nEndX = nDataX + nContentWidth * nLayoutSign;
2229     tools::Long nEndY = nDataY + nContentHeight;
2230     tools::Long nFrameEndX = nEndX;
2231     tools::Long nFrameEndY = nEndY;
2232 
2233     if ( bLayoutRTL )
2234     {
2235         //  each element's start position is its left edge
2236         //! subtract one pixel less?
2237         nInnerStartX -= nHeaderWidth;       // used for header
2238         nRepStartX   -= nRepeatWidth;
2239         nDataX       -= nContentWidth;
2240 
2241         //  continue right of the main elements again
2242         nEndX += nHeaderWidth + nRepeatWidth + nContentWidth;
2243     }
2244 
2245     //  Page frame / background
2246 
2247     //! adjust nEndX/Y
2248 
2249     tools::Long nBorderEndX = nEndX;
2250     tools::Long nBorderEndY = nEndY;
2251     if (pBorderItem)
2252     {
2253         nBorderEndX += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetRight()) +
2254                                     pBorderItem->GetDistance(SvxBoxItemLine::RIGHT) ) * nScaleX );
2255         nBorderEndY += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetBottom()) +
2256                                     pBorderItem->GetDistance(SvxBoxItemLine::BOTTOM) ) * nScaleY );
2257     }
2258     if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
2259     {
2260         nBorderEndX += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::RIGHT) * nScaleX );
2261         nBorderEndY += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::BOTTOM) * nScaleY );
2262     }
2263 
2264     if ( bDoPrint )
2265     {
2266         pDev->SetMapMode( aOffsetMode );
2267         DrawBorder( nStartX, nStartY, nBorderEndX-nStartX, nBorderEndY-nStartY,
2268                         pBorderItem, pBackgroundItem, pShadowItem );
2269 
2270         pDev->SetMapMode( aTwipMode );
2271     }
2272 
2273     pDev->SetMapMode( aOffsetMode );
2274 
2275     //  Output repeating rows/columns
2276 
2277     if (bDoRepCol && bDoRepRow)
2278     {
2279         if ( bDoPrint )
2280             PrintArea( nRepeatStartCol,nRepeatStartRow, nRepeatEndCol,nRepeatEndRow,
2281                             nRepStartX,nRepStartY, true, true, false, false );
2282         if ( pLocationData )
2283             LocateArea( nRepeatStartCol,nRepeatStartRow, nRepeatEndCol,nRepeatEndRow,
2284                             nRepStartX,nRepStartY, true, true, *pLocationData );
2285     }
2286     if (bDoRepCol)
2287     {
2288         if ( bDoPrint )
2289             PrintArea( nRepeatStartCol,nY1, nRepeatEndCol,nY2, nRepStartX,nDataY,
2290                         true, !bDoRepRow, false, true );
2291         if ( pLocationData )
2292             LocateArea( nRepeatStartCol,nY1, nRepeatEndCol,nY2, nRepStartX,nDataY, true, false, *pLocationData );
2293     }
2294     if (bDoRepRow)
2295     {
2296         if ( bDoPrint )
2297             PrintArea( nX1,nRepeatStartRow, nX2,nRepeatEndRow, nDataX,nRepStartY,
2298                         !bDoRepCol, true, true, false );
2299         if ( pLocationData )
2300             LocateArea( nX1,nRepeatStartRow, nX2,nRepeatEndRow, nDataX,nRepStartY, false, true, *pLocationData );
2301     }
2302 
2303     //  output data
2304 
2305     if ( bDoPrint )
2306         PrintArea( nX1,nY1, nX2,nY2, nDataX,nDataY, !bDoRepCol,!bDoRepRow, true, true );
2307     if ( pLocationData )
2308         LocateArea( nX1,nY1, nX2,nY2, nDataX,nDataY, false,false, *pLocationData );
2309 
2310     //  output column/row headers
2311     //  after data (through probably shadow)
2312 
2313     Color aGridColor( COL_BLACK );
2314     if ( bUseStyleColor )
2315         aGridColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
2316 
2317     if (aTableParam.bHeaders)
2318     {
2319         if ( bDoPrint )
2320         {
2321             pDev->SetLineColor( aGridColor );
2322             pDev->SetFillColor();
2323             pDev->SetMapMode(aOffsetMode);
2324         }
2325 
2326         ScPatternAttr aPattern( rDoc.GetPool() );
2327         vcl::Font aFont;
2328         ScAutoFontColorMode eColorMode = bUseStyleColor ? SC_AUTOCOL_DISPLAY : SC_AUTOCOL_PRINT;
2329         aPattern.GetFont( aFont, eColorMode, pDev );
2330         pDev->SetFont( aFont );
2331 
2332         if (bDoRepCol)
2333         {
2334             if ( bDoPrint )
2335                 PrintColHdr( nRepeatStartCol,nRepeatEndCol, nRepStartX,nInnerStartY );
2336             if ( pLocationData )
2337                 LocateColHdr( nRepeatStartCol,nRepeatEndCol, nRepStartX,nInnerStartY, true, *pLocationData );
2338         }
2339         if ( bDoPrint )
2340             PrintColHdr( nX1,nX2, nDataX,nInnerStartY );
2341         if ( pLocationData )
2342             LocateColHdr( nX1,nX2, nDataX,nInnerStartY, false, *pLocationData );
2343         if (bDoRepRow)
2344         {
2345             if ( bDoPrint )
2346                 PrintRowHdr( nRepeatStartRow,nRepeatEndRow, nInnerStartX,nRepStartY );
2347             if ( pLocationData )
2348                 LocateRowHdr( nRepeatStartRow,nRepeatEndRow, nInnerStartX,nRepStartY, true, *pLocationData );
2349         }
2350         if ( bDoPrint )
2351             PrintRowHdr( nY1,nY2, nInnerStartX,nDataY );
2352         if ( pLocationData )
2353             LocateRowHdr( nY1,nY2, nInnerStartX,nDataY, false, *pLocationData );
2354     }
2355 
2356     //  simple frame
2357 
2358     if ( bDoPrint && ( aTableParam.bGrid || aTableParam.bHeaders ) )
2359     {
2360         Size aOnePixel = pDev->PixelToLogic(Size(1,1));
2361         tools::Long nOneX = aOnePixel.Width();
2362         tools::Long nOneY = aOnePixel.Height();
2363 
2364         tools::Long nLeftX   = nFrameStartX;
2365         tools::Long nTopY    = nFrameStartY - nOneY;
2366         tools::Long nRightX  = nFrameEndX;
2367         tools::Long nBottomY = nFrameEndY - nOneY;
2368         if ( !bLayoutRTL )
2369         {
2370             nLeftX   -= nOneX;
2371             nRightX  -= nOneX;
2372         }
2373         pDev->SetMapMode(aOffsetMode);
2374         pDev->SetLineColor( aGridColor );
2375         pDev->SetFillColor();
2376         pDev->DrawRect( tools::Rectangle( nLeftX, nTopY, nRightX, nBottomY ) );
2377         //  nEndX/Y without frame-adaptation
2378     }
2379 
2380     if ( pPrinter && bDoPrint )
2381     {
2382         OSL_FAIL( "EndPage does not exist anymore" );
2383     }
2384 
2385     aLastSourceRange = ScRange( nX1, nY1, nPrintTab, nX2, nY2, nPrintTab );
2386     bSourceRangeValid = true;
2387 }
2388 
SetOffset(const Point & rOfs)2389 void ScPrintFunc::SetOffset( const Point& rOfs )
2390 {
2391     aSrcOffset = rOfs;
2392 }
2393 
SetManualZoom(sal_uInt16 nNewZoom)2394 void ScPrintFunc::SetManualZoom( sal_uInt16 nNewZoom )
2395 {
2396     nManualZoom = nNewZoom;
2397 }
2398 
SetClearFlag(bool bFlag)2399 void ScPrintFunc::SetClearFlag( bool bFlag )
2400 {
2401     bClearWin = bFlag;
2402 }
2403 
SetUseStyleColor(bool bFlag)2404 void ScPrintFunc::SetUseStyleColor( bool bFlag )
2405 {
2406     bUseStyleColor = bFlag;
2407     if (pEditEngine)
2408         pEditEngine->EnableAutoColor( bUseStyleColor );
2409 }
2410 
SetRenderFlag(bool bFlag)2411 void ScPrintFunc::SetRenderFlag( bool bFlag )
2412 {
2413     bIsRender = bFlag;      // set when using XRenderable (PDF)
2414 }
2415 
SetExclusivelyDrawOleAndDrawObjects()2416 void ScPrintFunc::SetExclusivelyDrawOleAndDrawObjects()
2417 {
2418     aTableParam.bCellContent = false;
2419     aTableParam.bNotes = false;
2420     aTableParam.bGrid = false;
2421     aTableParam.bHeaders = false;
2422     aTableParam.bFormulas = false;
2423     aTableParam.bNullVals = false;
2424 }
2425 
2426 //  UpdatePages is only called from outside to set the breaks correctly for viewing
2427 //  - always without UserArea
2428 
UpdatePages()2429 bool ScPrintFunc::UpdatePages()
2430 {
2431     if (!pParamSet)
2432         return false;
2433 
2434     //  Zoom
2435 
2436     nZoom = 100;
2437     if (aTableParam.bScalePageNum || aTableParam.bScaleTo)
2438         nZoom = ZOOM_MIN;                       // correct for breaks
2439     else if (aTableParam.bScaleAll)
2440     {
2441         nZoom = aTableParam.nScaleAll;
2442         if ( nZoom <= ZOOM_MIN )
2443             nZoom = ZOOM_MIN;
2444     }
2445 
2446     OUString aName = rDoc.GetPageStyle( nPrintTab );
2447     SCTAB nTabCount = rDoc.GetTableCount();
2448     for (SCTAB nTab=0; nTab<nTabCount; nTab++)
2449         if ( nTab==nPrintTab || rDoc.GetPageStyle(nTab)==aName )
2450         {
2451             //  Repeating rows/columns
2452             rDoc.SetRepeatArea( nTab, nRepeatStartCol,nRepeatEndCol, nRepeatStartRow,nRepeatEndRow );
2453 
2454             //  set breaks
2455             ResetBreaks(nTab);
2456             pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid);
2457         }
2458 
2459     return true;
2460 }
2461 
CountPages()2462 tools::Long ScPrintFunc::CountPages()                          // sets also nPagesX, nPagesY
2463 {
2464     bool bAreaOk = false;
2465 
2466     if (rDoc.HasTable( nPrintTab ))
2467     {
2468         if (aAreaParam.bPrintArea)                          // Specify print area?
2469         {
2470             if ( bPrintCurrentTable )
2471             {
2472                 ScRange& rRange = aAreaParam.aPrintArea;
2473 
2474                 //  Here, no comparison of the tables any more. Area is always valid for this table
2475                 //  If comparison should be done here, the table of print ranges must be adjusted
2476                 //  when inserting tables etc.!
2477 
2478                 nStartCol = rRange.aStart.Col();
2479                 nStartRow = rRange.aStart.Row();
2480                 nEndCol   = rRange.aEnd  .Col();
2481                 nEndRow   = rRange.aEnd  .Row();
2482                 bAreaOk   = AdjustPrintArea(false);         // limit
2483             }
2484             else
2485                 bAreaOk = false;
2486         }
2487         else                                                // search from document
2488             bAreaOk = AdjustPrintArea(true);
2489     }
2490 
2491     if (bAreaOk)
2492     {
2493         tools::Long nPages = 0;
2494         size_t nY;
2495         if (bMultiArea)
2496         {
2497             sal_uInt16 nRCount = rDoc.GetPrintRangeCount( nPrintTab );
2498             for (sal_uInt16 i=0; i<nRCount; i++)
2499             {
2500                 CalcZoom(i);
2501                 if ( aTableParam.bSkipEmpty )
2502                     for (nY=0; nY< m_aRanges.m_nPagesY; nY++)
2503                         nPages += (*m_aRanges.m_xPageRows)[nY].CountVisible();
2504                 else
2505                     nPages += static_cast<tools::Long>(m_aRanges.m_nPagesX) * m_aRanges.m_nPagesY;
2506                 if ( pPageData )
2507                     FillPageData();
2508             }
2509         }
2510         else
2511         {
2512             CalcZoom(RANGENO_NORANGE);                      // calculate Zoom
2513             if ( aTableParam.bSkipEmpty )
2514                 for (nY=0; nY<m_aRanges.m_nPagesY; nY++)
2515                     nPages += (*m_aRanges.m_xPageRows)[nY].CountVisible();
2516             else
2517                 nPages += static_cast<tools::Long>(m_aRanges.m_nPagesX) * m_aRanges.m_nPagesY;
2518             if ( pPageData )
2519                 FillPageData();
2520         }
2521         return nPages;
2522     }
2523     else
2524     {
2525         m_aRanges.m_nPagesX = m_aRanges.m_nPagesY = m_aRanges.m_nTotalY = 0;
2526         return 0;
2527     }
2528 }
2529 
CountNotePages()2530 tools::Long ScPrintFunc::CountNotePages()
2531 {
2532     if ( !aTableParam.bNotes || !bPrintCurrentTable )
2533         return 0;
2534 
2535     bool bError = false;
2536     if (!aAreaParam.bPrintArea)
2537         bError = !AdjustPrintArea(true);            // completely search in Doc
2538 
2539     sal_uInt16 nRepeats = 1;                            // how often go through it ?
2540     if (bMultiArea)
2541         nRepeats = rDoc.GetPrintRangeCount(nPrintTab);
2542     if (bError)
2543         nRepeats = 0;
2544 
2545     for (sal_uInt16 nStep=0; nStep<nRepeats; nStep++)
2546     {
2547         bool bDoThis = true;
2548         if (bMultiArea)             // go through all Areas
2549         {
2550             const ScRange* pThisRange = rDoc.GetPrintRange( nPrintTab, nStep );
2551             if ( pThisRange )
2552             {
2553                 nStartCol = pThisRange->aStart.Col();
2554                 nStartRow = pThisRange->aStart.Row();
2555                 nEndCol   = pThisRange->aEnd  .Col();
2556                 nEndRow   = pThisRange->aEnd  .Row();
2557                 bDoThis = AdjustPrintArea(false);
2558             }
2559         }
2560 
2561         if (bDoThis)
2562         {
2563             assert( bPrintAreaValid );
2564             for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
2565             {
2566                 if (rDoc.HasColNotes(nCol, nPrintTab))
2567                 {
2568                     for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow )
2569                         {
2570                             if ( rDoc.HasNote(nCol, nRow, nPrintTab) )
2571                                 aNotePosList.emplace_back( nCol, nRow, nPrintTab );
2572                         }
2573                 }
2574             }
2575         }
2576     }
2577 
2578     tools::Long nPages = 0;
2579     tools::Long nNoteNr = 0;
2580     tools::Long nNoteAdd;
2581     do
2582     {
2583         nNoteAdd = PrintNotes( nPages, nNoteNr, false, nullptr );
2584         if (nNoteAdd)
2585         {
2586             nNoteNr += nNoteAdd;
2587             ++nPages;
2588         }
2589     }
2590     while (nNoteAdd);
2591 
2592     return nPages;
2593 }
2594 
InitModes()2595 void ScPrintFunc::InitModes()               // set MapModes from  nZoom etc.
2596 {
2597     aOffset = Point( aSrcOffset.X()*100/nZoom, aSrcOffset.Y()*100/nZoom );
2598 
2599     tools::Long nEffZoom = nZoom * static_cast<tools::Long>(nManualZoom);
2600     nScaleX = nScaleY = HMM_PER_TWIPS;  // output in 1/100 mm
2601 
2602     Fraction aZoomFract( nEffZoom,10000 );
2603     Fraction aHorFract = aZoomFract;
2604 
2605     if ( !pPrinter && !bIsRender )                          // adjust scale for preview
2606     {
2607         double nFact = pDocShell->GetOutputFactor();
2608         aHorFract = Fraction( static_cast<tools::Long>( nEffZoom / nFact ), 10000 );
2609     }
2610 
2611     aLogicMode = MapMode( MapUnit::Map100thMM, Point(), aHorFract, aZoomFract );
2612 
2613     Point aLogicOfs( -aOffset.X(), -aOffset.Y() );
2614     aOffsetMode = MapMode( MapUnit::Map100thMM, aLogicOfs, aHorFract, aZoomFract );
2615 
2616     Point aTwipsOfs( static_cast<tools::Long>( -aOffset.X() / nScaleX + 0.5 ), static_cast<tools::Long>( -aOffset.Y() / nScaleY + 0.5 ) );
2617     aTwipMode = MapMode( MapUnit::MapTwip, aTwipsOfs, aHorFract, aZoomFract );
2618 }
2619 
ApplyPrintSettings()2620 void ScPrintFunc::ApplyPrintSettings()
2621 {
2622     if ( !pPrinter )
2623         return;
2624 
2625     //  Configure Printer to Printing
2626 
2627     Size aEnumSize = aPageSize;
2628 
2629     pPrinter->SetOrientation( bLandscape ? Orientation::Landscape : Orientation::Portrait );
2630     if ( bLandscape )
2631     {
2632             // landscape is always interpreted as a rotation by 90 degrees !
2633             // this leads to non WYSIWIG but at least it prints!
2634             // #i21775#
2635             tools::Long nTemp = aEnumSize.Width();
2636             aEnumSize.setWidth( aEnumSize.Height() );
2637             aEnumSize.setHeight( nTemp );
2638     }
2639     Paper ePaper = SvxPaperInfo::GetSvxPaper( aEnumSize, MapUnit::MapTwip );
2640     sal_uInt16 nPaperBin = pParamSet->Get(ATTR_PAGE_PAPERBIN).GetValue();
2641 
2642     pPrinter->SetPaper( ePaper );
2643     if ( PAPER_USER == ePaper )
2644     {
2645         MapMode aPrinterMode = pPrinter->GetMapMode();
2646         MapMode aLocalMode( MapUnit::MapTwip );
2647         pPrinter->SetMapMode( aLocalMode );
2648         pPrinter->SetPaperSizeUser( aEnumSize );
2649         pPrinter->SetMapMode( aPrinterMode );
2650     }
2651 
2652     pPrinter->SetPaperBin( nPaperBin );
2653 }
2654 
2655 //  rPageRanges   = range for all tables
2656 //  nStartPage    = rPageRanges starts at nStartPage
2657 //  nDisplayStart = continuous number for displaying the page number
2658 
DoPrint(const MultiSelection & rPageRanges,tools::Long nStartPage,tools::Long nDisplayStart,bool bDoPrint,ScPreviewLocationData * pLocationData)2659 tools::Long ScPrintFunc::DoPrint( const MultiSelection& rPageRanges,
2660                                 tools::Long nStartPage, tools::Long nDisplayStart, bool bDoPrint,
2661                                 ScPreviewLocationData* pLocationData )
2662 {
2663     OSL_ENSURE(pDev,"Device == NULL");
2664     if (!pParamSet)
2665         return 0;
2666 
2667     if ( pPrinter && bDoPrint )
2668         ApplyPrintSettings();
2669 
2670     InitModes();
2671     if ( pLocationData )
2672     {
2673         pLocationData->SetCellMapMode( aOffsetMode );
2674         pLocationData->SetPrintTab( nPrintTab );
2675     }
2676 
2677     MakeTableString();
2678 
2679     tools::Long nPageNo = 0;
2680     tools::Long nPrinted = 0;
2681     tools::Long nEndPage = rPageRanges.GetTotalRange().Max();
2682 
2683     sal_uInt16 nRepeats = 1;
2684     if (bMultiArea)
2685         nRepeats = rDoc.GetPrintRangeCount(nPrintTab);
2686     for (sal_uInt16 nStep=0; nStep<nRepeats; nStep++)
2687     {
2688         if (bMultiArea)                     // replace area
2689         {
2690             CalcZoom(nStep);                // also sets nStartCol etc. new
2691             InitModes();
2692         }
2693 
2694         SCCOL nX1;
2695         SCROW nY1;
2696         SCCOL nX2;
2697         SCROW nY2;
2698         size_t nCountX;
2699         size_t nCountY;
2700 
2701         if (aTableParam.bTopDown)                           // top-bottom
2702         {
2703             nX1 = nStartCol;
2704             for (nCountX=0; nCountX<m_aRanges.m_nPagesX; nCountX++)
2705             {
2706                 OSL_ENSURE(nCountX < m_aRanges.m_xPageEndX->size(), "vector access error for aPageEndX (!)");
2707                 nX2 = (*m_aRanges.m_xPageEndX)[nCountX];
2708                 for (nCountY=0; nCountY<m_aRanges.m_nPagesY; nCountY++)
2709                 {
2710                     auto& rPageRow = (*m_aRanges.m_xPageRows)[nCountY];
2711                     nY1 = rPageRow.GetStartRow();
2712                     nY2 = rPageRow.GetEndRow();
2713                     if ( !aTableParam.bSkipEmpty || !rPageRow.IsHidden(nCountX) )
2714                     {
2715                         if ( rPageRanges.IsSelected( nPageNo+nStartPage+1 ) )
2716                         {
2717                             PrintPage( nPageNo+nDisplayStart, nX1, nY1, nX2, nY2,
2718                                         bDoPrint, pLocationData );
2719                             ++nPrinted;
2720                         }
2721                         ++nPageNo;
2722                     }
2723                 }
2724                 nX1 = nX2 + 1;
2725             }
2726         }
2727         else                                                // left to right
2728         {
2729             for (nCountY=0; nCountY<m_aRanges.m_nPagesY; nCountY++)
2730             {
2731                 auto& rPageRow = (*m_aRanges.m_xPageRows)[nCountY];
2732                 nY1 = rPageRow.GetStartRow();
2733                 nY2 = rPageRow.GetEndRow();
2734                 nX1 = nStartCol;
2735                 for (nCountX=0; nCountX<m_aRanges.m_nPagesX; nCountX++)
2736                 {
2737                     OSL_ENSURE(nCountX < m_aRanges.m_xPageEndX->size(), "vector access error for aPageEndX");
2738                     nX2 = (*m_aRanges.m_xPageEndX)[nCountX];
2739                     if ( !aTableParam.bSkipEmpty || !rPageRow.IsHidden(nCountX) )
2740                     {
2741                         if ( rPageRanges.IsSelected( nPageNo+nStartPage+1 ) )
2742                         {
2743                             PrintPage( nPageNo+nDisplayStart, nX1, nY1, nX2, nY2,
2744                                         bDoPrint, pLocationData );
2745                             ++nPrinted;
2746                         }
2747                         ++nPageNo;
2748                     }
2749                     nX1 = nX2 + 1;
2750                 }
2751             }
2752         }
2753     }
2754 
2755     aFieldData.aTabName = ScResId( STR_NOTES );
2756 
2757     tools::Long nNoteNr = 0;
2758     tools::Long nNoteAdd;
2759     do
2760     {
2761         if ( nPageNo+nStartPage <= nEndPage )
2762         {
2763             bool bPageSelected = rPageRanges.IsSelected( nPageNo+nStartPage+1 );
2764             nNoteAdd = PrintNotes( nPageNo+nStartPage, nNoteNr, bDoPrint && bPageSelected,
2765                                     ( bPageSelected ? pLocationData : nullptr ) );
2766             if ( nNoteAdd )
2767             {
2768                 nNoteNr += nNoteAdd;
2769                 if (bPageSelected)
2770                 {
2771                     ++nPrinted;
2772                     bSourceRangeValid = false;      // last page was no cell range
2773                 }
2774                 ++nPageNo;
2775             }
2776         }
2777         else
2778             nNoteAdd = 0;
2779     }
2780     while (nNoteAdd);
2781 
2782     if ( bMultiArea )
2783         ResetBreaks(nPrintTab);                         //breaks correct for displaying
2784 
2785     return nPrinted;
2786 }
2787 
CalcZoom(sal_uInt16 nRangeNo)2788 void ScPrintFunc::CalcZoom( sal_uInt16 nRangeNo )                       // calculate zoom
2789 {
2790     sal_uInt16 nRCount = rDoc.GetPrintRangeCount( nPrintTab );
2791     const ScRange* pThisRange = nullptr;
2792     if (nRangeNo != RANGENO_NORANGE && nRangeNo < nRCount)
2793         pThisRange = rDoc.GetPrintRange( nPrintTab, nRangeNo );
2794     if ( pThisRange )
2795     {
2796         nStartCol = pThisRange->aStart.Col();
2797         nStartRow = pThisRange->aStart.Row();
2798         nEndCol   = pThisRange->aEnd  .Col();
2799         nEndRow   = pThisRange->aEnd  .Row();
2800     }
2801 
2802     if (!AdjustPrintArea(false))                        // empty
2803     {
2804         nZoom = 100;
2805         m_aRanges.m_nPagesX = m_aRanges.m_nPagesY = m_aRanges.m_nTotalY = 0;
2806         return;
2807     }
2808 
2809     rDoc.SetRepeatArea( nPrintTab, nRepeatStartCol,nRepeatEndCol, nRepeatStartRow,nRepeatEndRow );
2810 
2811     if (aTableParam.bScalePageNum)
2812     {
2813         nZoom = 100;
2814         sal_uInt16 nPagesToFit = aTableParam.nScalePageNum;
2815 
2816         // If manual breaks are forced, calculate minimum # pages required
2817         if (aTableParam.bForceBreaks)
2818         {
2819              sal_uInt16 nMinPages = 0;
2820              std::set<SCROW> aRowBreaks;
2821              std::set<SCCOL> aColBreaks;
2822              rDoc.GetAllRowBreaks(aRowBreaks, nPrintTab, false, true);
2823              rDoc.GetAllColBreaks(aColBreaks, nPrintTab, false, true);
2824              nMinPages = (aRowBreaks.size() + 1) * (aColBreaks.size() + 1);
2825 
2826              // #i54993# use min forced by breaks if it's > # pages in
2827              // scale parameter to avoid bottoming out at <= ZOOM_MIN
2828              nPagesToFit = std::max(nMinPages, nPagesToFit);
2829         }
2830 
2831         sal_uInt16 nLastFitZoom = 0, nLastNonFitZoom = 0;
2832         while (true)
2833         {
2834             if (nZoom <= ZOOM_MIN)
2835                 break;
2836 
2837             CalcPages();
2838             bool bFitsPage = (m_aRanges.m_nPagesX * m_aRanges.m_nPagesY <= nPagesToFit);
2839 
2840             if (bFitsPage)
2841             {
2842                 if (nZoom == 100)
2843                     // If it fits at 100%, it's good enough for me.
2844                     break;
2845 
2846                 nLastFitZoom = nZoom;
2847                 nZoom = (nLastNonFitZoom + nZoom) / 2;
2848 
2849                 if (nLastFitZoom == nZoom)
2850                     // It converged.  Use this zoom level.
2851                     break;
2852             }
2853             else
2854             {
2855                 if (nZoom - nLastFitZoom <= 1)
2856                 {
2857                     nZoom = nLastFitZoom;
2858                     CalcPages();
2859                     break;
2860                 }
2861 
2862                 nLastNonFitZoom = nZoom;
2863                 nZoom = (nLastFitZoom + nZoom) / 2;
2864             }
2865         }
2866     }
2867     else if (aTableParam.bScaleTo)
2868     {
2869         nZoom = 100;
2870         sal_uInt16 nW = aTableParam.nScaleWidth;
2871         sal_uInt16 nH = aTableParam.nScaleHeight;
2872 
2873         // If manual breaks are forced, calculate minimum # pages required
2874         if (aTableParam.bForceBreaks)
2875         {
2876              sal_uInt16 nMinPagesW = 0, nMinPagesH = 0;
2877              std::set<SCROW> aRowBreaks;
2878              std::set<SCCOL> aColBreaks;
2879              rDoc.GetAllRowBreaks(aRowBreaks, nPrintTab, false, true);
2880              rDoc.GetAllColBreaks(aColBreaks, nPrintTab, false, true);
2881              nMinPagesW = aColBreaks.size() + 1;
2882              nMinPagesH = aRowBreaks.size() + 1;
2883 
2884              // #i54993# use min forced by breaks if it's > # pages in
2885              // scale parameters to avoid bottoming out at <= ZOOM_MIN
2886              nW = std::max(nMinPagesW, nW);
2887              nH = std::max(nMinPagesH, nH);
2888         }
2889 
2890         sal_uInt16 nLastFitZoom = 0, nLastNonFitZoom = 0;
2891         while (true)
2892         {
2893             if (nZoom <= ZOOM_MIN)
2894                 break;
2895 
2896             CalcPages();
2897             bool bFitsPage = ((!nW || (m_aRanges.m_nPagesX <= nW)) && (!nH || (m_aRanges.m_nPagesY <= nH)));
2898 
2899             if (bFitsPage)
2900             {
2901                 if (nZoom == 100)
2902                     // If it fits at 100%, it's good enough for me.
2903                     break;
2904 
2905                 nLastFitZoom = nZoom;
2906                 nZoom = (nLastNonFitZoom + nZoom) / 2;
2907 
2908                 if (nLastFitZoom == nZoom)
2909                     // It converged.  Use this zoom level.
2910                     break;
2911             }
2912             else
2913             {
2914                 if (nZoom - nLastFitZoom <= 1)
2915                 {
2916                     nZoom = nLastFitZoom;
2917                     CalcPages();
2918                     break;
2919                 }
2920 
2921                 nLastNonFitZoom = nZoom;
2922                 nZoom = (nLastFitZoom + nZoom) / 2;
2923             }
2924         }
2925         // tdf#103516 remove the almost blank page(s) for better
2926         // interoperability by using slightly smaller zoom
2927         if (nW > 0 && nH == 0 && m_aRanges.m_nPagesY > 1)
2928         {
2929             sal_uInt32 nLastPagesY = m_aRanges.m_nPagesY;
2930             nLastFitZoom = nZoom;
2931             nZoom *= 0.98;
2932             if (nZoom < nLastFitZoom)
2933             {
2934                 CalcPages();
2935                 // same page count with smaller zoom: use the original zoom
2936                 if (m_aRanges.m_nPagesY == nLastPagesY)
2937                 {
2938                     nZoom = nLastFitZoom;
2939                     CalcPages();
2940                 }
2941             }
2942         }
2943     }
2944     else if (aTableParam.bScaleAll)
2945     {
2946         nZoom = aTableParam.nScaleAll;
2947         if ( nZoom <= ZOOM_MIN )
2948             nZoom = ZOOM_MIN;
2949         CalcPages();
2950     }
2951     else
2952     {
2953         OSL_ENSURE( aTableParam.bScaleNone, "no scale flag is set" );
2954         nZoom = 100;
2955         CalcPages();
2956     }
2957 }
2958 
GetDocPageSize()2959 Size ScPrintFunc::GetDocPageSize()
2960 {
2961                         // Adjust height of head/foot line
2962 
2963     InitModes();                            // initialize aTwipMode from nZoom
2964     pDev->SetMapMode( aTwipMode );          // head/foot line in Twips
2965     UpdateHFHeight( aHdr );
2966     UpdateHFHeight( aFtr );
2967 
2968                         //  Page size in Document-Twips
2969                         //  Calculating Left / Right also in PrintPage
2970 
2971     aPageRect = tools::Rectangle( Point(), aPageSize );
2972     aPageRect.SetLeft( ( aPageRect.Left()   + nLeftMargin                  ) * 100 / nZoom );
2973     aPageRect.SetRight( ( aPageRect.Right()  - nRightMargin                 ) * 100 / nZoom );
2974     aPageRect.SetTop( ( aPageRect.Top()    + nTopMargin    ) * 100 / nZoom + aHdr.nHeight );
2975     aPageRect.SetBottom( ( aPageRect.Bottom() - nBottomMargin ) * 100 / nZoom - aFtr.nHeight );
2976 
2977     Size aDocPageSize = aPageRect.GetSize();
2978     if (aTableParam.bHeaders)
2979     {
2980         aDocPageSize.AdjustWidth( -(tools::Long(PRINT_HEADER_WIDTH)) );
2981         aDocPageSize.AdjustHeight( -(tools::Long(PRINT_HEADER_HEIGHT)) );
2982     }
2983     if (pBorderItem)
2984     {
2985         aDocPageSize.AdjustWidth( -(lcl_LineTotal(pBorderItem->GetLeft()) +
2986                                  lcl_LineTotal(pBorderItem->GetRight()) +
2987                                  pBorderItem->GetDistance(SvxBoxItemLine::LEFT) +
2988                                  pBorderItem->GetDistance(SvxBoxItemLine::RIGHT)) );
2989         aDocPageSize.AdjustHeight( -(lcl_LineTotal(pBorderItem->GetTop()) +
2990                                  lcl_LineTotal(pBorderItem->GetBottom()) +
2991                                  pBorderItem->GetDistance(SvxBoxItemLine::TOP) +
2992                                  pBorderItem->GetDistance(SvxBoxItemLine::BOTTOM)) );
2993     }
2994     if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
2995     {
2996         aDocPageSize.AdjustWidth( -(pShadowItem->CalcShadowSpace(SvxShadowItemSide::LEFT) +
2997                                  pShadowItem->CalcShadowSpace(SvxShadowItemSide::RIGHT)) );
2998         aDocPageSize.AdjustHeight( -(pShadowItem->CalcShadowSpace(SvxShadowItemSide::TOP) +
2999                                  pShadowItem->CalcShadowSpace(SvxShadowItemSide::BOTTOM)) );
3000     }
3001     return aDocPageSize;
3002 }
3003 
ResetBreaks(SCTAB nTab)3004 void ScPrintFunc::ResetBreaks( SCTAB nTab )         // Set Breaks correctly for view
3005 {
3006     rDoc.SetPageSize( nTab, GetDocPageSize() );
3007     rDoc.UpdatePageBreaks( nTab );
3008 }
3009 
lcl_SetHidden(const ScDocument & rDoc,SCTAB nPrintTab,ScPageRowEntry & rPageRowEntry,SCCOL nStartCol,const std::vector<SCCOL> & rPageEndX)3010 static void lcl_SetHidden( const ScDocument& rDoc, SCTAB nPrintTab, ScPageRowEntry& rPageRowEntry,
3011                     SCCOL nStartCol, const std::vector< SCCOL >& rPageEndX )
3012 {
3013     size_t nPagesX   = rPageRowEntry.GetPagesX();
3014     SCROW nStartRow = rPageRowEntry.GetStartRow();
3015     SCROW nEndRow   = rPageRowEntry.GetEndRow();
3016 
3017     bool bLeftIsEmpty = false;
3018     ScRange aTempRange;
3019     tools::Rectangle aTempRect = rDoc.GetMMRect( 0,0, 0,0, 0 );
3020 
3021     for (size_t i=0; i<nPagesX; i++)
3022     {
3023         OSL_ENSURE(i < rPageEndX.size(), "vector access error for aPageEndX");
3024         SCCOL nEndCol = rPageEndX[i];
3025         if ( rDoc.IsPrintEmpty( nPrintTab, nStartCol, nStartRow, nEndCol, nEndRow,
3026                                     bLeftIsEmpty, &aTempRange, &aTempRect ) )
3027         {
3028             rPageRowEntry.SetHidden(i);
3029             bLeftIsEmpty = true;
3030         }
3031         else
3032             bLeftIsEmpty = false;
3033 
3034         nStartCol = nEndCol+1;
3035     }
3036 }
3037 
CalcPages()3038 void ScPrintFunc::CalcPages()               // calculates aPageRect and pages from nZoom
3039 {
3040     assert( bPrintAreaValid );
3041     m_aRanges.calculate(rDoc, aTableParam.bSkipEmpty, aAreaParam.bPrintArea, nStartRow, nEndRow, nStartCol, nEndCol, nPrintTab, GetDocPageSize());
3042 }
3043 
3044 namespace sc
3045 {
3046 
PrintPageRanges()3047 PrintPageRanges::PrintPageRanges()
3048     : m_nPagesX(0)
3049     , m_nPagesY(0)
3050     , m_nTotalY(0)
3051 {}
3052 
checkIfAlreadyCalculatedAndSet(bool bSkipEmpty,bool bPrintArea,SCROW nStartRow,SCROW nEndRow,SCCOL nStartCol,SCCOL nEndCol,SCTAB nPrintTab,Size const & rDocSize)3053 bool PrintPageRanges::checkIfAlreadyCalculatedAndSet(
3054                                     bool bSkipEmpty, bool bPrintArea,
3055                                     SCROW nStartRow, SCROW nEndRow,
3056                                     SCCOL nStartCol, SCCOL nEndCol,
3057                                     SCTAB nPrintTab, Size const & rDocSize)
3058 {
3059     if (bSkipEmpty == m_aInput.m_bSkipEmpty &&
3060         bPrintArea == m_aInput.m_bPrintArea &&
3061         nStartRow  == m_aInput.m_nStartRow && nEndRow == m_aInput.m_nEndRow &&
3062         nStartCol  == m_aInput.m_nStartCol && nEndCol == m_aInput.m_nEndCol &&
3063         nPrintTab  == m_aInput.m_nPrintTab &&
3064         rDocSize   == m_aInput.m_aDocSize)
3065     {
3066         return true;
3067     }
3068 
3069     m_aInput.m_bSkipEmpty = bSkipEmpty;
3070     m_aInput.m_bPrintArea = bPrintArea;
3071     m_aInput.m_nStartRow  = nStartRow;
3072     m_aInput.m_nEndRow    = nEndRow;
3073     m_aInput.m_nStartCol  = nStartCol;
3074     m_aInput.m_nEndCol    = nEndCol;
3075     m_aInput.m_nPrintTab  = nPrintTab;
3076     m_aInput.m_aDocSize   = rDocSize;
3077 
3078     return false;
3079 }
3080 
calculate(ScDocument & rDoc,bool bSkipEmpty,bool bPrintArea,SCROW nStartRow,SCROW nEndRow,SCCOL nStartCol,SCCOL nEndCol,SCTAB nPrintTab,Size const & rDocSize)3081 void PrintPageRanges::calculate(ScDocument& rDoc,
3082                                 bool bSkipEmpty, bool bPrintArea,
3083                                 SCROW nStartRow, SCROW nEndRow,
3084                                 SCCOL nStartCol, SCCOL nEndCol,
3085                                 SCTAB nPrintTab, Size const & rDocSize)
3086 {
3087     // Already calculated?
3088     if (checkIfAlreadyCalculatedAndSet(bSkipEmpty, bPrintArea,
3089                                        nStartRow, nEndRow, nStartCol, nEndCol,
3090                                        nPrintTab, rDocSize))
3091         return;
3092 
3093     rDoc.SetPageSize(nPrintTab, rDocSize);
3094 
3095     // #i123672# use dynamic mem to react on size changes
3096     if (m_xPageEndX->size() < static_cast<size_t>(rDoc.MaxCol()) + 1)
3097     {
3098         m_xPageEndX->resize(rDoc.MaxCol()+1, SCCOL());
3099     }
3100 
3101     if (bPrintArea)
3102     {
3103         ScRange aRange(nStartCol, nStartRow, nPrintTab, nEndCol, nEndRow, nPrintTab);
3104         rDoc.UpdatePageBreaks(nPrintTab, &aRange);
3105     }
3106     else
3107     {
3108         rDoc.UpdatePageBreaks(nPrintTab); // else, end is marked
3109     }
3110 
3111     const size_t nRealCnt = nEndRow - nStartRow + 1;
3112 
3113     // #i123672# use dynamic mem to react on size changes
3114     if (m_xPageEndY->size() < nRealCnt+1)
3115     {
3116         m_xPageEndY->resize(nRealCnt + 1, SCROW());
3117     }
3118 
3119     //  Page alignment/splitting after breaks in Col/RowFlags
3120     //  Of several breaks in a hidden area, only one counts.
3121 
3122     m_nPagesX = 0;
3123     m_nPagesY = 0;
3124     m_nTotalY = 0;
3125 
3126     bool bVisCol = false;
3127     for (SCCOL i = nStartCol; i <= nEndCol; i++)
3128     {
3129         bool bHidden = rDoc.ColHidden(i, nPrintTab);
3130         bool bPageBreak(rDoc.HasColBreak(i, nPrintTab) & ScBreakType::Page);
3131         if (i > nStartCol && bVisCol && bPageBreak)
3132         {
3133             OSL_ENSURE(m_nPagesX < m_xPageEndX->size(), "vector access error for aPageEndX");
3134             (*m_xPageEndX)[m_nPagesX] = i-1;
3135             ++m_nPagesX;
3136             bVisCol = false;
3137         }
3138         if (!bHidden)
3139             bVisCol = true;
3140     }
3141     if (bVisCol) // also at the end, no empty pages
3142     {
3143         OSL_ENSURE(m_nPagesX < m_xPageEndX->size(), "vector access error for aPageEndX");
3144         (*m_xPageEndX)[m_nPagesX] = nEndCol;
3145         ++m_nPagesX;
3146     }
3147 
3148     bool bVisRow = false;
3149     SCROW nPageStartRow = nStartRow;
3150     SCROW nLastVisibleRow = -1;
3151 
3152     std::unique_ptr<ScRowBreakIterator> pRowBreakIter(rDoc.GetRowBreakIterator(nPrintTab));
3153     SCROW nNextPageBreak = pRowBreakIter->first();
3154     while (nNextPageBreak != ScRowBreakIterator::NOT_FOUND && nNextPageBreak < nStartRow)
3155         // Skip until the page break position is at the start row or greater.
3156         nNextPageBreak = pRowBreakIter->next();
3157 
3158     for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
3159     {
3160         bool bPageBreak = (nNextPageBreak == nRow);
3161         if (bPageBreak)
3162             nNextPageBreak = pRowBreakIter->next();
3163 
3164         if (nRow > nStartRow && bVisRow && bPageBreak)
3165         {
3166             OSL_ENSURE(m_nTotalY < m_xPageEndY->size(), "vector access error for rPageEndY");
3167             (*m_xPageEndY)[m_nTotalY] = nRow - 1;
3168             ++m_nTotalY;
3169 
3170             if (!bSkipEmpty || !rDoc.IsPrintEmpty(nPrintTab, nStartCol, nPageStartRow, nEndCol, nRow-1))
3171             {
3172                 auto& rPageRow = (*m_xPageRows)[m_nPagesY];
3173                 rPageRow.SetStartRow(nPageStartRow);
3174                 rPageRow.SetEndRow(nRow - 1);
3175                 rPageRow.SetPagesX(m_nPagesX);
3176                 if (bSkipEmpty)
3177                     lcl_SetHidden(rDoc, nPrintTab, rPageRow, nStartCol, *m_xPageEndX);
3178                 ++m_nPagesY;
3179             }
3180 
3181             nPageStartRow = nRow;
3182             bVisRow = false;
3183         }
3184 
3185         if (nRow <= nLastVisibleRow)
3186         {
3187             // This row is still visible.  Don't bother calling RowHidden() to
3188             // find out, for speed optimization.
3189             bVisRow = true;
3190             continue;
3191         }
3192 
3193         SCROW nLastRow = -1;
3194         if (!rDoc.RowHidden(nRow, nPrintTab, nullptr, &nLastRow))
3195         {
3196             bVisRow = true;
3197             nLastVisibleRow = nLastRow;
3198         }
3199         else
3200         {
3201             // Skip all hidden rows until next pagebreak.
3202             nRow = ((nNextPageBreak == ScRowBreakIterator::NOT_FOUND) ? nLastRow :
3203                     std::min(nLastRow, nNextPageBreak - 1));
3204         }
3205     }
3206 
3207     if (!bVisRow)
3208         return;
3209 
3210     OSL_ENSURE(m_nTotalY < m_xPageEndY->size(), "vector access error for maPageEndY");
3211     (*m_xPageEndY)[m_nTotalY] = nEndRow;
3212     ++m_nTotalY;
3213 
3214     if (!bSkipEmpty || !rDoc.IsPrintEmpty(nPrintTab, nStartCol, nPageStartRow, nEndCol, nEndRow))
3215     {
3216         auto& rPageRow = (*m_xPageRows)[m_nPagesY];
3217         rPageRow.SetStartRow(nPageStartRow);
3218         rPageRow.SetEndRow(nEndRow);
3219         rPageRow.SetPagesX(m_nPagesX);
3220         if (bSkipEmpty)
3221             lcl_SetHidden(rDoc, nPrintTab, rPageRow, nStartCol, *m_xPageEndX);
3222         ++m_nPagesY;
3223     }
3224 }
3225 
3226 } // end namespace sc
3227 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3228