File indexing completed on 2024-11-10 09:39:12
0001 /* 0002 * This file is part of the HTML rendering engine for KDE. 0003 * 0004 * Copyright (C) 2002 Lars Knoll (knoll@kde.org) 0005 * (C) 2002 Dirk Mueller (mueller@kde.org) 0006 * 0007 * This library is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU Library General Public 0009 * License as published by the Free Software Foundation; either 0010 * version 2 of the License. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Library General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Library General Public License 0018 * along with this library; see the file COPYING.LIB. If not, write to 0019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 * 0022 */ 0023 #include "table_layout.h" 0024 #include "render_table.h" 0025 0026 using namespace khtml; 0027 0028 // #define DEBUG_LAYOUT 0029 0030 /* 0031 The text below is from the CSS 2.1 specs. 0032 0033 Fixed table layout 0034 ------------------ 0035 0036 With this (fast) algorithm, the horizontal layout of the table does 0037 not depend on the contents of the cells; it only depends on the 0038 table's width, the width of the columns, and borders or cell 0039 spacing. 0040 0041 The table's width may be specified explicitly with the 'width' 0042 property. A value of 'auto' (for both 'display: table' and 'display: 0043 inline-table') means use the automatic table layout algorithm. 0044 0045 In the fixed table layout algorithm, the width of each column is 0046 determined as follows: 0047 0048 1. A column element with a value other than 'auto' for the 'width' 0049 property sets the width for that column. 0050 0051 2. Otherwise, a cell in the first row with a value other than 0052 'auto' for the 'width' property sets the width for that column. If 0053 the cell spans more than one column, the width is divided over the 0054 columns. 0055 0056 3. Any remaining columns equally divide the remaining horizontal 0057 table space (minus borders or cell spacing). 0058 0059 The width of the table is then the greater of the value of the 0060 'width' property for the table element and the sum of the column 0061 widths (plus cell spacing or borders). If the table is wider than 0062 the columns, the extra space should be distributed over the columns. 0063 0064 In this manner, the user agent can begin to lay out the table once 0065 the entire first row has been received. Cells in subsequent rows do 0066 not affect column widths. Any cell that has content that overflows 0067 uses the 'overflow' property to determine whether to clip the 0068 overflow content. 0069 0070 _____________________________________________________ 0071 0072 This is not quite true when comparing to IE. IE always honors 0073 table-layout:fixed and treats a variable table width as 100%. Makes 0074 a lot of sense, and is implemented here the same way. 0075 0076 */ 0077 0078 FixedTableLayout::FixedTableLayout(RenderTable *table) 0079 : TableLayout(table) 0080 { 0081 } 0082 0083 FixedTableLayout::~FixedTableLayout() 0084 { 0085 } 0086 0087 int FixedTableLayout::calcWidthArray() 0088 { 0089 int usedWidth = 0; 0090 0091 // iterate over all <col> elements 0092 RenderObject *child = table->firstChild(); 0093 int nEffCols = table->numEffCols(); 0094 width.resize(nEffCols); 0095 width.fill(Length(Auto)); 0096 0097 #ifdef DEBUG_LAYOUT 0098 qDebug("FixedTableLayout::calcWidthArray()"); 0099 qDebug(" col elements:"); 0100 #endif 0101 0102 int currentEffectiveColumn = 0; 0103 Length grpWidth; 0104 while (child) { 0105 if (child->isTableCol()) { 0106 RenderTableCol *col = static_cast<RenderTableCol *>(child); 0107 if (col->firstChild()) { 0108 grpWidth = col->style()->width(); 0109 } else { 0110 Length w = col->style()->width(); 0111 if (w.isAuto()) { 0112 w = grpWidth; 0113 } 0114 int effWidth = 0; 0115 if (w.isFixed() && w.isPositive()) { 0116 effWidth = w.value(); 0117 effWidth = qMin(effWidth, 32760); 0118 } 0119 #ifdef DEBUG_LAYOUT 0120 qDebug(" col element: effCol=%d, span=%d: %d w=%d type=%d", 0121 cCol, span, effWidth, w.rawValue(), w.type()); 0122 #endif 0123 int span = col->span(); 0124 while (span) { 0125 int spanInCurrentEffectiveColumn; 0126 if (currentEffectiveColumn >= nEffCols) { 0127 table->appendColumn(span); 0128 nEffCols++; 0129 width.append(Length()); 0130 spanInCurrentEffectiveColumn = span; 0131 } else { 0132 if (span < table->spanOfEffCol(currentEffectiveColumn)) { 0133 table->splitColumn(currentEffectiveColumn, span); 0134 nEffCols++; 0135 width.append(Length()); 0136 } 0137 spanInCurrentEffectiveColumn = table->spanOfEffCol(currentEffectiveColumn); 0138 } 0139 if ((w.isFixed() || w.isPercent()) && w.isPositive()) { 0140 width[currentEffectiveColumn].setRawValue(w.type(), w.rawValue() * spanInCurrentEffectiveColumn); 0141 usedWidth += effWidth * spanInCurrentEffectiveColumn; 0142 #ifdef DEBUG_LAYOUT 0143 qDebug(" setting effCol %d (span=%d) to width %d(type=%d)", 0144 cCol + i, eSpan, width[cCol + i].rawValue(), width[cCol + i].type()); 0145 #endif 0146 } 0147 span -= spanInCurrentEffectiveColumn; 0148 currentEffectiveColumn++; 0149 } 0150 } 0151 } else { 0152 break; 0153 } 0154 0155 RenderObject *next = child->firstChild(); 0156 if (!next) { 0157 next = child->nextSibling(); 0158 } 0159 if (!next && child->parent()->isTableCol()) { 0160 next = child->parent()->nextSibling(); 0161 grpWidth = Length(); 0162 } 0163 child = next; 0164 } 0165 0166 #ifdef DEBUG_LAYOUT 0167 qDebug(" first row:"); 0168 #endif 0169 // iterate over the first row in case some are unspecified. 0170 RenderTableSection *section = table->head; 0171 if (!section) { 0172 section = table->firstBody; 0173 } 0174 if (!section) { 0175 section = table->foot; 0176 } 0177 if (section && section->firstChild()) { 0178 int cCol = 0; 0179 // get the first cell in the first row 0180 child = section->firstChild()->firstChild(); 0181 while (child) { 0182 if (child->isTableCell()) { 0183 RenderTableCell *cell = static_cast<RenderTableCell *>(child); 0184 Length w = cell->styleOrColWidth(); 0185 int span = cell->colSpan(); 0186 int effWidth = 0; 0187 // FIXME: This does not make sense (mixing percentages with absolute length) 0188 if ((w.isFixed() || w.isPercent()) && w.isPositive()) { 0189 effWidth = w.isPercent() ? w.rawValue() / PERCENT_SCALE_FACTOR : w.value(); 0190 effWidth = qMin(effWidth, 32760); 0191 } 0192 #ifdef DEBUG_LAYOUT 0193 qDebug(" table cell: effCol=%d, span=%d: %d", cCol, span, effWidth); 0194 #endif 0195 int usedSpan = 0; 0196 int i = 0; 0197 while (usedSpan < span) { 0198 Q_ASSERT(cCol + i < nEffCols); 0199 int eSpan = table->spanOfEffCol(cCol + i); 0200 // only set if no col element has already set it. 0201 if (width[cCol + i].isAuto() && !w.isAuto()) { 0202 width[cCol + i].setRawValue(w.type(), w.rawValue() * eSpan); 0203 usedWidth += effWidth * eSpan; 0204 #ifdef DEBUG_LAYOUT 0205 qDebug(" setting effCol %d (span=%d) to width %d(type=%d)", 0206 cCol + i, eSpan, width[cCol + i].rawValue(), width[cCol + i].type()); 0207 #endif 0208 } 0209 #ifdef DEBUG_LAYOUT 0210 else { 0211 qDebug(" width of col %d already defined (span=%d)", cCol, table->spanOfEffCol(cCol)); 0212 } 0213 #endif 0214 usedSpan += eSpan; 0215 i++; 0216 } 0217 cCol += i; 0218 } else { 0219 Q_ASSERT(false); 0220 } 0221 child = child->nextSibling(); 0222 } 0223 } 0224 0225 return usedWidth; 0226 0227 } 0228 0229 void FixedTableLayout::calcMinMaxWidth() 0230 { 0231 // we might want to wait until we have all of the first row before 0232 // layouting for the first time. 0233 0234 // only need to calculate the minimum width as the sum of the 0235 // cols/cells with a fixed width. 0236 // 0237 // The maximum width is qMax( minWidth, tableWidth ) if table 0238 // width is fixed. If table width is percent, we set maxWidth to 0239 // unlimited. 0240 0241 int bs = table->bordersPaddingAndSpacing(); 0242 int tableWidth = 0; 0243 if (table->style()->width().isFixed()) { 0244 tableWidth = table->calcBoxWidth(table->style()->width().value()); 0245 } 0246 0247 int mw = calcWidthArray() + bs; 0248 table->m_minWidth = qMin(qMax(mw, tableWidth), 0x7fff); 0249 table->m_maxWidth = table->m_minWidth; 0250 0251 if (!tableWidth) { 0252 bool haveNonFixed = false; 0253 for (int i = 0; i < width.size(); i++) { 0254 if (!width[i].isFixed()) { 0255 haveNonFixed = true; 0256 break; 0257 } 0258 } 0259 if (haveNonFixed) { 0260 table->m_maxWidth = 0x7fff; 0261 } 0262 } 0263 #ifdef DEBUG_LAYOUT 0264 qDebug("FixedTableLayout::calcMinMaxWidth: minWidth=%d, maxWidth=%d", table->m_minWidth, table->m_maxWidth); 0265 #endif 0266 } 0267 0268 void FixedTableLayout::layout() 0269 { 0270 int tableWidth = table->width() - table->bordersPaddingAndSpacing(); 0271 int available = tableWidth; 0272 int nEffCols = table->numEffCols(); 0273 #ifdef DEBUG_LAYOUT 0274 qDebug("FixedTableLayout::layout: tableWidth=%d, numEffCols=%d", tableWidth, nEffCols); 0275 #endif 0276 0277 QVector<int> calcWidth; 0278 calcWidth.resize(nEffCols); 0279 calcWidth.fill(-1); 0280 0281 // first assign fixed width 0282 for (int i = 0; i < nEffCols; i++) { 0283 if (width[i].isFixed()) { 0284 calcWidth[i] = width[i].value(); 0285 available -= width[i].value(); 0286 } 0287 } 0288 0289 // assign percent width 0290 if (available > 0) { 0291 int totalPercent = 0; 0292 for (int i = 0; i < nEffCols; i++) 0293 if (width[i].isPercent()) { 0294 totalPercent += width[i].rawValue(); 0295 } 0296 0297 // calculate how much to distribute to percent cells. 0298 int base = tableWidth * totalPercent / (100 * PERCENT_SCALE_FACTOR); 0299 if (base > available) { 0300 base = available; 0301 } 0302 0303 #ifdef DEBUG_LAYOUT 0304 qDebug("FixedTableLayout::layout: assigning percent width, base=%d, totalPercent=%d", base, totalPercent); 0305 #endif 0306 for (int i = 0; available > 0 && i < nEffCols; i++) { 0307 if (width[i].isPercent()) { 0308 // totalPercent may be 0 below if all %-width specified are 0%. (#172557) 0309 int w = totalPercent ? base * width[i].rawValue() / totalPercent : 0; 0310 available -= w; 0311 calcWidth[i] = w; 0312 } 0313 } 0314 } 0315 0316 // assign variable width 0317 if (available > 0) { 0318 int totalAuto = 0; 0319 for (int i = 0; i < nEffCols; i++) 0320 if (width[i].isAuto()) { 0321 totalAuto++; 0322 } 0323 0324 for (int i = 0; available > 0 && i < nEffCols; i++) { 0325 if (width[i].isAuto()) { 0326 // totalAuto may be 0 below if all the variable widths specified are 0. 0327 int w = totalAuto ? available / totalAuto : 0; 0328 available -= w; 0329 calcWidth[i] = w; 0330 totalAuto--; 0331 } 0332 } 0333 } 0334 0335 for (int i = 0; i < nEffCols; i++) 0336 if (calcWidth[i] < 0) { 0337 calcWidth[i] = 0; // IE gives min 1 px... 0338 } 0339 0340 // spread extra space over columns 0341 if (available > 0) { 0342 int total = nEffCols; 0343 // still have some width to spread 0344 int i = nEffCols; 0345 while (i--) { 0346 int w = available / total; 0347 available -= w; 0348 total--; 0349 calcWidth[i] += w; 0350 } 0351 } 0352 0353 int pos = 0; 0354 int hspacing = table->borderHSpacing(); 0355 for (int i = 0; i < nEffCols; i++) { 0356 #ifdef DEBUG_LAYOUT 0357 qDebug("col %d: %d (width %d)", i, pos, calcWidth[i]); 0358 #endif 0359 table->columnPos[i] = pos; 0360 pos += calcWidth[i] + hspacing; 0361 } 0362 table->columnPos[table->columnPos.size() - 1] = pos; 0363 } 0364 0365 // ------------------------------------------------------------------------- 0366 // ------------------------------------------------------------------------- 0367 0368 AutoTableLayout::AutoTableLayout(RenderTable *table) 0369 : TableLayout(table) 0370 { 0371 effWidthDirty = true; 0372 hasPercent = false; 0373 } 0374 0375 AutoTableLayout::~AutoTableLayout() 0376 { 0377 } 0378 0379 /* recalculates the full structure needed to do layouting and minmax calculations. 0380 This is usually calculated on the fly, but needs to be done fully when table cells change 0381 dynamically 0382 */ 0383 void AutoTableLayout::recalcColumn(int effCol) 0384 { 0385 Layout &l = layoutStruct[effCol]; 0386 0387 RenderObject *child = table->firstChild(); 0388 // first we iterate over all rows. 0389 0390 RenderTableCell *fixedContributor = nullptr; 0391 RenderTableCell *maxContributor = nullptr; 0392 0393 while (child) { 0394 if (child->isTableSection()) { 0395 RenderTableSection *section = static_cast<RenderTableSection *>(child); 0396 int numRows = section->numRows(); 0397 //RenderTableCell *last = 0; 0398 for (int i = 0; i < numRows; i++) { 0399 RenderTableCell *cell = section->cellAt(i, effCol); 0400 if (cell == (RenderTableCell *) - 1) { 0401 continue; 0402 } 0403 bool cellHasContent = cell && (cell->firstChild() || cell->style()->hasBorder() || cell->style()->hasPadding()); 0404 if (cellHasContent) { 0405 l.emptyCellsOnly = false; 0406 } 0407 if (cell && cell->colSpan() == 1) { 0408 // A cell originates in this column. Ensure we have 0409 // a min/max width of at least 1px for this column now. 0410 l.minWidth = qMax(int(l.minWidth), 1); 0411 l.maxWidth = qMax(int(l.maxWidth), cellHasContent ? 1 : 0); 0412 0413 if (!cell->minMaxKnown()) { 0414 cell->calcMinMaxWidth(); 0415 } 0416 if (cell->minWidth() > l.minWidth) { 0417 l.minWidth = cell->minWidth(); 0418 } 0419 if (cell->maxWidth() > l.maxWidth) { 0420 l.maxWidth = cell->maxWidth(); 0421 maxContributor = cell; 0422 } 0423 0424 Length w = cell->styleOrColWidth(); 0425 if (w.rawValue() > 32767) { 0426 w.setRawValue(32767); 0427 } 0428 if (w.isNegative()) { 0429 w.setValue(0); 0430 } 0431 switch (w.type()) { 0432 case Fixed: 0433 // ignore width=0 0434 if (w.isPositive() && !l.width.isPercent()) { 0435 int wval = cell->calcBoxWidth(w.value()); 0436 if (l.width.isFixed()) { 0437 // Nav/IE weirdness 0438 if ((wval > l.width.value()) || 0439 ((l.width.value() == wval) && (maxContributor == cell))) { 0440 l.width.setValue(wval); 0441 fixedContributor = cell; 0442 } 0443 } else { 0444 l.width = Length(wval, Fixed); 0445 fixedContributor = cell; 0446 } 0447 } 0448 break; 0449 case Percent: 0450 hasPercent = true; 0451 if (w.isPositive() && (!l.width.isPercent() || w.rawValue() > l.width.rawValue())) { 0452 l.width = w; 0453 } 0454 break; 0455 case Relative: 0456 if (w.isAuto() || (w.isRelative() && w.value() > l.width.rawValue())) { 0457 l.width = w; 0458 } 0459 default: 0460 break; 0461 } 0462 } else { 0463 if (cell && (!effCol || section->cellAt(i, effCol - 1) != cell)) { 0464 // This spanning cell originates in this column. Ensure we have 0465 // a min/max width of at least 1px for this column now. 0466 l.minWidth = qMax(int(l.minWidth), cellHasContent ? 1 : 0); 0467 l.maxWidth = qMax(int(l.maxWidth), 1); 0468 insertSpanCell(cell); 0469 } 0470 //last = cell; 0471 } 0472 } 0473 } 0474 child = child->nextSibling(); 0475 } 0476 0477 // Nav/IE weirdness 0478 if (l.width.isFixed()) { 0479 if (table->style()->htmlHacks() 0480 && (l.maxWidth > l.width.value()) && (fixedContributor != maxContributor)) { 0481 l.width = Length(); 0482 fixedContributor = nullptr; 0483 } 0484 } 0485 0486 l.maxWidth = qMax(l.maxWidth, int(l.minWidth)); 0487 #ifdef DEBUG_LAYOUT 0488 qDebug("col %d, final min=%d, max=%d, width=%d(%d)", effCol, l.minWidth, l.maxWidth, l.width.rawValue(), l.width.type()); 0489 #endif 0490 0491 // ### we need to add col elements aswell 0492 } 0493 0494 void AutoTableLayout::fullRecalc() 0495 { 0496 hasPercent = false; 0497 effWidthDirty = true; 0498 0499 int nEffCols = table->numEffCols(); 0500 layoutStruct.resize(nEffCols); 0501 layoutStruct.fill(Layout()); 0502 spanCells.fill(nullptr); 0503 0504 RenderObject *child = table->firstChild(); 0505 Length grpWidth; 0506 int cCol = 0; 0507 while (child) { 0508 if (child->isTableCol()) { 0509 RenderTableCol *col = static_cast<RenderTableCol *>(child); 0510 int span = col->span(); 0511 if (col->firstChild()) { 0512 grpWidth = col->style()->width(); 0513 } else { 0514 Length w = col->style()->width(); 0515 if (w.isAuto()) { 0516 w = grpWidth; 0517 } 0518 if ((w.isFixed() || w.isPercent()) && w.isZero()) { 0519 w = Length(); 0520 } 0521 int cEffCol = table->colToEffCol(cCol); 0522 #ifdef DEBUG_LAYOUT 0523 qDebug(" col element %d (eff=%d): Length=%d(%d), span=%d, effColSpan=%d", cCol, cEffCol, w.rawValue(), w.type(), span, table->spanOfEffCol(cEffCol)); 0524 #endif 0525 if (!w.isAuto() && span == 1 && cEffCol < nEffCols) { 0526 if (table->spanOfEffCol(cEffCol) == 1) { 0527 layoutStruct[cEffCol].width = w; 0528 if (w.isFixed() && layoutStruct[cEffCol].maxWidth < w.value()) { 0529 layoutStruct[cEffCol].maxWidth = w.value(); 0530 } 0531 } 0532 } 0533 cCol += span; 0534 } 0535 } else { 0536 break; 0537 } 0538 0539 RenderObject *next = child->firstChild(); 0540 if (!next) { 0541 next = child->nextSibling(); 0542 } 0543 if (!next && child->parent()->isTableCol()) { 0544 next = child->parent()->nextSibling(); 0545 grpWidth = Length(); 0546 } 0547 child = next; 0548 } 0549 0550 for (int i = 0; i < nEffCols; i++) { 0551 recalcColumn(i); 0552 } 0553 } 0554 0555 static bool shouldScaleColumns(RenderTable *table) 0556 { 0557 // A special case. If this table is not fixed width and contained inside 0558 // a cell, then don't bloat the maxwidth by examining percentage growth. 0559 bool scale = true; 0560 while (table) { 0561 Length tw = table->style()->width(); 0562 if ((tw.isAuto() || tw.isPercent()) && !table->isPositioned()) { 0563 RenderBlock *cb = table->containingBlock(); 0564 while (cb && !cb->isCanvas() && !cb->isTableCell() && 0565 cb->style()->width().isAuto() && !cb->isPositioned()) { 0566 cb = cb->containingBlock(); 0567 } 0568 0569 table = nullptr; 0570 if (cb && cb->isTableCell() && 0571 (cb->style()->width().isAuto() || cb->style()->width().isPercent())) { 0572 if (tw.isPercent()) { 0573 scale = false; 0574 } else { 0575 RenderTableCell *cell = static_cast<RenderTableCell *>(cb); 0576 if (cell->colSpan() > 1 || cell->table()->style()->width().isAuto()) { 0577 scale = false; 0578 } else { 0579 table = cell->table(); 0580 } 0581 } 0582 } 0583 } else { 0584 table = nullptr; 0585 } 0586 } 0587 return scale; 0588 } 0589 0590 void AutoTableLayout::calcMinMaxWidth() 0591 { 0592 #ifdef DEBUG_LAYOUT 0593 qDebug("AutoTableLayout::calcMinMaxWidth"); 0594 #endif 0595 fullRecalc(); 0596 0597 int spanMaxWidth = calcEffectiveWidth(); 0598 int minWidth = 0; 0599 int maxWidth = 0; 0600 int maxPercent = 0; 0601 int maxNonPercent = 0; 0602 0603 int remainingPercent = 100 * PERCENT_SCALE_FACTOR; 0604 for (int i = 0; i < layoutStruct.size(); i++) { 0605 minWidth += layoutStruct[i].effMinWidth; 0606 maxWidth += layoutStruct[i].effMaxWidth; 0607 if (layoutStruct[i].effWidth.isPercent()) { 0608 int percent = qMin(layoutStruct[i].effWidth.rawValue(), remainingPercent); 0609 int pw = (layoutStruct[i].effMaxWidth * 100 * PERCENT_SCALE_FACTOR) / qMax(percent, 1); 0610 remainingPercent -= percent; 0611 maxPercent = qMax(pw, maxPercent); 0612 } else { 0613 maxNonPercent += layoutStruct[i].effMaxWidth; 0614 } 0615 } 0616 0617 if (shouldScaleColumns(table)) { 0618 maxNonPercent = (maxNonPercent * 100 * PERCENT_SCALE_FACTOR) / qMax(remainingPercent, 1); 0619 maxWidth = qMax(maxNonPercent, maxWidth); 0620 maxWidth = qMax(maxWidth, maxPercent); 0621 } 0622 0623 maxWidth = qMax(maxWidth, spanMaxWidth); 0624 0625 int bs = table->bordersPaddingAndSpacing(); 0626 minWidth += bs; 0627 maxWidth += bs; 0628 0629 Length tw = table->style()->width(); 0630 if (tw.isFixed() && tw.isPositive()) { 0631 int width = table->calcBoxWidth(tw.value()); 0632 minWidth = qMax(minWidth, width); 0633 maxWidth = minWidth; 0634 } 0635 0636 table->m_maxWidth = qMin(maxWidth, 0x7fff); 0637 table->m_minWidth = qMin(minWidth, 0x7fff); 0638 #ifdef DEBUG_LAYOUT 0639 qDebug(" minWidth=%d, maxWidth=%d", table->m_minWidth, table->m_maxWidth); 0640 #endif 0641 } 0642 0643 /* 0644 This method takes care of colspans. 0645 effWidth is the same as width for cells without colspans. If we have colspans, they get modified. 0646 */ 0647 int AutoTableLayout::calcEffectiveWidth() 0648 { 0649 int tMaxWidth = 0; 0650 0651 unsigned int nEffCols = layoutStruct.size(); 0652 int hspacing = table->borderHSpacing(); 0653 #ifdef DEBUG_LAYOUT 0654 qDebug("AutoTableLayout::calcEffectiveWidth for %d cols", nEffCols); 0655 #endif 0656 for (unsigned int i = 0; i < nEffCols; i++) { 0657 layoutStruct[i].effWidth = layoutStruct[i].width; 0658 layoutStruct[i].effMinWidth = layoutStruct[i].minWidth; 0659 layoutStruct[i].effMaxWidth = layoutStruct[i].maxWidth; 0660 } 0661 0662 for (int i = 0; i < spanCells.size(); i++) { 0663 RenderTableCell *cell = spanCells[i]; 0664 if (!cell || cell == (RenderTableCell *) - 1) { 0665 break; 0666 } 0667 int span = cell->colSpan(); 0668 0669 Length w = cell->styleOrColWidth(); 0670 if (!w.isRelative() && w.isZero()) { 0671 w = Length(); // make it Auto 0672 } 0673 0674 int col = table->colToEffCol(cell->col()); 0675 unsigned int lastCol = col; 0676 int cMinWidth = cell->minWidth() + hspacing; 0677 int cMaxWidth = cell->maxWidth() + hspacing; 0678 int totalPercent = 0; 0679 int minWidth = 0; 0680 int maxWidth = 0; 0681 bool allColsArePercent = true; 0682 bool allColsAreFixed = true; 0683 bool haveAuto = false; 0684 bool spanHasEmptyCellsOnly = true; 0685 int fixedWidth = 0; 0686 #ifdef DEBUG_LAYOUT 0687 int cSpan = span; 0688 #endif 0689 while (lastCol < nEffCols && span > 0) { 0690 switch (layoutStruct[lastCol].width.type()) { 0691 case Percent: 0692 totalPercent += layoutStruct[lastCol].width.rawValue(); 0693 allColsAreFixed = false; 0694 break; 0695 case Fixed: 0696 if (layoutStruct[lastCol].width.isPositive()) { 0697 fixedWidth += layoutStruct[lastCol].width.value(); 0698 allColsArePercent = false; 0699 // IE resets effWidth to Auto here, but this breaks the konqueror about page and seems to be some bad 0700 // legacy behavior anyway. mozilla doesn't do this so I decided we don't either. 0701 break; 0702 } 0703 // fall through 0704 case Auto: 0705 haveAuto = true; 0706 // fall through 0707 default: 0708 // If the column is a percentage width, do not let the spanning cell overwrite the 0709 // width value. This caused a mis-rendering on amazon.com. 0710 // Sample snippet: 0711 // <table border=2 width=100%>< 0712 // <tr><td>1</td><td colspan=2>2-3</tr> 0713 // <tr><td>1</td><td colspan=2 width=100%>2-3</td></tr> 0714 // </table> 0715 if (!layoutStruct[lastCol].effWidth.isPercent()) { 0716 layoutStruct[lastCol].effWidth = Length(); 0717 allColsArePercent = false; 0718 } else { 0719 totalPercent += layoutStruct[lastCol].effWidth.rawValue(); 0720 } 0721 allColsAreFixed = false; 0722 } 0723 if (!layoutStruct[lastCol].emptyCellsOnly) { 0724 spanHasEmptyCellsOnly = false; 0725 } 0726 span -= table->spanOfEffCol(lastCol); 0727 minWidth += layoutStruct[lastCol].effMinWidth; 0728 maxWidth += layoutStruct[lastCol].effMaxWidth; 0729 lastCol++; 0730 cMinWidth -= hspacing; 0731 cMaxWidth -= hspacing; 0732 } 0733 #ifdef DEBUG_LAYOUT 0734 qDebug(" colspan cell %p at effCol %d, span %d, type %d, value %d cmin=%d min=%d fixedwidth=%d", cell, col, cSpan, w.type(), w.rawValue(), cMinWidth, minWidth, fixedWidth); 0735 #endif 0736 0737 // adjust table max width if needed 0738 if (w.isPercent()) { 0739 if (totalPercent > w.rawValue() || allColsArePercent) { 0740 // can't satify this condition, treat as variable 0741 w = Length(); 0742 } else { 0743 int spanMax = qMax(maxWidth, cMaxWidth); 0744 #ifdef DEBUG_LAYOUT 0745 qDebug(" adjusting tMaxWidth (%d): spanMax=%d, value=%d, totalPercent=%d", tMaxWidth, spanMax, w.rawValue(), totalPercent); 0746 #endif 0747 tMaxWidth = qMax(tMaxWidth, spanMax * 100 * PERCENT_SCALE_FACTOR / w.rawValue()); 0748 0749 // all non percent columns in the span get percent values to sum up correctly. 0750 int percentMissing = w.rawValue() - totalPercent; 0751 int totalWidth = 0; 0752 for (unsigned int pos = col; pos < lastCol; pos++) { 0753 if (!(layoutStruct[pos].width.isPercent())) { 0754 totalWidth += layoutStruct[pos].effMaxWidth; 0755 } 0756 } 0757 0758 for (unsigned int pos = col; pos < lastCol && totalWidth > 0; pos++) { 0759 if (!(layoutStruct[pos].width.isPercent())) { 0760 int percent = percentMissing * layoutStruct[pos].effMaxWidth / totalWidth; 0761 #ifdef DEBUG_LAYOUT 0762 qDebug(" col %d: setting percent value %d effMaxWidth=%d totalWidth=%d", pos, percent, layoutStruct[pos].effMaxWidth, totalWidth); 0763 #endif 0764 totalWidth -= layoutStruct[pos].effMaxWidth; 0765 percentMissing -= percent; 0766 if (percent > 0) { 0767 layoutStruct[pos].effWidth.setRawValue(Percent, percent); 0768 } else { 0769 layoutStruct[pos].effWidth = Length(); 0770 } 0771 } 0772 } 0773 0774 } 0775 } 0776 0777 // make sure minWidth and maxWidth of the spanning cell are honoured 0778 if (cMinWidth > minWidth) { 0779 if (allColsAreFixed) { 0780 #ifdef DEBUG_LAYOUT 0781 qDebug("extending minWidth of cols %d-%d to %dpx currentMin=%d accroding to fixed sum %d", col, lastCol - 1, cMinWidth, minWidth, fixedWidth); 0782 #endif 0783 for (unsigned int pos = col; fixedWidth > 0 && pos < lastCol; pos++) { 0784 int w = qMax(int(layoutStruct[pos].effMinWidth), cMinWidth * layoutStruct[pos].width.value() / fixedWidth); 0785 #ifdef DEBUG_LAYOUT 0786 qDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w); 0787 #endif 0788 fixedWidth -= layoutStruct[pos].width.value(); 0789 cMinWidth -= w; 0790 layoutStruct[pos].effMinWidth = w; 0791 } 0792 0793 } else if (allColsArePercent) { 0794 int maxw = maxWidth; 0795 int minw = minWidth; 0796 int cminw = cMinWidth; 0797 0798 for (unsigned int pos = col; maxw > 0 && pos < lastCol; pos++) { 0799 if (layoutStruct[pos].effWidth.isPercent() && layoutStruct[pos].effWidth.isPositive() && fixedWidth <= cMinWidth) { 0800 int w = layoutStruct[pos].effMinWidth; 0801 w = qMax(w, cminw * layoutStruct[pos].effWidth.rawValue() / totalPercent); 0802 w = qMin(layoutStruct[pos].effMinWidth + (cMinWidth - minw), w); 0803 #ifdef DEBUG_LAYOUT 0804 qDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w); 0805 #endif 0806 maxw -= layoutStruct[pos].effMaxWidth; 0807 minw -= layoutStruct[pos].effMinWidth; 0808 cMinWidth -= w; 0809 layoutStruct[pos].effMinWidth = w; 0810 } 0811 } 0812 } else { 0813 #ifdef DEBUG_LAYOUT 0814 qDebug("extending minWidth of cols %d-%d to %dpx currentMin=%d", col, lastCol - 1, cMinWidth, minWidth); 0815 #endif 0816 int maxw = maxWidth; 0817 int minw = minWidth; 0818 0819 // Give min to variable first, to fixed second, and to others third. 0820 for (unsigned int pos = col; maxw > 0 && pos < lastCol; pos++) { 0821 if (layoutStruct[pos].width.isFixed() && haveAuto && fixedWidth <= cMinWidth) { 0822 int w = qMax(int(layoutStruct[pos].effMinWidth), layoutStruct[pos].width.value()); 0823 fixedWidth -= layoutStruct[pos].width.value(); 0824 minw -= layoutStruct[pos].effMinWidth; 0825 #ifdef DEBUG_LAYOUT 0826 qDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w); 0827 #endif 0828 maxw -= layoutStruct[pos].effMaxWidth; 0829 cMinWidth -= w; 0830 layoutStruct[pos].effMinWidth = w; 0831 } 0832 } 0833 0834 for (unsigned int pos = col; maxw > 0 && pos < lastCol && minw < cMinWidth; pos++) { 0835 if (!(layoutStruct[pos].width.isFixed() && haveAuto && fixedWidth <= cMinWidth)) { 0836 int w = qMax(int(layoutStruct[pos].effMinWidth), cMinWidth * layoutStruct[pos].effMaxWidth / maxw); 0837 w = qMin(layoutStruct[pos].effMinWidth + (cMinWidth - minw), w); 0838 0839 #ifdef DEBUG_LAYOUT 0840 qDebug(" col %d: min=%d, effMin=%d, new=%d", pos, layoutStruct[pos].effMinWidth, layoutStruct[pos].effMinWidth, w); 0841 #endif 0842 maxw -= layoutStruct[pos].effMaxWidth; 0843 minw -= layoutStruct[pos].effMinWidth; 0844 cMinWidth -= w; 0845 layoutStruct[pos].effMinWidth = w; 0846 } 0847 } 0848 } 0849 } 0850 if (!w.isPercent()) { 0851 if (cMaxWidth > maxWidth) { 0852 #ifdef DEBUG_LAYOUT 0853 qDebug("extending maxWidth of cols %d-%d to %dpx", col, lastCol - 1, cMaxWidth); 0854 #endif 0855 for (unsigned int pos = col; maxWidth > 0 && pos < lastCol; pos++) { 0856 int w = qMax(int(layoutStruct[pos].effMaxWidth), cMaxWidth * layoutStruct[pos].effMaxWidth / maxWidth); 0857 #ifdef DEBUG_LAYOUT 0858 qDebug(" col %d: max=%d, effMax=%d, new=%d", pos, layoutStruct[pos].effMaxWidth, layoutStruct[pos].effMaxWidth, w); 0859 #endif 0860 maxWidth -= layoutStruct[pos].effMaxWidth; 0861 cMaxWidth -= w; 0862 layoutStruct[pos].effMaxWidth = w; 0863 } 0864 } 0865 } else { 0866 for (unsigned int pos = col; pos < lastCol; pos++) { 0867 layoutStruct[pos].maxWidth = qMax(layoutStruct[pos].maxWidth, int(layoutStruct[pos].minWidth)); 0868 } 0869 } 0870 // treat span ranges consisting of empty cells only as if they had content 0871 if (spanHasEmptyCellsOnly) 0872 for (unsigned int pos = col; pos < lastCol; pos++) { 0873 layoutStruct[pos].emptyCellsOnly = false; 0874 } 0875 } 0876 effWidthDirty = false; 0877 0878 // qDebug("calcEffectiveWidth: tMaxWidth=%d", tMaxWidth ); 0879 return tMaxWidth; 0880 } 0881 0882 /* gets all cells that originate in a column and have a cellspan > 1 0883 Sorts them by increasing cellspan 0884 */ 0885 void AutoTableLayout::insertSpanCell(RenderTableCell *cell) 0886 { 0887 if (!cell || cell == (RenderTableCell *) - 1 || cell->colSpan() == 1) { 0888 return; 0889 } 0890 0891 // qDebug("inserting span cell %p with span %d", cell, cell->colSpan() ); 0892 int size = spanCells.size(); 0893 if (!size || spanCells[size - 1] != nullptr) { 0894 spanCells.resize(size + 10); 0895 for (int i = 0; i < 10; i++) { 0896 spanCells[size + i] = nullptr; 0897 } 0898 size += 10; 0899 } 0900 0901 // add them in sort. This is a slow algorithm, and a binary search or a fast sorting after collection would be better 0902 int pos = 0; 0903 int span = cell->colSpan(); 0904 while (pos < spanCells.size() && spanCells[pos] && span > spanCells[pos]->colSpan()) { 0905 pos++; 0906 } 0907 memmove(spanCells.data() + pos + 1, spanCells.data() + pos, (size - pos - 1)*sizeof(RenderTableCell *)); 0908 spanCells[pos] = cell; 0909 } 0910 0911 void AutoTableLayout::layout() 0912 { 0913 // table layout based on the values collected in the layout structure. 0914 int tableWidth = table->width() - table->bordersPaddingAndSpacing(); 0915 int available = tableWidth; 0916 int nEffCols = table->numEffCols(); 0917 0918 if (nEffCols != layoutStruct.size()) { 0919 qWarning("WARNING: nEffCols is not equal to layoutstruct!"); 0920 fullRecalc(); 0921 nEffCols = table->numEffCols(); 0922 } 0923 #ifdef DEBUG_LAYOUT 0924 qDebug("AutoTableLayout::layout()"); 0925 #endif 0926 0927 if (effWidthDirty) { 0928 calcEffectiveWidth(); 0929 } 0930 0931 #ifdef DEBUG_LAYOUT 0932 qDebug(" tableWidth=%d, nEffCols=%d", tableWidth, nEffCols); 0933 for (int i = 0; i < nEffCols; i++) { 0934 qDebug(" effcol %d is of type %d value %d, minWidth=%d, maxWidth=%d", 0935 i, layoutStruct[i].width.type(), layoutStruct[i].width.rawValue(), 0936 layoutStruct[i].minWidth, layoutStruct[i].maxWidth); 0937 qDebug(" effective: type %d value %d, minWidth=%d, maxWidth=%d", 0938 layoutStruct[i].effWidth.type(), layoutStruct[i].effWidth.rawValue(), 0939 layoutStruct[i].effMinWidth, layoutStruct[i].effMaxWidth); 0940 } 0941 #endif 0942 0943 bool havePercent = false; 0944 bool haveRelative = false; 0945 int totalRelative = 0; 0946 int numAuto = 0; 0947 int numFixed = 0; 0948 int totalAuto = 0; 0949 int totalFixed = 0; 0950 int totalPercent = 0; 0951 int allocAuto = 0; 0952 int numAutoEmptyCellsOnly = 0; 0953 0954 // fill up every cell with it's minWidth 0955 for (int i = 0; i < nEffCols; i++) { 0956 int w = layoutStruct[i].effMinWidth; 0957 layoutStruct[i].calcWidth = w; 0958 available -= w; 0959 Length &width = layoutStruct[i].effWidth; 0960 switch (width.type()) { 0961 case Percent: 0962 havePercent = true; 0963 totalPercent += width.rawValue(); 0964 break; 0965 case Relative: 0966 haveRelative = true; 0967 totalRelative += width.value(); 0968 break; 0969 case Fixed: 0970 numFixed++; 0971 totalFixed += layoutStruct[i].effMaxWidth; 0972 // fall through 0973 break; 0974 case Auto: 0975 case Static: 0976 if (layoutStruct[i].emptyCellsOnly) { 0977 numAutoEmptyCellsOnly++; 0978 } else { 0979 numAuto++; 0980 totalAuto += layoutStruct[i].effMaxWidth; 0981 allocAuto += w; 0982 } 0983 break; 0984 } 0985 } 0986 0987 // allocate width to percent cols 0988 if (available > 0 && havePercent) { 0989 for (int i = 0; i < nEffCols; i++) { 0990 const Length &width = layoutStruct[i].effWidth; 0991 if (width.isPercent()) { 0992 int w = qMax(int(layoutStruct[i].effMinWidth), width.minWidth(tableWidth)); 0993 available += layoutStruct[i].calcWidth - w; 0994 layoutStruct[i].calcWidth = w; 0995 } 0996 } 0997 if (totalPercent > 100 * PERCENT_SCALE_FACTOR) { 0998 // remove overallocated space from the last columns 0999 int excess = tableWidth * (totalPercent - (100 * PERCENT_SCALE_FACTOR)) / (100 * PERCENT_SCALE_FACTOR); 1000 for (int i = nEffCols - 1; i >= 0; i--) { 1001 if (layoutStruct[i].effWidth.isPercent()) { 1002 int w = layoutStruct[i].calcWidth; 1003 int reduction = qMin(w, excess); 1004 // the lines below might look inconsistent, but that's the way it's handled in mozilla 1005 excess -= reduction; 1006 int newWidth = qMax(int (layoutStruct[i].effMinWidth), w - reduction); 1007 available += w - newWidth; 1008 layoutStruct[i].calcWidth = newWidth; 1009 //qDebug("col %d: reducing to %d px (reduction=%d)", i, newWidth, reduction ); 1010 } 1011 } 1012 } 1013 } 1014 #ifdef DEBUG_LAYOUT 1015 qDebug("percent satisfied: available is %d", available); 1016 #endif 1017 1018 // then allocate width to fixed cols 1019 if (available > 0 && numFixed) { 1020 for (int i = 0; i < nEffCols; ++i) { 1021 const Length &width = layoutStruct[i].effWidth; 1022 if (width.isFixed() && width.value() > layoutStruct[i].calcWidth) { 1023 available += layoutStruct[i].calcWidth - width.value(); 1024 layoutStruct[i].calcWidth = width.value(); 1025 } 1026 } 1027 } 1028 #ifdef DEBUG_LAYOUT 1029 qDebug("fixed satisfied: available is %d", available); 1030 #endif 1031 1032 // now satisfy relative 1033 if (available > 0 && haveRelative) { 1034 for (int i = 0; i < nEffCols; i++) { 1035 const Length &width = layoutStruct[i].effWidth; 1036 if (width.isRelative() && width.value()) { 1037 // width=0* gets effMinWidth. 1038 int w = width.value() * tableWidth / totalRelative; 1039 available += layoutStruct[i].calcWidth - w; 1040 layoutStruct[i].calcWidth = w; 1041 } 1042 } 1043 } 1044 1045 // now satisfy variable 1046 if (available > 0 && numAuto) { 1047 available += allocAuto; // this gets redistributed 1048 //qDebug("redistributing %dpx to %d variable columns. totalAuto=%d", available, numAuto, totalAuto ); 1049 for (int i = 0; i < nEffCols; i++) { 1050 const Length &width = layoutStruct[i].effWidth; 1051 if (width.isAuto() && totalAuto != 0 && !layoutStruct[i].emptyCellsOnly) { 1052 int w = qMax(int (layoutStruct[i].calcWidth), 1053 available * layoutStruct[i].effMaxWidth / totalAuto); 1054 available -= w; 1055 totalAuto -= layoutStruct[i].effMaxWidth; 1056 layoutStruct[i].calcWidth = w; 1057 } 1058 } 1059 } 1060 #ifdef DEBUG_LAYOUT 1061 qDebug("variable satisfied: available is %d", available); 1062 #endif 1063 1064 // spread over fixed columns 1065 if (available > 0 && numFixed) { 1066 // still have some width to spread, distribute to fixed columns 1067 for (int i = 0; i < nEffCols; i++) { 1068 const Length &width = layoutStruct[i].effWidth; 1069 if (width.isFixed()) { 1070 int w = available * layoutStruct[i].effMaxWidth / totalFixed; 1071 available -= w; 1072 totalFixed -= layoutStruct[i].effMaxWidth; 1073 layoutStruct[i].calcWidth += w; 1074 } 1075 } 1076 } 1077 1078 #ifdef DEBUG_LAYOUT 1079 qDebug("after fixed distribution: available=%d", available); 1080 #endif 1081 1082 // spread over percent columns 1083 if (available > 0 && hasPercent && totalPercent < 100 * PERCENT_SCALE_FACTOR) { 1084 // still have some width to spread, distribute weighted to percent columns 1085 for (int i = 0; i < nEffCols; i++) { 1086 const Length &width = layoutStruct[i].effWidth; 1087 if (width.isPercent()) { 1088 int w = available * width.rawValue() / totalPercent; 1089 available -= w; 1090 totalPercent -= width.rawValue(); 1091 layoutStruct[i].calcWidth += w; 1092 if (!available || !totalPercent) { 1093 break; 1094 } 1095 } 1096 } 1097 } 1098 1099 #ifdef DEBUG_LAYOUT 1100 qDebug("after percent distribution: available=%d", available); 1101 #endif 1102 1103 // spread over the rest 1104 if (available > 0 && nEffCols > numAutoEmptyCellsOnly) { 1105 int total = nEffCols; 1106 // still have some width to spread 1107 int i = nEffCols; 1108 while (i--) { 1109 // variable columns with empty cells only don't get any width 1110 if (layoutStruct[i].width.isAuto() && layoutStruct[i].emptyCellsOnly) { 1111 continue; 1112 } 1113 int w = available / total; 1114 available -= w; 1115 total--; 1116 layoutStruct[i].calcWidth += w; 1117 } 1118 } 1119 1120 #ifdef DEBUG_LAYOUT 1121 qDebug("after equal distribution: available=%d", available); 1122 #endif 1123 // if we have overallocated, reduce every cell according to the difference between desired width and minwidth 1124 // this seems to produce to the pixel exaxt results with IE. Wonder is some of this also holds for width distributing. 1125 if (available < 0) { 1126 // Need to reduce cells with the following prioritization: 1127 // (1) Auto 1128 // (2) Relative 1129 // (3) Fixed 1130 // (4) Percent 1131 // This is basically the reverse of how we grew the cells. 1132 if (available < 0) { 1133 int mw = 0; 1134 for (int i = nEffCols - 1; i >= 0; i--) { 1135 Length &width = layoutStruct[i].effWidth; 1136 if (width.isAuto()) { 1137 mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; 1138 } 1139 } 1140 1141 for (int i = nEffCols - 1; i >= 0 && mw > 0; i--) { 1142 Length &width = layoutStruct[i].effWidth; 1143 if (width.isAuto()) { 1144 int minMaxDiff = layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; 1145 int reduce = available * minMaxDiff / mw; 1146 layoutStruct[i].calcWidth += reduce; 1147 available -= reduce; 1148 mw -= minMaxDiff; 1149 if (available >= 0) { 1150 break; 1151 } 1152 } 1153 } 1154 } 1155 1156 if (available < 0 && haveRelative) { 1157 int mw = 0; 1158 for (int i = nEffCols - 1; i >= 0; i--) { 1159 Length &width = layoutStruct[i].effWidth; 1160 if (width.isRelative()) { 1161 mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; 1162 } 1163 } 1164 1165 for (int i = nEffCols - 1; i >= 0 && mw > 0; i--) { 1166 Length &width = layoutStruct[i].effWidth; 1167 if (width.isRelative()) { 1168 int minMaxDiff = layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; 1169 int reduce = available * minMaxDiff / mw; 1170 layoutStruct[i].calcWidth += reduce; 1171 available -= reduce; 1172 mw -= minMaxDiff; 1173 if (available >= 0) { 1174 break; 1175 } 1176 } 1177 } 1178 } 1179 1180 if (available < 0 && numFixed) { 1181 int mw = 0; 1182 for (int i = nEffCols - 1; i >= 0; i--) { 1183 Length &width = layoutStruct[i].effWidth; 1184 if (width.isFixed()) { 1185 mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; 1186 } 1187 } 1188 1189 for (int i = nEffCols - 1; i >= 0 && mw > 0; i--) { 1190 Length &width = layoutStruct[i].effWidth; 1191 if (width.isFixed()) { 1192 int minMaxDiff = layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; 1193 int reduce = available * minMaxDiff / mw; 1194 layoutStruct[i].calcWidth += reduce; 1195 available -= reduce; 1196 mw -= minMaxDiff; 1197 if (available >= 0) { 1198 break; 1199 } 1200 } 1201 } 1202 } 1203 1204 if (available < 0 && havePercent) { 1205 int mw = 0; 1206 for (int i = nEffCols - 1; i >= 0; i--) { 1207 Length &width = layoutStruct[i].effWidth; 1208 if (width.isPercent()) { 1209 mw += layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; 1210 } 1211 } 1212 1213 for (int i = nEffCols - 1; i >= 0 && mw > 0; i--) { 1214 Length &width = layoutStruct[i].effWidth; 1215 if (width.isPercent()) { 1216 int minMaxDiff = layoutStruct[i].calcWidth - layoutStruct[i].effMinWidth; 1217 int reduce = available * minMaxDiff / mw; 1218 layoutStruct[i].calcWidth += reduce; 1219 available -= reduce; 1220 mw -= minMaxDiff; 1221 if (available >= 0) { 1222 break; 1223 } 1224 } 1225 } 1226 } 1227 } 1228 1229 //qDebug( " final available=%d", available ); 1230 1231 int pos = 0; 1232 for (int i = 0; i < nEffCols; i++) { 1233 #ifdef DEBUG_LAYOUT 1234 qDebug("col %d: %d (width %d)", i, pos, layoutStruct[i].calcWidth); 1235 #endif 1236 table->columnPos[i] = pos; 1237 pos += layoutStruct[i].calcWidth + table->borderHSpacing(); 1238 } 1239 table->columnPos[table->columnPos.size() - 1] = pos; 1240 1241 } 1242 1243 #undef DEBUG_LAYOUT