2 * This file is part of the HTML rendering engine for KDE.
4 * Copyright (C) 2002 Lars Knoll (knoll@kde.org)
5 * (C) 2002 Dirk Mueller (mueller@kde.org)
6 * Copyright (C) 2003, 2006 Apple Computer, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
25 #include "AutoTableLayout.h"
27 #include "RenderTable.h"
28 #include "RenderTableCell.h"
29 #include "RenderTableCol.h"
30 #include "RenderTableSection.h"
36 AutoTableLayout::AutoTableLayout(RenderTable* table)
39 , m_percentagesDirty(true)
40 , m_effWidthDirty(true)
45 AutoTableLayout::~AutoTableLayout()
49 /* recalculates the full structure needed to do layouting and minmax calculations.
50 This is usually calculated on the fly, but needs to be done fully when table cells change
53 void AutoTableLayout::recalcColumn(int effCol)
55 Layout &l = m_layoutStruct[effCol];
57 RenderObject* child = m_table->firstChild();
58 // first we iterate over all rows.
60 RenderTableCell* fixedContributor = 0;
61 RenderTableCell* maxContributor = 0;
64 if (child->isTableSection()) {
65 RenderTableSection* section = static_cast<RenderTableSection*>(child);
66 int numRows = section->numRows();
67 RenderTableCell* last = 0;
68 for (int i = 0; i < numRows; i++) {
69 RenderTableSection::CellStruct current = section->cellAt(i, effCol);
70 RenderTableCell* cell = current.cell;
72 bool cellHasContent = cell && (cell->firstChild() || m_table->cellPadding() || cell->style()->hasBorder() || cell->style()->hasPadding());
74 l.emptyCellsOnly = false;
76 if (current.inColSpan)
78 if (cell && cell->colSpan() == 1) {
79 // A cell originates in this column. Ensure we have
80 // a min/max width of at least 1px for this column now.
81 l.minWidth = max(l.minWidth, cellHasContent ? 1 : 0);
82 l.maxWidth = max(l.maxWidth, 1);
83 if (cell->prefWidthsDirty())
84 cell->calcPrefWidths();
85 l.minWidth = max(cell->minPrefWidth(), l.minWidth);
86 if (cell->maxPrefWidth() > l.maxWidth) {
87 l.maxWidth = cell->maxPrefWidth();
88 maxContributor = cell;
91 Length w = cell->styleOrColWidth();
92 // FIXME: What is this arbitrary value?
93 if (w.rawValue() > 32760)
100 if (w.value() > 0 && (int)l.width.type() != Percent) {
101 int wval = cell->calcBorderBoxWidth(w.value());
102 if (l.width.isFixed()) {
104 if ((wval > l.width.value()) ||
105 ((l.width.value() == wval) && (maxContributor == cell))) {
106 l.width.setValue(wval);
107 fixedContributor = cell;
110 l.width.setValue(Fixed, wval);
111 fixedContributor = cell;
117 if (w.isPositive() && (!l.width.isPercent() || w.rawValue() > l.width.rawValue()))
121 // FIXME: Need to understand this case and whether it makes sense to compare values
122 // which are not necessarily of the same type.
123 if (w.isAuto() || (w.isRelative() && w.value() > l.width.rawValue()))
129 if (cell && (!effCol || section->cellAt(i, effCol-1).cell != cell)) {
130 // This spanning cell originates in this column. Ensure we have
131 // a min/max width of at least 1px for this column now.
132 l.minWidth = max(l.minWidth, cellHasContent ? 1 : 0);
133 l.maxWidth = max(l.maxWidth, 1);
134 insertSpanCell(cell);
140 child = child->nextSibling();
144 if (l.width.isFixed()) {
145 if (m_table->style()->htmlHacks() && l.maxWidth > l.width.value() && fixedContributor != maxContributor) {
147 fixedContributor = 0;
151 l.maxWidth = max(l.maxWidth, l.minWidth);
153 // ### we need to add col elements as well
156 void AutoTableLayout::fullRecalc()
158 m_percentagesDirty = true;
159 m_hasPercent = false;
160 m_effWidthDirty = true;
162 int nEffCols = m_table->numEffCols();
163 m_layoutStruct.resize(nEffCols);
164 m_layoutStruct.fill(Layout());
167 RenderObject *child = m_table->firstChild();
171 if (child->isTableCol()) {
172 RenderTableCol *col = static_cast<RenderTableCol*>(child);
173 int span = col->span();
174 if (col->firstChild()) {
175 grpWidth = col->style()->width();
177 Length w = col->style()->width();
180 if ((w.isFixed() || w.isPercent()) && w.isZero())
182 int cEffCol = m_table->colToEffCol(cCol);
183 if (!w.isAuto() && span == 1 && cEffCol < nEffCols) {
184 if (m_table->spanOfEffCol(cEffCol) == 1) {
185 m_layoutStruct[cEffCol].width = w;
186 if (w.isFixed() && m_layoutStruct[cEffCol].maxWidth < w.value())
187 m_layoutStruct[cEffCol].maxWidth = w.value();
196 RenderObject *next = child->firstChild();
198 next = child->nextSibling();
199 if (!next && child->parent()->isTableCol()) {
200 next = child->parent()->nextSibling();
207 for (int i = 0; i < nEffCols; i++)
211 static bool shouldScaleColumns(RenderTable* table)
213 // A special case. If this table is not fixed width and contained inside
214 // a cell, then don't bloat the maxwidth by examining percentage growth.
217 Length tw = table->style()->width();
218 if ((tw.isAuto() || tw.isPercent()) && !table->isPositioned()) {
219 RenderBlock* cb = table->containingBlock();
220 while (cb && !cb->isRenderView() && !cb->isTableCell() &&
221 cb->style()->width().isAuto() && !cb->isPositioned())
222 cb = cb->containingBlock();
225 if (cb && cb->isTableCell() &&
226 (cb->style()->width().isAuto() || cb->style()->width().isPercent())) {
230 RenderTableCell* cell = static_cast<RenderTableCell*>(cb);
231 if (cell->colSpan() > 1 || cell->table()->style()->width().isAuto())
234 table = cell->table();
244 void AutoTableLayout::calcPrefWidths(int& minWidth, int& maxWidth)
248 int spanMaxWidth = calcEffectiveWidth();
251 float maxPercent = 0;
252 float maxNonPercent = 0;
253 bool scaleColumns = shouldScaleColumns(m_table);
255 // We substitute 0 percent by (epsilon / percentScaleFactor) percent in two places below to avoid division by zero.
256 // FIXME: Handle the 0% cases properly.
257 const int epsilon = 1;
259 int remainingPercent = 100 * percentScaleFactor;
260 for (unsigned int i = 0; i < m_layoutStruct.size(); i++) {
261 minWidth += m_layoutStruct[i].effMinWidth;
262 maxWidth += m_layoutStruct[i].effMaxWidth;
264 if (m_layoutStruct[i].effWidth.isPercent()) {
265 int percent = min(m_layoutStruct[i].effWidth.rawValue(), remainingPercent);
266 float pw = static_cast<float>(m_layoutStruct[i].effMaxWidth) * 100 * percentScaleFactor / max(percent, epsilon);
267 maxPercent = max(pw, maxPercent);
268 remainingPercent -= percent;
270 maxNonPercent += m_layoutStruct[i].effMaxWidth;
275 maxNonPercent = maxNonPercent * 100 * percentScaleFactor / max(remainingPercent, epsilon);
276 maxWidth = max(maxWidth, static_cast<int>(min(maxNonPercent, INT_MAX / 2.0f)));
277 maxWidth = max(maxWidth, static_cast<int>(min(maxPercent, INT_MAX / 2.0f)));
280 maxWidth = max(maxWidth, spanMaxWidth);
282 int bs = m_table->bordersPaddingAndSpacing();
286 Length tw = m_table->style()->width();
287 if (tw.isFixed() && tw.value() > 0) {
288 minWidth = max(minWidth, tw.value());
294 This method takes care of colspans.
295 effWidth is the same as width for cells without colspans. If we have colspans, they get modified.
297 int AutoTableLayout::calcEffectiveWidth()
301 unsigned int nEffCols = m_layoutStruct.size();
302 int hspacing = m_table->hBorderSpacing();
304 for (unsigned int i = 0; i < nEffCols; i++) {
305 m_layoutStruct[i].effWidth = m_layoutStruct[i].width;
306 m_layoutStruct[i].effMinWidth = m_layoutStruct[i].minWidth;
307 m_layoutStruct[i].effMaxWidth = m_layoutStruct[i].maxWidth;
310 for (unsigned int i = 0; i < m_spanCells.size(); i++) {
311 RenderTableCell *cell = m_spanCells[i];
314 int span = cell->colSpan();
316 Length w = cell->styleOrColWidth();
317 if (!w.isRelative() && w.isZero())
318 w = Length(); // make it Auto
320 int col = m_table->colToEffCol(cell->col());
321 unsigned int lastCol = col;
322 int cMinWidth = cell->minPrefWidth() + hspacing;
323 float cMaxWidth = cell->maxPrefWidth() + hspacing;
324 int totalPercent = 0;
327 bool allColsArePercent = true;
328 bool allColsAreFixed = true;
329 bool haveAuto = false;
330 bool spanHasEmptyCellsOnly = true;
332 while (lastCol < nEffCols && span > 0) {
333 switch (m_layoutStruct[lastCol].width.type()) {
335 totalPercent += m_layoutStruct[lastCol].width.rawValue();
336 allColsAreFixed = false;
339 if (m_layoutStruct[lastCol].width.value() > 0) {
340 fixedWidth += m_layoutStruct[lastCol].width.value();
341 allColsArePercent = false;
342 // IE resets effWidth to Auto here, but this breaks the konqueror about page and seems to be some bad
343 // legacy behaviour anyway. mozilla doesn't do this so I decided we don't neither.
351 // If the column is a percentage width, do not let the spanning cell overwrite the
352 // width value. This caused a mis-rendering on amazon.com.
354 // <table border=2 width=100%><
355 // <tr><td>1</td><td colspan=2>2-3</tr>
356 // <tr><td>1</td><td colspan=2 width=100%>2-3</td></tr>
358 if (!m_layoutStruct[lastCol].effWidth.isPercent()) {
359 m_layoutStruct[lastCol].effWidth = Length();
360 allColsArePercent = false;
363 totalPercent += m_layoutStruct[lastCol].effWidth.rawValue();
364 allColsAreFixed = false;
366 if (!m_layoutStruct[lastCol].emptyCellsOnly)
367 spanHasEmptyCellsOnly = false;
368 span -= m_table->spanOfEffCol(lastCol);
369 minWidth += m_layoutStruct[lastCol].effMinWidth;
370 maxWidth += m_layoutStruct[lastCol].effMaxWidth;
372 cMinWidth -= hspacing;
373 cMaxWidth -= hspacing;
376 // adjust table max width if needed
378 if (totalPercent > w.rawValue() || allColsArePercent) {
379 // can't satify this condition, treat as variable
382 float spanMax = max(maxWidth, cMaxWidth);
383 tMaxWidth = max(tMaxWidth, spanMax * 100 * percentScaleFactor / w.rawValue());
385 // all non percent columns in the span get percent vlaues to sum up correctly.
386 int percentMissing = w.rawValue() - totalPercent;
387 float totalWidth = 0;
388 for (unsigned int pos = col; pos < lastCol; pos++) {
389 if (!(m_layoutStruct[pos].effWidth.isPercent()))
390 totalWidth += m_layoutStruct[pos].effMaxWidth;
393 for (unsigned int pos = col; pos < lastCol && totalWidth > 0; pos++) {
394 if (!(m_layoutStruct[pos].effWidth.isPercent())) {
395 int percent = static_cast<int>(percentMissing * static_cast<float>(m_layoutStruct[pos].effMaxWidth) / totalWidth);
396 totalWidth -= m_layoutStruct[pos].effMaxWidth;
397 percentMissing -= percent;
399 m_layoutStruct[pos].effWidth.setRawValue(Percent, percent);
401 m_layoutStruct[pos].effWidth = Length();
408 // make sure minWidth and maxWidth of the spanning cell are honoured
409 if (cMinWidth > minWidth) {
410 if (allColsAreFixed) {
411 for (unsigned int pos = col; fixedWidth > 0 && pos < lastCol; pos++) {
412 int w = max(m_layoutStruct[pos].effMinWidth, cMinWidth * m_layoutStruct[pos].width.value() / fixedWidth);
413 fixedWidth -= m_layoutStruct[pos].width.value();
415 m_layoutStruct[pos].effMinWidth = w;
419 float maxw = maxWidth;
422 // Give min to variable first, to fixed second, and to others third.
423 for (unsigned int pos = col; maxw >= 0 && pos < lastCol; pos++) {
424 if (m_layoutStruct[pos].width.isFixed() && haveAuto && fixedWidth <= cMinWidth) {
425 int w = max(m_layoutStruct[pos].effMinWidth, m_layoutStruct[pos].width.value());
426 fixedWidth -= m_layoutStruct[pos].width.value();
427 minw -= m_layoutStruct[pos].effMinWidth;
428 maxw -= m_layoutStruct[pos].effMaxWidth;
430 m_layoutStruct[pos].effMinWidth = w;
434 for (unsigned int pos = col; maxw >= 0 && pos < lastCol && minw < cMinWidth; pos++) {
435 if (!(m_layoutStruct[pos].width.isFixed() && haveAuto && fixedWidth <= cMinWidth)) {
436 int w = max(m_layoutStruct[pos].effMinWidth, static_cast<int>(maxw ? cMinWidth * static_cast<float>(m_layoutStruct[pos].effMaxWidth) / maxw : cMinWidth));
437 w = min(m_layoutStruct[pos].effMinWidth+(cMinWidth-minw), w);
439 maxw -= m_layoutStruct[pos].effMaxWidth;
440 minw -= m_layoutStruct[pos].effMinWidth;
442 m_layoutStruct[pos].effMinWidth = w;
447 if (!(w.isPercent())) {
448 if (cMaxWidth > maxWidth) {
449 for (unsigned int pos = col; maxWidth >= 0 && pos < lastCol; pos++) {
450 int w = max(m_layoutStruct[pos].effMaxWidth, static_cast<int>(maxWidth ? cMaxWidth * static_cast<float>(m_layoutStruct[pos].effMaxWidth) / maxWidth : cMaxWidth));
451 maxWidth -= m_layoutStruct[pos].effMaxWidth;
453 m_layoutStruct[pos].effMaxWidth = w;
457 for (unsigned int pos = col; pos < lastCol; pos++)
458 m_layoutStruct[pos].maxWidth = max(m_layoutStruct[pos].maxWidth, m_layoutStruct[pos].minWidth);
460 // treat span ranges consisting of empty cells only as if they had content
461 if (spanHasEmptyCellsOnly)
462 for (unsigned int pos = col; pos < lastCol; pos++)
463 m_layoutStruct[pos].emptyCellsOnly = false;
465 m_effWidthDirty = false;
467 return static_cast<int>(min(tMaxWidth, INT_MAX / 2.0f));
470 /* gets all cells that originate in a column and have a cellspan > 1
471 Sorts them by increasing cellspan
473 void AutoTableLayout::insertSpanCell(RenderTableCell *cell)
475 if (!cell || cell->colSpan() == 1)
478 int size = m_spanCells.size();
479 if (!size || m_spanCells[size-1] != 0) {
480 m_spanCells.resize(size + 10);
481 for (int i = 0; i < 10; i++)
482 m_spanCells[size+i] = 0;
486 // add them in sort. This is a slow algorithm, and a binary search or a fast sorting after collection would be better
487 unsigned int pos = 0;
488 int span = cell->colSpan();
489 while (pos < m_spanCells.size() && m_spanCells[pos] && span > m_spanCells[pos]->colSpan())
491 memmove(m_spanCells.data()+pos+1, m_spanCells.data()+pos, (size-pos-1)*sizeof(RenderTableCell *));
492 m_spanCells[pos] = cell;
496 void AutoTableLayout::layout()
498 // table layout based on the values collected in the layout structure.
499 int tableWidth = m_table->width() - m_table->bordersPaddingAndSpacing();
500 int available = tableWidth;
501 int nEffCols = m_table->numEffCols();
503 if (nEffCols != (int)m_layoutStruct.size()) {
505 nEffCols = m_table->numEffCols();
509 calcEffectiveWidth();
511 bool havePercent = false;
512 bool haveRelative = false;
513 int totalRelative = 0;
517 float totalFixed = 0;
518 int totalPercent = 0;
520 int numAutoEmptyCellsOnly = 0;
522 // fill up every cell with its minWidth
523 for (int i = 0; i < nEffCols; i++) {
524 int w = m_layoutStruct[i].effMinWidth;
525 m_layoutStruct[i].calcWidth = w;
527 Length& width = m_layoutStruct[i].effWidth;
528 switch (width.type()) {
531 totalPercent += width.rawValue();
535 totalRelative += width.value();
539 totalFixed += m_layoutStruct[i].effMaxWidth;
544 if (m_layoutStruct[i].emptyCellsOnly)
545 numAutoEmptyCellsOnly++;
548 totalAuto += m_layoutStruct[i].effMaxWidth;
557 // allocate width to percent cols
558 if (available > 0 && havePercent) {
559 for (int i = 0; i < nEffCols; i++) {
560 Length &width = m_layoutStruct[i].effWidth;
561 if (width.isPercent()) {
562 int w = max(int(m_layoutStruct[i].effMinWidth), width.calcMinValue(tableWidth));
563 available += m_layoutStruct[i].calcWidth - w;
564 m_layoutStruct[i].calcWidth = w;
567 if (totalPercent > 100 * percentScaleFactor) {
568 // remove overallocated space from the last columns
569 int excess = tableWidth*(totalPercent - 100 * percentScaleFactor) / (100 * percentScaleFactor);
570 for (int i = nEffCols-1; i >= 0; i--) {
571 if (m_layoutStruct[i].effWidth.isPercent()) {
572 int w = m_layoutStruct[i].calcWidth;
573 int reduction = min(w, excess);
574 // the lines below might look inconsistent, but that's the way it's handled in mozilla
576 int newWidth = max(int (m_layoutStruct[i].effMinWidth), w - reduction);
577 available += w - newWidth;
578 m_layoutStruct[i].calcWidth = newWidth;
584 // then allocate width to fixed cols
586 for (int i = 0; i < nEffCols; ++i) {
587 Length &width = m_layoutStruct[i].effWidth;
588 if (width.isFixed() && width.value() > m_layoutStruct[i].calcWidth) {
589 available += m_layoutStruct[i].calcWidth - width.value();
590 m_layoutStruct[i].calcWidth = width.value();
595 // now satisfy relative
597 for (int i = 0; i < nEffCols; i++) {
598 Length &width = m_layoutStruct[i].effWidth;
599 if (width.isRelative() && width.value() != 0) {
600 // width=0* gets effMinWidth.
601 int w = width.value() * tableWidth / totalRelative;
602 available += m_layoutStruct[i].calcWidth - w;
603 m_layoutStruct[i].calcWidth = w;
608 // now satisfy variable
609 if (available > 0 && numAuto) {
610 available += allocAuto; // this gets redistributed
611 for (int i = 0; i < nEffCols; i++) {
612 Length &width = m_layoutStruct[i].effWidth;
613 if (width.isAuto() && totalAuto != 0 && !m_layoutStruct[i].emptyCellsOnly) {
614 int w = max(m_layoutStruct[i].calcWidth, static_cast<int>(available * static_cast<float>(m_layoutStruct[i].effMaxWidth) / totalAuto));
616 totalAuto -= m_layoutStruct[i].effMaxWidth;
617 m_layoutStruct[i].calcWidth = w;
622 // spread over fixed columns
623 if (available > 0 && numFixed) {
624 // still have some width to spread, distribute to fixed columns
625 for (int i = 0; i < nEffCols; i++) {
626 Length &width = m_layoutStruct[i].effWidth;
627 if (width.isFixed()) {
628 int w = static_cast<int>(available * static_cast<float>(m_layoutStruct[i].effMaxWidth) / totalFixed);
630 totalFixed -= m_layoutStruct[i].effMaxWidth;
631 m_layoutStruct[i].calcWidth += w;
636 // spread over percent colums
637 if (available > 0 && m_hasPercent && totalPercent < 100 * percentScaleFactor) {
638 // still have some width to spread, distribute weighted to percent columns
639 for (int i = 0; i < nEffCols; i++) {
640 Length &width = m_layoutStruct[i].effWidth;
641 if (width.isPercent()) {
642 int w = available * width.rawValue() / totalPercent;
644 totalPercent -= width.rawValue();
645 m_layoutStruct[i].calcWidth += w;
646 if (!available || !totalPercent) break;
651 // spread over the rest
652 if (available > 0 && nEffCols > numAutoEmptyCellsOnly) {
653 int total = nEffCols - numAutoEmptyCellsOnly;
654 // still have some width to spread
657 // variable columns with empty cells only don't get any width
658 if (m_layoutStruct[i].effWidth.isAuto() && m_layoutStruct[i].emptyCellsOnly)
660 int w = available / total;
663 m_layoutStruct[i].calcWidth += w;
667 // if we have overallocated, reduce every cell according to the difference between desired width and minwidth
668 // this seems to produce to the pixel exaxt results with IE. Wonder is some of this also holds for width distributing.
670 // Need to reduce cells with the following prioritization:
675 // This is basically the reverse of how we grew the cells.
678 for (int i = nEffCols-1; i >= 0; i--) {
679 Length &width = m_layoutStruct[i].effWidth;
681 mw += m_layoutStruct[i].calcWidth - m_layoutStruct[i].effMinWidth;
684 for (int i = nEffCols-1; i >= 0 && mw > 0; i--) {
685 Length &width = m_layoutStruct[i].effWidth;
686 if (width.isAuto()) {
687 int minMaxDiff = m_layoutStruct[i].calcWidth-m_layoutStruct[i].effMinWidth;
688 int reduce = available * minMaxDiff / mw;
689 m_layoutStruct[i].calcWidth += reduce;
700 for (int i = nEffCols-1; i >= 0; i--) {
701 Length& width = m_layoutStruct[i].effWidth;
702 if (width.isRelative())
703 mw += m_layoutStruct[i].calcWidth - m_layoutStruct[i].effMinWidth;
706 for (int i = nEffCols-1; i >= 0 && mw > 0; i--) {
707 Length& width = m_layoutStruct[i].effWidth;
708 if (width.isRelative()) {
709 int minMaxDiff = m_layoutStruct[i].calcWidth-m_layoutStruct[i].effMinWidth;
710 int reduce = available * minMaxDiff / mw;
711 m_layoutStruct[i].calcWidth += reduce;
722 for (int i = nEffCols-1; i >= 0; i--) {
723 Length& width = m_layoutStruct[i].effWidth;
725 mw += m_layoutStruct[i].calcWidth - m_layoutStruct[i].effMinWidth;
728 for (int i = nEffCols-1; i >= 0 && mw > 0; i--) {
729 Length& width = m_layoutStruct[i].effWidth;
730 if (width.isFixed()) {
731 int minMaxDiff = m_layoutStruct[i].calcWidth-m_layoutStruct[i].effMinWidth;
732 int reduce = available * minMaxDiff / mw;
733 m_layoutStruct[i].calcWidth += reduce;
744 for (int i = nEffCols-1; i >= 0; i--) {
745 Length& width = m_layoutStruct[i].effWidth;
746 if (width.isPercent())
747 mw += m_layoutStruct[i].calcWidth - m_layoutStruct[i].effMinWidth;
750 for (int i = nEffCols-1; i >= 0 && mw > 0; i--) {
751 Length& width = m_layoutStruct[i].effWidth;
752 if (width.isPercent()) {
753 int minMaxDiff = m_layoutStruct[i].calcWidth-m_layoutStruct[i].effMinWidth;
754 int reduce = available * minMaxDiff / mw;
755 m_layoutStruct[i].calcWidth += reduce;
766 for (int i = 0; i < nEffCols; i++) {
767 m_table->columnPositions()[i] = pos;
768 pos += m_layoutStruct[i].calcWidth + m_table->hBorderSpacing();
770 m_table->columnPositions()[m_table->columnPositions().size() - 1] = pos;
774 void AutoTableLayout::calcPercentages() const
776 unsigned totalPercent = 0;
777 for (unsigned i = 0; i < m_layoutStruct.size(); i++) {
778 if (m_layoutStruct[i].width.isPercent())
779 totalPercent += m_layoutStruct[i].width.rawValue();
781 m_totalPercent = totalPercent / percentScaleFactor;
782 m_percentagesDirty = false;