KHtml

html_tableimpl.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1997 Martin Jones ([email protected])
5  * (C) 1997 Torben Weis ([email protected])
6  * (C) 1998 Waldo Bastian ([email protected])
7  * (C) 1999-2003 Lars Knoll ([email protected])
8  * (C) 1999 Antti Koivisto ([email protected])
9  * (C) 2003 Apple Computer, Inc.
10  * (C) 2006 Maksim Orlovich ([email protected])
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB. If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27 
28 #include "html_tableimpl.h"
29 
30 #include "html_documentimpl.h"
31 
32 #include <dom/dom_exception.h>
33 #include <dom/dom_node.h>
34 
35 #include <khtmlview.h>
36 #include <khtml_part.h>
37 
38 #include <css/cssstyleselector.h>
39 #include <css/cssproperties.h>
40 #include <css/cssvalues.h>
41 
42 #include <rendering/render_table.h>
43 
44 #include "khtml_debug.h"
45 
46 using namespace khtml;
47 using namespace DOM;
48 
49 HTMLTableElementImpl::HTMLTableElementImpl(DocumentImpl *doc)
50  : HTMLElementImpl(doc)
51 {
52  rules = None;
53  frame = Void;
54 
55  padding = 1;
56 
57  m_solid = false;
58 }
59 
60 HTMLTableElementImpl::~HTMLTableElementImpl()
61 {
62 }
63 
64 NodeImpl::Id HTMLTableElementImpl::id() const
65 {
66  return ID_TABLE;
67 }
68 
69 NodeImpl *HTMLTableElementImpl::setCaption(HTMLTableCaptionElementImpl *c)
70 {
71  int exceptioncode = 0;
72  NodeImpl *r;
73  if (ElementImpl *cap = caption()) {
74  replaceChild(c, cap, exceptioncode);
75  r = c;
76  } else {
77  r = insertBefore(c, firstChild(), exceptioncode);
78  }
79  tCaption = c;
80  return r;
81 }
82 
83 NodeImpl *HTMLTableElementImpl::setTHead(HTMLTableSectionElementImpl *s)
84 {
85  int exceptioncode = 0;
86  NodeImpl *r;
87  if (ElementImpl *head = tHead()) {
88  replaceChild(s, head, exceptioncode);
89  r = s;
90  } else if (ElementImpl *foot = tFoot()) {
91  r = insertBefore(s, foot, exceptioncode);
92  } else if (ElementImpl *firstBody = tFirstBody()) {
93  r = insertBefore(s, firstBody, exceptioncode);
94  } else {
95  r = appendChild(s, exceptioncode);
96  }
97 
98  head = s;
99  return r;
100 }
101 
102 NodeImpl *HTMLTableElementImpl::setTFoot(HTMLTableSectionElementImpl *s)
103 {
104  int exceptioncode = 0;
105  NodeImpl *r;
106  if (ElementImpl *foot = tFoot()) {
107  replaceChild(s, foot, exceptioncode);
108  r = s;
109  } else if (ElementImpl *firstBody = tFirstBody()) {
110  r = insertBefore(s, firstBody, exceptioncode);
111  } else {
112  r = appendChild(s, exceptioncode);
113  }
114  foot = s;
115  return r;
116 }
117 
118 NodeImpl *HTMLTableElementImpl::setTBody(HTMLTableSectionElementImpl *s)
119 {
120  int exceptioncode = 0;
121  NodeImpl *r;
122 
123  if (ElementImpl *firstBody = tFirstBody()) {
124  replaceChild(s, firstBody, exceptioncode);
125  r = s;
126  } else {
127  r = appendChild(s, exceptioncode);
128  }
129  firstBody = s;
130 
131  return r;
132 }
133 
134 HTMLElementImpl *HTMLTableElementImpl::createTHead()
135 {
136  if (!tHead()) {
137  int exceptioncode = 0;
138  ElementImpl *head = new HTMLTableSectionElementImpl(docPtr(), ID_THEAD, true /* implicit */);
139  if (ElementImpl *foot = tFoot()) {
140  insertBefore(head, foot, exceptioncode);
141  } else if (ElementImpl *firstBody = tFirstBody()) {
142  insertBefore(head, firstBody, exceptioncode);
143  } else {
144  appendChild(head, exceptioncode);
145  }
146  }
147  return tHead();
148 }
149 
150 void HTMLTableElementImpl::deleteTHead()
151 {
152  if (ElementImpl *head = tHead()) {
153  int exceptioncode = 0;
154  removeChild(head, exceptioncode);
155  }
156 }
157 
158 HTMLElementImpl *HTMLTableElementImpl::createTFoot()
159 {
160  if (!tFoot()) {
161  int exceptioncode = 0;
162  ElementImpl *foot = new HTMLTableSectionElementImpl(docPtr(), ID_TFOOT, true /*implicit */);
163  if (ElementImpl *firstBody = tFirstBody()) {
164  insertBefore(foot, firstBody, exceptioncode);
165  } else {
166  appendChild(foot, exceptioncode);
167  }
168  }
169  return tFoot();
170 }
171 
172 void HTMLTableElementImpl::deleteTFoot()
173 {
174  if (ElementImpl *foot = tFoot()) {
175  int exceptioncode = 0;
176  removeChild(foot, exceptioncode);
177  }
178 }
179 
180 HTMLElementImpl *HTMLTableElementImpl::createCaption()
181 {
182  if (!caption()) {
183  int exceptioncode = 0;
184  ElementImpl *tCaption = new HTMLTableCaptionElementImpl(docPtr());
185  insertBefore(tCaption, firstChild(), exceptioncode);
186  }
187  return caption();
188 }
189 
190 void HTMLTableElementImpl::deleteCaption()
191 {
192  if (ElementImpl *tCaption = caption()) {
193  int exceptioncode = 0;
194  removeChild(tCaption, exceptioncode);
195  }
196 }
197 
198 /**
199  Helper. This checks whether the section contains the desired index, and if so,
200  returns the section. Otherwise, it adjust the index, and returns 0.
201  indices < 0 are considered to be infinite.
202 
203  lastSection is adjusted to reflect the parameter passed in.
204 */
205 static inline HTMLTableSectionElementImpl *processSection(HTMLTableSectionElementImpl *section,
206  HTMLTableSectionElementImpl *&lastSection, long &index)
207 {
208  lastSection = section;
209  if (index < 0) { //append/last mode
210  return nullptr;
211  }
212 
213  long rows = section->numRows();
214  if (index >= rows) {
215  section = nullptr;
216  index -= rows;
217  }
218  return section;
219 }
220 
221 bool HTMLTableElementImpl::findRowSection(long index,
222  HTMLTableSectionElementImpl *&outSection,
223  long &outIndex) const
224 {
225  HTMLTableSectionElementImpl *foot = tFoot();
226  HTMLTableSectionElementImpl *head = tHead();
227 
228  HTMLTableSectionElementImpl *section = nullptr;
229  HTMLTableSectionElementImpl *lastSection = nullptr;
230 
231  if (head) {
232  section = processSection(head, lastSection, index);
233  }
234 
235  if (!section) {
236  for (NodeImpl *node = firstChild(); node; node = node->nextSibling()) {
237  if ((node->id() == ID_THEAD || node->id() == ID_TFOOT || node->id() == ID_TBODY) &&
238  node != foot && node != head) {
239  section = processSection(static_cast<HTMLTableSectionElementImpl *>(node),
240  lastSection, index);
241  if (section) {
242  break;
243  }
244  }
245  }
246  }
247 
248  if (!section && foot) {
249  section = processSection(foot, lastSection, index);
250  }
251 
252  outIndex = index;
253  if (section) {
254  outSection = section;
255  return true;
256  } else {
257  outSection = lastSection;
258  return false;
259  }
260 }
261 
262 HTMLElementImpl *HTMLTableElementImpl::insertRow(long index, int &exceptioncode)
263 {
264  // The DOM requires that we create a tbody if the table is empty
265  // (cf DOM2TS HTMLTableElement31 test). This includes even the cases where
266  // there are <tr>'s immediately under the table, as they're essentially
267  // ignored by these functions.
268  HTMLTableSectionElementImpl *foot = tFoot();
269  HTMLTableSectionElementImpl *head = tHead();
270  if (!tFirstBody() && !foot && !head) {
271  setTBody(new HTMLTableSectionElementImpl(docPtr(), ID_TBODY, true /* implicit */));
272  }
273 
274  //qCDebug(KHTML_LOG) << index;
275 
276  long sectionIndex;
277  HTMLTableSectionElementImpl *section;
278  if (findRowSection(index, section, sectionIndex)) {
279  return section->insertRow(sectionIndex, exceptioncode);
280  } else if (index == -1 || sectionIndex == 0) {
281  return section->insertRow(section->numRows(), exceptioncode);
282  }
283 
284  // The index is too big.
285  exceptioncode = DOMException::INDEX_SIZE_ERR;
286  return nullptr;
287 }
288 
289 void HTMLTableElementImpl::deleteRow(long index, int &exceptioncode)
290 {
291  long sectionIndex;
292  HTMLTableSectionElementImpl *section;
293  if (findRowSection(index, section, sectionIndex)) {
294  section->deleteRow(sectionIndex, exceptioncode);
295  } else if (section && index == -1) {
296  section->deleteRow(-1, exceptioncode);
297  } else {
298  exceptioncode = DOMException::INDEX_SIZE_ERR;
299  }
300 }
301 
302 NodeImpl *HTMLTableElementImpl::appendChild(NodeImpl *child, int &exceptioncode)
303 {
304  NodeImpl *retval = HTMLElementImpl::appendChild(child, exceptioncode);
305  if (retval) {
306  handleChildAppend(child);
307  }
308  return retval;
309 }
310 
311 void HTMLTableElementImpl::handleChildAdd(NodeImpl *child)
312 {
313  if (!child) {
314  return;
315  }
316  switch (child->id()) {
317  case ID_CAPTION:
318  tCaption.childAdded(this, child);
319  break;
320  case ID_THEAD:
321  head.childAdded(this, child);
322  break;
323  case ID_TFOOT:
324  foot.childAdded(this, child);
325  break;
326  case ID_TBODY:
327  firstBody.childAdded(this, child);
328  break;
329  }
330 }
331 
332 void HTMLTableElementImpl::handleChildAppend(NodeImpl *child)
333 {
334  if (!child) {
335  return;
336  }
337  switch (child->id()) {
338  case ID_CAPTION:
339  tCaption.childAppended(child);
340  break;
341  case ID_THEAD:
342  head.childAppended(child);
343  break;
344  case ID_TFOOT:
345  foot.childAppended(child);
346  break;
347  case ID_TBODY:
348  firstBody.childAppended(child);
349  break;
350  }
351 }
352 
353 void HTMLTableElementImpl::handleChildRemove(NodeImpl *child)
354 {
355  if (!child) {
356  return;
357  }
358  switch (child->id()) {
359  case ID_CAPTION:
360  tCaption.childRemoved(this, child);
361  break;
362  case ID_THEAD:
363  head.childRemoved(this, child);
364  break;
365  case ID_TFOOT:
366  foot.childRemoved(this, child);
367  break;
368  case ID_TBODY:
369  firstBody.childRemoved(this, child);
370  break;
371  }
372 }
373 
374 NodeImpl *HTMLTableElementImpl::addChild(NodeImpl *child)
375 {
376 #ifdef DEBUG_LAYOUT
377  // qCDebug(KHTML_LOG) << nodeName().string() << "(Table)::addChild( " << child->nodeName().string() << " )";
378 #endif
379 
380  NodeImpl *retval = HTMLElementImpl::addChild(child);
381  if (retval) {
382  handleChildAppend(child);
383  }
384 
385  return retval;
386 }
387 
388 NodeImpl *HTMLTableElementImpl::insertBefore(NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode)
389 {
390  NodeImpl *retval = HTMLElementImpl::insertBefore(newChild, refChild, exceptioncode);
391  if (retval) {
392  handleChildAdd(newChild);
393  }
394 
395  return retval;
396 }
397 
398 void HTMLTableElementImpl::replaceChild(NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode)
399 {
400  handleChildRemove(oldChild); //Always safe.
401  HTMLElementImpl::replaceChild(newChild, oldChild, exceptioncode);
402  if (!exceptioncode) {
403  handleChildAdd(newChild);
404  }
405 }
406 
407 void HTMLTableElementImpl::removeChild(NodeImpl *oldChild, int &exceptioncode)
408 {
409  handleChildRemove(oldChild);
410  HTMLElementImpl::removeChild(oldChild, exceptioncode);
411 }
412 
413 void HTMLTableElementImpl::removeChildren()
414 {
415  HTMLElementImpl::removeChildren();
416  tCaption.clear();
417  head.clear();
418  foot.clear();
419  firstBody.clear();
420 }
421 
422 static inline bool isTableCellAncestor(NodeImpl *n)
423 {
424  return n->id() == ID_THEAD || n->id() == ID_TBODY ||
425  n->id() == ID_TFOOT || n->id() == ID_TR;
426 }
427 
428 static bool setTableCellsChanged(NodeImpl *n)
429 {
430  assert(n);
431  bool cellChanged = false;
432 
433  if (n->id() == ID_TD || n->id() == ID_TH) {
434  cellChanged = true;
435  } else if (isTableCellAncestor(n)) {
436  for (NodeImpl *child = n->firstChild(); child; child = child->nextSibling()) {
437  cellChanged |= setTableCellsChanged(child);
438  }
439  }
440 
441  if (cellChanged) {
442  n->setChanged();
443  }
444 
445  return cellChanged;
446 }
447 
448 void HTMLTableElementImpl::parseAttribute(AttributeImpl *attr)
449 {
450  // ### to CSS!!
451  switch (attr->id()) {
452  case ATTR_WIDTH:
453  if (!attr->value().isEmpty()) {
454  addCSSLength(CSS_PROP_WIDTH, attr->value());
455  } else {
456  removeCSSProperty(CSS_PROP_WIDTH);
457  }
458  break;
459  case ATTR_HEIGHT:
460  if (!attr->value().isEmpty()) {
461  addCSSLength(CSS_PROP_HEIGHT, attr->value());
462  } else {
463  removeCSSProperty(CSS_PROP_HEIGHT);
464  }
465  break;
466  case ATTR_BORDER: {
467  int border;
468  bool ok = true;
469  // ### this needs more work, as the border value is not only
470  // the border of the box, but also between the cells
471  if (!attr->val()) {
472  border = 0;
473  } else if (attr->val()->l == 0) {
474  border = 1;
475  } else {
476  border = attr->val()->toInt(&ok);
477  }
478  if (!ok) {
479  border = 1;
480  }
481 #ifdef DEBUG_DRAW_BORDER
482  border = 1;
483 #endif
484  DOMString v = QString::number(border);
485  addCSSLength(CSS_PROP_BORDER_WIDTH, v);
486 
487  attr->rewriteValue(v);
488 
489  // wanted by HTML4 specs
490  if (!border) {
491  frame = Void, rules = None;
492  } else {
493  frame = Box, rules = All;
494  }
495 
496  if (attached()) {
497  updateFrame();
498  if (tFirstBody()) {
499  setTableCellsChanged(tFirstBody());
500  }
501  }
502  break;
503  }
504  case ATTR_BGCOLOR:
505  if (!attr->value().isEmpty()) {
506  addHTMLColor(CSS_PROP_BACKGROUND_COLOR, attr->value());
507  } else {
508  removeCSSProperty(CSS_PROP_BACKGROUND_COLOR);
509  }
510  break;
511  case ATTR_BORDERCOLOR:
512  if (!attr->value().isEmpty()) {
513  addHTMLColor(CSS_PROP_BORDER_COLOR, attr->value());
514  m_solid = true;
515  }
516 
517  if (attached()) {
518  updateFrame();
519  }
520  break;
521  case ATTR_BACKGROUND: {
522  QString url = attr->value().trimSpaces().string();
523  if (!url.isEmpty()) {
524  url = document()->completeURL(url);
525  addCSSProperty(CSS_PROP_BACKGROUND_IMAGE, DOMString("url('" + url + "')"));
526  } else {
527  removeCSSProperty(CSS_PROP_BACKGROUND_IMAGE);
528  }
529  break;
530  }
531  case ATTR_FRAME:
532 
533  if (strcasecmp(attr->value(), "void") == 0) {
534  frame = Void;
535  } else if (strcasecmp(attr->value(), "border") == 0) {
536  frame = Box;
537  } else if (strcasecmp(attr->value(), "box") == 0) {
538  frame = Box;
539  } else if (strcasecmp(attr->value(), "hsides") == 0) {
540  frame = Hsides;
541  } else if (strcasecmp(attr->value(), "vsides") == 0) {
542  frame = Vsides;
543  } else if (strcasecmp(attr->value(), "above") == 0) {
544  frame = Above;
545  } else if (strcasecmp(attr->value(), "below") == 0) {
546  frame = Below;
547  } else if (strcasecmp(attr->value(), "lhs") == 0) {
548  frame = Lhs;
549  } else if (strcasecmp(attr->value(), "rhs") == 0) {
550  frame = Rhs;
551  }
552 
553  if (attached()) {
554  updateFrame();
555  }
556  break;
557  case ATTR_RULES:
558  if (strcasecmp(attr->value(), "none") == 0) {
559  rules = None;
560  } else if (strcasecmp(attr->value(), "groups") == 0) {
561  rules = Groups;
562  } else if (strcasecmp(attr->value(), "rows") == 0) {
563  rules = Rows;
564  } else if (strcasecmp(attr->value(), "cols") == 0) {
565  rules = Cols;
566  } else if (strcasecmp(attr->value(), "all") == 0) {
567  rules = All;
568  }
569 
570  if (attached() && tFirstBody())
571  if (setTableCellsChanged(tFirstBody())) {
572  setChanged();
573  }
574  break;
575  case ATTR_CELLSPACING:
576  if (!attr->value().isEmpty()) {
577  addCSSLength(CSS_PROP_BORDER_SPACING, attr->value(), true);
578  } else {
579  removeCSSProperty(CSS_PROP_BORDER_SPACING);
580  }
581  break;
582  case ATTR_CELLPADDING:
583  if (!attr->value().isEmpty()) {
584  padding = qMax(0, attr->value().toInt());
585  } else {
586  padding = 1;
587  }
588  if (m_render && m_render->isTable()) {
589  static_cast<RenderTable *>(m_render)->setCellPadding(padding);
590  if (!m_render->needsLayout()) {
591  m_render->setNeedsLayout(true);
592  }
593  }
594  break;
595  case ATTR_COLS: {
596  // ###
597 #if 0
598  int c;
599  c = attr->val()->toInt();
600  addColumns(c - totalCols);
601 #endif
602  break;
603 
604  }
605  case ATTR_ALIGN:
606  setChanged();
607  break;
608  case ATTR_VALIGN:
609  if (!attr->value().isEmpty()) {
610  addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
611  } else {
612  removeCSSProperty(CSS_PROP_VERTICAL_ALIGN);
613  }
614  break;
615  case ATTR_NOSAVE:
616  break;
617  default:
618  HTMLElementImpl::parseAttribute(attr);
619  }
620 }
621 
622 void HTMLTableElementImpl::attach()
623 {
624  updateFrame();
625  HTMLElementImpl::attach();
626  if (m_render && m_render->isTable()) {
627  static_cast<RenderTable *>(m_render)->setCellPadding(padding);
628  }
629 }
630 
631 void HTMLTableElementImpl::close()
632 {
633  ElementImpl *firstBody = tFirstBody();
634  if (firstBody && !firstBody->closed()) {
635  firstBody->close();
636  }
637  HTMLElementImpl::close();
638 }
639 
640 void HTMLTableElementImpl::updateFrame()
641 {
642  int v = m_solid ? CSS_VAL_SOLID : CSS_VAL_OUTSET;
643  if (frame & Above) {
644  addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, v);
645  } else {
646  addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_NONE);
647  }
648  if (frame & Below) {
649  addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, v);
650  } else {
651  addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_NONE);
652  }
653  if (frame & Lhs) {
654  addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, v);
655  } else {
656  addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_NONE);
657  }
658  if (frame & Rhs) {
659  addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, v);
660  } else {
661  addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_NONE);
662  }
663 }
664 
665 // --------------------------------------------------------------------------
666 
667 void HTMLTablePartElementImpl::parseAttribute(AttributeImpl *attr)
668 {
669  switch (attr->id()) {
670  case ATTR_BGCOLOR:
671  if (attr->val()) {
672  addHTMLColor(CSS_PROP_BACKGROUND_COLOR, attr->value());
673  } else {
674  removeCSSProperty(CSS_PROP_BACKGROUND_COLOR);
675  }
676  break;
677  case ATTR_BACKGROUND: {
678  QString url = attr->value().trimSpaces().string();
679  if (!url.isEmpty()) {
680  url = document()->completeURL(url);
681  addCSSProperty(CSS_PROP_BACKGROUND_IMAGE, DOMString("url('" + url + "')"));
682  } else {
683  removeCSSProperty(CSS_PROP_BACKGROUND_IMAGE);
684  }
685  break;
686  }
687  case ATTR_BORDERCOLOR: {
688  if (!attr->value().isEmpty()) {
689  addHTMLColor(CSS_PROP_BORDER_COLOR, attr->value());
690  addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID);
691  addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID);
692  addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID);
693  addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID);
694  }
695  break;
696  }
697  case ATTR_ALIGN: {
698  DOMString v = attr->value();
699  if (strcasecmp(attr->value(), "middle") == 0 || strcasecmp(attr->value(), "center") == 0) {
700  addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_CENTER);
701  } else if (strcasecmp(attr->value(), "absmiddle") == 0) {
702  addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL_CENTER);
703  } else if (strcasecmp(attr->value(), "left") == 0) {
704  addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_LEFT);
705  } else if (strcasecmp(attr->value(), "right") == 0) {
706  addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_RIGHT);
707  } else {
708  addCSSProperty(CSS_PROP_TEXT_ALIGN, v);
709  }
710  break;
711  }
712  case ATTR_VALIGN: {
713  if (!attr->value().isEmpty()) {
714  addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
715  } else {
716  removeCSSProperty(CSS_PROP_VERTICAL_ALIGN);
717  }
718  break;
719  }
720  case ATTR_HEIGHT:
721  if (!attr->value().isEmpty()) {
722  addCSSLength(CSS_PROP_HEIGHT, attr->value());
723  } else {
724  removeCSSProperty(CSS_PROP_HEIGHT);
725  }
726  break;
727  case ATTR_NOSAVE:
728  break;
729  default:
730  HTMLElementImpl::parseAttribute(attr);
731  }
732 }
733 
734 // -------------------------------------------------------------------------
735 
736 HTMLTableSectionElementImpl::HTMLTableSectionElementImpl(DocumentImpl *doc,
737  ushort tagid, bool implicit)
738  : HTMLTablePartElementImpl(doc)
739 {
740  _id = tagid;
741  m_implicit = implicit;
742 }
743 
744 HTMLTableSectionElementImpl::~HTMLTableSectionElementImpl()
745 {
746 }
747 
748 NodeImpl::Id HTMLTableSectionElementImpl::id() const
749 {
750  return _id;
751 }
752 
753 // these functions are rather slow, since we need to get the row at
754 // the index... but they aren't used during usual HTML parsing anyway
755 HTMLElementImpl *HTMLTableSectionElementImpl::insertRow(long index, int &exceptioncode)
756 {
757  HTMLTableRowElementImpl *r = nullptr;
758  HTMLCollectionImpl rows(const_cast<HTMLTableSectionElementImpl *>(this), HTMLCollectionImpl::TSECTION_ROWS);
759  int numRows = rows.length();
760  //qCDebug(KHTML_LOG) << "index=" << index << " numRows=" << numRows;
761  if (index < -1 || index > numRows) {
762  exceptioncode = DOMException::INDEX_SIZE_ERR; // per the DOM
763  } else {
764  r = new HTMLTableRowElementImpl(docPtr());
765  if (numRows == index || index == -1) {
766  appendChild(r, exceptioncode);
767  } else {
768  NodeImpl *n;
769  if (index < 1) {
770  n = firstChild();
771  } else {
772  n = rows.item(index);
773  }
774  insertBefore(r, n, exceptioncode);
775  }
776  }
777  return r;
778 }
779 
780 void HTMLTableSectionElementImpl::deleteRow(long index, int &exceptioncode)
781 {
782  HTMLCollectionImpl rows(const_cast<HTMLTableSectionElementImpl *>(this), HTMLCollectionImpl::TSECTION_ROWS);
783  int numRows = rows.length();
784  if (index == -1) {
785  index = numRows - 1;
786  }
787  if (index >= 0 && index < numRows) {
788  HTMLElementImpl::removeChild(rows.item(index), exceptioncode);
789  } else {
790  exceptioncode = DOMException::INDEX_SIZE_ERR;
791  }
792 }
793 
794 int HTMLTableSectionElementImpl::numRows() const
795 {
796  HTMLCollectionImpl rows(const_cast<HTMLTableSectionElementImpl *>(this), HTMLCollectionImpl::TSECTION_ROWS);
797  return rows.length();
798 }
799 
800 // -------------------------------------------------------------------------
801 
802 NodeImpl::Id HTMLTableRowElementImpl::id() const
803 {
804  return ID_TR;
805 }
806 
807 long HTMLTableRowElementImpl::rowIndex() const
808 {
809  int rIndex = 0;
810 
811  NodeImpl *table = parentNode();
812  if (!table) {
813  return -1;
814  }
815  table = table->parentNode();
816  if (!table || table->id() != ID_TABLE) {
817  return -1;
818  }
819 
820  HTMLTableSectionElementImpl *head = static_cast<HTMLTableElementImpl *>(table)->tHead();
821  HTMLTableSectionElementImpl *foot = static_cast<HTMLTableElementImpl *>(table)->tFoot();
822 
823  if (head) {
824  const NodeImpl *row = head->firstChild();
825  while (row) {
826  if (row == this) {
827  return rIndex;
828  }
829  if (row->id() == ID_TR) {
830  rIndex++;
831  }
832  row = row->nextSibling();
833  }
834  }
835 
836  NodeImpl *node = table->firstChild();
837  while (node) {
838  if (node != foot && node != head && (node->id() == ID_THEAD || node->id() == ID_TFOOT || node->id() == ID_TBODY)) {
839  HTMLTableSectionElementImpl *section = static_cast<HTMLTableSectionElementImpl *>(node);
840  const NodeImpl *row = section->firstChild();
841  while (row) {
842  if (row == this) {
843  return rIndex;
844  }
845  if (row->id() == ID_TR) {
846  rIndex++;
847  }
848  row = row->nextSibling();
849  }
850  }
851  node = node->nextSibling();
852  }
853  const NodeImpl *row = foot->firstChild();
854  while (row) {
855  if (row == this) {
856  return rIndex;
857  }
858  if (row->id() == ID_TR) {
859  rIndex++;
860  }
861  row = row->nextSibling();
862  }
863  // should never happen
864  return -1;
865 }
866 
867 long HTMLTableRowElementImpl::sectionRowIndex() const
868 {
869  int rIndex = 0;
870  const NodeImpl *n = this;
871  do {
872  n = n->previousSibling();
873  if (n && n->id() == ID_TR) {
874  rIndex++;
875  }
876  } while (n);
877 
878  return rIndex;
879 }
880 
881 HTMLElementImpl *HTMLTableRowElementImpl::insertCell(long index, int &exceptioncode)
882 {
883  HTMLTableCellElementImpl *c = nullptr;
884  HTMLCollectionImpl children(const_cast<HTMLTableRowElementImpl *>(this), HTMLCollectionImpl::TR_CELLS);
885  int numCells = children.length();
886  if (index < -1 || index > numCells) {
887  exceptioncode = DOMException::INDEX_SIZE_ERR; // per the DOM
888  } else {
889  c = new HTMLTableCellElementImpl(docPtr(), ID_TD);
890  if (numCells == index || index == -1) {
891  appendChild(c, exceptioncode);
892  } else {
893  NodeImpl *n;
894  if (index < 1) {
895  n = firstChild();
896  } else {
897  n = children.item(index);
898  }
899  insertBefore(c, n, exceptioncode);
900  }
901  }
902  return c;
903 }
904 
905 void HTMLTableRowElementImpl::deleteCell(long index, int &exceptioncode)
906 {
907  HTMLCollectionImpl children(const_cast<HTMLTableRowElementImpl *>(this), HTMLCollectionImpl::TR_CELLS);
908  int numCells = children.length();
909  if (index == -1) {
910  index = numCells - 1;
911  }
912  if (index >= 0 && index < numCells) {
913  HTMLElementImpl::removeChild(children.item(index), exceptioncode);
914  } else {
915  exceptioncode = DOMException::INDEX_SIZE_ERR;
916  }
917 }
918 
919 // -------------------------------------------------------------------------
920 
921 HTMLTableCellElementImpl::HTMLTableCellElementImpl(DocumentImpl *doc, int tag)
922  : HTMLTablePartElementImpl(doc)
923 {
924  _col = -1;
925  _row = -1;
926  cSpan = rSpan = 1;
927  _id = tag;
928  rowHeight = 0;
929  m_solid = false;
930 }
931 
932 HTMLTableCellElementImpl::~HTMLTableCellElementImpl()
933 {
934 }
935 
936 long HTMLTableCellElementImpl::cellIndex() const
937 {
938  int index = 0;
939  for (const NodeImpl *node = previousSibling(); node; node = node->previousSibling()) {
940  if (node->id() == ID_TD || node->id() == ID_TH) {
941  index++;
942  }
943  }
944 
945  return index;
946 }
947 
948 void HTMLTableCellElementImpl::parseAttribute(AttributeImpl *attr)
949 {
950  switch (attr->id()) {
951  case ATTR_BORDER:
952  // euhm? not supported by other browsers as far as I can see (Dirk)
953  //addCSSLength(CSS_PROP_BORDER_WIDTH, attr->value());
954  break;
955  case ATTR_ROWSPAN: {
956  bool Ok = true;
957  rSpan = attr->val() ? attr->val()->toInt(&Ok) : 1;
958  // limit this to something not causing an overflow with short int
959  if (rSpan < 0 || rSpan > 1024 || !Ok || (!rSpan && document()->inCompatMode())) {
960  rSpan = 1;
961  }
962  if (renderer()) {
963  renderer()->updateFromElement();
964  }
965  break;
966  }
967  case ATTR_COLSPAN: {
968  bool Ok = true;
969  cSpan = attr->val() ? attr->val()->toInt(&Ok) : 1;
970  // limit this to something not causing an overflow with short int
971  if (cSpan < 0 || cSpan > 1024 || !Ok || (!cSpan && document()->inCompatMode())) {
972  cSpan = 1;
973  }
974  if (renderer()) {
975  renderer()->updateFromElement();
976  }
977  break;
978  }
979  case ATTR_NOWRAP:
980  if (attr->val() != nullptr) {
981  addCSSProperty(CSS_PROP_WHITE_SPACE, CSS_VAL__KHTML_NOWRAP);
982  } else {
983  removeCSSProperty(CSS_PROP_WHITE_SPACE);
984  }
985  break;
986  case ATTR_WIDTH:
987  if (!attr->value().isEmpty()) {
988  addCSSLength(CSS_PROP_WIDTH, attr->value());
989  } else {
990  removeCSSProperty(CSS_PROP_WIDTH);
991  }
992  break;
993  case ATTR_NOSAVE:
994  break;
995  default:
996  HTMLTablePartElementImpl::parseAttribute(attr);
997  }
998 }
999 
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 }
QString caption()
Node insertBefore(const Node &newChild, const Node &refChild)
Inserts the node newChild before the existing child node refChild .
Definition: dom_node.cpp:314
HTMLCollection rows() const
The collection of rows in this table section.
Node previousSibling() const
The node immediately preceding this node.
Definition: dom_node.cpp:282
Node appendChild(const Node &newChild)
Adds the node newChild to the end of the list of children of this node.
Definition: dom_node.cpp:354
This file is part of the HTML rendering engine for KDE.
unsigned long index() const
Definition: dom_node.cpp:517
Node replaceChild(const Node &newChild, const Node &oldChild)
Replaces the child node oldChild with newChild in the list of children, and returns the oldChild node...
Definition: dom_node.cpp:327
QString number(int n, int base)
Node parentNode() const
The parent of this node.
Definition: dom_node.cpp:250
bool isEmpty() const const
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
Node removeChild(const Node &oldChild)
Removes the child node indicated by oldChild from the list of children, and returns it...
Definition: dom_node.cpp:340
Node firstChild() const
The first child of this node.
Definition: dom_node.cpp:266
This library provides a full-featured HTML parser and widget.
unsigned long length() const
This attribute specifies the length or size of the list.
Definition: html_misc.cpp:171
Node item(unsigned long index) const
This method retrieves a node specified by ordinal index.
Definition: html_misc.cpp:179
Node nextSibling() const
The node immediately following this node.
Definition: dom_node.cpp:290
HTMLCollection children() const
Retrieves a collection of nodes that are direct descendants of this node.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:48:02 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.