Coverage Report

Created: 2026-09-28 10:59

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