Coverage Report

Created: 2026-07-20 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/MWAWPageSpan.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libmwaw
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
#include <librevenge/librevenge.h>
35
36
#include "libmwaw_internal.hxx"
37
#include "MWAWListener.hxx"
38
#include "MWAWParagraph.hxx"
39
#include "MWAWSubDocument.hxx"
40
41
#include "MWAWPageSpan.hxx"
42
43
/** Internal: the structures of a MWAWPageSpan */
44
namespace MWAWPageSpanInternal
45
{
46
////////////////////////////////////////
47
//! Internal: the subdocument of a MWAWParser
48
class SubDocument final : public MWAWSubDocument
49
{
50
public:
51
  //! constructor
52
  explicit SubDocument(MWAWHeaderFooter const &headerFooter)
53
0
    : MWAWSubDocument(nullptr, MWAWInputStreamPtr(), MWAWEntry())
54
0
    , m_headerFooter(headerFooter)
55
0
  {
56
0
  }
57
58
  //! destructor
59
0
  ~SubDocument() final {}
60
61
  //! operator!=
62
  bool operator!=(MWAWSubDocument const &doc) const final
63
0
  {
64
0
    if (MWAWSubDocument::operator!=(doc)) return true;
65
0
    auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
66
0
    if (!sDoc) return true;
67
0
    if (m_headerFooter != sDoc->m_headerFooter) return true;
68
0
    return false;
69
0
  }
70
71
  //! the parser function
72
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
73
74
protected:
75
  //! the header footer
76
  MWAWHeaderFooter const &m_headerFooter;
77
};
78
79
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type)
80
0
{
81
0
  if (!listener.get()) {
82
0
    MWAW_DEBUG_MSG(("MWAWPageSpanInternal::SubDocument::parse: no listener\n"));
83
0
    return;
84
0
  }
85
0
  if (m_headerFooter.m_pageNumberPosition >= MWAWHeaderFooter::TopLeft &&
86
0
      m_headerFooter.m_pageNumberPosition <= MWAWHeaderFooter::TopRight)
87
0
    m_headerFooter.insertPageNumberParagraph(listener.get());
88
0
  if (m_headerFooter.m_subDocument)
89
0
    m_headerFooter.m_subDocument->parse(listener, type);
90
0
  if (m_headerFooter.m_pageNumberPosition >= MWAWHeaderFooter::BottomLeft &&
91
0
      m_headerFooter.m_pageNumberPosition <= MWAWHeaderFooter::BottomRight)
92
0
    m_headerFooter.insertPageNumberParagraph(listener.get());
93
0
}
94
}
95
96
// ----------------- MWAWHeaderFooter ------------------------
97
MWAWHeaderFooter::MWAWHeaderFooter(MWAWHeaderFooter::Type const type, MWAWHeaderFooter::Occurrence const occurrence)
98
1.32M
  : m_type(type)
99
1.32M
  , m_occurrence(occurrence)
100
1.32M
  , m_height(0)
101
1.32M
  , m_pageNumberPosition(MWAWHeaderFooter::None)
102
1.32M
  , m_pageNumberType(libmwaw::ARABIC)
103
1.32M
  , m_pageNumberFont(20,12)
104
1.32M
  , m_subDocument()
105
1.32M
{
106
1.32M
}
107
108
MWAWHeaderFooter::~MWAWHeaderFooter()
109
8.53M
{
110
8.53M
}
111
112
bool MWAWHeaderFooter::operator==(MWAWHeaderFooter const &hf) const
113
0
{
114
0
  if (&hf==this) return true;
115
0
  if (m_type != hf.m_type)
116
0
    return false;
117
0
  if (m_type == UNDEF)
118
0
    return true;
119
0
  if (m_occurrence != hf.m_occurrence)
120
0
    return false;
121
0
  if (m_height < hf.m_height || m_height > hf.m_height)
122
0
    return false;
123
0
  if (m_pageNumberPosition != hf.m_pageNumberPosition ||
124
0
      m_pageNumberType != hf.m_pageNumberType ||
125
0
      m_pageNumberFont != hf.m_pageNumberFont)
126
0
    return false;
127
0
  if (!m_subDocument)
128
0
    return !hf.m_subDocument;
129
0
  if (*m_subDocument.get() != hf.m_subDocument)
130
0
    return false;
131
0
  return true;
132
0
}
133
134
// send data to the listener
135
void MWAWHeaderFooter::send(MWAWListener *listener) const
136
1.88M
{
137
1.88M
  if (m_type == UNDEF)
138
0
    return;
139
1.88M
  if (!listener) {
140
0
    MWAW_DEBUG_MSG(("MWAWHeaderFooter::send: called without listener\n"));
141
0
    return;
142
0
  }
143
1.88M
  librevenge::RVNGPropertyList propList;
144
1.88M
  switch (m_occurrence) {
145
32.7k
  case ODD:
146
32.7k
    propList.insert("librevenge:occurrence", "odd");
147
32.7k
    break;
148
33.2k
  case EVEN:
149
33.2k
    propList.insert("librevenge:occurrence", "even");
150
33.2k
    break;
151
1.81M
  case ALL:
152
1.81M
    propList.insert("librevenge:occurrence", "all");
153
1.81M
    break;
154
0
  case NEVER:
155
#if !defined(__clang__)
156
  default:
157
#endif
158
0
    break;
159
1.88M
  }
160
1.88M
  if (m_pageNumberPosition!=None) {
161
0
    std::shared_ptr<MWAWPageSpanInternal::SubDocument> doc
162
0
    (new MWAWPageSpanInternal::SubDocument(*this));
163
0
    if (m_type == HEADER)
164
0
      listener->insertHeader(doc,propList);
165
0
    else
166
0
      listener->insertFooter(doc,propList);
167
0
    return;
168
0
  }
169
1.88M
  if (m_type == HEADER)
170
1.37M
    listener->insertHeader(m_subDocument,propList);
171
507k
  else
172
507k
    listener->insertFooter(m_subDocument,propList);
173
1.88M
}
174
175
void MWAWHeaderFooter::insertPageNumberParagraph(MWAWListener *listener) const
176
0
{
177
0
  MWAWParagraph para;
178
0
  para.m_justify = MWAWParagraph::JustificationCenter;
179
0
  switch (m_pageNumberPosition) {
180
0
  case TopLeft:
181
0
  case BottomLeft:
182
0
    para.m_justify = MWAWParagraph::JustificationLeft;
183
0
    break;
184
0
  case TopRight:
185
0
  case BottomRight:
186
0
    para.m_justify = MWAWParagraph::JustificationRight;
187
0
    break;
188
0
  case TopCenter:
189
0
  case BottomCenter:
190
0
  case None:
191
0
    break;
192
#if !defined(__clang__)
193
  default:
194
    MWAW_DEBUG_MSG(("MWAWHeaderFooter::insertPageNumberParagraph: unexpected value\n"));
195
    break;
196
#endif
197
0
  }
198
0
  listener->setParagraph(para);
199
0
  listener->setFont(m_pageNumberFont);
200
0
  if (listener->isParagraphOpened())
201
0
    listener->insertEOL();
202
203
0
  MWAWField field(MWAWField::PageNumber);
204
0
  field.m_numberingType=m_pageNumberType;
205
0
  listener->insertField(field);
206
0
}
207
208
// ----------------- MWAWPageSpan ------------------------
209
MWAWPageSpan::MWAWPageSpan()
210
24.4M
  : m_formLength(11.0)
211
24.4M
  , m_formWidth(8.5)
212
24.4M
  , m_name("")
213
24.4M
  , m_masterName("")
214
24.4M
  , m_formOrientation(MWAWPageSpan::PORTRAIT)
215
24.4M
  , m_backgroundColor(MWAWColor::white())
216
24.4M
  , m_headerFooterList()
217
24.4M
  , m_pageNumber(-1)
218
24.4M
  , m_pageSpan(1)
219
24.4M
{
220
97.8M
  for (auto &margin : m_margins) margin = 1.0;
221
24.4M
}
222
223
MWAWPageSpan::~MWAWPageSpan()
224
49.8M
{
225
49.8M
}
226
227
void MWAWPageSpan::setHeaderFooter(MWAWHeaderFooter const &hF)
228
208k
{
229
208k
  MWAWHeaderFooter::Type const type=hF.m_type;
230
208k
  switch (hF.m_occurrence) {
231
0
  case MWAWHeaderFooter::NEVER:
232
0
    removeHeaderFooter(type, MWAWHeaderFooter::ALL);
233
0
    MWAW_FALLTHROUGH;
234
195k
  case MWAWHeaderFooter::ALL:
235
195k
    removeHeaderFooter(type, MWAWHeaderFooter::ODD);
236
195k
    removeHeaderFooter(type, MWAWHeaderFooter::EVEN);
237
195k
    break;
238
6.61k
  case MWAWHeaderFooter::ODD:
239
6.61k
    removeHeaderFooter(type, MWAWHeaderFooter::ALL);
240
6.61k
    break;
241
7.12k
  case MWAWHeaderFooter::EVEN:
242
7.12k
    removeHeaderFooter(type, MWAWHeaderFooter::ALL);
243
7.12k
    break;
244
#if !defined(__clang__)
245
  default:
246
    break;
247
#endif
248
208k
  }
249
208k
  int pos = getHeaderFooterPosition(hF.m_type, hF.m_occurrence);
250
208k
  if (pos != -1)
251
208k
    m_headerFooterList[size_t(pos)]=hF;
252
253
208k
  bool containsHFLeft = containsHeaderFooter(type, MWAWHeaderFooter::ODD);
254
208k
  bool containsHFRight = containsHeaderFooter(type, MWAWHeaderFooter::EVEN);
255
256
208k
  if (containsHFLeft && !containsHFRight) {
257
6.61k
    MWAW_DEBUG_MSG(("Inserting dummy header right\n"));
258
6.61k
    MWAWHeaderFooter dummy(type, MWAWHeaderFooter::EVEN);
259
6.61k
    pos = getHeaderFooterPosition(type, MWAWHeaderFooter::EVEN);
260
6.61k
    if (pos != -1)
261
6.61k
      m_headerFooterList[size_t(pos)]=MWAWHeaderFooter(type, MWAWHeaderFooter::EVEN);
262
6.61k
  }
263
202k
  else if (!containsHFLeft && containsHFRight) {
264
1.11k
    MWAW_DEBUG_MSG(("Inserting dummy header left\n"));
265
1.11k
    pos = getHeaderFooterPosition(type, MWAWHeaderFooter::ODD);
266
1.11k
    if (pos != -1)
267
1.11k
      m_headerFooterList[size_t(pos)]=MWAWHeaderFooter(type, MWAWHeaderFooter::ODD);
268
1.11k
  }
269
208k
}
270
271
void MWAWPageSpan::checkMargins()
272
2.38k
{
273
2.38k
  if (m_margins[libmwaw::Left]+m_margins[libmwaw::Right] > 0.95*m_formWidth) {
274
676
    MWAW_DEBUG_MSG(("MWAWPageSpan::checkMargins: left/right margins seems bad\n"));
275
676
    m_margins[libmwaw::Left] = m_margins[libmwaw::Right] = 0.05*m_formWidth;
276
676
  }
277
2.38k
  if (m_margins[libmwaw::Top]+m_margins[libmwaw::Bottom] > 0.95*m_formLength) {
278
836
    MWAW_DEBUG_MSG(("MWAWPageSpan::checkMargins: top/bottom margins seems bad\n"));
279
836
    m_margins[libmwaw::Top] = m_margins[libmwaw::Bottom] = 0.05*m_formLength;
280
836
  }
281
2.38k
}
282
283
void MWAWPageSpan::sendHeaderFooters(MWAWListener *listener) const
284
959k
{
285
959k
  if (!listener) {
286
0
    MWAW_DEBUG_MSG(("MWAWPageSpan::sendHeaderFooters: no listener\n"));
287
0
    return;
288
0
  }
289
290
1.54M
  for (auto const &hf : m_headerFooterList) {
291
1.54M
    if (!hf.isDefined()) continue;
292
361k
    hf.send(listener);
293
361k
  }
294
959k
}
295
296
void MWAWPageSpan::sendHeaderFooters(MWAWListener *listener, MWAWHeaderFooter::Occurrence occurrence) const
297
10.4M
{
298
10.4M
  if (!listener) {
299
0
    MWAW_DEBUG_MSG(("MWAWPageSpan::sendHeaderFooters: no listener\n"));
300
0
    return;
301
0
  }
302
303
10.4M
  for (auto const &hf : m_headerFooterList) {
304
5.14M
    if (!hf.isDefined()) continue;
305
1.52M
    if (hf.m_occurrence==occurrence || hf.m_occurrence==MWAWHeaderFooter::ALL)
306
1.52M
      hf.send(listener);
307
1.52M
  }
308
10.4M
}
309
310
void MWAWPageSpan::getPageProperty(librevenge::RVNGPropertyList &propList, bool isPresentation) const
311
11.4M
{
312
11.4M
  propList.insert("librevenge:num-pages", getPageSpan());
313
314
11.4M
  if (hasPageName())
315
26.4k
    propList.insert("draw:name", getPageName());
316
11.4M
  if (hasMasterPageName())
317
50.4k
    propList.insert("librevenge:master-page-name", getMasterPageName());
318
11.4M
  propList.insert("fo:page-height", getFormLength(), librevenge::RVNG_INCH);
319
11.4M
  propList.insert("fo:page-width", getFormWidth(), librevenge::RVNG_INCH);
320
11.4M
  if (getFormOrientation() == LANDSCAPE)
321
1.55k
    propList.insert("style:print-orientation", "landscape");
322
11.3M
  else
323
11.3M
    propList.insert("style:print-orientation", "portrait");
324
11.4M
  propList.insert("fo:margin-left", getMarginLeft(), librevenge::RVNG_INCH);
325
11.4M
  propList.insert("fo:margin-right", getMarginRight(), librevenge::RVNG_INCH);
326
11.4M
  propList.insert("fo:margin-top", getMarginTop(), librevenge::RVNG_INCH);
327
11.4M
  propList.insert("fo:margin-bottom", getMarginBottom(), librevenge::RVNG_INCH);
328
11.4M
  if (!m_backgroundColor.isWhite()) {
329
10.7k
    if (isPresentation) {
330
127
      propList.insert("draw:fill", "solid");
331
127
      propList.insert("draw:fill-color", m_backgroundColor.str().c_str());
332
127
    }
333
10.6k
    else
334
10.6k
      propList.insert("fo:background-color", m_backgroundColor.str().c_str());
335
10.7k
  }
336
11.4M
}
337
338
339
bool MWAWPageSpan::operator==(std::shared_ptr<MWAWPageSpan> const &page2) const
340
0
{
341
0
  if (!page2) return false;
342
0
  if (page2.get() == this) return true;
343
0
  if (m_formLength < page2->m_formLength || m_formLength > page2->m_formLength ||
344
0
      m_formWidth < page2->m_formWidth || m_formWidth > page2->m_formWidth ||
345
0
      m_formOrientation != page2->m_formOrientation)
346
0
    return false;
347
0
  if (getMarginLeft() < page2->getMarginLeft() || getMarginLeft() > page2->getMarginLeft() ||
348
0
      getMarginRight() < page2->getMarginRight() || getMarginRight() > page2->getMarginRight() ||
349
0
      getMarginTop() < page2->getMarginTop() || getMarginTop() > page2->getMarginTop() ||
350
0
      getMarginBottom() < page2->getMarginBottom() || getMarginBottom() > page2->getMarginBottom())
351
0
    return false;
352
0
  if (getPageName() != page2->getPageName() || getMasterPageName() != page2->getMasterPageName() ||
353
0
      backgroundColor() != page2->backgroundColor())
354
0
    return false;
355
356
0
  if (getPageNumber() != page2->getPageNumber())
357
0
    return false;
358
359
0
  size_t numHF = m_headerFooterList.size();
360
0
  size_t numHF2 = page2->m_headerFooterList.size();
361
0
  for (size_t i = numHF; i < numHF2; i++) {
362
0
    if (page2->m_headerFooterList[i].isDefined())
363
0
      return false;
364
0
  }
365
0
  for (size_t i = numHF2; i < numHF; i++) {
366
0
    if (m_headerFooterList[i].isDefined())
367
0
      return false;
368
0
  }
369
0
  if (numHF2 < numHF) numHF = numHF2;
370
0
  for (size_t i = 0; i < numHF; i++) {
371
0
    if (m_headerFooterList[i] != page2->m_headerFooterList[i])
372
0
      return false;
373
0
  }
374
0
  MWAW_DEBUG_MSG(("WordPerfect: MWAWPageSpan == comparison finished, found no differences\n"));
375
376
0
  return true;
377
0
}
378
379
// -------------- manage header footer list ------------------
380
void MWAWPageSpan::removeHeaderFooter(MWAWHeaderFooter::Type type, MWAWHeaderFooter::Occurrence occurrence)
381
404k
{
382
404k
  int pos = getHeaderFooterPosition(type, occurrence);
383
404k
  if (pos == -1) return;
384
404k
  m_headerFooterList[size_t(pos)]=MWAWHeaderFooter();
385
404k
}
386
387
bool MWAWPageSpan::containsHeaderFooter(MWAWHeaderFooter::Type type, MWAWHeaderFooter::Occurrence occurrence)
388
417k
{
389
417k
  int pos = getHeaderFooterPosition(type, occurrence);
390
417k
  if (pos == -1 || !m_headerFooterList[size_t(pos)].isDefined()) return false;
391
19.7k
  return true;
392
417k
}
393
394
int MWAWPageSpan::getHeaderFooterPosition(MWAWHeaderFooter::Type type, MWAWHeaderFooter::Occurrence occurrence)
395
1.03M
{
396
1.03M
  int typePos = 0, occurrencePos = 0;
397
1.03M
  switch (type) {
398
548k
  case MWAWHeaderFooter::HEADER:
399
548k
    typePos = 0;
400
548k
    break;
401
490k
  case MWAWHeaderFooter::FOOTER:
402
490k
    typePos = 1;
403
490k
    break;
404
0
  case MWAWHeaderFooter::UNDEF:
405
#if !defined(__clang__)
406
  default:
407
#endif
408
0
    MWAW_DEBUG_MSG(("MWAWPageSpan::getVectorPosition: unknown type\n"));
409
0
    return -1;
410
1.03M
  }
411
1.03M
  switch (occurrence) {
412
208k
  case MWAWHeaderFooter::ALL:
413
208k
    occurrencePos = 0;
414
208k
    break;
415
411k
  case MWAWHeaderFooter::ODD:
416
411k
    occurrencePos = 1;
417
411k
    break;
418
417k
  case MWAWHeaderFooter::EVEN:
419
417k
    occurrencePos = 2;
420
417k
    break;
421
0
  case MWAWHeaderFooter::NEVER:
422
#if !defined(__clang__)
423
  default:
424
#endif
425
0
    MWAW_DEBUG_MSG(("MWAWPageSpan::getVectorPosition: unknown occurrence\n"));
426
0
    return -1;
427
1.03M
  }
428
1.03M
  auto res = size_t(typePos*3+occurrencePos);
429
1.03M
  if (res >= m_headerFooterList.size())
430
412k
    m_headerFooterList.resize(res+1);
431
1.03M
  return int(res);
432
1.03M
}
433
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: