File indexing completed on 2024-05-05 16:10:15
0001 /** 0002 * This file is part of the DOM implementation for KDE. 0003 * 0004 * Copyright (C) 1997 Martin Jones (mjones@kde.org) 0005 * (C) 1997 Torben Weis (weis@kde.org) 0006 * (C) 1998 Waldo Bastian (bastian@kde.org) 0007 * (C) 1999-2003 Lars Knoll (knoll@kde.org) 0008 * (C) 1999 Antti Koivisto (koivisto@kde.org) 0009 * (C) 2003 Apple Computer, Inc. 0010 * (C) 2006 Maksim Orlovich (maksim@kde.org) 0011 * 0012 * This library is free software; you can redistribute it and/or 0013 * modify it under the terms of the GNU Library General Public 0014 * License as published by the Free Software Foundation; either 0015 * version 2 of the License, or (at your option) any later version. 0016 * 0017 * This library is distributed in the hope that it will be useful, 0018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0020 * Library General Public License for more details. 0021 * 0022 * You should have received a copy of the GNU Library General Public License 0023 * along with this library; see the file COPYING.LIB. If not, write to 0024 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0025 * Boston, MA 02110-1301, USA. 0026 */ 0027 0028 #include "html_tableimpl.h" 0029 0030 #include "html_documentimpl.h" 0031 0032 #include <dom/dom_exception.h> 0033 #include <dom/dom_node.h> 0034 0035 #include <khtmlview.h> 0036 #include <khtml_part.h> 0037 0038 #include <css/cssstyleselector.h> 0039 #include <css/cssproperties.h> 0040 #include <css/cssvalues.h> 0041 0042 #include <rendering/render_table.h> 0043 0044 #include "khtml_debug.h" 0045 0046 using namespace khtml; 0047 using namespace DOM; 0048 0049 HTMLTableElementImpl::HTMLTableElementImpl(DocumentImpl *doc) 0050 : HTMLElementImpl(doc) 0051 { 0052 rules = None; 0053 frame = Void; 0054 0055 padding = 1; 0056 0057 m_solid = false; 0058 } 0059 0060 HTMLTableElementImpl::~HTMLTableElementImpl() 0061 { 0062 } 0063 0064 NodeImpl::Id HTMLTableElementImpl::id() const 0065 { 0066 return ID_TABLE; 0067 } 0068 0069 NodeImpl *HTMLTableElementImpl::setCaption(HTMLTableCaptionElementImpl *c) 0070 { 0071 int exceptioncode = 0; 0072 NodeImpl *r; 0073 if (ElementImpl *cap = caption()) { 0074 replaceChild(c, cap, exceptioncode); 0075 r = c; 0076 } else { 0077 r = insertBefore(c, firstChild(), exceptioncode); 0078 } 0079 tCaption = c; 0080 return r; 0081 } 0082 0083 NodeImpl *HTMLTableElementImpl::setTHead(HTMLTableSectionElementImpl *s) 0084 { 0085 int exceptioncode = 0; 0086 NodeImpl *r; 0087 if (ElementImpl *head = tHead()) { 0088 replaceChild(s, head, exceptioncode); 0089 r = s; 0090 } else if (ElementImpl *foot = tFoot()) { 0091 r = insertBefore(s, foot, exceptioncode); 0092 } else if (ElementImpl *firstBody = tFirstBody()) { 0093 r = insertBefore(s, firstBody, exceptioncode); 0094 } else { 0095 r = appendChild(s, exceptioncode); 0096 } 0097 0098 head = s; 0099 return r; 0100 } 0101 0102 NodeImpl *HTMLTableElementImpl::setTFoot(HTMLTableSectionElementImpl *s) 0103 { 0104 int exceptioncode = 0; 0105 NodeImpl *r; 0106 if (ElementImpl *foot = tFoot()) { 0107 replaceChild(s, foot, exceptioncode); 0108 r = s; 0109 } else if (ElementImpl *firstBody = tFirstBody()) { 0110 r = insertBefore(s, firstBody, exceptioncode); 0111 } else { 0112 r = appendChild(s, exceptioncode); 0113 } 0114 foot = s; 0115 return r; 0116 } 0117 0118 NodeImpl *HTMLTableElementImpl::setTBody(HTMLTableSectionElementImpl *s) 0119 { 0120 int exceptioncode = 0; 0121 NodeImpl *r; 0122 0123 if (ElementImpl *firstBody = tFirstBody()) { 0124 replaceChild(s, firstBody, exceptioncode); 0125 r = s; 0126 } else { 0127 r = appendChild(s, exceptioncode); 0128 } 0129 firstBody = s; 0130 0131 return r; 0132 } 0133 0134 HTMLElementImpl *HTMLTableElementImpl::createTHead() 0135 { 0136 if (!tHead()) { 0137 int exceptioncode = 0; 0138 ElementImpl *head = new HTMLTableSectionElementImpl(docPtr(), ID_THEAD, true /* implicit */); 0139 if (ElementImpl *foot = tFoot()) { 0140 insertBefore(head, foot, exceptioncode); 0141 } else if (ElementImpl *firstBody = tFirstBody()) { 0142 insertBefore(head, firstBody, exceptioncode); 0143 } else { 0144 appendChild(head, exceptioncode); 0145 } 0146 } 0147 return tHead(); 0148 } 0149 0150 void HTMLTableElementImpl::deleteTHead() 0151 { 0152 if (ElementImpl *head = tHead()) { 0153 int exceptioncode = 0; 0154 removeChild(head, exceptioncode); 0155 } 0156 } 0157 0158 HTMLElementImpl *HTMLTableElementImpl::createTFoot() 0159 { 0160 if (!tFoot()) { 0161 int exceptioncode = 0; 0162 ElementImpl *foot = new HTMLTableSectionElementImpl(docPtr(), ID_TFOOT, true /*implicit */); 0163 if (ElementImpl *firstBody = tFirstBody()) { 0164 insertBefore(foot, firstBody, exceptioncode); 0165 } else { 0166 appendChild(foot, exceptioncode); 0167 } 0168 } 0169 return tFoot(); 0170 } 0171 0172 void HTMLTableElementImpl::deleteTFoot() 0173 { 0174 if (ElementImpl *foot = tFoot()) { 0175 int exceptioncode = 0; 0176 removeChild(foot, exceptioncode); 0177 } 0178 } 0179 0180 HTMLElementImpl *HTMLTableElementImpl::createCaption() 0181 { 0182 if (!caption()) { 0183 int exceptioncode = 0; 0184 ElementImpl *tCaption = new HTMLTableCaptionElementImpl(docPtr()); 0185 insertBefore(tCaption, firstChild(), exceptioncode); 0186 } 0187 return caption(); 0188 } 0189 0190 void HTMLTableElementImpl::deleteCaption() 0191 { 0192 if (ElementImpl *tCaption = caption()) { 0193 int exceptioncode = 0; 0194 removeChild(tCaption, exceptioncode); 0195 } 0196 } 0197 0198 /** 0199 Helper. This checks whether the section contains the desired index, and if so, 0200 returns the section. Otherwise, it adjust the index, and returns 0. 0201 indices < 0 are considered to be infinite. 0202 0203 lastSection is adjusted to reflect the parameter passed in. 0204 */ 0205 static inline HTMLTableSectionElementImpl *processSection(HTMLTableSectionElementImpl *section, 0206 HTMLTableSectionElementImpl *&lastSection, long &index) 0207 { 0208 lastSection = section; 0209 if (index < 0) { //append/last mode 0210 return nullptr; 0211 } 0212 0213 long rows = section->numRows(); 0214 if (index >= rows) { 0215 section = nullptr; 0216 index -= rows; 0217 } 0218 return section; 0219 } 0220 0221 bool HTMLTableElementImpl::findRowSection(long index, 0222 HTMLTableSectionElementImpl *&outSection, 0223 long &outIndex) const 0224 { 0225 HTMLTableSectionElementImpl *foot = tFoot(); 0226 HTMLTableSectionElementImpl *head = tHead(); 0227 0228 HTMLTableSectionElementImpl *section = nullptr; 0229 HTMLTableSectionElementImpl *lastSection = nullptr; 0230 0231 if (head) { 0232 section = processSection(head, lastSection, index); 0233 } 0234 0235 if (!section) { 0236 for (NodeImpl *node = firstChild(); node; node = node->nextSibling()) { 0237 if ((node->id() == ID_THEAD || node->id() == ID_TFOOT || node->id() == ID_TBODY) && 0238 node != foot && node != head) { 0239 section = processSection(static_cast<HTMLTableSectionElementImpl *>(node), 0240 lastSection, index); 0241 if (section) { 0242 break; 0243 } 0244 } 0245 } 0246 } 0247 0248 if (!section && foot) { 0249 section = processSection(foot, lastSection, index); 0250 } 0251 0252 outIndex = index; 0253 if (section) { 0254 outSection = section; 0255 return true; 0256 } else { 0257 outSection = lastSection; 0258 return false; 0259 } 0260 } 0261 0262 HTMLElementImpl *HTMLTableElementImpl::insertRow(long index, int &exceptioncode) 0263 { 0264 // The DOM requires that we create a tbody if the table is empty 0265 // (cf DOM2TS HTMLTableElement31 test). This includes even the cases where 0266 // there are <tr>'s immediately under the table, as they're essentially 0267 // ignored by these functions. 0268 HTMLTableSectionElementImpl *foot = tFoot(); 0269 HTMLTableSectionElementImpl *head = tHead(); 0270 if (!tFirstBody() && !foot && !head) { 0271 setTBody(new HTMLTableSectionElementImpl(docPtr(), ID_TBODY, true /* implicit */)); 0272 } 0273 0274 //qCDebug(KHTML_LOG) << index; 0275 0276 long sectionIndex; 0277 HTMLTableSectionElementImpl *section; 0278 if (findRowSection(index, section, sectionIndex)) { 0279 return section->insertRow(sectionIndex, exceptioncode); 0280 } else if (index == -1 || sectionIndex == 0) { 0281 return section->insertRow(section->numRows(), exceptioncode); 0282 } 0283 0284 // The index is too big. 0285 exceptioncode = DOMException::INDEX_SIZE_ERR; 0286 return nullptr; 0287 } 0288 0289 void HTMLTableElementImpl::deleteRow(long index, int &exceptioncode) 0290 { 0291 long sectionIndex; 0292 HTMLTableSectionElementImpl *section; 0293 if (findRowSection(index, section, sectionIndex)) { 0294 section->deleteRow(sectionIndex, exceptioncode); 0295 } else if (section && index == -1) { 0296 section->deleteRow(-1, exceptioncode); 0297 } else { 0298 exceptioncode = DOMException::INDEX_SIZE_ERR; 0299 } 0300 } 0301 0302 NodeImpl *HTMLTableElementImpl::appendChild(NodeImpl *child, int &exceptioncode) 0303 { 0304 NodeImpl *retval = HTMLElementImpl::appendChild(child, exceptioncode); 0305 if (retval) { 0306 handleChildAppend(child); 0307 } 0308 return retval; 0309 } 0310 0311 void HTMLTableElementImpl::handleChildAdd(NodeImpl *child) 0312 { 0313 if (!child) { 0314 return; 0315 } 0316 switch (child->id()) { 0317 case ID_CAPTION: 0318 tCaption.childAdded(this, child); 0319 break; 0320 case ID_THEAD: 0321 head.childAdded(this, child); 0322 break; 0323 case ID_TFOOT: 0324 foot.childAdded(this, child); 0325 break; 0326 case ID_TBODY: 0327 firstBody.childAdded(this, child); 0328 break; 0329 } 0330 } 0331 0332 void HTMLTableElementImpl::handleChildAppend(NodeImpl *child) 0333 { 0334 if (!child) { 0335 return; 0336 } 0337 switch (child->id()) { 0338 case ID_CAPTION: 0339 tCaption.childAppended(child); 0340 break; 0341 case ID_THEAD: 0342 head.childAppended(child); 0343 break; 0344 case ID_TFOOT: 0345 foot.childAppended(child); 0346 break; 0347 case ID_TBODY: 0348 firstBody.childAppended(child); 0349 break; 0350 } 0351 } 0352 0353 void HTMLTableElementImpl::handleChildRemove(NodeImpl *child) 0354 { 0355 if (!child) { 0356 return; 0357 } 0358 switch (child->id()) { 0359 case ID_CAPTION: 0360 tCaption.childRemoved(this, child); 0361 break; 0362 case ID_THEAD: 0363 head.childRemoved(this, child); 0364 break; 0365 case ID_TFOOT: 0366 foot.childRemoved(this, child); 0367 break; 0368 case ID_TBODY: 0369 firstBody.childRemoved(this, child); 0370 break; 0371 } 0372 } 0373 0374 NodeImpl *HTMLTableElementImpl::addChild(NodeImpl *child) 0375 { 0376 #ifdef DEBUG_LAYOUT 0377 // qCDebug(KHTML_LOG) << nodeName().string() << "(Table)::addChild( " << child->nodeName().string() << " )"; 0378 #endif 0379 0380 NodeImpl *retval = HTMLElementImpl::addChild(child); 0381 if (retval) { 0382 handleChildAppend(child); 0383 } 0384 0385 return retval; 0386 } 0387 0388 NodeImpl *HTMLTableElementImpl::insertBefore(NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode) 0389 { 0390 NodeImpl *retval = HTMLElementImpl::insertBefore(newChild, refChild, exceptioncode); 0391 if (retval) { 0392 handleChildAdd(newChild); 0393 } 0394 0395 return retval; 0396 } 0397 0398 void HTMLTableElementImpl::replaceChild(NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode) 0399 { 0400 handleChildRemove(oldChild); //Always safe. 0401 HTMLElementImpl::replaceChild(newChild, oldChild, exceptioncode); 0402 if (!exceptioncode) { 0403 handleChildAdd(newChild); 0404 } 0405 } 0406 0407 void HTMLTableElementImpl::removeChild(NodeImpl *oldChild, int &exceptioncode) 0408 { 0409 handleChildRemove(oldChild); 0410 HTMLElementImpl::removeChild(oldChild, exceptioncode); 0411 } 0412 0413 void HTMLTableElementImpl::removeChildren() 0414 { 0415 HTMLElementImpl::removeChildren(); 0416 tCaption.clear(); 0417 head.clear(); 0418 foot.clear(); 0419 firstBody.clear(); 0420 } 0421 0422 static inline bool isTableCellAncestor(NodeImpl *n) 0423 { 0424 return n->id() == ID_THEAD || n->id() == ID_TBODY || 0425 n->id() == ID_TFOOT || n->id() == ID_TR; 0426 } 0427 0428 static bool setTableCellsChanged(NodeImpl *n) 0429 { 0430 assert(n); 0431 bool cellChanged = false; 0432 0433 if (n->id() == ID_TD || n->id() == ID_TH) { 0434 cellChanged = true; 0435 } else if (isTableCellAncestor(n)) { 0436 for (NodeImpl *child = n->firstChild(); child; child = child->nextSibling()) { 0437 cellChanged |= setTableCellsChanged(child); 0438 } 0439 } 0440 0441 if (cellChanged) { 0442 n->setChanged(); 0443 } 0444 0445 return cellChanged; 0446 } 0447 0448 void HTMLTableElementImpl::parseAttribute(AttributeImpl *attr) 0449 { 0450 // ### to CSS!! 0451 switch (attr->id()) { 0452 case ATTR_WIDTH: 0453 if (!attr->value().isEmpty()) { 0454 addCSSLength(CSS_PROP_WIDTH, attr->value()); 0455 } else { 0456 removeCSSProperty(CSS_PROP_WIDTH); 0457 } 0458 break; 0459 case ATTR_HEIGHT: 0460 if (!attr->value().isEmpty()) { 0461 addCSSLength(CSS_PROP_HEIGHT, attr->value()); 0462 } else { 0463 removeCSSProperty(CSS_PROP_HEIGHT); 0464 } 0465 break; 0466 case ATTR_BORDER: { 0467 int border; 0468 bool ok = true; 0469 // ### this needs more work, as the border value is not only 0470 // the border of the box, but also between the cells 0471 if (!attr->val()) { 0472 border = 0; 0473 } else if (attr->val()->l == 0) { 0474 border = 1; 0475 } else { 0476 border = attr->val()->toInt(&ok); 0477 } 0478 if (!ok) { 0479 border = 1; 0480 } 0481 #ifdef DEBUG_DRAW_BORDER 0482 border = 1; 0483 #endif 0484 DOMString v = QString::number(border); 0485 addCSSLength(CSS_PROP_BORDER_WIDTH, v); 0486 0487 attr->rewriteValue(v); 0488 0489 // wanted by HTML4 specs 0490 if (!border) { 0491 frame = Void, rules = None; 0492 } else { 0493 frame = Box, rules = All; 0494 } 0495 0496 if (attached()) { 0497 updateFrame(); 0498 if (tFirstBody()) { 0499 setTableCellsChanged(tFirstBody()); 0500 } 0501 } 0502 break; 0503 } 0504 case ATTR_BGCOLOR: 0505 if (!attr->value().isEmpty()) { 0506 addHTMLColor(CSS_PROP_BACKGROUND_COLOR, attr->value()); 0507 } else { 0508 removeCSSProperty(CSS_PROP_BACKGROUND_COLOR); 0509 } 0510 break; 0511 case ATTR_BORDERCOLOR: 0512 if (!attr->value().isEmpty()) { 0513 addHTMLColor(CSS_PROP_BORDER_COLOR, attr->value()); 0514 m_solid = true; 0515 } 0516 0517 if (attached()) { 0518 updateFrame(); 0519 } 0520 break; 0521 case ATTR_BACKGROUND: { 0522 QString url = attr->value().trimSpaces().string(); 0523 if (!url.isEmpty()) { 0524 url = document()->completeURL(url); 0525 addCSSProperty(CSS_PROP_BACKGROUND_IMAGE, DOMString("url('" + url + "')")); 0526 } else { 0527 removeCSSProperty(CSS_PROP_BACKGROUND_IMAGE); 0528 } 0529 break; 0530 } 0531 case ATTR_FRAME: 0532 0533 if (strcasecmp(attr->value(), "void") == 0) { 0534 frame = Void; 0535 } else if (strcasecmp(attr->value(), "border") == 0) { 0536 frame = Box; 0537 } else if (strcasecmp(attr->value(), "box") == 0) { 0538 frame = Box; 0539 } else if (strcasecmp(attr->value(), "hsides") == 0) { 0540 frame = Hsides; 0541 } else if (strcasecmp(attr->value(), "vsides") == 0) { 0542 frame = Vsides; 0543 } else if (strcasecmp(attr->value(), "above") == 0) { 0544 frame = Above; 0545 } else if (strcasecmp(attr->value(), "below") == 0) { 0546 frame = Below; 0547 } else if (strcasecmp(attr->value(), "lhs") == 0) { 0548 frame = Lhs; 0549 } else if (strcasecmp(attr->value(), "rhs") == 0) { 0550 frame = Rhs; 0551 } 0552 0553 if (attached()) { 0554 updateFrame(); 0555 } 0556 break; 0557 case ATTR_RULES: 0558 if (strcasecmp(attr->value(), "none") == 0) { 0559 rules = None; 0560 } else if (strcasecmp(attr->value(), "groups") == 0) { 0561 rules = Groups; 0562 } else if (strcasecmp(attr->value(), "rows") == 0) { 0563 rules = Rows; 0564 } else if (strcasecmp(attr->value(), "cols") == 0) { 0565 rules = Cols; 0566 } else if (strcasecmp(attr->value(), "all") == 0) { 0567 rules = All; 0568 } 0569 0570 if (attached() && tFirstBody()) 0571 if (setTableCellsChanged(tFirstBody())) { 0572 setChanged(); 0573 } 0574 break; 0575 case ATTR_CELLSPACING: 0576 if (!attr->value().isEmpty()) { 0577 addCSSLength(CSS_PROP_BORDER_SPACING, attr->value(), true); 0578 } else { 0579 removeCSSProperty(CSS_PROP_BORDER_SPACING); 0580 } 0581 break; 0582 case ATTR_CELLPADDING: 0583 if (!attr->value().isEmpty()) { 0584 padding = qMax(0, attr->value().toInt()); 0585 } else { 0586 padding = 1; 0587 } 0588 if (m_render && m_render->isTable()) { 0589 static_cast<RenderTable *>(m_render)->setCellPadding(padding); 0590 if (!m_render->needsLayout()) { 0591 m_render->setNeedsLayout(true); 0592 } 0593 } 0594 break; 0595 case ATTR_COLS: { 0596 // ### 0597 #if 0 0598 int c; 0599 c = attr->val()->toInt(); 0600 addColumns(c - totalCols); 0601 #endif 0602 break; 0603 0604 } 0605 case ATTR_ALIGN: 0606 setChanged(); 0607 break; 0608 case ATTR_VALIGN: 0609 if (!attr->value().isEmpty()) { 0610 addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower()); 0611 } else { 0612 removeCSSProperty(CSS_PROP_VERTICAL_ALIGN); 0613 } 0614 break; 0615 case ATTR_NOSAVE: 0616 break; 0617 default: 0618 HTMLElementImpl::parseAttribute(attr); 0619 } 0620 } 0621 0622 void HTMLTableElementImpl::attach() 0623 { 0624 updateFrame(); 0625 HTMLElementImpl::attach(); 0626 if (m_render && m_render->isTable()) { 0627 static_cast<RenderTable *>(m_render)->setCellPadding(padding); 0628 } 0629 } 0630 0631 void HTMLTableElementImpl::close() 0632 { 0633 ElementImpl *firstBody = tFirstBody(); 0634 if (firstBody && !firstBody->closed()) { 0635 firstBody->close(); 0636 } 0637 HTMLElementImpl::close(); 0638 } 0639 0640 void HTMLTableElementImpl::updateFrame() 0641 { 0642 int v = m_solid ? CSS_VAL_SOLID : CSS_VAL_OUTSET; 0643 if (frame & Above) { 0644 addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, v); 0645 } else { 0646 addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_NONE); 0647 } 0648 if (frame & Below) { 0649 addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, v); 0650 } else { 0651 addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_NONE); 0652 } 0653 if (frame & Lhs) { 0654 addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, v); 0655 } else { 0656 addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_NONE); 0657 } 0658 if (frame & Rhs) { 0659 addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, v); 0660 } else { 0661 addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_NONE); 0662 } 0663 } 0664 0665 // -------------------------------------------------------------------------- 0666 0667 void HTMLTablePartElementImpl::parseAttribute(AttributeImpl *attr) 0668 { 0669 switch (attr->id()) { 0670 case ATTR_BGCOLOR: 0671 if (attr->val()) { 0672 addHTMLColor(CSS_PROP_BACKGROUND_COLOR, attr->value()); 0673 } else { 0674 removeCSSProperty(CSS_PROP_BACKGROUND_COLOR); 0675 } 0676 break; 0677 case ATTR_BACKGROUND: { 0678 QString url = attr->value().trimSpaces().string(); 0679 if (!url.isEmpty()) { 0680 url = document()->completeURL(url); 0681 addCSSProperty(CSS_PROP_BACKGROUND_IMAGE, DOMString("url('" + url + "')")); 0682 } else { 0683 removeCSSProperty(CSS_PROP_BACKGROUND_IMAGE); 0684 } 0685 break; 0686 } 0687 case ATTR_BORDERCOLOR: { 0688 if (!attr->value().isEmpty()) { 0689 addHTMLColor(CSS_PROP_BORDER_COLOR, attr->value()); 0690 addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID); 0691 addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID); 0692 addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID); 0693 addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID); 0694 } 0695 break; 0696 } 0697 case ATTR_ALIGN: { 0698 DOMString v = attr->value(); 0699 if (strcasecmp(attr->value(), "middle") == 0 || strcasecmp(attr->value(), "center") == 0) { 0700 addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_CENTER); 0701 } else if (strcasecmp(attr->value(), "absmiddle") == 0) { 0702 addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL_CENTER); 0703 } else if (strcasecmp(attr->value(), "left") == 0) { 0704 addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_LEFT); 0705 } else if (strcasecmp(attr->value(), "right") == 0) { 0706 addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_RIGHT); 0707 } else { 0708 addCSSProperty(CSS_PROP_TEXT_ALIGN, v); 0709 } 0710 break; 0711 } 0712 case ATTR_VALIGN: { 0713 if (!attr->value().isEmpty()) { 0714 addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower()); 0715 } else { 0716 removeCSSProperty(CSS_PROP_VERTICAL_ALIGN); 0717 } 0718 break; 0719 } 0720 case ATTR_HEIGHT: 0721 if (!attr->value().isEmpty()) { 0722 addCSSLength(CSS_PROP_HEIGHT, attr->value()); 0723 } else { 0724 removeCSSProperty(CSS_PROP_HEIGHT); 0725 } 0726 break; 0727 case ATTR_NOSAVE: 0728 break; 0729 default: 0730 HTMLElementImpl::parseAttribute(attr); 0731 } 0732 } 0733 0734 // ------------------------------------------------------------------------- 0735 0736 HTMLTableSectionElementImpl::HTMLTableSectionElementImpl(DocumentImpl *doc, 0737 ushort tagid, bool implicit) 0738 : HTMLTablePartElementImpl(doc) 0739 { 0740 _id = tagid; 0741 m_implicit = implicit; 0742 } 0743 0744 HTMLTableSectionElementImpl::~HTMLTableSectionElementImpl() 0745 { 0746 } 0747 0748 NodeImpl::Id HTMLTableSectionElementImpl::id() const 0749 { 0750 return _id; 0751 } 0752 0753 // these functions are rather slow, since we need to get the row at 0754 // the index... but they aren't used during usual HTML parsing anyway 0755 HTMLElementImpl *HTMLTableSectionElementImpl::insertRow(long index, int &exceptioncode) 0756 { 0757 HTMLTableRowElementImpl *r = nullptr; 0758 HTMLCollectionImpl rows(const_cast<HTMLTableSectionElementImpl *>(this), HTMLCollectionImpl::TSECTION_ROWS); 0759 int numRows = rows.length(); 0760 //qCDebug(KHTML_LOG) << "index=" << index << " numRows=" << numRows; 0761 if (index < -1 || index > numRows) { 0762 exceptioncode = DOMException::INDEX_SIZE_ERR; // per the DOM 0763 } else { 0764 r = new HTMLTableRowElementImpl(docPtr()); 0765 if (numRows == index || index == -1) { 0766 appendChild(r, exceptioncode); 0767 } else { 0768 NodeImpl *n; 0769 if (index < 1) { 0770 n = firstChild(); 0771 } else { 0772 n = rows.item(index); 0773 } 0774 insertBefore(r, n, exceptioncode); 0775 } 0776 } 0777 return r; 0778 } 0779 0780 void HTMLTableSectionElementImpl::deleteRow(long index, int &exceptioncode) 0781 { 0782 HTMLCollectionImpl rows(const_cast<HTMLTableSectionElementImpl *>(this), HTMLCollectionImpl::TSECTION_ROWS); 0783 int numRows = rows.length(); 0784 if (index == -1) { 0785 index = numRows - 1; 0786 } 0787 if (index >= 0 && index < numRows) { 0788 HTMLElementImpl::removeChild(rows.item(index), exceptioncode); 0789 } else { 0790 exceptioncode = DOMException::INDEX_SIZE_ERR; 0791 } 0792 } 0793 0794 int HTMLTableSectionElementImpl::numRows() const 0795 { 0796 HTMLCollectionImpl rows(const_cast<HTMLTableSectionElementImpl *>(this), HTMLCollectionImpl::TSECTION_ROWS); 0797 return rows.length(); 0798 } 0799 0800 // ------------------------------------------------------------------------- 0801 0802 NodeImpl::Id HTMLTableRowElementImpl::id() const 0803 { 0804 return ID_TR; 0805 } 0806 0807 long HTMLTableRowElementImpl::rowIndex() const 0808 { 0809 int rIndex = 0; 0810 0811 NodeImpl *table = parentNode(); 0812 if (!table) { 0813 return -1; 0814 } 0815 table = table->parentNode(); 0816 if (!table || table->id() != ID_TABLE) { 0817 return -1; 0818 } 0819 0820 HTMLTableSectionElementImpl *head = static_cast<HTMLTableElementImpl *>(table)->tHead(); 0821 HTMLTableSectionElementImpl *foot = static_cast<HTMLTableElementImpl *>(table)->tFoot(); 0822 0823 if (head) { 0824 const NodeImpl *row = head->firstChild(); 0825 while (row) { 0826 if (row == this) { 0827 return rIndex; 0828 } 0829 if (row->id() == ID_TR) { 0830 rIndex++; 0831 } 0832 row = row->nextSibling(); 0833 } 0834 } 0835 0836 NodeImpl *node = table->firstChild(); 0837 while (node) { 0838 if (node != foot && node != head && (node->id() == ID_THEAD || node->id() == ID_TFOOT || node->id() == ID_TBODY)) { 0839 HTMLTableSectionElementImpl *section = static_cast<HTMLTableSectionElementImpl *>(node); 0840 const NodeImpl *row = section->firstChild(); 0841 while (row) { 0842 if (row == this) { 0843 return rIndex; 0844 } 0845 if (row->id() == ID_TR) { 0846 rIndex++; 0847 } 0848 row = row->nextSibling(); 0849 } 0850 } 0851 node = node->nextSibling(); 0852 } 0853 const NodeImpl *row = foot->firstChild(); 0854 while (row) { 0855 if (row == this) { 0856 return rIndex; 0857 } 0858 if (row->id() == ID_TR) { 0859 rIndex++; 0860 } 0861 row = row->nextSibling(); 0862 } 0863 // should never happen 0864 return -1; 0865 } 0866 0867 long HTMLTableRowElementImpl::sectionRowIndex() const 0868 { 0869 int rIndex = 0; 0870 const NodeImpl *n = this; 0871 do { 0872 n = n->previousSibling(); 0873 if (n && n->id() == ID_TR) { 0874 rIndex++; 0875 } 0876 } while (n); 0877 0878 return rIndex; 0879 } 0880 0881 HTMLElementImpl *HTMLTableRowElementImpl::insertCell(long index, int &exceptioncode) 0882 { 0883 HTMLTableCellElementImpl *c = nullptr; 0884 HTMLCollectionImpl children(const_cast<HTMLTableRowElementImpl *>(this), HTMLCollectionImpl::TR_CELLS); 0885 int numCells = children.length(); 0886 if (index < -1 || index > numCells) { 0887 exceptioncode = DOMException::INDEX_SIZE_ERR; // per the DOM 0888 } else { 0889 c = new HTMLTableCellElementImpl(docPtr(), ID_TD); 0890 if (numCells == index || index == -1) { 0891 appendChild(c, exceptioncode); 0892 } else { 0893 NodeImpl *n; 0894 if (index < 1) { 0895 n = firstChild(); 0896 } else { 0897 n = children.item(index); 0898 } 0899 insertBefore(c, n, exceptioncode); 0900 } 0901 } 0902 return c; 0903 } 0904 0905 void HTMLTableRowElementImpl::deleteCell(long index, int &exceptioncode) 0906 { 0907 HTMLCollectionImpl children(const_cast<HTMLTableRowElementImpl *>(this), HTMLCollectionImpl::TR_CELLS); 0908 int numCells = children.length(); 0909 if (index == -1) { 0910 index = numCells - 1; 0911 } 0912 if (index >= 0 && index < numCells) { 0913 HTMLElementImpl::removeChild(children.item(index), exceptioncode); 0914 } else { 0915 exceptioncode = DOMException::INDEX_SIZE_ERR; 0916 } 0917 } 0918 0919 // ------------------------------------------------------------------------- 0920 0921 HTMLTableCellElementImpl::HTMLTableCellElementImpl(DocumentImpl *doc, int tag) 0922 : HTMLTablePartElementImpl(doc) 0923 { 0924 _col = -1; 0925 _row = -1; 0926 cSpan = rSpan = 1; 0927 _id = tag; 0928 rowHeight = 0; 0929 m_solid = false; 0930 } 0931 0932 HTMLTableCellElementImpl::~HTMLTableCellElementImpl() 0933 { 0934 } 0935 0936 long HTMLTableCellElementImpl::cellIndex() const 0937 { 0938 int index = 0; 0939 for (const NodeImpl *node = previousSibling(); node; node = node->previousSibling()) { 0940 if (node->id() == ID_TD || node->id() == ID_TH) { 0941 index++; 0942 } 0943 } 0944 0945 return index; 0946 } 0947 0948 void HTMLTableCellElementImpl::parseAttribute(AttributeImpl *attr) 0949 { 0950 switch (attr->id()) { 0951 case ATTR_BORDER: 0952 // euhm? not supported by other browsers as far as I can see (Dirk) 0953 //addCSSLength(CSS_PROP_BORDER_WIDTH, attr->value()); 0954 break; 0955 case ATTR_ROWSPAN: { 0956 bool Ok = true; 0957 rSpan = attr->val() ? attr->val()->toInt(&Ok) : 1; 0958 // limit this to something not causing an overflow with short int 0959 if (rSpan < 0 || rSpan > 1024 || !Ok || (!rSpan && document()->inCompatMode())) { 0960 rSpan = 1; 0961 } 0962 if (renderer()) { 0963 renderer()->updateFromElement(); 0964 } 0965 break; 0966 } 0967 case ATTR_COLSPAN: { 0968 bool Ok = true; 0969 cSpan = attr->val() ? attr->val()->toInt(&Ok) : 1; 0970 // limit this to something not causing an overflow with short int 0971 if (cSpan < 0 || cSpan > 1024 || !Ok || (!cSpan && document()->inCompatMode())) { 0972 cSpan = 1; 0973 } 0974 if (renderer()) { 0975 renderer()->updateFromElement(); 0976 } 0977 break; 0978 } 0979 case ATTR_NOWRAP: 0980 if (attr->val() != nullptr) { 0981 addCSSProperty(CSS_PROP_WHITE_SPACE, CSS_VAL__KHTML_NOWRAP); 0982 } else { 0983 removeCSSProperty(CSS_PROP_WHITE_SPACE); 0984 } 0985 break; 0986 case ATTR_WIDTH: 0987 if (!attr->value().isEmpty()) { 0988 addCSSLength(CSS_PROP_WIDTH, attr->value()); 0989 } else { 0990 removeCSSProperty(CSS_PROP_WIDTH); 0991 } 0992 break; 0993 case ATTR_NOSAVE: 0994 break; 0995 default: 0996 HTMLTablePartElementImpl::parseAttribute(attr); 0997 } 0998 } 0999 1000 void HTMLTableCellElementImpl::attach() 1001 { 1002 HTMLTablePartElementImpl::attach(); 1003 } 1004 1005 // ------------------------------------------------------------------------- 1006 1007 HTMLTableColElementImpl::HTMLTableColElementImpl(DocumentImpl *doc, ushort i) 1008 : HTMLTablePartElementImpl(doc) 1009 { 1010 _id = i; 1011 _span = 1; 1012 } 1013 1014 NodeImpl::Id HTMLTableColElementImpl::id() const 1015 { 1016 return _id; 1017 } 1018 1019 void HTMLTableColElementImpl::parseAttribute(AttributeImpl *attr) 1020 { 1021 switch (attr->id()) { 1022 case ATTR_SPAN: 1023 _span = attr->val() ? attr->val()->toInt() : 1; 1024 if (_span < 1) { 1025 _span = 1; 1026 } 1027 break; 1028 case ATTR_WIDTH: 1029 if (!attr->value().isEmpty()) { 1030 addCSSLength(CSS_PROP_WIDTH, attr->value(), false, true); 1031 } else { 1032 removeCSSProperty(CSS_PROP_WIDTH); 1033 } 1034 break; 1035 case ATTR_VALIGN: 1036 if (!attr->value().isEmpty()) { 1037 addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower()); 1038 } else { 1039 removeCSSProperty(CSS_PROP_VERTICAL_ALIGN); 1040 } 1041 break; 1042 default: 1043 HTMLTablePartElementImpl::parseAttribute(attr); 1044 } 1045 1046 } 1047 1048 // ------------------------------------------------------------------------- 1049 1050 NodeImpl::Id HTMLTableCaptionElementImpl::id() const 1051 { 1052 return ID_CAPTION; 1053 } 1054 1055 void HTMLTableCaptionElementImpl::parseAttribute(AttributeImpl *attr) 1056 { 1057 switch (attr->id()) { 1058 case ATTR_ALIGN: 1059 if (!attr->value().isEmpty()) { 1060 addCSSProperty(CSS_PROP_CAPTION_SIDE, attr->value().lower()); 1061 } else { 1062 removeCSSProperty(CSS_PROP_CAPTION_SIDE); 1063 } 1064 break; 1065 default: 1066 HTMLElementImpl::parseAttribute(attr); 1067 } 1068 1069 }