Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwps/src/lib/WPSTable.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
/* libwps
3
 * Version: MPL 2.0 / LGPLv2.1+
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
 * Major Contributor(s):
10
 * Copyright (C) 2009, 2011 Alonso Laurent (alonso@loria.fr)
11
 * Copyright (C) 2006, 2007 Andrew Ziem
12
 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
13
 * Copyright (C) 2004 Marc Maurer (uwog@uwog.net)
14
 * Copyright (C) 2003-2005 William Lachance (william.lachance@sympatico.ca)
15
 *
16
 * For minor contributions see the git repository.
17
 *
18
 * Alternatively, the contents of this file may be used under the terms
19
 * of the GNU Lesser General Public License Version 2.1 or later
20
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
21
 * applicable instead of those above.
22
 *
23
 * For further information visit http://libwps.sourceforge.net
24
 */
25
26
/*
27
 * Structure to store and construct a table from an unstructured list
28
 * of cell
29
 *
30
 */
31
32
#include <iostream>
33
#include <set>
34
35
#include "WPSContentListener.h"
36
#include "WPSCell.h"
37
38
#include "WPSTable.h"
39
40
////////////////////////////////////////////////////////////
41
// WPSColumnFormat
42
std::ostream &operator<<(std::ostream &o, WPSColumnFormat const &column)
43
0
{
44
0
  if (column.m_width>=0)
45
0
  {
46
0
    if (column.m_isPercentWidth)
47
0
      o<<"w=" << column.m_width << "%,";
48
0
    else
49
0
      o<<"w=" << column.m_width << ",";
50
0
  }
51
0
  if (column.m_useOptimalWidth) o << "optimal[h],";
52
0
  if (column.m_isHeader) o << "table[header],";
53
0
  if (column.m_numRepeat>1) o << "repeat=" << column.m_numRepeat << ",";
54
0
  return o;
55
0
}
56
57
void WPSColumnFormat::addTo(librevenge::RVNGPropertyList &propList) const
58
1.56M
{
59
1.56M
  if (m_width>=0)
60
1.55M
    propList.insert("style:column-width", double(m_width), m_isPercentWidth ? librevenge::RVNG_PERCENT : librevenge::RVNG_POINT);
61
1.56M
  if (m_useOptimalWidth)
62
907k
    propList.insert("style:use-optimal-column-width", true);
63
1.56M
  if (m_isHeader)
64
0
    propList.insert("librevenge:is-header-column", true); // checkme
65
1.56M
  if (m_numRepeat>1)
66
457k
    propList.insert("table:number-columns-repeated", m_numRepeat);
67
1.56M
}
68
69
////////////////////////////////////////////////////////////
70
// WPSRowFormat
71
std::ostream &operator<<(std::ostream &o, WPSRowFormat const &row)
72
0
{
73
0
  if (row.m_height>=0)
74
0
  {
75
0
    if (row.m_isMinimalHeight)
76
0
      o<<"h[min]=" << row.m_height << ",";
77
0
    else
78
0
      o<<"h=" << row.m_height << ",";
79
0
  }
80
0
  if (row.m_useOptimalHeight) o << "optimal[h],";
81
0
  if (row.m_isHeader) o << "table[header],";
82
0
  return o;
83
0
}
84
85
void WPSRowFormat::addTo(librevenge::RVNGPropertyList &propList) const
86
6.15M
{
87
6.15M
  if (m_height>=0)
88
6.15M
  {
89
6.15M
    if (m_isMinimalHeight)
90
1.37M
      propList.insert("style:min-row-height", double(m_height), librevenge::RVNG_POINT);
91
4.78M
    else
92
4.78M
      propList.insert("style:row-height", double(m_height), librevenge::RVNG_POINT);
93
6.15M
  }
94
6.15M
  if (m_useOptimalHeight)
95
5.00k
    propList.insert("style:use-optimal-row-height", true);
96
6.15M
  propList.insert("librevenge:is-header-row", m_isHeader);
97
6.15M
}
98
99
////////////////////////////////////////////////////////////
100
// destructor, ...
101
WPSTable::~WPSTable()
102
339k
{
103
339k
}
104
105
void WPSTable::add(WPSCellPtr &cell)
106
214k
{
107
214k
  m_cellsList.push_back(cell);
108
214k
}
109
110
WPSCellPtr WPSTable::getCell(int id)
111
36.3k
{
112
36.3k
  if (id < 0 || id >= int(m_cellsList.size()))
113
0
  {
114
0
    WPS_DEBUG_MSG(("WPSTable::get: cell %d does not exists\n",id));
115
0
    return std::shared_ptr<WPSCell>();
116
0
  }
117
36.3k
  return m_cellsList[size_t(id)];
118
36.3k
}
119
120
////////////////////////////////////////////////////////////
121
// build the table structure
122
bool WPSTable::buildStructures()
123
391
{
124
391
  if (m_colsSize.size())
125
66
    return true;
126
127
325
  size_t nCells = m_cellsList.size();
128
325
  std::vector<float> listPositions[2];
129
975
  for (int dim = 0; dim < 2; dim++)
130
650
  {
131
650
    WPSCell::Compare compareFunction(dim);
132
650
    std::set<WPSCell::Compare::Point,
133
650
        WPSCell::Compare> set(compareFunction);
134
2.69k
    for (size_t c = 0; c < nCells; c++)
135
2.04k
    {
136
2.04k
      set.insert(WPSCell::Compare::Point(0, m_cellsList[c].get()));
137
2.04k
      set.insert(WPSCell::Compare::Point(1, m_cellsList[c].get()));
138
2.04k
    }
139
140
650
    std::vector<float> positions;
141
650
    float maxPosiblePos=0;
142
650
    int actCell = -1;
143
650
    for (auto const &it : set)
144
4.09k
    {
145
4.09k
      float pos = it.getPos(dim);
146
4.09k
      if (actCell < 0 || pos > maxPosiblePos)
147
2.09k
      {
148
2.09k
        actCell++;
149
2.09k
        positions.push_back(pos);
150
2.09k
        maxPosiblePos = pos+2.0f; // 2 pixel ok
151
2.09k
      }
152
4.09k
      if (it.m_which == 0 && it.getPos(dim)-2.0f < maxPosiblePos)
153
2.01k
        maxPosiblePos = pos;
154
4.09k
    }
155
650
    listPositions[dim] = positions;
156
650
  }
157
325
  std::vector<int> numYSet(listPositions[1].size(), 0);
158
325
  std::vector<int> numYUnset(listPositions[1].size(), 0);
159
325
  for (auto const &cell : m_cellsList)
160
896
  {
161
896
    int cellPos[2], spanCell[2];
162
2.45k
    for (int dim = 0; dim < 2; dim++)
163
1.68k
    {
164
1.68k
      float const pt[2] = { cell->box().min()[dim],
165
1.68k
                            cell->box().max()[dim]
166
1.68k
                          };
167
1.68k
      std::vector<float> const &pos = listPositions[dim];
168
1.68k
      size_t numPos = pos.size();
169
1.68k
      size_t i = 0;
170
2.57k
      while (i+1 < numPos && pos[i+1] < pt[0])
171
882
        i++;
172
2.15k
      while (i+1 < numPos && (pos[i]+pos[i+1])/2 < pt[0])
173
465
        i++;
174
1.68k
      if (i+1 > numPos)
175
0
      {
176
0
        WPS_DEBUG_MSG(("WPSTable::buildStructures: impossible to find cell position !!!\n"));
177
0
        return false;
178
0
      }
179
1.68k
      cellPos[dim] = int(i);
180
1.92k
      while (i+1 < numPos && pos[i+1] < pt[1])
181
233
        i++;
182
1.68k
      if (i+1 < numPos && (pos[i]+pos[i+1])/2 < pt[1])
183
1.29k
        i++;
184
1.68k
      spanCell[dim] = int(i)-cellPos[dim];
185
1.68k
      if (spanCell[dim]==0 &&
186
390
              (cell->box().size()[dim]<0||cell->box().size()[dim]>0))
187
135
      {
188
135
        WPS_DEBUG_MSG(("WPSTable::buildStructures: impossible to find span number !!!\n"));
189
135
        return false;
190
135
      }
191
1.55k
      if (spanCell[dim] > 1 &&
192
158
              pos[size_t(cellPos[dim])]+2.0f > pos[size_t(cellPos[dim]+1)])
193
89
      {
194
89
        spanCell[dim]--;
195
89
        cellPos[dim]++;
196
89
      }
197
1.55k
      if (spanCell[dim] > 1 &&
198
99
              pos[size_t(cellPos[dim])]+2.0f > pos[size_t(cellPos[dim]+1)])
199
30
      {
200
30
        spanCell[dim]--;
201
30
        cellPos[dim]++;
202
30
      }
203
1.55k
    }
204
761
    cell->m_position = Vec2i(cellPos[0], cellPos[1]);
205
761
    cell->m_numberCellSpanned = Vec2i(spanCell[0], spanCell[1]);
206
761
    if (spanCell[1] > 0)
207
650
    {
208
1.34k
      for (int x = cellPos[0]; x < cellPos[0]+spanCell[0]; x++)
209
692
      {
210
692
        if (cell->isVerticalSet())
211
160
          numYSet[size_t(cellPos[1]+spanCell[1]-1)]++;
212
532
        else
213
532
          numYUnset[size_t(cellPos[1]+spanCell[1]-1)]++;
214
692
      }
215
650
    }
216
761
  }
217
  // finally update the row/col size
218
570
  for (int dim = 0; dim < 2; dim++)
219
380
  {
220
380
    std::vector<float> const &pos = listPositions[dim];
221
380
    size_t numPos = pos.size();
222
380
    if (!numPos) continue;
223
358
    std::vector<float> &res = (dim==0) ? m_colsSize : m_rowsSize;
224
358
    res.resize(numPos-1);
225
1.12k
    for (size_t i = 0; i < numPos-1; i++)
226
769
    {
227
769
      if (dim==0 || numYUnset[i]==0)
228
524
        res[i] = pos[i+1]-pos[i];
229
245
      else if (numYSet[i])
230
38
        res[i] = -(pos[i+1]-pos[i]);
231
207
      else
232
207
        res[i] = 0;
233
769
    }
234
358
  }
235
236
190
  return true;
237
325
}
238
239
////////////////////////////////////////////////////////////
240
// try to send the table
241
bool WPSTable::sendTable(WPSContentListenerPtr listener)
242
391
{
243
391
  if (!buildStructures())
244
135
    return false;
245
256
  if (!listener)
246
0
    return true;
247
248
256
  size_t numCols = m_colsSize.size();
249
256
  size_t numRows = m_rowsSize.size();
250
256
  if (!numCols || !numRows)
251
28
    return false;
252
228
  std::vector<int> cellsId(numCols*numRows, -1);
253
228
  size_t nCells = m_cellsList.size();
254
852
  for (size_t c = 0; c < nCells; c++)
255
642
  {
256
642
    if (!m_cellsList[c]) continue;
257
642
    Vec2i const &pos=m_cellsList[c]->m_position;
258
642
    Vec2i const &span=m_cellsList[c]->m_numberCellSpanned;
259
260
1.25k
    for (int x = pos[0]; x < pos[0]+span[0]; x++)
261
631
    {
262
631
      if (x >= int(numCols))
263
0
      {
264
0
        WPS_DEBUG_MSG(("WPSTable::sendTable: x is too big !!!\n"));
265
0
        return false;
266
0
      }
267
1.26k
      for (int y = pos[1]; y < pos[1]+span[1]; y++)
268
655
      {
269
655
        if (y >= int(numRows))
270
0
        {
271
0
          WPS_DEBUG_MSG(("WPSTable::sendTable: y is too big !!!\n"));
272
0
          return false;
273
0
        }
274
655
        auto tablePos = size_t(y*int(numCols)+x);
275
655
        if (cellsId[tablePos] != -1)
276
18
        {
277
18
          WPS_DEBUG_MSG(("WPSTable::sendTable: cells is used!!!\n"));
278
18
          return false;
279
18
        }
280
637
        if (x == pos[0] && y == pos[1])
281
558
          cellsId[tablePos] = int(c);
282
79
        else
283
79
          cellsId[tablePos] = -2;
284
637
      }
285
631
    }
286
642
  }
287
288
210
  listener->openTable(m_colsSize, librevenge::RVNG_POINT);
289
210
  WPSListenerPtr listen=listener;
290
663
  for (size_t r = 0; r < numRows; r++)
291
453
  {
292
453
    listener->openTableRow(m_rowsSize[r], librevenge::RVNG_POINT);
293
1.51k
    for (size_t c = 0; c < numCols; c++)
294
1.05k
    {
295
1.05k
      size_t tablePos = r*numCols+c;
296
1.05k
      int id = cellsId[tablePos];
297
1.05k
      if (id == -1)
298
559
        listener->addEmptyTableCell(Vec2i(int(c), int(r)));
299
1.05k
      if (id < 0)
300
577
        continue;
301
302
481
      m_cellsList[size_t(id)]->send(listen);
303
481
    }
304
453
    listener->closeTableRow();
305
453
  }
306
210
  listener->closeTable();
307
308
210
  return true;
309
228
}
310
311
312
////////////////////////////////////////////////////////////
313
// try to send the table
314
bool WPSTable::sendAsText(WPSContentListenerPtr listener)
315
181
{
316
181
  if (!listener) return true;
317
318
181
  WPSListenerPtr listen=listener;
319
181
  for (auto &cell : m_cellsList)
320
585
  {
321
585
    if (!cell) continue;
322
585
    cell->sendContent(listen);
323
585
    listener->insertEOL();
324
585
  }
325
181
  return true;
326
181
}
327
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */