tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / view / printfun.cxx
bloba8c3990b1288ac311c3010ed0d27989c6b45b594
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <scitems.hxx>
21 #include <editeng/eeitem.hxx>
23 #include <printfun.hxx>
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 <vcl/pdfextoutdevdata.hxx>
33 #include <editeng/frmdiritem.hxx>
34 #include <editeng/lrspitem.hxx>
35 #include <editeng/paperinf.hxx>
36 #include <editeng/pbinitem.hxx>
37 #include <editeng/shaditem.hxx>
38 #include <editeng/sizeitem.hxx>
39 #include <editeng/fhgtitem.hxx>
40 #include <editeng/ulspitem.hxx>
41 #include <sfx2/printer.hxx>
42 #include <tools/multisel.hxx>
43 #include <sfx2/docfile.hxx>
44 #include <tools/urlobj.hxx>
45 #include <osl/diagnose.h>
47 #include <editutil.hxx>
48 #include <docsh.hxx>
49 #include <output.hxx>
50 #include <viewdata.hxx>
51 #include <viewopti.hxx>
52 #include <stlpool.hxx>
53 #include <pagepar.hxx>
54 #include <attrib.hxx>
55 #include <patattr.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>
67 #include <memory>
68 #include <com/sun/star/document/XDocumentProperties.hpp>
70 #define ZOOM_MIN 10
72 namespace{
74 bool lcl_GetBool(const SfxItemSet* pSet, sal_uInt16 nWhich)
76 return static_cast<const SfxBoolItem&>(pSet->Get(nWhich)).GetValue();
79 sal_uInt16 lcl_GetUShort(const SfxItemSet* pSet, sal_uInt16 nWhich)
81 return static_cast<const SfxUInt16Item&>(pSet->Get(nWhich)).GetValue();
84 bool lcl_GetShow(const SfxItemSet* pSet, sal_uInt16 nWhich)
86 return ScVObjMode::VOBJ_MODE_SHOW == static_cast<const ScViewObjectModeItem&>(pSet->Get(nWhich)).GetValue();
90 } // namespace
92 ScPageRowEntry::ScPageRowEntry(const ScPageRowEntry& r)
94 nStartRow = r.nStartRow;
95 nEndRow = r.nEndRow;
96 nPagesX = r.nPagesX;
97 aHidden = r.aHidden;
98 aHidden.resize(nPagesX, false);
101 ScPageRowEntry& ScPageRowEntry::operator=(const ScPageRowEntry& r)
103 nStartRow = r.nStartRow;
104 nEndRow = r.nEndRow;
105 nPagesX = r.nPagesX;
106 aHidden = r.aHidden;
107 aHidden.resize(nPagesX, false);
108 return *this;
111 void ScPageRowEntry::SetPagesX(size_t nNew)
113 nPagesX = nNew;
114 aHidden.resize(nPagesX, false);
117 void ScPageRowEntry::SetHidden(size_t nX)
119 if ( nX < nPagesX )
121 if ( nX+1 == nPagesX ) // last page?
122 --nPagesX;
123 else
125 aHidden.resize(nPagesX, false);
126 aHidden[nX] = true;
131 bool ScPageRowEntry::IsHidden(size_t nX) const
133 return nX >= nPagesX || aHidden[nX]; //! inline?
136 size_t ScPageRowEntry::CountVisible() const
138 if (!aHidden.empty())
140 size_t nVis = 0;
141 for (size_t i=0; i<nPagesX; i++)
142 if (!aHidden[i])
143 ++nVis;
144 return nVis;
146 else
147 return nPagesX;
150 static tools::Long lcl_LineTotal(const ::editeng::SvxBorderLine* pLine)
152 return pLine ? ( pLine->GetScaledWidth() ) : 0;
155 void ScPrintFunc::Construct( const ScPrintOptions* pOptions )
157 pDocShell->UpdatePendingRowHeights( nPrintTab );
159 SfxPrinter* pDocPrinter = rDoc.GetPrinter(); // use the printer, even for preview
160 if (pDocPrinter)
161 aOldPrinterMode = pDocPrinter->GetMapMode();
163 // unified MapMode for all calls (e.g. Repaint!!!)
164 // else, EditEngine outputs different text heights
165 pDev->SetMapMode(MapMode(MapUnit::MapPixel));
167 pBorderItem = nullptr;
168 pBackgroundItem = nullptr;
169 pShadowItem = nullptr;
171 pEditEngine = nullptr;
172 pEditDefaults = nullptr;
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
182 OSL_FAIL("Template not found" );
183 pParamSet = nullptr;
186 if (!bFromPrintState)
187 nZoom = 100;
188 nManualZoom = 100;
189 bClearWin = false;
190 bUseStyleColor = false;
191 bIsRender = false;
193 InitParam(pOptions);
195 pPageData = nullptr; // is only needed for initialisation
198 ScPrintFunc::ScPrintFunc(ScDocShell* pShell, SfxPrinter* pNewPrinter, SCTAB nTab, tools::Long nPage,
199 tools::Long nDocP, const ScRange* pArea, const ScPrintOptions* pOptions,
200 ScPageBreakData* pData, Size aSize, bool bPrintLandscape, bool bUsed)
201 : pDocShell ( pShell ),
202 rDoc(pDocShell->GetDocument()),
203 pPrinter ( pNewPrinter ),
204 pDrawView ( nullptr ),
205 nPrintTab ( nTab ),
206 nPageStart ( nPage ),
207 nDocPages ( nDocP ),
208 pUserArea ( pArea ),
209 bFromPrintState ( false ),
210 bSourceRangeValid ( false ),
211 bPrintCurrentTable ( false ),
212 bMultiArea ( false ),
213 mbHasPrintRange(true),
214 nTabPages ( 0 ),
215 nTotalPages ( 0 ),
216 bPrintAreaValid ( false ),
217 pPageData ( pData ),
218 aPrintPageSize ( aSize ),
219 bPrintPageLandscape ( bPrintLandscape ),
220 bUsePrintDialogSetting ( bUsed )
222 pDev = pPrinter.get();
223 aSrcOffset = pPrinter->PixelToLogic(pPrinter->GetPageOffsetPixel(), MapMode(MapUnit::Map100thMM));
224 m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
225 m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
226 m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
227 Construct( pOptions );
230 ScPrintFunc::ScPrintFunc(ScDocShell* pShell, SfxPrinter* pNewPrinter, const ScPrintState& rState,
231 const ScPrintOptions* pOptions, Size aSize, bool bPrintLandscape,
232 bool bUsed)
233 : pDocShell ( pShell ),
234 rDoc(pDocShell->GetDocument()),
235 pPrinter ( pNewPrinter ),
236 pDrawView ( nullptr ),
237 pUserArea ( nullptr ),
238 bSourceRangeValid ( false ),
239 bPrintCurrentTable ( false ),
240 bMultiArea ( false ),
241 mbHasPrintRange(true),
242 pPageData ( nullptr ),
243 aPrintPageSize ( aSize ),
244 bPrintPageLandscape ( bPrintLandscape ),
245 bUsePrintDialogSetting ( bUsed )
247 pDev = pPrinter.get();
249 nPrintTab = rState.nPrintTab;
250 nStartCol = rState.nStartCol;
251 nStartRow = rState.nStartRow;
252 nEndCol = rState.nEndCol;
253 nEndRow = rState.nEndRow;
254 bPrintAreaValid = rState.bPrintAreaValid;
255 nZoom = rState.nZoom;
256 m_aRanges = rState.m_aRanges;
257 nTabPages = rState.nTabPages;
258 nTotalPages = rState.nTotalPages;
259 nPageStart = rState.nPageStart;
260 nDocPages = rState.nDocPages;
261 bFromPrintState = true;
263 aSrcOffset = pPrinter->PixelToLogic(pPrinter->GetPageOffsetPixel(), MapMode(MapUnit::Map100thMM));
264 Construct( pOptions );
267 ScPrintFunc::ScPrintFunc( OutputDevice* pOutDev, ScDocShell* pShell, SCTAB nTab,
268 tools::Long nPage, tools::Long nDocP, const ScRange* pArea,
269 const ScPrintOptions* pOptions )
270 : pDocShell ( pShell ),
271 rDoc(pDocShell->GetDocument()),
272 pPrinter ( nullptr ),
273 pDrawView ( nullptr ),
274 nPrintTab ( nTab ),
275 nPageStart ( nPage ),
276 nDocPages ( nDocP ),
277 pUserArea ( pArea ),
278 bFromPrintState ( false ),
279 bSourceRangeValid ( false ),
280 bPrintCurrentTable ( false ),
281 bMultiArea ( false ),
282 mbHasPrintRange(true),
283 nTabPages ( 0 ),
284 nTotalPages ( 0 ),
285 bPrintAreaValid ( false ),
286 pPageData ( nullptr ),
287 aPrintPageSize ( Size() ),
288 bPrintPageLandscape ( false ),
289 bUsePrintDialogSetting ( false )
291 pDev = pOutDev;
292 m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
293 m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
294 m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
295 Construct( pOptions );
298 ScPrintFunc::ScPrintFunc(OutputDevice* pOutDev, ScDocShell* pShell, const ScPrintState& rState,
299 const ScPrintOptions* pOptions, Size aSize, bool bPrintLandscape,
300 bool bUsed)
301 : pDocShell ( pShell ),
302 rDoc(pDocShell->GetDocument()),
303 pPrinter ( nullptr ),
304 pDrawView ( nullptr ),
305 pUserArea ( nullptr ),
306 bSourceRangeValid ( false ),
307 bPrintCurrentTable ( false ),
308 bMultiArea ( false ),
309 mbHasPrintRange(true),
310 pPageData ( nullptr ),
311 aPrintPageSize ( aSize ),
312 bPrintPageLandscape ( bPrintLandscape ),
313 bUsePrintDialogSetting ( bUsed )
315 pDev = pOutDev;
317 nPrintTab = rState.nPrintTab;
318 nStartCol = rState.nStartCol;
319 nStartRow = rState.nStartRow;
320 nEndCol = rState.nEndCol;
321 nEndRow = rState.nEndRow;
322 bPrintAreaValid = rState.bPrintAreaValid;
323 nZoom = rState.nZoom;
324 m_aRanges = rState.m_aRanges;
325 nTabPages = rState.nTabPages;
326 nTotalPages = rState.nTotalPages;
327 nPageStart = rState.nPageStart;
328 nDocPages = rState.nDocPages;
329 bFromPrintState = true;
331 Construct( pOptions );
334 void ScPrintFunc::GetPrintState(ScPrintState& rState)
336 rState.nPrintTab = nPrintTab;
337 rState.nStartCol = nStartCol;
338 rState.nStartRow = nStartRow;
339 rState.nEndCol = nEndCol;
340 rState.nEndRow = nEndRow;
341 rState.bPrintAreaValid = bPrintAreaValid;
342 rState.nZoom = nZoom;
343 rState.nTabPages = nTabPages;
344 rState.nTotalPages = nTotalPages;
345 rState.nPageStart = nPageStart;
346 rState.nDocPages = nDocPages;
347 rState.m_aRanges = m_aRanges;
350 bool ScPrintFunc::GetLastSourceRange( ScRange& rRange ) const
352 rRange = aLastSourceRange;
353 return bSourceRangeValid;
356 void ScPrintFunc::FillPageData()
358 if (!pPageData)
359 return;
361 sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( pPageData->GetCount() );
362 ScPrintRangeData& rData = pPageData->GetData(nCount); // count up
364 assert( bPrintAreaValid );
365 rData.SetPrintRange( ScRange( nStartCol, nStartRow, nPrintTab,
366 nEndCol, nEndRow, nPrintTab ) );
367 // #i123672#
368 if(m_aRanges.m_xPageEndX->empty())
370 OSL_ENSURE(false, "vector access error for maPageEndX (!)");
372 else
374 rData.SetPagesX( m_aRanges.m_nPagesX, m_aRanges.m_xPageEndX->data());
377 // #i123672#
378 if(m_aRanges.m_xPageEndY->empty())
380 OSL_ENSURE(false, "vector access error for maPageEndY (!)");
382 else
384 rData.SetPagesY( m_aRanges.m_nTotalY, m_aRanges.m_xPageEndY->data());
387 // Settings
388 rData.SetTopDown( aTableParam.bTopDown );
389 rData.SetAutomatic( !aAreaParam.bPrintArea );
392 ScPrintFunc::~ScPrintFunc()
394 pEditDefaults.reset();
395 pEditEngine.reset();
397 // Printer settings are now restored from outside
399 // For DrawingLayer/Charts, the MapMode of the printer (RefDevice) must always be correct
400 SfxPrinter* pDocPrinter = rDoc.GetPrinter(); // use Preview also for the printer
401 if (pDocPrinter)
402 pDocPrinter->SetMapMode(aOldPrinterMode);
405 void ScPrintFunc::SetDrawView( FmFormView* pNew )
407 pDrawView = pNew;
410 static void lcl_HidePrint( const ScTableInfo& rTabInfo, SCCOL nX1, SCCOL nX2 )
412 for (SCSIZE nArrY=1; nArrY+1<rTabInfo.mnArrCount; nArrY++)
414 RowInfo* pThisRowInfo = &rTabInfo.mpRowInfo[nArrY];
415 for (SCCOL nX=nX1; nX<=nX2; nX++)
417 ScCellInfo& rCellInfo = pThisRowInfo->cellInfo(nX);
418 ScBasicCellInfo& rBasicCellInfo = pThisRowInfo->basicCellInfo(nX);
419 if (!rBasicCellInfo.bEmptyCellText)
420 if (rCellInfo.pPatternAttr->
421 GetItem(ATTR_PROTECTION, rCellInfo.pConditionSet).GetHidePrint())
423 rCellInfo.maCell.clear();
424 rBasicCellInfo.bEmptyCellText = true;
430 // output to Device (static)
432 // us used for:
433 // - Clipboard/Bitmap
434 // - Ole-Object (DocShell::Draw)
435 // - Preview of templates
437 void ScPrintFunc::DrawToDev(ScDocument& rDoc, OutputDevice* pDev, double /* nPrintFactor */,
438 const tools::Rectangle& rBound, ScViewData* pViewData, bool bMetaFile)
440 if (rDoc.GetMaxTableNumber() < 0)
441 return;
443 //! evaluate nPrintFactor !!!
445 SCTAB nTab = 0;
446 if (pViewData)
447 nTab = pViewData->GetTabNo();
449 bool bDoGrid, bNullVal, bFormula;
450 ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
451 SfxStyleSheetBase* pStyleSheet = pStylePool->Find( rDoc.GetPageStyle( nTab ), SfxStyleFamily::Page );
452 if (pStyleSheet)
454 SfxItemSet& rSet = pStyleSheet->GetItemSet();
455 bDoGrid = rSet.Get(ATTR_PAGE_GRID).GetValue();
456 bNullVal = rSet.Get(ATTR_PAGE_NULLVALS).GetValue();
457 bFormula = rSet.Get(ATTR_PAGE_FORMULAS).GetValue();
459 else
461 const ScViewOptions& rOpt = rDoc.GetViewOptions();
462 bDoGrid = rOpt.GetOption(VOPT_GRID);
463 bNullVal = rOpt.GetOption(VOPT_NULLVALS);
464 bFormula = rOpt.GetOption(VOPT_FORMULAS);
467 MapMode aMode = pDev->GetMapMode();
469 tools::Rectangle aRect = rBound;
471 if (aRect.Right() < aRect.Left() || aRect.Bottom() < aRect.Top())
472 aRect = tools::Rectangle( Point(), pDev->GetOutputSize() );
474 SCCOL nX1 = 0;
475 SCROW nY1 = 0;
476 SCCOL nX2 = OLE_STD_CELLS_X - 1;
477 SCROW nY2 = OLE_STD_CELLS_Y - 1;
478 if (bMetaFile)
480 ScRange aRange = rDoc.GetRange( nTab, rBound );
481 nX1 = aRange.aStart.Col();
482 nY1 = aRange.aStart.Row();
483 nX2 = aRange.aEnd.Col();
484 nY2 = aRange.aEnd.Row();
486 else if (pViewData)
488 ScSplitPos eWhich = pViewData->GetActivePart();
489 ScHSplitPos eHWhich = WhichH(eWhich);
490 ScVSplitPos eVWhich = WhichV(eWhich);
491 nX1 = pViewData->GetPosX(eHWhich);
492 nY1 = pViewData->GetPosY(eVWhich);
493 nX2 = nX1 + pViewData->VisibleCellsX(eHWhich);
494 if (nX2>nX1) --nX2;
495 nY2 = nY1 + pViewData->VisibleCellsY(eVWhich);
496 if (nY2>nY1) --nY2;
499 if (nX1 > rDoc.MaxCol()) nX1 = rDoc.MaxCol();
500 if (nX2 > rDoc.MaxCol()) nX2 = rDoc.MaxCol();
501 if (nY1 > rDoc.MaxRow()) nY1 = rDoc.MaxRow();
502 if (nY2 > rDoc.MaxRow()) nY2 = rDoc.MaxRow();
504 tools::Long nDevSizeX = aRect.Right()-aRect.Left()+1;
505 tools::Long nDevSizeY = aRect.Bottom()-aRect.Top()+1;
507 tools::Long nTwipsSizeX = 0;
508 for (SCCOL i=nX1; i<=nX2; i++)
509 nTwipsSizeX += rDoc.GetColWidth( i, nTab );
510 tools::Long nTwipsSizeY = rDoc.GetRowHeight( nY1, nY2, nTab );
512 // if no lines, still space for the outline frame (20 Twips = 1pt)
513 // (HasLines initializes aLines to 0,0,0,0)
514 nTwipsSizeX += 20;
515 nTwipsSizeY += 20;
517 double nScaleX = static_cast<double>(nDevSizeX) / nTwipsSizeX;
518 double nScaleY = static_cast<double>(nDevSizeY) / nTwipsSizeY;
520 //! hand over Flag at FillInfo !!!!!
521 ScRange aERange;
522 bool bEmbed = rDoc.IsEmbedded();
523 if (bEmbed)
525 rDoc.GetEmbedded(aERange);
526 rDoc.ResetEmbedded();
529 // Assemble data
531 ScTableInfo aTabInfo(nY1, nY2, true);
532 rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nTab,
533 nScaleX, nScaleY, false, bFormula );
534 lcl_HidePrint( aTabInfo, nX1, nX2 );
536 if (bEmbed)
537 rDoc.SetEmbedded(aERange);
539 tools::Long nScrX = aRect.Left();
540 tools::Long nScrY = aRect.Top();
542 // If no lines, still leave space for grid lines
543 // (would be elseways cut away)
544 nScrX += 1;
545 nScrY += 1;
547 ScOutputData aOutputData( pDev, OUTTYPE_PRINTER, aTabInfo, &rDoc, nTab,
548 nScrX, nScrY, nX1, nY1, nX2, nY2, nScaleX, nScaleY );
549 aOutputData.SetMetaFileMode(bMetaFile);
550 aOutputData.SetShowNullValues(bNullVal);
551 aOutputData.SetShowFormulas(bFormula);
553 vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData());
554 bool bTaggedPDF = pPDF && pPDF->GetIsExportTaggedPDF();
555 if (bTaggedPDF)
557 bool bReopen = aOutputData.ReopenPDFStructureElement(vcl::PDFWriter::Part);
558 if (!bReopen)
560 sal_Int32 nId = pPDF->EnsureStructureElement(nullptr);
561 pPDF->InitStructureElement(nId, vcl::PDFWriter::Part, u"Worksheet"_ustr);
562 pPDF->BeginStructureElement(nId);
563 pPDF->GetScPDFState()->m_WorksheetId = nId;
567 ScDrawLayer* pModel = rDoc.GetDrawLayer();
568 std::unique_ptr<FmFormView> pDrawView;
570 if( pModel )
572 pDrawView.reset(
573 new FmFormView(
574 *pModel,
575 pDev));
576 pDrawView->ShowSdrPage(pDrawView->GetModel().GetPage(nTab));
577 pDrawView->SetPrintPreview();
578 aOutputData.SetDrawView( pDrawView.get() );
581 //! SetUseStyleColor ??
583 if ( bMetaFile && pDev->IsVirtual() )
584 aOutputData.SetSnapPixel();
586 Point aLogStart = pDev->PixelToLogic(Point(nScrX, nScrY), MapMode(MapUnit::Map100thMM));
587 tools::Long nLogStX = aLogStart.X();
588 tools::Long nLogStY = aLogStart.Y();
590 //! nZoom for GetFont in OutputData ???
592 if (!bMetaFile && pViewData)
593 pDev->SetMapMode(pViewData->GetLogicMode(pViewData->GetActivePart()));
595 // #i72502#
596 const Point aMMOffset(aOutputData.PrePrintDrawingLayer(nLogStX, nLogStY));
597 aOutputData.PrintDrawingLayer(SC_LAYER_BACK, aMMOffset);
599 if (!bMetaFile && pViewData)
600 pDev->SetMapMode(aMode);
602 aOutputData.DrawBackground(*pDev);
604 aOutputData.DrawShadow();
605 aOutputData.DrawFrame(*pDev);
606 aOutputData.DrawSparklines(*pDev);
607 aOutputData.DrawStrings();
609 if (!bMetaFile && pViewData)
610 pDev->SetMapMode(pViewData->GetLogicMode(pViewData->GetActivePart()));
612 aOutputData.DrawEdit(!bMetaFile);
614 if (bDoGrid)
616 if (!bMetaFile && pViewData)
617 pDev->SetMapMode(aMode);
619 aOutputData.DrawGrid(*pDev, true, false); // no page breaks
621 pDev->SetLineColor( COL_BLACK );
623 Size aOne = pDev->PixelToLogic( Size(1,1) );
624 if (bMetaFile)
625 aOne = Size(1,1); // compatible with DrawGrid
626 tools::Long nRight = nScrX + aOutputData.GetScrW() - aOne.Width();
627 tools::Long nBottom = nScrY + aOutputData.GetScrH() - aOne.Height();
629 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
631 // extra line at the left edge for left-to-right, right for right-to-left
632 if ( bLayoutRTL )
633 pDev->DrawLine( Point(nRight,nScrY), Point(nRight,nBottom) );
634 else
635 pDev->DrawLine( Point(nScrX,nScrY), Point(nScrX,nBottom) );
636 // extra line at the top in both cases
637 pDev->DrawLine( Point(nScrX,nScrY), Point(nRight,nScrY) );
640 // #i72502#
641 aOutputData.PrintDrawingLayer(SC_LAYER_FRONT, aMMOffset);
643 if (bTaggedPDF)
644 pPDF->EndStructureElement();
646 aOutputData.PrintDrawingLayer(SC_LAYER_INTERN, aMMOffset);
647 aOutputData.PostPrintDrawingLayer(aMMOffset); // #i74768#
650 // Printing
652 static void lcl_FillHFParam( ScPrintHFParam& rParam, const SfxItemSet* pHFSet )
654 // nDistance must be initialized differently before
656 if ( pHFSet == nullptr )
658 rParam.bEnable = false;
659 rParam.pBorder = nullptr;
660 rParam.pBack = nullptr;
661 rParam.pShadow = nullptr;
663 else
665 rParam.bEnable = pHFSet->Get(ATTR_PAGE_ON).GetValue();
666 rParam.bDynamic = pHFSet->Get(ATTR_PAGE_DYNAMIC).GetValue();
667 rParam.bShared = pHFSet->Get(ATTR_PAGE_SHARED).GetValue();
668 rParam.bSharedFirst = pHFSet->Get(ATTR_PAGE_SHARED_FIRST).GetValue();
669 rParam.nHeight = pHFSet->Get(ATTR_PAGE_SIZE).GetSize().Height();
670 const SvxLRSpaceItem* pHFLR = &pHFSet->Get(ATTR_LRSPACE);
671 tools::Long nTmp;
672 nTmp = pHFLR->ResolveLeft({});
673 rParam.nLeft = nTmp < 0 ? 0 : sal_uInt16(nTmp);
674 nTmp = pHFLR->ResolveRight({});
675 rParam.nRight = nTmp < 0 ? 0 : sal_uInt16(nTmp);
676 rParam.pBorder = &pHFSet->Get(ATTR_BORDER);
677 rParam.pBack = &pHFSet->Get(ATTR_BACKGROUND);
678 rParam.pShadow = &pHFSet->Get(ATTR_SHADOW);
680 // now back in the dialog:
681 // rParam.nHeight += rParam.nDistance; // not in the dialog any more ???
683 rParam.nHeight += lcl_LineTotal( rParam.pBorder->GetTop() ) +
684 lcl_LineTotal( rParam.pBorder->GetBottom() );
686 rParam.nManHeight = rParam.nHeight;
689 if (!rParam.bEnable)
690 rParam.nHeight = 0;
693 // bNew = TRUE: search for used part of the document
694 // bNew = FALSE: only limit whole lines/columns
696 bool ScPrintFunc::AdjustPrintArea( bool bNew )
698 SCCOL nOldEndCol = nEndCol; // only important for !bNew
699 SCROW nOldEndRow = nEndRow;
700 bool bChangeCol = true; // at bNew both are being adjusted
701 bool bChangeRow = true;
703 bool bNotes = aTableParam.bNotes;
704 if ( bNew )
706 nStartCol = 0;
707 nStartRow = 0;
708 if (!rDoc.GetPrintArea( nPrintTab, nEndCol, nEndRow, bNotes ) && aTableParam.bSkipEmpty)
709 return false; // nothing
710 bPrintAreaValid = true;
712 else
714 bool bFound = true;
715 bChangeCol = ( nStartCol == 0 && nEndCol == rDoc.MaxCol() );
716 bChangeRow = ( nStartRow == 0 && nEndRow == rDoc.MaxRow() );
717 bool bForcedChangeRow = false;
719 // #i53558# Crop entire column of old row limit to real print area with
720 // some fuzzyness.
721 if (!bChangeRow && nStartRow == 0)
723 SCROW nPAEndRow;
724 bFound = rDoc.GetPrintAreaVer( nPrintTab, nStartCol, nEndCol, nPAEndRow, bNotes );
725 // Say we don't want to print more than ~1000 empty rows, which are
726 // about 14 pages intentionally left blank...
727 const SCROW nFuzzy = 23*42;
728 if (nPAEndRow + nFuzzy < nEndRow)
730 bForcedChangeRow = true;
731 nEndRow = nPAEndRow;
733 else
734 bFound = true; // user seems to _want_ to print some empty rows
736 // TODO: in case we extend the number of columns we may have to do the
737 // same for horizontal cropping.
739 if ( bChangeCol && bChangeRow )
740 bFound = rDoc.GetPrintArea( nPrintTab, nEndCol, nEndRow, bNotes );
741 else if ( bChangeCol )
742 bFound = rDoc.GetPrintAreaHor( nPrintTab, nStartRow, nEndRow, nEndCol );
743 else if ( bChangeRow )
744 bFound = rDoc.GetPrintAreaVer( nPrintTab, nStartCol, nEndCol, nEndRow, bNotes );
746 if (!bFound)
747 return false; // empty
749 bPrintAreaValid = true;
750 if (bForcedChangeRow)
751 bChangeRow = true;
754 assert( bPrintAreaValid );
755 rDoc.ExtendMerge( nStartCol,nStartRow, nEndCol,nEndRow, nPrintTab ); // no Refresh, incl. Attrs
757 if ( bChangeCol )
759 OutputDevice* pRefDev = rDoc.GetPrinter(); // use the printer also for Preview
760 pRefDev->SetMapMode(MapMode(MapUnit::MapPixel)); // important for GetNeededSize
762 rDoc.ExtendPrintArea( pRefDev,
763 nPrintTab, nStartCol, nStartRow, nEndCol, nEndRow );
764 // changing nEndCol
767 if ( nEndCol < rDoc.MaxCol() && rDoc.HasAttrib(
768 nEndCol,nStartRow,nPrintTab, nEndCol,nEndRow,nPrintTab, HasAttrFlags::ShadowRight ) )
769 ++nEndCol;
770 if ( nEndRow < rDoc.MaxRow() && rDoc.HasAttrib(
771 nStartCol,nEndRow,nPrintTab, nEndCol,nEndRow,nPrintTab, HasAttrFlags::ShadowDown ) )
772 ++nEndRow;
774 if (!bChangeCol) nEndCol = nOldEndCol;
775 if (!bChangeRow) nEndRow = nOldEndRow;
777 return true;
780 tools::Long ScPrintFunc::TextHeight( const EditTextObject* pObject )
782 if (!pObject)
783 return 0;
785 pEditEngine->SetTextTempDefaults(*pObject, *pEditDefaults);
787 return static_cast<tools::Long>(pEditEngine->GetTextHeight());
790 // nZoom must be set !!!
791 // and the respective Twip-MapMode configured
793 void ScPrintFunc::UpdateHFHeight( ScPrintHFParam& rParam )
795 OSL_ENSURE( aPageSize.Width(), "UpdateHFHeight without aPageSize");
797 if (!(rParam.bEnable && rParam.bDynamic))
798 return;
800 // calculate nHeight from content
802 MakeEditEngine();
803 tools::Long nPaperWidth = ( aPageSize.Width() - nLeftMargin - nRightMargin -
804 rParam.nLeft - rParam.nRight ) * 100 / nZoom;
805 if (rParam.pBorder)
806 nPaperWidth -= ( rParam.pBorder->GetDistance(SvxBoxItemLine::LEFT) +
807 rParam.pBorder->GetDistance(SvxBoxItemLine::RIGHT) +
808 lcl_LineTotal(rParam.pBorder->GetLeft()) +
809 lcl_LineTotal(rParam.pBorder->GetRight()) ) * 100 / nZoom;
811 if (rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE)
812 nPaperWidth -= ( rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::LEFT) +
813 rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::RIGHT) ) * 100 / nZoom;
815 if (nPaperWidth <= 0)
817 SAL_WARN("sc.ui", "Header/Footer unreasonably narrow width of: " << nPaperWidth << ", cannot calculate height");
818 return;
821 pEditEngine->SetPaperSize( Size( nPaperWidth, 10000 ) );
823 tools::Long nMaxHeight = 0;
824 if ( rParam.pLeft )
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() ) );
830 if ( rParam.pRight )
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() ) );
836 if ( rParam.pFirst )
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() ) );
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);
853 if (rParam.nHeight < rParam.nManHeight)
854 rParam.nHeight = rParam.nManHeight; // configured minimum
857 void ScPrintFunc::InitParam( const ScPrintOptions* pOptions )
859 if (!pParamSet)
860 return;
862 // TabPage "Page"
863 const SvxLRSpaceItem* pLRItem = &pParamSet->Get( ATTR_LRSPACE );
864 tools::Long nTmp;
865 nTmp = pLRItem->ResolveLeft({});
866 nLeftMargin = nTmp < 0 ? 0 : sal_uInt16(nTmp);
867 nTmp = pLRItem->ResolveRight({});
868 nRightMargin = nTmp < 0 ? 0 : sal_uInt16(nTmp);
869 const SvxULSpaceItem* pULItem = &pParamSet->Get( ATTR_ULSPACE );
870 nTopMargin = pULItem->GetUpper();
871 nBottomMargin = pULItem->GetLower();
873 const SvxPageItem* pPageItem = &pParamSet->Get( ATTR_PAGE );
874 nPageUsage = pPageItem->GetPageUsage();
875 bLandscape = bUsePrintDialogSetting ? bPrintPageLandscape : pPageItem->IsLandscape();
876 aFieldData.eNumType = pPageItem->GetNumType();
878 bCenterHor = pParamSet->Get(ATTR_PAGE_HORCENTER).GetValue();
879 bCenterVer = pParamSet->Get(ATTR_PAGE_VERCENTER).GetValue();
881 aPageSize = bUsePrintDialogSetting ? aPrintPageSize : pParamSet->Get(ATTR_PAGE_SIZE).GetSize();
882 if ( !aPageSize.Width() || !aPageSize.Height() )
884 OSL_FAIL("PageSize Null ?!?!?");
885 aPageSize = SvxPaperInfo::GetPaperSize( PAPER_A4 );
888 pBorderItem = &pParamSet->Get(ATTR_BORDER);
889 pBackgroundItem = &pParamSet->Get(ATTR_BACKGROUND);
890 pShadowItem = &pParamSet->Get(ATTR_SHADOW);
892 // TabPage "Headline"
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);
898 const SfxItemSet* pHeaderSet = nullptr;
899 if ( const SvxSetItem* pHeaderSetItem = pParamSet->GetItemIfSet( ATTR_PAGE_HEADERSET, false ) )
901 pHeaderSet = &pHeaderSetItem->GetItemSet();
902 // Headline has space below
903 aHdr.nDistance = pHeaderSet->Get(ATTR_ULSPACE).GetLower();
905 lcl_FillHFParam( aHdr, pHeaderSet );
907 // TabPage "Footline"
909 aFtr.pLeft = &pParamSet->Get(ATTR_PAGE_FOOTERLEFT); // Content
910 aFtr.pRight = &pParamSet->Get(ATTR_PAGE_FOOTERRIGHT);
911 aFtr.pFirst = &pParamSet->Get(ATTR_PAGE_FOOTERFIRST);
913 const SfxItemSet* pFooterSet = nullptr;
914 if ( const SvxSetItem* pFooterSetItem = pParamSet->GetItemIfSet( ATTR_PAGE_FOOTERSET, false ) )
916 pFooterSet = &pFooterSetItem->GetItemSet();
917 // Footline has space above
918 aFtr.nDistance = pFooterSet->Get(ATTR_ULSPACE).GetUpper();
920 lcl_FillHFParam( aFtr, pFooterSet );
922 // Compile Table-/Area-Params from single Items
924 // TabPage "Table"
926 const SfxUInt16Item* pScaleItem = nullptr;
927 const ScPageScaleToItem* pScaleToItem = nullptr;
928 const SfxUInt16Item* pScaleToPagesItem = nullptr;
929 SfxItemState eState;
931 eState = pParamSet->GetItemState( ATTR_PAGE_SCALE, false,
932 reinterpret_cast<const SfxPoolItem**>(&pScaleItem) );
933 if ( SfxItemState::DEFAULT == eState )
934 pScaleItem = &pParamSet->GetPool()->GetUserOrPoolDefaultItem( ATTR_PAGE_SCALE );
936 eState = pParamSet->GetItemState( ATTR_PAGE_SCALETO, false,
937 reinterpret_cast<const SfxPoolItem**>(&pScaleToItem) );
938 if ( SfxItemState::DEFAULT == eState )
939 pScaleToItem = &pParamSet->GetPool()->GetUserOrPoolDefaultItem( ATTR_PAGE_SCALETO );
941 eState = pParamSet->GetItemState( ATTR_PAGE_SCALETOPAGES, false,
942 reinterpret_cast<const SfxPoolItem**>(&pScaleToPagesItem) );
943 if ( SfxItemState::DEFAULT == eState )
944 pScaleToPagesItem = &pParamSet->GetPool()->GetUserOrPoolDefaultItem( ATTR_PAGE_SCALETOPAGES );
946 OSL_ENSURE( pScaleItem && pScaleToItem && pScaleToPagesItem, "Missing ScaleItem! :-/" );
948 aTableParam.bCellContent = true;
949 aTableParam.bNotes = lcl_GetBool(pParamSet,ATTR_PAGE_NOTES);
950 aTableParam.bGrid = lcl_GetBool(pParamSet,ATTR_PAGE_GRID);
951 aTableParam.bHeaders = lcl_GetBool(pParamSet,ATTR_PAGE_HEADERS);
952 aTableParam.bFormulas = lcl_GetBool(pParamSet,ATTR_PAGE_FORMULAS);
953 aTableParam.bNullVals = lcl_GetBool(pParamSet,ATTR_PAGE_NULLVALS);
954 aTableParam.bCharts = lcl_GetShow(pParamSet,ATTR_PAGE_CHARTS);
955 aTableParam.bObjects = lcl_GetShow(pParamSet,ATTR_PAGE_OBJECTS);
956 aTableParam.bDrawings = lcl_GetShow(pParamSet,ATTR_PAGE_DRAWINGS);
957 aTableParam.bTopDown = lcl_GetBool(pParamSet,ATTR_PAGE_TOPDOWN);
958 aTableParam.bLeftRight = !aTableParam.bLeftRight;
959 aTableParam.nFirstPageNo = lcl_GetUShort(pParamSet,ATTR_PAGE_FIRSTPAGENO);
960 if (!aTableParam.nFirstPageNo)
961 aTableParam.nFirstPageNo = static_cast<sal_uInt16>(nPageStart); // from previous table
963 if ( pScaleItem && pScaleToItem && pScaleToPagesItem )
965 sal_uInt16 nScaleAll = pScaleItem->GetValue();
966 sal_uInt16 nScaleToPages = pScaleToPagesItem->GetValue();
968 aTableParam.bScaleNone = (nScaleAll == 100);
969 aTableParam.bScaleAll = (nScaleAll > 0 );
970 aTableParam.bScaleTo = pScaleToItem->IsValid();
971 aTableParam.bScalePageNum = (nScaleToPages > 0 );
972 aTableParam.nScaleAll = nScaleAll;
973 aTableParam.nScaleWidth = pScaleToItem->GetWidth();
974 aTableParam.nScaleHeight = pScaleToItem->GetHeight();
975 aTableParam.nScalePageNum = nScaleToPages;
977 else
979 aTableParam.bScaleNone = true;
980 aTableParam.bScaleAll = false;
981 aTableParam.bScaleTo = false;
982 aTableParam.bScalePageNum = false;
983 aTableParam.nScaleAll = 0;
984 aTableParam.nScaleWidth = 0;
985 aTableParam.nScaleHeight = 0;
986 aTableParam.nScalePageNum = 0;
989 // skip empty pages only if options with that flag are passed
990 aTableParam.bSkipEmpty = pOptions && pOptions->GetSkipEmpty();
991 if ( pPageData )
992 aTableParam.bSkipEmpty = false;
993 // If pPageData is set, only the breaks are interesting for the
994 // pagebreak preview, empty pages are not addressed separately.
996 aTableParam.bForceBreaks = pOptions && pOptions->GetForceBreaks();
998 // TabPage "Parts":
1000 //! walk through all PrintAreas of the table !!!
1001 const ScRange* pPrintArea = rDoc.GetPrintRange( nPrintTab, 0 );
1002 std::optional<ScRange> oRepeatCol = rDoc.GetRepeatColRange( nPrintTab );
1003 std::optional<ScRange> oRepeatRow = rDoc.GetRepeatRowRange( nPrintTab );
1005 // ignoring ATTR_PAGE_PRINTTABLES
1007 bool bHasPrintRange = rDoc.HasPrintRange();
1008 sal_uInt16 nPrintRangeCount = rDoc.GetPrintRangeCount(nPrintTab);
1009 bool bPrintEntireSheet = rDoc.IsPrintEntireSheet(nPrintTab);
1011 if (!bPrintEntireSheet && !nPrintRangeCount)
1012 mbHasPrintRange = false;
1014 if ( pUserArea ) // UserArea (selection) has priority
1016 bPrintCurrentTable =
1017 aAreaParam.bPrintArea = true; // Selection
1018 aAreaParam.aPrintArea = *pUserArea;
1020 // The table-query is already in DocShell::Print, here always
1021 aAreaParam.aPrintArea.aStart.SetTab(nPrintTab);
1022 aAreaParam.aPrintArea.aEnd.SetTab(nPrintTab);
1024 else if (bHasPrintRange)
1026 if ( pPrintArea ) // at least one set?
1028 bPrintCurrentTable =
1029 aAreaParam.bPrintArea = true;
1030 aAreaParam.aPrintArea = *pPrintArea;
1032 bMultiArea = nPrintRangeCount > 1;
1034 else
1036 // do not print hidden sheets with "Print entire sheet" flag
1037 bPrintCurrentTable = rDoc.IsPrintEntireSheet( nPrintTab ) && rDoc.IsVisible( nPrintTab );
1038 aAreaParam.bPrintArea = !bPrintCurrentTable; // otherwise the table is always counted
1041 else
1043 // don't print hidden tables if there's no print range defined there
1044 if ( rDoc.IsVisible( nPrintTab ) )
1046 aAreaParam.bPrintArea = false;
1047 bPrintCurrentTable = true;
1049 else
1051 aAreaParam.bPrintArea = true; // otherwise the table is always counted
1052 bPrintCurrentTable = false;
1056 if ( oRepeatCol )
1058 aAreaParam.bRepeatCol = true;
1059 nRepeatStartCol = oRepeatCol->aStart.Col();
1060 nRepeatEndCol = oRepeatCol->aEnd .Col();
1062 else
1064 aAreaParam.bRepeatCol = false;
1065 nRepeatStartCol = nRepeatEndCol = SCCOL_REPEAT_NONE;
1068 if ( oRepeatRow )
1070 aAreaParam.bRepeatRow = true;
1071 nRepeatStartRow = oRepeatRow->aStart.Row();
1072 nRepeatEndRow = oRepeatRow->aEnd .Row();
1074 else
1076 aAreaParam.bRepeatRow = false;
1077 nRepeatStartRow = nRepeatEndRow = SCROW_REPEAT_NONE;
1080 // Split pages
1082 if (!bPrintAreaValid)
1084 nTabPages = CountPages(); // also calculates zoom
1085 nTotalPages = nTabPages;
1086 nTotalPages += CountNotePages();
1088 else
1090 CalcPages(); // search breaks only
1091 CountNotePages(); // Count notes, even if number of pages is already known
1094 if (nDocPages)
1095 aFieldData.nTotalPages = nDocPages;
1096 else
1097 aFieldData.nTotalPages = nTotalPages;
1099 SetDateTime( DateTime( DateTime::SYSTEM ) );
1101 if( pDocShell->getDocProperties()->getTitle().getLength() != 0 )
1102 aFieldData.aTitle = pDocShell->getDocProperties()->getTitle();
1103 else
1104 aFieldData.aTitle = pDocShell->GetTitle();
1106 const INetURLObject& rURLObj = pDocShell->GetMedium()->GetURLObject();
1107 aFieldData.aLongDocName = rURLObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
1108 if ( !aFieldData.aLongDocName.isEmpty() )
1109 aFieldData.aShortDocName = rURLObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
1110 else
1111 aFieldData.aShortDocName = aFieldData.aLongDocName = aFieldData.aTitle;
1113 // Printer settings (Orientation, Paper) at DoPrint
1116 Size ScPrintFunc::GetDataSize() const
1118 Size aSize = aPageSize;
1119 aSize.AdjustWidth( -(nLeftMargin + nRightMargin) );
1120 aSize.AdjustHeight( -(nTopMargin + nBottomMargin) );
1121 aSize.AdjustHeight( -(aHdr.nHeight + aFtr.nHeight) );
1122 return aSize;
1125 void ScPrintFunc::GetScaleData( Size& rPhysSize, tools::Long& rDocHdr, tools::Long& rDocFtr )
1127 rPhysSize = aPageSize;
1128 rPhysSize.AdjustWidth( -(nLeftMargin + nRightMargin) );
1129 rPhysSize.AdjustHeight( -(nTopMargin + nBottomMargin) );
1131 rDocHdr = aHdr.nHeight;
1132 rDocFtr = aFtr.nHeight;
1135 void ScPrintFunc::SetDateTime( const DateTime& rDateTime )
1137 aFieldData.aDateTime = rDateTime;
1140 static void lcl_DrawGraphic( const Graphic &rGraphic, vcl::RenderContext& rOutDev,
1141 const tools::Rectangle &rGrf, const tools::Rectangle &rOut )
1143 const bool bNotInside = !rOut.Contains( rGrf );
1144 if ( bNotInside )
1146 rOutDev.Push();
1147 rOutDev.IntersectClipRegion( rOut );
1150 rGraphic.Draw(rOutDev, rGrf.TopLeft(), rGrf.GetSize());
1152 if ( bNotInside )
1153 rOutDev.Pop();
1156 static void lcl_DrawGraphic( const SvxBrushItem &rBrush, vcl::RenderContext& rOutDev, const OutputDevice* pRefDev,
1157 const tools::Rectangle &rOrg, const tools::Rectangle &rOut,
1158 OUString const & referer )
1160 Size aGrfSize(0,0);
1161 const Graphic *pGraphic = rBrush.GetGraphic(referer);
1162 SvxGraphicPosition ePos;
1163 if ( pGraphic && pGraphic->IsSupportedGraphic() )
1165 const MapMode aMapMM( MapUnit::Map100thMM );
1166 if ( pGraphic->GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
1167 aGrfSize = pRefDev->PixelToLogic( pGraphic->GetPrefSize(), aMapMM );
1168 else
1169 aGrfSize = OutputDevice::LogicToLogic( pGraphic->GetPrefSize(),
1170 pGraphic->GetPrefMapMode(), aMapMM );
1171 ePos = rBrush.GetGraphicPos();
1173 else
1174 ePos = GPOS_NONE;
1176 Point aPos;
1177 Size aDrawSize = aGrfSize;
1179 bool bDraw = true;
1180 switch ( ePos )
1182 case GPOS_LT: aPos = rOrg.TopLeft();
1183 break;
1184 case GPOS_MT: aPos.setY( rOrg.Top() );
1185 aPos.setX( rOrg.Left() + rOrg.GetSize().Width()/2 - aGrfSize.Width()/2 );
1186 break;
1187 case GPOS_RT: aPos.setY( rOrg.Top() );
1188 aPos.setX( rOrg.Right() - aGrfSize.Width() );
1189 break;
1191 case GPOS_LM: aPos.setY( rOrg.Top() + rOrg.GetSize().Height()/2 - aGrfSize.Height()/2 );
1192 aPos.setX( rOrg.Left() );
1193 break;
1194 case GPOS_MM: aPos.setY( rOrg.Top() + rOrg.GetSize().Height()/2 - aGrfSize.Height()/2 );
1195 aPos.setX( rOrg.Left() + rOrg.GetSize().Width()/2 - aGrfSize.Width()/2 );
1196 break;
1197 case GPOS_RM: aPos.setY( rOrg.Top() + rOrg.GetSize().Height()/2 - aGrfSize.Height()/2 );
1198 aPos.setX( rOrg.Right() - aGrfSize.Width() );
1199 break;
1201 case GPOS_LB: aPos.setY( rOrg.Bottom() - aGrfSize.Height() );
1202 aPos.setX( rOrg.Left() );
1203 break;
1204 case GPOS_MB: aPos.setY( rOrg.Bottom() - aGrfSize.Height() );
1205 aPos.setX( rOrg.Left() + rOrg.GetSize().Width()/2 - aGrfSize.Width()/2 );
1206 break;
1207 case GPOS_RB: aPos.setY( rOrg.Bottom() - aGrfSize.Height() );
1208 aPos.setX( rOrg.Right() - aGrfSize.Width() );
1209 break;
1211 case GPOS_AREA:
1212 aPos = rOrg.TopLeft();
1213 aDrawSize = rOrg.GetSize();
1214 break;
1215 case GPOS_TILED:
1217 // use GraphicObject::DrawTiled instead of an own loop
1218 // (pixel rounding is handled correctly, and a very small bitmap
1219 // is duplicated into a bigger one for better performance)
1221 GraphicObject aObject( *pGraphic );
1223 if( rOutDev.GetOutDevType() == OUTDEV_PDF &&
1224 (aObject.GetType() == GraphicType::Bitmap || aObject.GetType() == GraphicType::Default) )
1226 // For PDF export, every draw
1227 // operation for bitmaps takes a noticeable
1228 // amount of place (~50 characters). Thus,
1229 // optimize between tile bitmap size and
1230 // number of drawing operations here.
1232 // A_out
1233 // n_chars = k1 * ---------- + k2 * A_bitmap
1234 // A_bitmap
1236 // minimum n_chars is obtained for (derive for
1237 // A_bitmap, set to 0, take positive
1238 // solution):
1239 // k1
1240 // A_bitmap = Sqrt( ---- A_out )
1241 // k2
1243 // where k1 is the number of chars per draw
1244 // operation, and k2 is the number of chars
1245 // per bitmap pixel. This is approximately 50
1246 // and 7 for current PDF writer, respectively.
1248 const double k1( 50 );
1249 const double k2( 7 );
1250 const Size aSize( rOrg.GetSize() );
1251 const double Abitmap( k1/k2 * aSize.Width()*aSize.Height() );
1253 aObject.DrawTiled( rOutDev, rOrg, aGrfSize, Size(0,0),
1254 ::std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap)) + .5 ) ) );
1256 else
1258 aObject.DrawTiled( rOutDev, rOrg, aGrfSize, Size(0,0) );
1261 bDraw = false;
1263 break;
1265 case GPOS_NONE:
1266 bDraw = false;
1267 break;
1269 default: OSL_ENSURE( false, "new Graphic position?" );
1271 tools::Rectangle aGrf( aPos,aDrawSize );
1272 if ( bDraw && aGrf.Overlaps( rOut ) )
1274 lcl_DrawGraphic( *pGraphic, rOutDev, aGrf, rOut );
1278 // The frame is drawn inwards
1280 void ScPrintFunc::DrawBorder( tools::Long nScrX, tools::Long nScrY, tools::Long nScrW, tools::Long nScrH,
1281 const SvxBoxItem* pBorderData, const SvxBrushItem* pBackground,
1282 const SvxShadowItem* pShadow )
1284 //! direct output from SvxBoxItem !!!
1286 if (pBorderData)
1287 if ( !pBorderData->GetTop() && !pBorderData->GetBottom() && !pBorderData->GetLeft() &&
1288 !pBorderData->GetRight() )
1289 pBorderData = nullptr;
1291 if (!pBorderData && !pBackground && !pShadow)
1292 return; // nothing to do
1294 tools::Long nLeft = 0;
1295 tools::Long nRight = 0;
1296 tools::Long nTop = 0;
1297 tools::Long nBottom = 0;
1299 // aFrameRect - outside around frame, without shadow
1300 if ( pShadow && pShadow->GetLocation() != SvxShadowLocation::NONE )
1302 nLeft += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::LEFT) * nScaleX );
1303 nRight += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::RIGHT) * nScaleX );
1304 nTop += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::TOP) * nScaleY );
1305 nBottom += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM) * nScaleY );
1307 tools::Rectangle aFrameRect( Point(nScrX+nLeft, nScrY+nTop),
1308 Size(nScrW-nLeft-nRight, nScrH-nTop-nBottom) );
1310 // center of frame, to paint lines through OutputData
1311 if (pBorderData)
1313 nLeft += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetLeft()) * nScaleX / 2 );
1314 nRight += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetRight()) * nScaleX / 2 );
1315 nTop += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetTop()) * nScaleY / 2 );
1316 nBottom += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetBottom()) * nScaleY / 2 );
1318 tools::Long nEffHeight = nScrH - nTop - nBottom;
1319 tools::Long nEffWidth = nScrW - nLeft - nRight;
1320 if (nEffHeight<=0 || nEffWidth<=0)
1321 return; // empty
1323 if ( pBackground )
1325 if (pBackground->GetGraphicPos() != GPOS_NONE)
1327 OutputDevice* pRefDev;
1328 if ( bIsRender )
1329 pRefDev = pDev; // don't use printer for PDF
1330 else
1331 pRefDev = rDoc.GetPrinter(); // use printer also for preview
1332 OUString referer;
1333 if (pDocShell->HasName()) {
1334 referer = pDocShell->GetMedium()->GetName();
1336 lcl_DrawGraphic(*pBackground, *pDev, pRefDev, aFrameRect, aFrameRect, referer);
1338 else
1340 pDev->SetFillColor(pBackground->GetColor());
1341 pDev->SetLineColor();
1342 pDev->DrawRect(aFrameRect);
1346 if ( pShadow && pShadow->GetLocation() != SvxShadowLocation::NONE )
1348 pDev->SetFillColor(pShadow->GetColor());
1349 pDev->SetLineColor();
1350 tools::Long nShadowX = static_cast<tools::Long>( pShadow->GetWidth() * nScaleX );
1351 tools::Long nShadowY = static_cast<tools::Long>( pShadow->GetWidth() * nScaleY );
1352 switch (pShadow->GetLocation())
1354 case SvxShadowLocation::TopLeft:
1355 pDev->DrawRect( tools::Rectangle(
1356 aFrameRect.Left()-nShadowX, aFrameRect.Top()-nShadowY,
1357 aFrameRect.Right()-nShadowX, aFrameRect.Top() ) );
1358 pDev->DrawRect( tools::Rectangle(
1359 aFrameRect.Left()-nShadowX, aFrameRect.Top()-nShadowY,
1360 aFrameRect.Left(), aFrameRect.Bottom()-nShadowY ) );
1361 break;
1362 case SvxShadowLocation::TopRight:
1363 pDev->DrawRect( tools::Rectangle(
1364 aFrameRect.Left()+nShadowX, aFrameRect.Top()-nShadowY,
1365 aFrameRect.Right()+nShadowX, aFrameRect.Top() ) );
1366 pDev->DrawRect( tools::Rectangle(
1367 aFrameRect.Right(), aFrameRect.Top()-nShadowY,
1368 aFrameRect.Right()+nShadowX, aFrameRect.Bottom()-nShadowY ) );
1369 break;
1370 case SvxShadowLocation::BottomLeft:
1371 pDev->DrawRect( tools::Rectangle(
1372 aFrameRect.Left()-nShadowX, aFrameRect.Bottom(),
1373 aFrameRect.Right()-nShadowX, aFrameRect.Bottom()+nShadowY ) );
1374 pDev->DrawRect( tools::Rectangle(
1375 aFrameRect.Left()-nShadowX, aFrameRect.Top()+nShadowY,
1376 aFrameRect.Left(), aFrameRect.Bottom()+nShadowY ) );
1377 break;
1378 case SvxShadowLocation::BottomRight:
1379 pDev->DrawRect( tools::Rectangle(
1380 aFrameRect.Left()+nShadowX, aFrameRect.Bottom(),
1381 aFrameRect.Right()+nShadowX, aFrameRect.Bottom()+nShadowY ) );
1382 pDev->DrawRect( tools::Rectangle(
1383 aFrameRect.Right(), aFrameRect.Top()+nShadowY,
1384 aFrameRect.Right()+nShadowX, aFrameRect.Bottom()+nShadowY ) );
1385 break;
1386 default:
1388 // added to avoid warnings
1393 if (!pBorderData)
1394 return;
1396 ScDocumentUniquePtr pBorderDoc(new ScDocument( SCDOCMODE_UNDO ));
1397 pBorderDoc->InitUndo( rDoc, 0,0, true,true );
1398 pBorderDoc->ApplyAttr( 0,0,0, *pBorderData );
1400 ScTableInfo aTabInfo(0, 1, false);
1401 pBorderDoc->FillInfo( aTabInfo, 0,0, 0,0, 0,
1402 nScaleX, nScaleY, false, false );
1403 OSL_ENSURE(aTabInfo.mnArrCount,"nArrCount == 0");
1405 aTabInfo.mpRowInfo[1].nHeight = static_cast<sal_uInt16>(nEffHeight);
1406 aTabInfo.mpRowInfo[0].basicCellInfo(0).nWidth =
1407 aTabInfo.mpRowInfo[1].basicCellInfo(0).nWidth = static_cast<sal_uInt16>(nEffWidth);
1409 ScOutputData aOutputData( pDev, OUTTYPE_PRINTER, aTabInfo, pBorderDoc.get(), 0,
1410 nScrX+nLeft, nScrY+nTop, 0,0, 0,0, nScaleX, nScaleY );
1411 aOutputData.SetUseStyleColor( bUseStyleColor );
1413 aOutputData.DrawFrame(*pDev);
1416 void ScPrintFunc::PrintColHdr( SCCOL nX1, SCCOL nX2, tools::Long nScrX, tools::Long nScrY )
1418 bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
1419 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
1421 Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1422 tools::Long nOneX = aOnePixel.Width();
1423 tools::Long nOneY = aOnePixel.Height();
1424 SCCOL nCol;
1426 tools::Long nHeight = static_cast<tools::Long>(PRINT_HEADER_HEIGHT * nScaleY);
1427 tools::Long nEndY = nScrY + nHeight - nOneY;
1429 tools::Long nPosX = nScrX;
1430 if ( bLayoutRTL )
1432 for (nCol=nX1; nCol<=nX2; nCol++)
1433 nPosX += static_cast<tools::Long>( rDoc.GetColWidth( nCol, nPrintTab ) * nScaleX );
1435 else
1436 nPosX -= nOneX;
1437 tools::Long nPosY = nScrY - nOneY;
1438 OUString aText;
1440 for (nCol=nX1; nCol<=nX2; nCol++)
1442 sal_uInt16 nDocW = rDoc.GetColWidth( nCol, nPrintTab );
1443 if (nDocW)
1445 tools::Long nWidth = static_cast<tools::Long>(nDocW * nScaleX);
1446 tools::Long nEndX = nPosX + nWidth * nLayoutSign;
1448 pDev->DrawRect( tools::Rectangle( nPosX,nPosY,nEndX,nEndY ) );
1450 aText = ::ScColToAlpha( nCol);
1451 tools::Long nTextWidth = pDev->GetTextWidth(aText);
1452 tools::Long nTextHeight = pDev->GetTextHeight();
1453 tools::Long nAddX = ( nWidth - nTextWidth ) / 2;
1454 tools::Long nAddY = ( nHeight - nTextHeight ) / 2;
1455 tools::Long nTextPosX = nPosX+nAddX;
1456 if ( bLayoutRTL )
1457 nTextPosX -= nWidth;
1458 pDev->DrawText( Point( nTextPosX,nPosY+nAddY ), aText );
1460 nPosX = nEndX;
1465 void ScPrintFunc::PrintRowHdr( SCROW nY1, SCROW nY2, tools::Long nScrX, tools::Long nScrY )
1467 Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1468 tools::Long nOneX = aOnePixel.Width();
1469 tools::Long nOneY = aOnePixel.Height();
1471 bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
1473 tools::Long nWidth = static_cast<tools::Long>(PRINT_HEADER_WIDTH * nScaleX);
1474 tools::Long nEndX = nScrX + nWidth;
1475 tools::Long nPosX = nScrX;
1476 if ( !bLayoutRTL )
1478 nEndX -= nOneX;
1479 nPosX -= nOneX;
1481 tools::Long nPosY = nScrY - nOneY;
1482 OUString aText;
1484 for (SCROW nRow=nY1; nRow<=nY2; nRow++)
1486 sal_uInt16 nDocH = rDoc.GetRowHeight( nRow, nPrintTab );
1487 if (nDocH)
1489 tools::Long nHeight = static_cast<tools::Long>(nDocH * nScaleY);
1490 tools::Long nEndY = nPosY + nHeight;
1492 pDev->DrawRect( tools::Rectangle( nPosX,nPosY,nEndX,nEndY ) );
1494 aText = OUString::number( nRow+1 );
1495 tools::Long nTextWidth = pDev->GetTextWidth(aText);
1496 tools::Long nTextHeight = pDev->GetTextHeight();
1497 tools::Long nAddX = ( nWidth - nTextWidth ) / 2;
1498 tools::Long nAddY = ( nHeight - nTextHeight ) / 2;
1499 pDev->DrawText( Point( nPosX+nAddX,nPosY+nAddY ), aText );
1501 nPosY = nEndY;
1506 void ScPrintFunc::LocateColHdr( SCCOL nX1, SCCOL nX2, tools::Long nScrX, tools::Long nScrY,
1507 bool bRepCol, ScPreviewLocationData& rLocationData )
1509 Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1510 tools::Long nOneX = aOnePixel.Width();
1511 tools::Long nOneY = aOnePixel.Height();
1513 tools::Long nHeight = static_cast<tools::Long>(PRINT_HEADER_HEIGHT * nScaleY);
1514 tools::Long nEndY = nScrY + nHeight - nOneY;
1516 tools::Long nPosX = nScrX - nOneX;
1517 for (SCCOL nCol=nX1; nCol<=nX2; nCol++)
1519 sal_uInt16 nDocW = rDoc.GetColWidth( nCol, nPrintTab );
1520 if (nDocW)
1521 nPosX += static_cast<tools::Long>(nDocW * nScaleX);
1523 tools::Rectangle aCellRect( nScrX, nScrY, nPosX, nEndY );
1524 rLocationData.AddColHeaders( aCellRect, nX1, nX2, bRepCol );
1527 void ScPrintFunc::LocateRowHdr( SCROW nY1, SCROW nY2, tools::Long nScrX, tools::Long nScrY,
1528 bool bRepRow, ScPreviewLocationData& rLocationData )
1530 Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1531 tools::Long nOneX = aOnePixel.Width();
1532 tools::Long nOneY = aOnePixel.Height();
1534 bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
1536 tools::Long nWidth = static_cast<tools::Long>(PRINT_HEADER_WIDTH * nScaleX);
1537 tools::Long nEndX = nScrX + nWidth;
1538 if ( !bLayoutRTL )
1539 nEndX -= nOneX;
1541 tools::Long nPosY = nScrY - nOneY;
1542 nPosY += rDoc.GetScaledRowHeight( nY1, nY2, nPrintTab, nScaleY);
1543 tools::Rectangle aCellRect( nScrX, nScrY, nEndX, nPosY );
1544 rLocationData.AddRowHeaders( aCellRect, nY1, nY2, bRepRow );
1547 void ScPrintFunc::LocateArea( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
1548 tools::Long nScrX, tools::Long nScrY, bool bRepCol, bool bRepRow,
1549 ScPreviewLocationData& rLocationData )
1551 // get MapMode for drawing objects (same MapMode as in ScOutputData::PrintDrawingLayer)
1553 Point aLogPos = OutputDevice::LogicToLogic(Point(nScrX,nScrY), aOffsetMode, aLogicMode);
1554 tools::Long nLogStX = aLogPos.X();
1555 tools::Long nLogStY = aLogPos.Y();
1557 SCCOL nCol;
1558 Point aTwipOffset;
1559 for (nCol=0; nCol<nX1; nCol++)
1560 aTwipOffset.AdjustX( -(rDoc.GetColWidth( nCol, nPrintTab )) );
1561 aTwipOffset.AdjustY( -sal_Int32(rDoc.GetRowHeight( 0, nY1-1, nPrintTab )) );
1563 Point aMMOffset(o3tl::convert(aTwipOffset, o3tl::Length::twip, o3tl::Length::mm100));
1564 aMMOffset += Point( nLogStX, nLogStY );
1565 MapMode aDrawMapMode( MapUnit::Map100thMM, aMMOffset, aLogicMode.GetScaleX(), aLogicMode.GetScaleY() );
1567 // get pixel rectangle
1569 Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1570 tools::Long nOneX = aOnePixel.Width();
1571 tools::Long nOneY = aOnePixel.Height();
1573 tools::Long nPosX = nScrX - nOneX;
1574 for (nCol=nX1; nCol<=nX2; nCol++)
1576 sal_uInt16 nDocW = rDoc.GetColWidth( nCol, nPrintTab );
1577 if (nDocW)
1578 nPosX += static_cast<tools::Long>(nDocW * nScaleX);
1581 tools::Long nPosY = nScrY - nOneY;
1582 nPosY += rDoc.GetScaledRowHeight( nY1, nY2, nPrintTab, nScaleY);
1583 tools::Rectangle aCellRect( nScrX, nScrY, nPosX, nPosY );
1584 rLocationData.AddCellRange( aCellRect, ScRange( nX1,nY1,nPrintTab, nX2,nY2,nPrintTab ),
1585 bRepCol, bRepRow, aDrawMapMode );
1588 void ScPrintFunc::PrintArea( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
1589 tools::Long nScrX, tools::Long nScrY,
1590 bool bShLeft, bool bShTop, bool bShRight, bool bShBottom )
1592 // #i47547# nothing to do if the end of the print area is before the end of
1593 // the repeat columns/rows (don't use negative size for ScOutputData)
1594 if ( nX2 < nX1 || nY2 < nY1 )
1595 return;
1597 //! hand over Flag at FillInfo !!!!!
1598 ScRange aERange;
1599 bool bEmbed = rDoc.IsEmbedded();
1600 if (bEmbed)
1602 rDoc.GetEmbedded(aERange);
1603 rDoc.ResetEmbedded();
1606 Point aPos = OutputDevice::LogicToLogic(Point(nScrX,nScrY), aOffsetMode, aLogicMode);
1607 tools::Long nLogStX = aPos.X();
1608 tools::Long nLogStY = aPos.Y();
1610 // Assemble data
1612 ScTableInfo aTabInfo(nY1, nY2, true);
1613 rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nPrintTab,
1614 nScaleX, nScaleY, true, aTableParam.bFormulas );
1615 lcl_HidePrint( aTabInfo, nX1, nX2 );
1617 if (bEmbed)
1618 rDoc.SetEmbedded(aERange);
1620 ScOutputData aOutputData( pDev, OUTTYPE_PRINTER, aTabInfo, &rDoc, nPrintTab,
1621 nScrX, nScrY, nX1, nY1, nX2, nY2, nScaleX, nScaleY );
1623 vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData());
1624 bool bTaggedPDF = pPDF && pPDF->GetIsExportTaggedPDF();
1625 if (bTaggedPDF)
1627 bool bReopen = aOutputData.ReopenPDFStructureElement(vcl::PDFWriter::Part);
1628 if (!bReopen)
1630 sal_Int32 nId = pPDF->EnsureStructureElement(nullptr);
1631 pPDF->InitStructureElement(nId, vcl::PDFWriter::Part, u"Worksheet"_ustr);
1632 pPDF->BeginStructureElement(nId);
1633 pPDF->GetScPDFState()->m_WorksheetId = nId;
1637 aOutputData.SetDrawView( pDrawView );
1639 // test if all paint parts are hidden, then a paint is not necessary at all
1640 const Point aMMOffset(aOutputData.PrePrintDrawingLayer(nLogStX, nLogStY));
1641 const bool bHideAllDrawingLayer( pDrawView && pDrawView->getHideOle() && pDrawView->getHideChart()
1642 && pDrawView->getHideDraw() && pDrawView->getHideFormControl() );
1644 if(!bHideAllDrawingLayer)
1646 pDev->SetMapMode(aLogicMode);
1647 // don's set Clipping here (Mapmode is being moved)
1649 // #i72502#
1650 aOutputData.PrintDrawingLayer(SC_LAYER_BACK, aMMOffset);
1653 pDev->SetMapMode(aOffsetMode);
1655 aOutputData.SetShowFormulas( aTableParam.bFormulas );
1656 aOutputData.SetShowNullValues( aTableParam.bNullVals );
1657 aOutputData.SetUseStyleColor( bUseStyleColor );
1659 Color aGridColor( COL_BLACK );
1660 if ( bUseStyleColor )
1661 aGridColor = ScModule::get()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
1662 aOutputData.SetGridColor( aGridColor );
1664 if ( !pPrinter )
1666 OutputDevice* pRefDev = rDoc.GetPrinter(); // use the printer also for Preview
1667 Fraction aPrintFrac( nZoom, 100 ); // without nManualZoom
1668 // MapMode, as it would arrive at the printer:
1669 pRefDev->SetMapMode( MapMode( MapUnit::Map100thMM, Point(), aPrintFrac, aPrintFrac ) );
1671 // when rendering (PDF), don't use printer as ref device, but printer's MapMode
1672 // has to be set anyway, as charts still use it (#106409#)
1673 if ( !bIsRender )
1674 aOutputData.SetRefDevice( pRefDev );
1677 if( aTableParam.bCellContent )
1678 aOutputData.DrawBackground(*pDev);
1680 pDev->SetClipRegion(vcl::Region(tools::Rectangle(
1681 aPos, Size(aOutputData.GetScrW(), aOutputData.GetScrH()))));
1682 pDev->SetClipRegion();
1684 if( aTableParam.bCellContent )
1686 aOutputData.DrawExtraShadow( bShLeft, bShTop, bShRight, bShBottom );
1687 aOutputData.DrawFrame(*pDev);
1688 aOutputData.DrawSparklines(*pDev);
1689 aOutputData.DrawStrings();
1690 aOutputData.DrawEdit(false);
1693 if (aTableParam.bGrid)
1694 aOutputData.DrawGrid(*pDev, true, false); // no page breaks
1696 aOutputData.AddPDFNotes(); // has no effect if not rendering PDF with notes enabled
1698 // test if all paint parts are hidden, then a paint is not necessary at all
1699 if(!bHideAllDrawingLayer)
1701 // #i72502#
1702 aOutputData.PrintDrawingLayer(SC_LAYER_FRONT, aMMOffset);
1705 if (bTaggedPDF)
1707 aOutputData.PrintDrawingLayer(SC_LAYER_CONTROLS, aMMOffset);
1708 pPDF->EndStructureElement();
1711 // #i72502#
1712 aOutputData.PrintDrawingLayer(SC_LAYER_INTERN, aMMOffset);
1714 if (!bTaggedPDF)
1715 aOutputData.PostPrintDrawingLayer(aMMOffset); // #i74768#
1718 bool ScPrintFunc::IsMirror( tools::Long nPageNo ) // Mirror margins?
1720 return nPageUsage == SvxPageUsage::Mirror && (nPageNo & 1);
1723 bool ScPrintFunc::IsLeft( tools::Long nPageNo ) // left foot notes?
1725 bool bLeft;
1726 if (nPageUsage == SvxPageUsage::Left)
1727 bLeft = true;
1728 else if (nPageUsage == SvxPageUsage::Right)
1729 bLeft = false;
1730 else
1731 bLeft = (nPageNo & 1) != 0;
1732 return bLeft;
1735 void ScPrintFunc::MakeTableString()
1737 OUString aTmp;
1738 rDoc.GetName(nPrintTab, aTmp);
1739 aFieldData.aTabName = aTmp;
1742 void ScPrintFunc::MakeEditEngine()
1744 if (!pEditEngine)
1746 // can't use document's edit engine pool here,
1747 // because pool must have twips as default metric
1748 pEditEngine.reset( new ScHeaderEditEngine( EditEngine::CreatePool().get() ) );
1750 pEditEngine->EnableUndo(false);
1751 //fdo#45869 we want text to be positioned as it would be for the
1752 //high dpi printed output, not as would be ideal for the 96dpi preview
1753 //window itself
1754 pEditEngine->SetRefDevice(pPrinter ? pPrinter : rDoc.GetRefDevice());
1755 pEditEngine->SetWordDelimiters(
1756 ScEditUtil::ModifyDelimiters( pEditEngine->GetWordDelimiters() ) );
1757 pEditEngine->SetControlWord( pEditEngine->GetControlWord() & ~EEControlBits::RTFSTYLESHEETS );
1758 rDoc.ApplyAsianEditSettings( *pEditEngine );
1759 pEditEngine->EnableAutoColor( bUseStyleColor );
1761 // Default-Set for alignment
1762 pEditDefaults.reset( new SfxItemSet( pEditEngine->GetEmptyItemSet() ) );
1764 const ScPatternAttr& rPattern(rDoc.getCellAttributeHelper().getDefaultCellAttribute());
1766 rPattern.FillEditItemSet( pEditDefaults.get() );
1767 // FillEditItemSet adjusts font height to 1/100th mm,
1768 // but for header/footer twips is needed, as in the PatternAttr:
1769 pEditDefaults->Put( rPattern.GetItem(ATTR_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT) );
1770 pEditDefaults->Put( rPattern.GetItem(ATTR_CJK_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CJK) );
1771 pEditDefaults->Put( rPattern.GetItem(ATTR_CTL_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CTL) );
1772 // don't use font color, because background color is not used
1773 //! there's no way to set the background for note pages
1774 pEditDefaults->ClearItem( EE_CHAR_COLOR );
1775 if (ScGlobal::IsSystemRTL())
1776 pEditDefaults->Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
1779 pEditEngine->SetData( aFieldData ); // Set page count etc.
1782 // nStartY = logic
1783 void ScPrintFunc::PrintHF( tools::Long nPageNo, bool bHeader, tools::Long nStartY,
1784 bool bDoPrint, ScPreviewLocationData* pLocationData )
1786 vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData());
1787 bool bTaggedPDF = pPDF && pPDF->GetIsExportTaggedPDF();
1788 if (bTaggedPDF)
1789 pPDF->WrapBeginStructureElement(vcl::PDFWriter::NonStructElement);
1791 const ScPrintHFParam& rParam = bHeader ? aHdr : aFtr;
1793 pDev->SetMapMode( aTwipMode ); // Head-/Footlines in Twips
1795 bool bFirst = 0 == nPageNo && !rParam.bSharedFirst;
1796 bool bLeft = IsLeft(nPageNo) && !rParam.bShared;
1797 const ScPageHFItem* pHFItem = bFirst ? rParam.pFirst : (bLeft ? rParam.pLeft : rParam.pRight);
1799 tools::Long nLineStartX = aPageRect.Left() + rParam.nLeft;
1800 tools::Long nLineEndX = aPageRect.Right() - rParam.nRight;
1801 tools::Long nLineWidth = nLineEndX - nLineStartX + 1;
1803 // Edit-Engine
1805 Point aStart( nLineStartX, nStartY );
1806 Size aPaperSize( nLineWidth, rParam.nHeight-rParam.nDistance );
1807 if ( rParam.pBorder )
1809 tools::Long nLeft = lcl_LineTotal( rParam.pBorder->GetLeft() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::LEFT);
1810 tools::Long nTop = lcl_LineTotal( rParam.pBorder->GetTop() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::TOP);
1811 aStart.AdjustX(nLeft );
1812 aStart.AdjustY(nTop );
1813 aPaperSize.AdjustWidth( -(nLeft + lcl_LineTotal( rParam.pBorder->GetRight() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::RIGHT)) );
1814 aPaperSize.AdjustHeight( -(nTop + lcl_LineTotal( rParam.pBorder->GetBottom() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::BOTTOM)) );
1817 if ( rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE )
1819 tools::Long nLeft = rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::LEFT);
1820 tools::Long nTop = rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::TOP);
1821 aStart.AdjustX(nLeft );
1822 aStart.AdjustY(nTop );
1823 aPaperSize.AdjustWidth( -(nLeft + rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::RIGHT)) );
1824 aPaperSize.AdjustHeight( -(nTop + rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM)) );
1827 aFieldData.nPageNo = nPageNo+aTableParam.nFirstPageNo;
1828 MakeEditEngine();
1830 pEditEngine->SetPaperSize(aPaperSize);
1832 // Frame / Background
1834 Point aBorderStart( nLineStartX, nStartY );
1835 Size aBorderSize( nLineWidth, rParam.nHeight-rParam.nDistance );
1836 if ( rParam.bDynamic )
1838 // adjust here again, for even/odd head-/footlines
1839 // and probably other breaks by variable (page number etc.)
1841 tools::Long nMaxHeight = 0;
1842 nMaxHeight = std::max( nMaxHeight, TextHeight( pHFItem->GetLeftArea() ) );
1843 nMaxHeight = std::max( nMaxHeight, TextHeight( pHFItem->GetCenterArea() ) );
1844 nMaxHeight = std::max( nMaxHeight, TextHeight( pHFItem->GetRightArea() ) );
1845 if (rParam.pBorder)
1846 nMaxHeight += lcl_LineTotal( rParam.pBorder->GetTop() ) +
1847 lcl_LineTotal( rParam.pBorder->GetBottom() ) +
1848 rParam.pBorder->GetDistance(SvxBoxItemLine::TOP) +
1849 rParam.pBorder->GetDistance(SvxBoxItemLine::BOTTOM);
1850 if (rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE)
1851 nMaxHeight += rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::TOP) +
1852 rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM);
1854 if (nMaxHeight < rParam.nManHeight-rParam.nDistance)
1855 nMaxHeight = rParam.nManHeight-rParam.nDistance; // configured Minimum
1857 aBorderSize.setHeight( nMaxHeight );
1860 if ( bDoPrint )
1862 double nOldScaleX = nScaleX;
1863 double nOldScaleY = nScaleY;
1864 nScaleX = nScaleY = 1.0; // output directly in Twips
1865 DrawBorder( aBorderStart.X(), aBorderStart.Y(), aBorderSize.Width(), aBorderSize.Height(),
1866 rParam.pBorder, rParam.pBack, rParam.pShadow );
1867 nScaleX = nOldScaleX;
1868 nScaleY = nOldScaleY;
1870 // Clipping for Text
1872 pDev->SetClipRegion(vcl::Region(tools::Rectangle(aStart, aPaperSize)));
1874 // left
1876 const EditTextObject* pObject = pHFItem->GetLeftArea();
1877 if (pObject)
1879 pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
1880 pEditEngine->SetTextTempDefaults(*pObject, *pEditDefaults);
1881 Point aDraw = aStart;
1882 tools::Long nDif = aPaperSize.Height() - static_cast<tools::Long>(pEditEngine->GetTextHeight());
1883 if (nDif > 0)
1884 aDraw.AdjustY(nDif / 2 );
1885 pEditEngine->Draw(*pDev, aDraw);
1888 // center
1890 pObject = pHFItem->GetCenterArea();
1891 if (pObject)
1893 pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) );
1894 pEditEngine->SetTextTempDefaults(*pObject, *pEditDefaults);
1895 Point aDraw = aStart;
1896 tools::Long nDif = aPaperSize.Height() - static_cast<tools::Long>(pEditEngine->GetTextHeight());
1897 if (nDif > 0)
1898 aDraw.AdjustY(nDif / 2 );
1899 pEditEngine->Draw(*pDev, aDraw);
1902 // right
1904 pObject = pHFItem->GetRightArea();
1905 if (pObject)
1907 pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
1908 pEditEngine->SetTextTempDefaults(*pObject, *pEditDefaults);
1909 Point aDraw = aStart;
1910 tools::Long nDif = aPaperSize.Height() - static_cast<tools::Long>(pEditEngine->GetTextHeight());
1911 if (nDif > 0)
1912 aDraw.AdjustY(nDif / 2 );
1913 pEditEngine->Draw(*pDev, aDraw);
1916 pDev->SetClipRegion();
1919 if ( pLocationData )
1921 tools::Rectangle aHeaderRect( aBorderStart, aBorderSize );
1922 pLocationData->AddHeaderFooter( aHeaderRect, bHeader, bLeft );
1925 if (bTaggedPDF)
1926 pPDF->EndStructureElement();
1929 tools::Long ScPrintFunc::DoNotes( tools::Long nNoteStart, bool bDoPrint, ScPreviewLocationData* pLocationData )
1931 if (bDoPrint)
1932 pDev->SetMapMode(aTwipMode);
1934 MakeEditEngine();
1935 pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
1936 pEditEngine->SetDefaults( *pEditDefaults );
1938 vcl::Font aMarkFont;
1939 ScAutoFontColorMode eColorMode = bUseStyleColor ? ScAutoFontColorMode::Display : ScAutoFontColorMode::Print;
1940 rDoc.getCellAttributeHelper().getDefaultCellAttribute().fillFont(aMarkFont, eColorMode);
1941 pDev->SetFont(aMarkFont);
1942 tools::Long nMarkLen = pDev->GetTextWidth(u"GW99999:"_ustr);
1943 // without Space-Char, because it rarely arrives there
1945 Size aDataSize = aPageRect.GetSize();
1946 if ( nMarkLen > aDataSize.Width() / 2 ) // everything much too small?
1947 nMarkLen = aDataSize.Width() / 2; // split the page appropriately
1948 aDataSize.AdjustWidth( -nMarkLen );
1950 pEditEngine->SetPaperSize( aDataSize );
1951 tools::Long nPosX = aPageRect.Left() + nMarkLen;
1952 tools::Long nPosY = aPageRect.Top();
1954 tools::Long nCount = 0;
1955 tools::Long nSize = aNotePosList.size();
1956 bool bOk;
1959 bOk = false;
1960 if ( nNoteStart + nCount < nSize)
1962 ScAddress &rPos = aNotePosList[ nNoteStart + nCount ];
1964 if( const ScPostIt* pNote = rDoc.GetNote( rPos ) )
1966 if(const EditTextObject *pEditText = pNote->GetEditTextObject())
1967 pEditEngine->SetTextCurrentDefaults(*pEditText);
1968 tools::Long nTextHeight = pEditEngine->GetTextHeight();
1969 if ( nPosY + nTextHeight < aPageRect.Bottom() )
1971 if (bDoPrint)
1973 pEditEngine->Draw(*pDev, Point(nPosX, nPosY));
1975 OUString aMarkStr(rPos.Format(ScRefFlags::VALID, &rDoc, rDoc.GetAddressConvention()) + ":");
1977 // cell position also via EditEngine, for correct positioning
1978 pEditEngine->SetTextCurrentDefaults(aMarkStr);
1979 pEditEngine->Draw(*pDev, Point(aPageRect.Left(), nPosY));
1982 if ( pLocationData )
1984 tools::Rectangle aTextRect( Point( nPosX, nPosY ), Size( aDataSize.Width(), nTextHeight ) );
1985 pLocationData->AddNoteText( aTextRect, rPos );
1986 tools::Rectangle aMarkRect( Point( aPageRect.Left(), nPosY ), Size( nMarkLen, nTextHeight ) );
1987 pLocationData->AddNoteMark( aMarkRect, rPos );
1990 nPosY += nTextHeight;
1991 nPosY += 200; // Distance
1992 ++nCount;
1993 bOk = true;
1998 while (bOk);
2000 return nCount;
2003 tools::Long ScPrintFunc::PrintNotes( tools::Long nPageNo, tools::Long nNoteStart, bool bDoPrint, ScPreviewLocationData* pLocationData )
2005 if ( nNoteStart >= static_cast<tools::Long>(aNotePosList.size()) || !aTableParam.bNotes )
2006 return 0;
2008 if ( bDoPrint && bClearWin )
2010 //! aggregate PrintPage !!!
2012 Color aBackgroundColor( COL_WHITE );
2013 if ( bUseStyleColor )
2014 aBackgroundColor = ScModule::get()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
2016 pDev->SetMapMode(aOffsetMode);
2017 pDev->SetLineColor();
2018 pDev->SetFillColor(aBackgroundColor);
2019 pDev->DrawRect(tools::Rectangle(Point(),
2020 Size(static_cast<tools::Long>(aPageSize.Width() * nScaleX * 100 / nZoom),
2021 static_cast<tools::Long>(aPageSize.Height() * nScaleY * 100 / nZoom))));
2024 // adjust aPageRect for left/right page
2026 tools::Rectangle aTempRect( Point(), aPageSize );
2027 if (IsMirror(nPageNo))
2029 aPageRect.SetLeft( ( aTempRect.Left() + nRightMargin ) * 100 / nZoom );
2030 aPageRect.SetRight( ( aTempRect.Right() - nLeftMargin ) * 100 / nZoom );
2032 else
2034 aPageRect.SetLeft( ( aTempRect.Left() + nLeftMargin ) * 100 / nZoom );
2035 aPageRect.SetRight( ( aTempRect.Right() - nRightMargin ) * 100 / nZoom );
2038 if ( pPrinter && bDoPrint )
2040 OSL_FAIL( "StartPage does not exist anymore" );
2043 if ( bDoPrint || pLocationData )
2045 // Head and foot lines
2047 if (aHdr.bEnable)
2049 tools::Long nHeaderY = aPageRect.Top()-aHdr.nHeight;
2050 PrintHF( nPageNo, true, nHeaderY, bDoPrint, pLocationData );
2052 if (aFtr.bEnable)
2054 tools::Long nFooterY = aPageRect.Bottom()+aFtr.nDistance;
2055 PrintHF( nPageNo, false, nFooterY, bDoPrint, pLocationData );
2059 tools::Long nCount = DoNotes( nNoteStart, bDoPrint, pLocationData );
2061 if ( pPrinter && bDoPrint )
2063 OSL_FAIL( "EndPage does not exist anymore" );
2066 return nCount;
2069 void ScPrintFunc::PrintPage( tools::Long nPageNo, SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
2070 bool bDoPrint, ScPreviewLocationData* pLocationData )
2072 bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
2073 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
2075 // nPageNo is the page number within all sheets of one "start page" setting
2077 if ( bClearWin && bDoPrint )
2079 // must exactly fit to painting the frame in preview.cxx !!!
2081 Color aBackgroundColor( COL_WHITE );
2082 if ( bUseStyleColor )
2083 aBackgroundColor = ScModule::get()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
2085 pDev->SetMapMode(aOffsetMode);
2086 pDev->SetLineColor();
2087 pDev->SetFillColor(aBackgroundColor);
2088 pDev->DrawRect(tools::Rectangle(Point(),
2089 Size(static_cast<tools::Long>(aPageSize.Width() * nScaleX * 100 / nZoom),
2090 static_cast<tools::Long>(aPageSize.Height() * nScaleY * 100 / nZoom))));
2093 // adjust aPageRect for left/right page
2095 tools::Rectangle aTempRect( Point(), aPageSize );
2096 if (IsMirror(nPageNo))
2098 aPageRect.SetLeft( ( aTempRect.Left() + nRightMargin ) * 100 / nZoom );
2099 aPageRect.SetRight( ( aTempRect.Right() - nLeftMargin ) * 100 / nZoom );
2101 else
2103 aPageRect.SetLeft( ( aTempRect.Left() + nLeftMargin ) * 100 / nZoom );
2104 aPageRect.SetRight( ( aTempRect.Right() - nRightMargin ) * 100 / nZoom );
2107 if ( aAreaParam.bRepeatCol )
2108 if ( nX1 > nRepeatStartCol && nX1 <= nRepeatEndCol )
2109 nX1 = nRepeatEndCol + 1;
2110 bool bDoRepCol = (aAreaParam.bRepeatCol && nX1 > nRepeatEndCol);
2111 if ( aAreaParam.bRepeatRow )
2112 if ( nY1 > nRepeatStartRow && nY1 <= nRepeatEndRow )
2113 nY1 = nRepeatEndRow + 1;
2114 bool bDoRepRow = (aAreaParam.bRepeatRow && nY1 > nRepeatEndRow);
2116 // use new object hide flags in SdrPaintView
2117 if(pDrawView)
2119 pDrawView->setHideOle(!aTableParam.bObjects);
2120 pDrawView->setHideChart(!aTableParam.bCharts);
2121 pDrawView->setHideDraw(!aTableParam.bDrawings);
2122 pDrawView->setHideFormControl(!aTableParam.bDrawings);
2125 if ( pPrinter && bDoPrint )
2127 OSL_FAIL( "StartPage does not exist anymore" );
2130 // head and foot lines (without centering)
2132 if (aHdr.bEnable)
2134 tools::Long nHeaderY = aPageRect.Top()-aHdr.nHeight;
2135 PrintHF( nPageNo, true, nHeaderY, bDoPrint, pLocationData );
2137 if (aFtr.bEnable)
2139 tools::Long nFooterY = aPageRect.Bottom()+aFtr.nDistance;
2140 PrintHF( nPageNo, false, nFooterY, bDoPrint, pLocationData );
2143 // Position ( margins / centering )
2145 tools::Long nLeftSpace = aPageRect.Left(); // Document-Twips
2146 tools::Long nTopSpace = aPageRect.Top();
2147 if ( bCenterHor || bLayoutRTL )
2149 tools::Long nDataWidth = 0;
2150 SCCOL i;
2151 for (i=nX1; i<=nX2; i++)
2152 nDataWidth += rDoc.GetColWidth( i,nPrintTab );
2153 if (bDoRepCol)
2154 for (i=nRepeatStartCol; i<=nRepeatEndCol; i++)
2155 nDataWidth += rDoc.GetColWidth( i,nPrintTab );
2156 if (aTableParam.bHeaders)
2157 nDataWidth += tools::Long(PRINT_HEADER_WIDTH);
2158 if (pBorderItem)
2159 nDataWidth += pBorderItem->GetDistance(SvxBoxItemLine::LEFT) +
2160 pBorderItem->GetDistance(SvxBoxItemLine::RIGHT); //! Line width?
2161 if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
2162 nDataWidth += pShadowItem->CalcShadowSpace(SvxShadowItemSide::LEFT) +
2163 pShadowItem->CalcShadowSpace(SvxShadowItemSide::RIGHT);
2164 if ( bCenterHor )
2166 nLeftSpace += ( aPageRect.GetWidth() - nDataWidth ) / 2; // LTR or RTL
2167 if (pBorderItem)
2168 nLeftSpace -= lcl_LineTotal(pBorderItem->GetLeft());
2170 else if ( bLayoutRTL )
2171 nLeftSpace += aPageRect.GetWidth() - nDataWidth; // align to the right edge of the page
2173 if ( bCenterVer )
2175 tools::Long nDataHeight = rDoc.GetRowHeight( nY1, nY2, nPrintTab);
2176 if (bDoRepRow)
2177 nDataHeight += rDoc.GetRowHeight( nRepeatStartRow,
2178 nRepeatEndRow, nPrintTab);
2179 if (aTableParam.bHeaders)
2180 nDataHeight += tools::Long(PRINT_HEADER_HEIGHT);
2181 if (pBorderItem)
2182 nDataHeight += pBorderItem->GetDistance(SvxBoxItemLine::TOP) +
2183 pBorderItem->GetDistance(SvxBoxItemLine::BOTTOM); //! Line width?
2184 if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
2185 nDataHeight += pShadowItem->CalcShadowSpace(SvxShadowItemSide::TOP) +
2186 pShadowItem->CalcShadowSpace(SvxShadowItemSide::BOTTOM);
2187 nTopSpace += ( aPageRect.GetHeight() - nDataHeight ) / 2;
2188 if (pBorderItem)
2189 nTopSpace -= lcl_LineTotal(pBorderItem->GetTop());
2192 // calculate sizes of the elements for partitioning
2193 // (header, repeat, data)
2195 tools::Long nHeaderWidth = 0;
2196 tools::Long nHeaderHeight = 0;
2197 tools::Long nRepeatWidth = 0;
2198 tools::Long nRepeatHeight = 0;
2199 tools::Long nContentWidth = 0; // scaled - not the same as nDataWidth above
2200 tools::Long nContentHeight = 0;
2201 if (aTableParam.bHeaders)
2203 nHeaderWidth = static_cast<tools::Long>(PRINT_HEADER_WIDTH * nScaleX);
2204 nHeaderHeight = static_cast<tools::Long>(PRINT_HEADER_HEIGHT * nScaleY);
2206 if (bDoRepCol)
2207 for (SCCOL i=nRepeatStartCol; i<=nRepeatEndCol; i++)
2208 nRepeatWidth += static_cast<tools::Long>(rDoc.GetColWidth(i,nPrintTab) * nScaleX);
2209 if (bDoRepRow)
2210 nRepeatHeight += rDoc.GetScaledRowHeight( nRepeatStartRow,
2211 nRepeatEndRow, nPrintTab, nScaleY);
2212 for (SCCOL i=nX1; i<=nX2; i++)
2213 nContentWidth += static_cast<tools::Long>(rDoc.GetColWidth(i,nPrintTab) * nScaleX);
2214 nContentHeight += rDoc.GetScaledRowHeight( nY1, nY2, nPrintTab,
2215 nScaleY);
2217 // partition the page
2219 tools::Long nStartX = static_cast<tools::Long>( nLeftSpace * nScaleX );
2220 tools::Long nStartY = static_cast<tools::Long>( nTopSpace * nScaleY );
2221 tools::Long nInnerStartX = nStartX;
2222 tools::Long nInnerStartY = nStartY;
2223 if (pBorderItem)
2225 nInnerStartX += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetLeft()) +
2226 pBorderItem->GetDistance(SvxBoxItemLine::LEFT) ) * nScaleX );
2227 nInnerStartY += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetTop()) +
2228 pBorderItem->GetDistance(SvxBoxItemLine::TOP) ) * nScaleY );
2230 if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
2232 nInnerStartX += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::LEFT) * nScaleX );
2233 nInnerStartY += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::TOP) * nScaleY );
2236 if ( bLayoutRTL )
2238 // arrange elements starting from the right edge
2239 nInnerStartX += nHeaderWidth + nRepeatWidth + nContentWidth;
2241 // make rounding easier so the elements are really next to each other in preview
2242 Size aOffsetOnePixel = pDev->PixelToLogic( Size(1,1), aOffsetMode );
2243 tools::Long nOffsetOneX = aOffsetOnePixel.Width();
2244 nInnerStartX += nOffsetOneX / 2;
2247 tools::Long nFrameStartX = nInnerStartX;
2248 tools::Long nFrameStartY = nInnerStartY;
2250 tools::Long nRepStartX = nInnerStartX + nHeaderWidth * nLayoutSign; // widths/heights are 0 if not used
2251 tools::Long nRepStartY = nInnerStartY + nHeaderHeight;
2252 tools::Long nDataX = nRepStartX + nRepeatWidth * nLayoutSign;
2253 tools::Long nDataY = nRepStartY + nRepeatHeight;
2254 tools::Long nEndX = nDataX + nContentWidth * nLayoutSign;
2255 tools::Long nEndY = nDataY + nContentHeight;
2256 tools::Long nFrameEndX = nEndX;
2257 tools::Long nFrameEndY = nEndY;
2259 if ( bLayoutRTL )
2261 // each element's start position is its left edge
2262 //! subtract one pixel less?
2263 nInnerStartX -= nHeaderWidth; // used for header
2264 nRepStartX -= nRepeatWidth;
2265 nDataX -= nContentWidth;
2267 // continue right of the main elements again
2268 nEndX += nHeaderWidth + nRepeatWidth + nContentWidth;
2271 // Page frame / background
2273 //! adjust nEndX/Y
2275 tools::Long nBorderEndX = nEndX;
2276 tools::Long nBorderEndY = nEndY;
2277 if (pBorderItem)
2279 nBorderEndX += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetRight()) +
2280 pBorderItem->GetDistance(SvxBoxItemLine::RIGHT) ) * nScaleX );
2281 nBorderEndY += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetBottom()) +
2282 pBorderItem->GetDistance(SvxBoxItemLine::BOTTOM) ) * nScaleY );
2284 if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
2286 nBorderEndX += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::RIGHT) * nScaleX );
2287 nBorderEndY += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::BOTTOM) * nScaleY );
2290 if ( bDoPrint )
2292 pDev->SetMapMode( aOffsetMode );
2293 DrawBorder( nStartX, nStartY, nBorderEndX-nStartX, nBorderEndY-nStartY,
2294 pBorderItem, pBackgroundItem, pShadowItem );
2296 pDev->SetMapMode( aTwipMode );
2299 pDev->SetMapMode( aOffsetMode );
2301 // Output repeating rows/columns
2303 if (bDoRepCol && bDoRepRow)
2305 if ( bDoPrint )
2306 PrintArea( nRepeatStartCol,nRepeatStartRow, nRepeatEndCol,nRepeatEndRow,
2307 nRepStartX,nRepStartY, true, true, false, false );
2308 if ( pLocationData )
2309 LocateArea( nRepeatStartCol,nRepeatStartRow, nRepeatEndCol,nRepeatEndRow,
2310 nRepStartX,nRepStartY, true, true, *pLocationData );
2312 if (bDoRepCol)
2314 if ( bDoPrint )
2315 PrintArea( nRepeatStartCol,nY1, nRepeatEndCol,nY2, nRepStartX,nDataY,
2316 true, !bDoRepRow, false, true );
2317 if ( pLocationData )
2318 LocateArea( nRepeatStartCol,nY1, nRepeatEndCol,nY2, nRepStartX,nDataY, true, false, *pLocationData );
2320 if (bDoRepRow)
2322 if ( bDoPrint )
2323 PrintArea( nX1,nRepeatStartRow, nX2,nRepeatEndRow, nDataX,nRepStartY,
2324 !bDoRepCol, true, true, false );
2325 if ( pLocationData )
2326 LocateArea( nX1,nRepeatStartRow, nX2,nRepeatEndRow, nDataX,nRepStartY, false, true, *pLocationData );
2329 // output data
2331 if ( bDoPrint )
2332 PrintArea( nX1,nY1, nX2,nY2, nDataX,nDataY, !bDoRepCol,!bDoRepRow, true, true );
2333 if ( pLocationData )
2334 LocateArea( nX1,nY1, nX2,nY2, nDataX,nDataY, false,false, *pLocationData );
2336 // output column/row headers
2337 // after data (through probably shadow)
2339 Color aGridColor( COL_BLACK );
2340 if ( bUseStyleColor )
2341 aGridColor = ScModule::get()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
2343 if (aTableParam.bHeaders)
2345 if ( bDoPrint )
2347 pDev->SetLineColor( aGridColor );
2348 pDev->SetFillColor();
2349 pDev->SetMapMode(aOffsetMode);
2352 ScPatternAttr aPattern(rDoc.getCellAttributeHelper());
2353 vcl::Font aFont;
2354 ScAutoFontColorMode eColorMode = bUseStyleColor ? ScAutoFontColorMode::Display : ScAutoFontColorMode::Print;
2355 aPattern.fillFont(aFont, eColorMode, pDev);
2356 pDev->SetFont(aFont);
2358 if (bDoRepCol)
2360 if ( bDoPrint )
2361 PrintColHdr( nRepeatStartCol,nRepeatEndCol, nRepStartX,nInnerStartY );
2362 if ( pLocationData )
2363 LocateColHdr( nRepeatStartCol,nRepeatEndCol, nRepStartX,nInnerStartY, true, *pLocationData );
2365 if ( bDoPrint )
2366 PrintColHdr( nX1,nX2, nDataX,nInnerStartY );
2367 if ( pLocationData )
2368 LocateColHdr( nX1,nX2, nDataX,nInnerStartY, false, *pLocationData );
2369 if (bDoRepRow)
2371 if ( bDoPrint )
2372 PrintRowHdr( nRepeatStartRow,nRepeatEndRow, nInnerStartX,nRepStartY );
2373 if ( pLocationData )
2374 LocateRowHdr( nRepeatStartRow,nRepeatEndRow, nInnerStartX,nRepStartY, true, *pLocationData );
2376 if ( bDoPrint )
2377 PrintRowHdr( nY1,nY2, nInnerStartX,nDataY );
2378 if ( pLocationData )
2379 LocateRowHdr( nY1,nY2, nInnerStartX,nDataY, false, *pLocationData );
2382 // simple frame
2384 if ( bDoPrint && ( aTableParam.bGrid || aTableParam.bHeaders ) )
2386 Size aOnePixel = pDev->PixelToLogic(Size(1,1));
2387 tools::Long nOneX = aOnePixel.Width();
2388 tools::Long nOneY = aOnePixel.Height();
2390 tools::Long nLeftX = nFrameStartX;
2391 tools::Long nTopY = nFrameStartY - nOneY;
2392 tools::Long nRightX = nFrameEndX;
2393 tools::Long nBottomY = nFrameEndY - nOneY;
2394 if ( !bLayoutRTL )
2396 nLeftX -= nOneX;
2397 nRightX -= nOneX;
2399 pDev->SetMapMode(aOffsetMode);
2400 pDev->SetLineColor( aGridColor );
2401 pDev->SetFillColor();
2402 pDev->DrawRect( tools::Rectangle( nLeftX, nTopY, nRightX, nBottomY ) );
2403 // nEndX/Y without frame-adaptation
2406 if ( pPrinter && bDoPrint )
2408 OSL_FAIL( "EndPage does not exist anymore" );
2411 aLastSourceRange = ScRange( nX1, nY1, nPrintTab, nX2, nY2, nPrintTab );
2412 bSourceRangeValid = true;
2415 void ScPrintFunc::SetOffset( const Point& rOfs )
2417 aSrcOffset = rOfs;
2420 void ScPrintFunc::SetManualZoom( sal_uInt16 nNewZoom )
2422 nManualZoom = nNewZoom;
2425 void ScPrintFunc::SetClearFlag( bool bFlag )
2427 bClearWin = bFlag;
2430 void ScPrintFunc::SetUseStyleColor( bool bFlag )
2432 bUseStyleColor = bFlag;
2433 if (pEditEngine)
2434 pEditEngine->EnableAutoColor( bUseStyleColor );
2437 void ScPrintFunc::SetRenderFlag( bool bFlag )
2439 bIsRender = bFlag; // set when using XRenderable (PDF)
2442 void ScPrintFunc::SetExclusivelyDrawOleAndDrawObjects()
2444 aTableParam.bCellContent = false;
2445 aTableParam.bNotes = false;
2446 aTableParam.bGrid = false;
2447 aTableParam.bHeaders = false;
2448 aTableParam.bFormulas = false;
2449 aTableParam.bNullVals = false;
2452 // UpdatePages is only called from outside to set the breaks correctly for viewing
2453 // - always without UserArea
2455 bool ScPrintFunc::UpdatePages()
2457 if (!pParamSet)
2458 return false;
2460 // Zoom
2462 nZoom = 100;
2463 if (aTableParam.bScalePageNum || aTableParam.bScaleTo)
2464 nZoom = ZOOM_MIN; // correct for breaks
2465 else if (aTableParam.bScaleAll)
2467 nZoom = aTableParam.nScaleAll;
2468 if ( nZoom <= ZOOM_MIN )
2469 nZoom = ZOOM_MIN;
2472 OUString aName = rDoc.GetPageStyle( nPrintTab );
2473 SCTAB nTabCount = rDoc.GetTableCount();
2474 for (SCTAB nTab=0; nTab<nTabCount; nTab++)
2475 if ( nTab==nPrintTab || rDoc.GetPageStyle(nTab)==aName )
2477 // Repeating rows/columns
2478 rDoc.SetRepeatArea( nTab, nRepeatStartCol,nRepeatEndCol, nRepeatStartRow,nRepeatEndRow );
2480 // set breaks
2481 ResetBreaks(nTab);
2482 pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid);
2485 return true;
2488 tools::Long ScPrintFunc::CountPages() // sets also nPagesX, nPagesY
2490 bool bAreaOk = false;
2492 if (rDoc.HasTable( nPrintTab ))
2494 if (aAreaParam.bPrintArea) // Specify print area?
2496 if ( bPrintCurrentTable )
2498 ScRange& rRange = aAreaParam.aPrintArea;
2500 // Here, no comparison of the tables any more. Area is always valid for this table
2501 // If comparison should be done here, the table of print ranges must be adjusted
2502 // when inserting tables etc.!
2504 nStartCol = rRange.aStart.Col();
2505 nStartRow = rRange.aStart.Row();
2506 nEndCol = rRange.aEnd .Col();
2507 nEndRow = rRange.aEnd .Row();
2508 bAreaOk = AdjustPrintArea(false); // limit
2510 else
2511 bAreaOk = false;
2513 else // search from document
2514 bAreaOk = AdjustPrintArea(true);
2517 if (bAreaOk)
2519 tools::Long nPages = 0;
2520 size_t nY;
2521 if (bMultiArea)
2523 sal_uInt16 nRCount = rDoc.GetPrintRangeCount( nPrintTab );
2524 for (sal_uInt16 i=0; i<nRCount; i++)
2526 CalcZoom(i);
2527 if ( aTableParam.bSkipEmpty )
2528 for (nY=0; nY< m_aRanges.m_nPagesY; nY++)
2529 nPages += (*m_aRanges.m_xPageRows)[nY].CountVisible();
2530 else
2531 nPages += static_cast<tools::Long>(m_aRanges.m_nPagesX) * m_aRanges.m_nPagesY;
2532 if ( pPageData )
2533 FillPageData();
2536 else
2538 CalcZoom(RANGENO_NORANGE); // calculate Zoom
2539 if ( aTableParam.bSkipEmpty )
2540 for (nY=0; nY<m_aRanges.m_nPagesY; nY++)
2541 nPages += (*m_aRanges.m_xPageRows)[nY].CountVisible();
2542 else
2543 nPages += static_cast<tools::Long>(m_aRanges.m_nPagesX) * m_aRanges.m_nPagesY;
2544 if ( pPageData )
2545 FillPageData();
2547 return nPages;
2549 else
2551 m_aRanges.m_nPagesX = m_aRanges.m_nPagesY = m_aRanges.m_nTotalY = 0;
2552 return 0;
2556 tools::Long ScPrintFunc::CountNotePages()
2558 if ( !aTableParam.bNotes || !bPrintCurrentTable )
2559 return 0;
2561 bool bError = false;
2562 if (!aAreaParam.bPrintArea)
2563 bError = !AdjustPrintArea(true); // completely search in Doc
2565 sal_uInt16 nRepeats = 1; // how often go through it ?
2566 if (bMultiArea)
2567 nRepeats = rDoc.GetPrintRangeCount(nPrintTab);
2568 if (bError)
2569 nRepeats = 0;
2571 for (sal_uInt16 nStep=0; nStep<nRepeats; nStep++)
2573 bool bDoThis = true;
2574 if (bMultiArea) // go through all Areas
2576 const ScRange* pThisRange = rDoc.GetPrintRange( nPrintTab, nStep );
2577 if ( pThisRange )
2579 nStartCol = pThisRange->aStart.Col();
2580 nStartRow = pThisRange->aStart.Row();
2581 nEndCol = pThisRange->aEnd .Col();
2582 nEndRow = pThisRange->aEnd .Row();
2583 bDoThis = AdjustPrintArea(false);
2587 if (bDoThis)
2589 assert( bPrintAreaValid );
2590 for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
2592 if (rDoc.HasColNotes(nCol, nPrintTab))
2594 for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow )
2596 if ( rDoc.HasNote(nCol, nRow, nPrintTab) )
2597 aNotePosList.emplace_back( nCol, nRow, nPrintTab );
2604 tools::Long nPages = 0;
2605 tools::Long nNoteNr = 0;
2606 tools::Long nNoteAdd;
2609 nNoteAdd = PrintNotes( nPages, nNoteNr, false, nullptr );
2610 if (nNoteAdd)
2612 nNoteNr += nNoteAdd;
2613 ++nPages;
2616 while (nNoteAdd);
2618 return nPages;
2621 void ScPrintFunc::InitModes() // set MapModes from nZoom etc.
2623 aOffset = Point( aSrcOffset.X()*100/nZoom, aSrcOffset.Y()*100/nZoom );
2625 tools::Long nEffZoom = nZoom * static_cast<tools::Long>(nManualZoom);
2626 constexpr auto HMM_PER_TWIPS = o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100);
2627 nScaleX = nScaleY = HMM_PER_TWIPS; // output in 1/100 mm
2629 Fraction aZoomFract( nEffZoom,10000 );
2630 Fraction aHorFract = aZoomFract;
2632 if ( !pPrinter && !bIsRender ) // adjust scale for preview
2634 double nFact = pDocShell->GetOutputFactor();
2635 aHorFract = Fraction( static_cast<tools::Long>( nEffZoom / nFact ), 10000 );
2638 aLogicMode = MapMode( MapUnit::Map100thMM, Point(), aHorFract, aZoomFract );
2640 Point aLogicOfs( -aOffset.X(), -aOffset.Y() );
2641 aOffsetMode = MapMode( MapUnit::Map100thMM, aLogicOfs, aHorFract, aZoomFract );
2643 Point aTwipsOfs( static_cast<tools::Long>( -aOffset.X() / nScaleX + 0.5 ), static_cast<tools::Long>( -aOffset.Y() / nScaleY + 0.5 ) );
2644 aTwipMode = MapMode( MapUnit::MapTwip, aTwipsOfs, aHorFract, aZoomFract );
2647 void ScPrintFunc::ApplyPrintSettings()
2649 if ( !pPrinter )
2650 return;
2652 // Configure Printer to Printing
2654 Size aEnumSize = aPageSize;
2656 pPrinter->SetOrientation( bLandscape ? Orientation::Landscape : Orientation::Portrait );
2657 if ( bLandscape )
2659 // landscape is always interpreted as a rotation by 90 degrees !
2660 // this leads to non WYSIWIG but at least it prints!
2661 // #i21775#
2662 tools::Long nTemp = aEnumSize.Width();
2663 aEnumSize.setWidth( aEnumSize.Height() );
2664 aEnumSize.setHeight( nTemp );
2666 Paper ePaper = SvxPaperInfo::GetSvxPaper( aEnumSize, MapUnit::MapTwip );
2667 sal_uInt16 nPaperBin = pParamSet->Get(ATTR_PAGE_PAPERBIN).GetValue();
2669 pPrinter->SetPaper( ePaper );
2670 if ( PAPER_USER == ePaper )
2672 MapMode aPrinterMode = pPrinter->GetMapMode();
2673 MapMode aLocalMode( MapUnit::MapTwip );
2674 pPrinter->SetMapMode( aLocalMode );
2675 pPrinter->SetPaperSizeUser( aEnumSize );
2676 pPrinter->SetMapMode( aPrinterMode );
2679 pPrinter->SetPaperBin( nPaperBin );
2682 // rPageRanges = range for all tables
2683 // nStartPage = rPageRanges starts at nStartPage
2684 // nDisplayStart = continuous number for displaying the page number
2686 tools::Long ScPrintFunc::DoPrint( const MultiSelection& rPageRanges,
2687 tools::Long nStartPage, tools::Long nDisplayStart, bool bDoPrint,
2688 ScPreviewLocationData* pLocationData )
2690 OSL_ENSURE(pDev,"Device == NULL");
2691 if (!pParamSet)
2692 return 0;
2694 if ( pPrinter && bDoPrint )
2695 ApplyPrintSettings();
2697 InitModes();
2698 if ( pLocationData )
2700 pLocationData->SetCellMapMode( aOffsetMode );
2701 pLocationData->SetPrintTab( nPrintTab );
2704 MakeTableString();
2706 tools::Long nPageNo = 0;
2707 tools::Long nPrinted = 0;
2708 tools::Long nEndPage = rPageRanges.GetTotalRange().Max();
2710 sal_uInt16 nRepeats = 1;
2711 if (bMultiArea)
2712 nRepeats = rDoc.GetPrintRangeCount(nPrintTab);
2713 for (sal_uInt16 nStep=0; nStep<nRepeats; nStep++)
2715 if (bMultiArea) // replace area
2717 CalcZoom(nStep); // also sets nStartCol etc. new
2718 InitModes();
2721 SCCOL nX1;
2722 SCROW nY1;
2723 SCCOL nX2;
2724 SCROW nY2;
2725 size_t nCountX;
2726 size_t nCountY;
2728 if (aTableParam.bTopDown) // top-bottom
2730 nX1 = nStartCol;
2731 for (nCountX=0; nCountX<m_aRanges.m_nPagesX; nCountX++)
2733 OSL_ENSURE(nCountX < m_aRanges.m_xPageEndX->size(), "vector access error for aPageEndX (!)");
2734 nX2 = (*m_aRanges.m_xPageEndX)[nCountX];
2735 for (nCountY=0; nCountY<m_aRanges.m_nPagesY; nCountY++)
2737 auto& rPageRow = (*m_aRanges.m_xPageRows)[nCountY];
2738 nY1 = rPageRow.GetStartRow();
2739 nY2 = rPageRow.GetEndRow();
2740 if ( !aTableParam.bSkipEmpty || !rPageRow.IsHidden(nCountX) )
2742 if ( rPageRanges.IsSelected( nPageNo+nStartPage+1 ) )
2744 PrintPage( nPageNo+nDisplayStart, nX1, nY1, nX2, nY2,
2745 bDoPrint, pLocationData );
2746 ++nPrinted;
2748 ++nPageNo;
2751 nX1 = nX2 + 1;
2754 else // left to right
2756 for (nCountY=0; nCountY<m_aRanges.m_nPagesY; nCountY++)
2758 auto& rPageRow = (*m_aRanges.m_xPageRows)[nCountY];
2759 nY1 = rPageRow.GetStartRow();
2760 nY2 = rPageRow.GetEndRow();
2761 nX1 = nStartCol;
2762 for (nCountX=0; nCountX<m_aRanges.m_nPagesX; nCountX++)
2764 OSL_ENSURE(nCountX < m_aRanges.m_xPageEndX->size(), "vector access error for aPageEndX");
2765 nX2 = (*m_aRanges.m_xPageEndX)[nCountX];
2766 if ( !aTableParam.bSkipEmpty || !rPageRow.IsHidden(nCountX) )
2768 if ( rPageRanges.IsSelected( nPageNo+nStartPage+1 ) )
2770 PrintPage( nPageNo+nDisplayStart, nX1, nY1, nX2, nY2,
2771 bDoPrint, pLocationData );
2772 ++nPrinted;
2774 ++nPageNo;
2776 nX1 = nX2 + 1;
2782 aFieldData.aTabName = ScResId( STR_NOTES );
2784 tools::Long nNoteNr = 0;
2785 tools::Long nNoteAdd;
2788 if ( nPageNo+nStartPage <= nEndPage )
2790 bool bPageSelected = rPageRanges.IsSelected( nPageNo+nStartPage+1 );
2791 nNoteAdd = PrintNotes( nPageNo+nStartPage, nNoteNr, bDoPrint && bPageSelected,
2792 ( bPageSelected ? pLocationData : nullptr ) );
2793 if ( nNoteAdd )
2795 nNoteNr += nNoteAdd;
2796 if (bPageSelected)
2798 ++nPrinted;
2799 bSourceRangeValid = false; // last page was no cell range
2801 ++nPageNo;
2804 else
2805 nNoteAdd = 0;
2807 while (nNoteAdd);
2809 if ( bMultiArea )
2810 ResetBreaks(nPrintTab); //breaks correct for displaying
2812 return nPrinted;
2815 void ScPrintFunc::CalcZoom( sal_uInt16 nRangeNo ) // calculate zoom
2817 sal_uInt16 nRCount = rDoc.GetPrintRangeCount( nPrintTab );
2818 const ScRange* pThisRange = nullptr;
2819 if (nRangeNo != RANGENO_NORANGE && nRangeNo < nRCount)
2820 pThisRange = rDoc.GetPrintRange( nPrintTab, nRangeNo );
2821 if ( pThisRange )
2823 nStartCol = pThisRange->aStart.Col();
2824 nStartRow = pThisRange->aStart.Row();
2825 nEndCol = pThisRange->aEnd .Col();
2826 nEndRow = pThisRange->aEnd .Row();
2829 if (!AdjustPrintArea(false)) // empty
2831 nZoom = 100;
2832 m_aRanges.m_nPagesX = m_aRanges.m_nPagesY = m_aRanges.m_nTotalY = 0;
2833 return;
2836 rDoc.SetRepeatArea( nPrintTab, nRepeatStartCol,nRepeatEndCol, nRepeatStartRow,nRepeatEndRow );
2838 if (aTableParam.bScalePageNum)
2840 nZoom = 100;
2841 sal_uInt16 nPagesToFit = aTableParam.nScalePageNum;
2843 // If manual breaks are forced, calculate minimum # pages required
2844 if (aTableParam.bForceBreaks)
2846 sal_uInt16 nMinPages = 0;
2847 std::set<SCROW> aRowBreaks;
2848 std::set<SCCOL> aColBreaks;
2849 rDoc.GetAllRowBreaks(aRowBreaks, nPrintTab, false, true);
2850 rDoc.GetAllColBreaks(aColBreaks, nPrintTab, false, true);
2851 nMinPages = (aRowBreaks.size() + 1) * (aColBreaks.size() + 1);
2853 // #i54993# use min forced by breaks if it's > # pages in
2854 // scale parameter to avoid bottoming out at <= ZOOM_MIN
2855 nPagesToFit = std::max(nMinPages, nPagesToFit);
2858 sal_uInt16 nLastFitZoom = 0, nLastNonFitZoom = 0;
2859 while (true)
2861 if (nZoom <= ZOOM_MIN)
2862 break;
2864 CalcPages();
2865 bool bFitsPage = (m_aRanges.m_nPagesX * m_aRanges.m_nPagesY <= nPagesToFit);
2867 if (bFitsPage)
2869 if (nZoom == 100)
2870 // If it fits at 100%, it's good enough for me.
2871 break;
2873 nLastFitZoom = nZoom;
2874 nZoom = (nLastNonFitZoom + nZoom) / 2;
2876 if (nLastFitZoom == nZoom)
2877 // It converged. Use this zoom level.
2878 break;
2880 else
2882 if (nZoom - nLastFitZoom <= 1)
2884 nZoom = nLastFitZoom;
2885 CalcPages();
2886 break;
2889 nLastNonFitZoom = nZoom;
2890 nZoom = (nLastFitZoom + nZoom) / 2;
2894 else if (aTableParam.bScaleTo)
2896 nZoom = 100;
2897 sal_uInt16 nW = aTableParam.nScaleWidth;
2898 sal_uInt16 nH = aTableParam.nScaleHeight;
2900 // If manual breaks are forced, calculate minimum # pages required
2901 if (aTableParam.bForceBreaks)
2903 sal_uInt16 nMinPagesW = 0, nMinPagesH = 0;
2904 std::set<SCROW> aRowBreaks;
2905 std::set<SCCOL> aColBreaks;
2906 rDoc.GetAllRowBreaks(aRowBreaks, nPrintTab, false, true);
2907 rDoc.GetAllColBreaks(aColBreaks, nPrintTab, false, true);
2908 nMinPagesW = aColBreaks.size() + 1;
2909 nMinPagesH = aRowBreaks.size() + 1;
2911 // #i54993# use min forced by breaks if it's > # pages in
2912 // scale parameters to avoid bottoming out at <= ZOOM_MIN
2913 nW = std::max(nMinPagesW, nW);
2914 nH = std::max(nMinPagesH, nH);
2917 sal_uInt16 nLastFitZoom = 0, nLastNonFitZoom = 0;
2918 while (true)
2920 if (nZoom <= ZOOM_MIN)
2921 break;
2923 CalcPages();
2924 bool bFitsPage = ((!nW || (m_aRanges.m_nPagesX <= nW)) && (!nH || (m_aRanges.m_nPagesY <= nH)));
2926 if (bFitsPage)
2928 if (nZoom == 100)
2929 // If it fits at 100%, it's good enough for me.
2930 break;
2932 nLastFitZoom = nZoom;
2933 nZoom = (nLastNonFitZoom + nZoom) / 2;
2935 if (nLastFitZoom == nZoom)
2936 // It converged. Use this zoom level.
2937 break;
2939 else
2941 if (nZoom - nLastFitZoom <= 1)
2943 nZoom = nLastFitZoom;
2944 CalcPages();
2945 break;
2948 nLastNonFitZoom = nZoom;
2949 nZoom = (nLastFitZoom + nZoom) / 2;
2952 // tdf#103516 remove the almost blank page(s) for better
2953 // interoperability by using slightly smaller zoom
2954 if (nW > 0 && nH == 0 && m_aRanges.m_nPagesY > 1)
2956 sal_uInt32 nLastPagesY = m_aRanges.m_nPagesY;
2957 nLastFitZoom = nZoom;
2958 nZoom *= 0.98;
2959 if (nZoom < nLastFitZoom)
2961 CalcPages();
2962 // same page count with smaller zoom: use the original zoom
2963 if (m_aRanges.m_nPagesY == nLastPagesY)
2965 nZoom = nLastFitZoom;
2966 CalcPages();
2971 else if (aTableParam.bScaleAll)
2973 nZoom = aTableParam.nScaleAll;
2974 if ( nZoom <= ZOOM_MIN )
2975 nZoom = ZOOM_MIN;
2976 CalcPages();
2978 else
2980 OSL_ENSURE( aTableParam.bScaleNone, "no scale flag is set" );
2981 nZoom = 100;
2982 CalcPages();
2986 Size ScPrintFunc::GetDocPageSize()
2988 // Adjust height of head/foot line
2990 InitModes(); // initialize aTwipMode from nZoom
2991 pDev->SetMapMode( aTwipMode ); // head/foot line in Twips
2992 UpdateHFHeight( aHdr );
2993 UpdateHFHeight( aFtr );
2995 // Page size in Document-Twips
2996 // Calculating Left / Right also in PrintPage
2998 aPageRect = tools::Rectangle( Point(), aPageSize );
2999 aPageRect.SetLeft( ( aPageRect.Left() + nLeftMargin ) * 100 / nZoom );
3000 aPageRect.SetRight( ( aPageRect.Right() - nRightMargin ) * 100 / nZoom );
3001 aPageRect.SetTop( ( aPageRect.Top() + nTopMargin ) * 100 / nZoom + aHdr.nHeight );
3002 aPageRect.SetBottom( ( aPageRect.Bottom() - nBottomMargin ) * 100 / nZoom - aFtr.nHeight );
3004 Size aDocPageSize = aPageRect.GetSize();
3005 if (aTableParam.bHeaders)
3007 aDocPageSize.AdjustWidth( -(tools::Long(PRINT_HEADER_WIDTH)) );
3008 aDocPageSize.AdjustHeight( -(tools::Long(PRINT_HEADER_HEIGHT)) );
3010 if (pBorderItem)
3012 aDocPageSize.AdjustWidth( -(lcl_LineTotal(pBorderItem->GetLeft()) +
3013 lcl_LineTotal(pBorderItem->GetRight()) +
3014 pBorderItem->GetDistance(SvxBoxItemLine::LEFT) +
3015 pBorderItem->GetDistance(SvxBoxItemLine::RIGHT)) );
3016 aDocPageSize.AdjustHeight( -(lcl_LineTotal(pBorderItem->GetTop()) +
3017 lcl_LineTotal(pBorderItem->GetBottom()) +
3018 pBorderItem->GetDistance(SvxBoxItemLine::TOP) +
3019 pBorderItem->GetDistance(SvxBoxItemLine::BOTTOM)) );
3021 if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
3023 aDocPageSize.AdjustWidth( -(pShadowItem->CalcShadowSpace(SvxShadowItemSide::LEFT) +
3024 pShadowItem->CalcShadowSpace(SvxShadowItemSide::RIGHT)) );
3025 aDocPageSize.AdjustHeight( -(pShadowItem->CalcShadowSpace(SvxShadowItemSide::TOP) +
3026 pShadowItem->CalcShadowSpace(SvxShadowItemSide::BOTTOM)) );
3028 return aDocPageSize;
3031 void ScPrintFunc::ResetBreaks( SCTAB nTab ) // Set Breaks correctly for view
3033 rDoc.SetPageSize( nTab, GetDocPageSize() );
3034 rDoc.UpdatePageBreaks( nTab );
3037 static void lcl_SetHidden( const ScDocument& rDoc, SCTAB nPrintTab, ScPageRowEntry& rPageRowEntry,
3038 SCCOL nStartCol, const std::vector< SCCOL >& rPageEndX )
3040 size_t nPagesX = rPageRowEntry.GetPagesX();
3041 SCROW nStartRow = rPageRowEntry.GetStartRow();
3042 SCROW nEndRow = rPageRowEntry.GetEndRow();
3044 bool bLeftIsEmpty = false;
3045 ScRange aTempRange;
3046 tools::Rectangle aTempRect = rDoc.GetMMRect( 0,0, 0,0, 0 );
3048 for (size_t i=0; i<nPagesX; i++)
3050 OSL_ENSURE(i < rPageEndX.size(), "vector access error for aPageEndX");
3051 SCCOL nEndCol = rPageEndX[i];
3052 if ( rDoc.IsPrintEmpty( nStartCol, nStartRow, nEndCol, nEndRow, nPrintTab,
3053 bLeftIsEmpty, &aTempRange, &aTempRect ) )
3055 rPageRowEntry.SetHidden(i);
3056 bLeftIsEmpty = true;
3058 else
3059 bLeftIsEmpty = false;
3061 nStartCol = nEndCol+1;
3065 void ScPrintFunc::CalcPages() // calculates aPageRect and pages from nZoom
3067 assert( bPrintAreaValid );
3069 sc::PrintPageRangesInput aInput(aTableParam.bSkipEmpty, aAreaParam.bPrintArea,
3070 ScRange(nStartCol, nStartRow, nPrintTab, nEndCol, nEndRow, nPrintTab),
3071 GetDocPageSize());
3072 m_aRanges.calculate(rDoc, aInput);
3075 namespace sc
3078 PrintPageRanges::PrintPageRanges()
3079 : m_nPagesX(0)
3080 , m_nPagesY(0)
3081 , m_nTotalY(0)
3084 void PrintPageRanges::calculate(ScDocument& rDoc, PrintPageRangesInput const& rInput)
3086 // Already calculated?
3087 if (m_aInput == rInput)
3088 return;
3090 m_aInput = rInput;
3092 rDoc.SetPageSize(m_aInput.getPrintTab(), m_aInput.m_aDocSize);
3094 // Clear the map to prevent any outdated values to "survive" when
3095 // we have to recalculate the new values anyway
3096 m_xPageRows->clear();
3098 // #i123672# use dynamic mem to react on size changes
3099 if (m_xPageEndX->size() < static_cast<size_t>(rDoc.MaxCol()) + 1)
3101 m_xPageEndX->resize(rDoc.MaxCol()+1, SCCOL());
3104 if (m_aInput.m_bPrintArea)
3106 ScRange aRange(m_aInput.getStartColumn(), m_aInput.getStartRow(), m_aInput.getPrintTab(), m_aInput.getEndColumn(), m_aInput.getEndRow(), m_aInput.getPrintTab());
3107 rDoc.UpdatePageBreaks(m_aInput.getPrintTab(), &aRange);
3109 else
3111 rDoc.UpdatePageBreaks(m_aInput.getPrintTab()); // else, end is marked
3114 const size_t nRealCnt = m_aInput.getEndRow() - m_aInput.getStartRow() + 1;
3116 // #i123672# use dynamic mem to react on size changes
3117 if (m_xPageEndY->size() < nRealCnt+1)
3119 m_xPageEndY->resize(nRealCnt + 1, SCROW());
3122 // Page alignment/splitting after breaks in Col/RowFlags
3123 // Of several breaks in a hidden area, only one counts.
3125 m_nPagesX = 0;
3126 m_nPagesY = 0;
3127 m_nTotalY = 0;
3129 bool bVisCol = false;
3130 for (SCCOL i = m_aInput.getStartColumn(); i <= m_aInput.getEndColumn(); i++)
3132 bool bHidden = rDoc.ColHidden(i, m_aInput.getPrintTab());
3133 bool bPageBreak(rDoc.HasColBreak(i, m_aInput.getPrintTab()) & ScBreakType::Page);
3134 if (i > m_aInput.getStartColumn() && bVisCol && bPageBreak)
3136 OSL_ENSURE(m_nPagesX < m_xPageEndX->size(), "vector access error for aPageEndX");
3137 (*m_xPageEndX)[m_nPagesX] = i-1;
3138 ++m_nPagesX;
3139 bVisCol = false;
3141 if (!bHidden)
3142 bVisCol = true;
3144 if (bVisCol) // also at the end, no empty pages
3146 OSL_ENSURE(m_nPagesX < m_xPageEndX->size(), "vector access error for aPageEndX");
3147 (*m_xPageEndX)[m_nPagesX] = m_aInput.getEndColumn();
3148 ++m_nPagesX;
3151 bool bVisRow = false;
3152 SCROW nPageStartRow = m_aInput.getStartRow();
3153 SCROW nLastVisibleRow = -1;
3155 std::unique_ptr<ScRowBreakIterator> pRowBreakIter(rDoc.GetRowBreakIterator(m_aInput.getPrintTab()));
3156 SCROW nNextPageBreak = pRowBreakIter->first();
3157 while (nNextPageBreak != ScRowBreakIterator::NOT_FOUND && nNextPageBreak < m_aInput.getStartRow())
3158 // Skip until the page break position is at the start row or greater.
3159 nNextPageBreak = pRowBreakIter->next();
3161 for (SCROW nRow = m_aInput.getStartRow(); nRow <= m_aInput.getEndRow(); ++nRow)
3163 bool bPageBreak = (nNextPageBreak == nRow);
3164 if (bPageBreak)
3165 nNextPageBreak = pRowBreakIter->next();
3167 if (nRow > m_aInput.getStartRow() && bVisRow && bPageBreak)
3169 OSL_ENSURE(m_nTotalY < m_xPageEndY->size(), "vector access error for rPageEndY");
3170 (*m_xPageEndY)[m_nTotalY] = nRow - 1;
3171 ++m_nTotalY;
3173 if (!m_aInput.m_bSkipEmpty || !rDoc.IsPrintEmpty(m_aInput.getStartColumn(), nPageStartRow, m_aInput.getEndColumn(), nRow-1, m_aInput.getPrintTab()))
3175 auto& rPageRow = (*m_xPageRows)[m_nPagesY];
3176 rPageRow.SetStartRow(nPageStartRow);
3177 rPageRow.SetEndRow(nRow - 1);
3178 rPageRow.SetPagesX(m_nPagesX);
3179 if (m_aInput.m_bSkipEmpty)
3180 lcl_SetHidden(rDoc, m_aInput.getPrintTab(), rPageRow, m_aInput.getStartColumn(), *m_xPageEndX);
3181 ++m_nPagesY;
3184 nPageStartRow = nRow;
3185 bVisRow = false;
3188 if (nRow <= nLastVisibleRow)
3190 // This row is still visible. Don't bother calling RowHidden() to
3191 // find out, for speed optimization.
3192 bVisRow = true;
3193 continue;
3196 SCROW nLastRow = -1;
3197 if (!rDoc.RowHidden(nRow, m_aInput.getPrintTab(), nullptr, &nLastRow))
3199 bVisRow = true;
3200 nLastVisibleRow = nLastRow;
3202 else
3204 // Skip all hidden rows until next pagebreak.
3205 nRow = ((nNextPageBreak == ScRowBreakIterator::NOT_FOUND) ? nLastRow :
3206 std::min(nLastRow, nNextPageBreak - 1));
3210 if (!bVisRow)
3211 return;
3213 OSL_ENSURE(m_nTotalY < m_xPageEndY->size(), "vector access error for maPageEndY");
3214 (*m_xPageEndY)[m_nTotalY] = m_aInput.getEndRow();
3215 ++m_nTotalY;
3217 if (!m_aInput.m_bSkipEmpty || !rDoc.IsPrintEmpty(m_aInput.getStartColumn(), nPageStartRow, m_aInput.getEndColumn(), m_aInput.getEndRow(), m_aInput.getPrintTab()))
3219 auto& rPageRow = (*m_xPageRows)[m_nPagesY];
3220 rPageRow.SetStartRow(nPageStartRow);
3221 rPageRow.SetEndRow(m_aInput.getEndRow());
3222 rPageRow.SetPagesX(m_nPagesX);
3223 if (m_aInput.m_bSkipEmpty)
3224 lcl_SetHidden(rDoc, m_aInput.getPrintTab(), rPageRow, m_aInput.getStartColumn(), *m_xPageEndX);
3225 ++m_nPagesY;
3229 } // end namespace sc
3230 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */