KHtml

html_miscimpl.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll ([email protected])
5  * (C) 1999 Antti Koivisto ([email protected])
6  * (C) 2005 Maksim Orlovich ([email protected])
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB. If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24 // -------------------------------------------------------------------------
25 #include "html_miscimpl.h"
26 #include "html_tableimpl.h"
27 #include "html_formimpl.h"
28 #include "html_documentimpl.h"
29 
30 #include <dom/dom_node.h>
31 
32 using namespace DOM;
33 
34 #include "khtml_debug.h"
35 
36 HTMLBaseFontElementImpl::HTMLBaseFontElementImpl(DocumentImpl *doc)
37  : HTMLElementImpl(doc)
38 {
39 }
40 
41 HTMLBaseFontElementImpl::~HTMLBaseFontElementImpl()
42 {
43 }
44 
45 NodeImpl::Id HTMLBaseFontElementImpl::id() const
46 {
47  return ID_BASEFONT;
48 }
49 
50 // -------------------------------------------------------------------------
51 
52 struct CollectionCache: public DynamicNodeListImpl::Cache {
53  static Cache *make()
54  {
55  return new CollectionCache;
56  }
57 
59 
60  CollectionCache(): Cache(DocumentImpl::TV_IDNameHref) {}
61 
62  void clear(DocumentImpl *doc) override
63  {
64  Cache::clear(doc);
65  qDeleteAll(nameCache);
66  nameCache.clear();
67  }
68 
69  virtual ~CollectionCache()
70  {
71  qDeleteAll(nameCache);
72  }
73 };
74 
75 HTMLCollectionImpl::HTMLCollectionImpl(NodeImpl *_base, int _type):
76  DynamicNodeListImpl(_base, _type, CollectionCache::make)
77 {
78  type = _type;
79 }
80 
81 bool HTMLCollectionImpl::nodeMatches(NodeImpl *current, bool &deep) const
82 {
83  if (current->nodeType() != Node::ELEMENT_NODE) {
84  deep = false;
85  return false;
86  }
87 
88  bool check = false;
89  HTMLElementImpl *e = static_cast<HTMLElementImpl *>(current);
90  switch (type) {
91  case DOC_IMAGES:
92  if (e->id() == ID_IMG) {
93  check = true;
94  }
95  break;
96  case DOC_SCRIPTS:
97  if (e->id() == ID_SCRIPT) {
98  check = true;
99  }
100  break;
101  case DOC_FORMS:
102  if (e->id() == ID_FORM) {
103  check = true;
104  }
105  break;
106  case DOC_LAYERS:
107  if (e->id() == ID_LAYER || e->id() == ID_ILAYER) {
108  check = true;
109  }
110  break;
111  case TABLE_TBODIES:
112  if (e->id() == ID_TBODY) {
113  check = true;
114  } else if (e->id() == ID_TABLE) {
115  deep = false;
116  }
117  break;
118  case TR_CELLS:
119  if (e->id() == ID_TD || e->id() == ID_TH) {
120  check = true;
121  } else if (e->id() == ID_TABLE) {
122  deep = false;
123  }
124  break;
125  case TABLE_ROWS:
126  case TSECTION_ROWS:
127  if (e->id() == ID_TR) {
128  check = true;
129  } else if (e->id() == ID_TABLE) {
130  deep = false;
131  }
132  break;
133  case SELECT_OPTIONS:
134  if (e->id() == ID_OPTION) {
135  check = true;
136  }
137  break;
138  case MAP_AREAS:
139  if (e->id() == ID_AREA) {
140  check = true;
141  }
142  break;
143  case FORMLESS_INPUT:
144  if (e->id() == ID_INPUT && !static_cast<HTMLInputElementImpl *>(e)->form()) {
145  check = true;
146  }
147  break;
148  case DOC_APPLETS: // all OBJECT and APPLET elements
149  if (e->id() == ID_OBJECT || e->id() == ID_APPLET || e->id() == ID_EMBED) {
150  check = true;
151  }
152  break;
153  case DOC_LINKS: // all A _and_ AREA elements with a value for href
154  if (e->id() == ID_A || e->id() == ID_AREA)
155  if (!e->getAttribute(ATTR_HREF).isNull()) {
156  check = true;
157  }
158  break;
159  case DOC_ANCHORS: // all A elements with a value for name and/or id
160  if (e->id() == ID_A) {
161  if (e->hasID() || !e->getAttribute(ATTR_NAME).isNull()) {
162  check = true;
163  }
164  }
165  break;
166  case DOC_ALL: // "all" elements
167  check = true;
168  break;
169  case NODE_CHILDREN: // first-level children
170  check = true;
171  deep = false;
172  break;
173  default:
174  // qCDebug(KHTML_LOG) << "Error in HTMLCollection, wrong tagId!";
175  break;
176  }
177 
178  return check;
179 }
180 
181 bool HTMLCollectionImpl::checkForNameMatch(NodeImpl *node, const DOMString &name) const
182 {
183  if (node->nodeType() != Node::ELEMENT_NODE) {
184  return false;
185  }
186 
187  HTMLElementImpl *e = static_cast<HTMLElementImpl *>(node);
188 
189  //If ID matches, this is definitely a match
190  if (e->getAttribute(ATTR_ID) == name) {
191  return true;
192  }
193 
194  //Despite what the DOM spec says, neither IE nor Gecko actually
195  //care to prefer IDs. Instead, they just match everything
196  //that has ID or a name for nodes that have a name.
197  //Except for the form elements collection, Gecko always returns
198  //just one item. IE is more complex: its namedItem
199  //and call notation access return everything that matches,
200  //but the subscript notation is sometimes different.
201  //For now, we try to match IE, but without the subscript
202  //oddness, which I don't understand -- Maks.
203 
204  bool checkName;
205  switch (e->id()) {
206  case ID_A:
207  case ID_APPLET:
208  case ID_BUTTON:
209  case ID_EMBED:
210  case ID_FORM:
211  case ID_IMG:
212  case ID_INPUT:
213  case ID_MAP:
214  case ID_META:
215  case ID_OBJECT:
216  case ID_SELECT:
217  case ID_TEXTAREA:
218  case ID_FRAME:
219  case ID_IFRAME:
220  case ID_FRAMESET:
221  checkName = true;
222  break;
223  default:
224  checkName = false;
225  }
226 
227  if (checkName) {
228  return e->getAttribute(ATTR_NAME) == name;
229  } else {
230  return false;
231  }
232 }
233 
234 NodeImpl *HTMLCollectionImpl::item(unsigned long index) const
235 {
236  //Most of the time, we just go in normal document order
237  if (type != TABLE_ROWS) {
238  return DynamicNodeListImpl::item(index);
239  }
240 
241  //For table.rows, we first need to check header, then bodies, then footer.
242  //we pack any extra headers/footer with bodies. This matches IE, and
243  //means doing the usual thing with length is right
244  const HTMLTableElementImpl *table = static_cast<const HTMLTableElementImpl *>(m_refNode);
245 
246  long sectionIndex;
247  HTMLTableSectionElementImpl *section;
248 
249  NodeImpl *found = nullptr;
250  if (table->findRowSection(index, section, sectionIndex)) {
251  HTMLCollectionImpl rows(section, TSECTION_ROWS);
252  found = rows.item(sectionIndex);
253  }
254 
255  m_cache->current.node = found; //namedItem needs this.
256  m_cache->position = index;
257  return found;
258 }
259 
260 unsigned long HTMLCollectionImpl::calcLength(NodeImpl *start) const
261 {
262  if (type != TABLE_ROWS) {
263  return DynamicNodeListImpl::calcLength(start);
264  }
265 
266  unsigned length = 0;
267  const HTMLTableElementImpl *table = static_cast<const HTMLTableElementImpl *>(m_refNode);
268  for (NodeImpl *kid = table->firstChild(); kid; kid = kid->nextSibling()) {
269  HTMLCollectionImpl rows(kid, TSECTION_ROWS);
270  length += rows.length();
271  }
272  return length;
273 }
274 
275 NodeImpl *HTMLCollectionImpl::firstItem() const
276 {
277  return item(0);
278 }
279 
280 NodeImpl *HTMLCollectionImpl::nextItem() const
281 {
282  //### this assumes this is called immediately after nextItem --
283  //it this sane?
284  return item(m_cache->position + 1);
285 }
286 
287 NodeImpl *HTMLCollectionImpl::namedItem(const DOMString &name) const
288 {
289  if (name.isEmpty()) {
290  return nullptr;
291  }
292 
293  //Reset the position. The invariant is that nextNamedItem will start looking
294  //from the current position.
295  firstItem();
296 
297  return nextNamedItem(name);
298 }
299 
300 NodeImpl *HTMLCollectionImpl::nextNamedItem(const DOMString &name) const
301 {
302  if (name.isEmpty()) {
303  return nullptr;
304  }
305 
306  while (NodeImpl *candidate = m_cache->current.node) {
307  //Always advance, for next call
308  nextItem();
309  if (checkForNameMatch(candidate, name)) {
310  return candidate;
311  }
312  }
313  return nullptr;
314 }
315 
316 QList<NodeImpl *> HTMLCollectionImpl::namedItems(const DOMString &name) const
317 {
318  if (name.isEmpty()) {
319  return QList<NodeImpl *>();
320  }
321 
322  //We use a work-conserving design for the name cache presently -- only
323  //remember stuff about elements we were asked for.
324  m_cache->updateNodeListInfo(m_refNode->document());
325  CollectionCache *cache = static_cast<CollectionCache *>(m_cache);
326  if (QList<NodeImpl *> *info = cache->nameCache.value(name)) {
327  return *info;
328  } else {
329  QList<NodeImpl *> *newInfo = new QList<NodeImpl *>;
330 
331  NodeImpl *match = namedItem(name);
332  while (match) {
333  newInfo->append(match);
334  match = nextNamedItem(name);
335  }
336 
337  cache->nameCache.insertMulti(name, newInfo);
338  return *newInfo;
339  }
340 }
341 
342 // -----------------------------------------------------------------------------
343 
344 HTMLFormCollectionImpl::HTMLFormCollectionImpl(NodeImpl *_base)
345  : HTMLCollectionImpl(_base, FORM_ELEMENTS), currentNamePos(0), currentNameImgPos(0)
346 {}
347 
348 NodeImpl *HTMLFormCollectionImpl::item(unsigned long index) const
349 {
350  m_cache->updateNodeListInfo(m_refNode->document());
351 
352  unsigned int dist = index;
353  unsigned int strt = 0;
354  if (m_cache->current.index && m_cache->position <= index) {
355  dist = index - m_cache->position;
356  strt = m_cache->current.index;
357  }
358 
359  QList<HTMLGenericFormElementImpl *> &l = static_cast<HTMLFormElementImpl *>(m_refNode)->formElements;
360  for (unsigned i = strt; i < (unsigned)l.count(); i++) {
361  if (l.at(i)->isEnumerable()) {
362  if (dist == 0) {
363  //Found it!
364  m_cache->position = index;
365  m_cache->current.index = i;
366  return l.at(i);
367  } else {
368  --dist;
369  }
370  }
371  }
372  return nullptr;
373 }
374 
375 unsigned long HTMLFormCollectionImpl::calcLength(NodeImpl *start) const
376 {
377  Q_UNUSED(start);
378  unsigned length = 0;
379  QList<HTMLGenericFormElementImpl *> l = static_cast<HTMLFormElementImpl *>(m_refNode)->formElements;
380  for (unsigned i = 0; i < (unsigned)l.count(); i++)
381  if (l.at(i)->isEnumerable()) {
382  ++length;
383  }
384  return length;
385 }
386 
387 NodeImpl *HTMLFormCollectionImpl::namedItem(const DOMString &name) const
388 {
389  currentNamePos = 0;
390  currentNameImgPos = 0;
391  foundInput = false;
392  return nextNamedItem(name);
393 }
394 
395 NodeImpl *HTMLFormCollectionImpl::nextNamedItem(const DOMString &name) const
396 {
397  QList<HTMLGenericFormElementImpl *> &l = static_cast<HTMLFormElementImpl *>(m_refNode)->formElements;
398 
399  //Go through the list, trying to find the appropriate named form element.
400  for (; currentNamePos < (unsigned)l.count(); ++currentNamePos) {
401  HTMLGenericFormElementImpl *el = l.at(currentNamePos);
402  if (el->isEnumerable() &&
403  ((el->getAttribute(ATTR_ID) == name) ||
404  (el->getAttribute(ATTR_NAME) == name))) {
405  ++currentNamePos; //Make next call start after this
406  foundInput = true;//No need to look for img
407  return el;
408  }
409  }
410 
411  //If we got this far, we may need to start looking through the images,
412  //but only if no input tags were matched
413  if (foundInput) {
414  return nullptr;
415  }
416 
417  QList<HTMLImageElementImpl *> &il = static_cast<HTMLFormElementImpl *>(m_refNode)->imgElements;
418  for (; currentNameImgPos < (unsigned)il.count(); ++currentNameImgPos) {
419  HTMLImageElementImpl *el = il.at(currentNameImgPos);
420  if ((el->getAttribute(ATTR_ID) == name) ||
421  (el->getAttribute(ATTR_NAME) == name)) {
422  ++currentNameImgPos; //Make next call start after this
423  return el;
424  }
425  }
426 
427  return nullptr;
428 }
429 
430 // -------------------------------------------------------------------------
431 HTMLMappedNameCollectionImpl::HTMLMappedNameCollectionImpl(NodeImpl *_base, int _type, const DOMString &_name):
432  HTMLCollectionImpl(_base, DynamicNodeListImpl::UNCACHEABLE), name(_name)
433 {
434  type = _type; //We pass uncacheable to collection, but need our own type internally.
435 }
436 
437 bool HTMLMappedNameCollectionImpl::nodeMatches(NodeImpl *current, bool &deep) const
438 {
439  if (current->nodeType() != Node::ELEMENT_NODE) {
440  deep = false;
441  return false;
442  }
443 
444  HTMLElementImpl *e = static_cast<HTMLElementImpl *>(current);
445 
446  return matchesName(e, type, name);
447 }
448 
449 bool HTMLMappedNameCollectionImpl::matchesName(ElementImpl *el, int type, const DOMString &name)
450 {
451  switch (el->id()) {
452  case ID_IMG:
453  case ID_FORM:
454  //Under document. these require non-empty name to see the element
455  if (type == DOCUMENT_NAMED_ITEMS && el->getAttribute(ATTR_NAME).isNull()) {
456  return false;
457  }
458  //Otherwise, fallthrough
459  case ID_OBJECT:
460  case ID_EMBED:
461  case ID_APPLET:
462  case ID_LAYER:
463  if (el->getAttribute(ATTR_NAME) == name || el->getAttribute(ATTR_ID) == name) {
464  return true;
465  } else {
466  return false;
467  }
468  default:
469  return false;
470  }
471 }
472 
const T & at(int i) const const
int count(const T &value) const const
void append(const T &value)
Type type(const QSqlDatabase &db)
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
void clear()
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 namedItem(const DOMString &name) const
This method retrieves a Node using a name.
Definition: html_misc.cpp:187
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.