summaryrefslogtreecommitdiffstats
path: root/khtml/html/html_miscimpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'khtml/html/html_miscimpl.cpp')
-rw-r--r--khtml/html/html_miscimpl.cpp443
1 files changed, 443 insertions, 0 deletions
diff --git a/khtml/html/html_miscimpl.cpp b/khtml/html/html_miscimpl.cpp
new file mode 100644
index 000000000..bf0c56e00
--- /dev/null
+++ b/khtml/html/html_miscimpl.cpp
@@ -0,0 +1,443 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2005 Maksim Orlovich (maksim@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+// -------------------------------------------------------------------------
+#include "html/html_tableimpl.h"
+#include "html/html_miscimpl.h"
+#include "html/html_formimpl.h"
+#include "html/html_documentimpl.h"
+
+#include "misc/htmlhashes.h"
+#include "dom/dom_node.h"
+
+using namespace DOM;
+
+#include <kdebug.h>
+
+HTMLBaseFontElementImpl::HTMLBaseFontElementImpl(DocumentImpl *doc)
+ : HTMLElementImpl(doc)
+{
+}
+
+HTMLBaseFontElementImpl::~HTMLBaseFontElementImpl()
+{
+}
+
+NodeImpl::Id HTMLBaseFontElementImpl::id() const
+{
+ return ID_BASEFONT;
+}
+
+// -------------------------------------------------------------------------
+
+struct CollectionCache: public NodeListImpl::Cache
+{
+ static Cache* make() { return new CollectionCache; }
+
+ QDict<QValueList<NodeImpl*> > nameCache;
+
+ CollectionCache(): nameCache(127)
+ {
+ nameCache.setAutoDelete(true);
+ }
+
+ virtual void clear(DocumentImpl* doc)
+ {
+ Cache::clear(doc);
+ //qDeletaAll here in Qt4
+ nameCache.clear();
+ }
+};
+
+HTMLCollectionImpl::HTMLCollectionImpl(NodeImpl *_base, int _type):
+ NodeListImpl(_base, _type, CollectionCache::make)
+{
+ type = _type;
+}
+
+bool HTMLCollectionImpl::nodeMatches(NodeImpl *current, bool& deep) const
+{
+ if ( current->nodeType() != Node::ELEMENT_NODE )
+ {
+ deep = false;
+ return false;
+ }
+
+ bool check = false;
+ HTMLElementImpl *e = static_cast<HTMLElementImpl *>(current);
+ switch(type)
+ {
+ case DOC_IMAGES:
+ if(e->id() == ID_IMG)
+ check = true;
+ break;
+ case DOC_SCRIPTS:
+ if(e->id() == ID_SCRIPT)
+ check = true;
+ break;
+ case DOC_FORMS:
+ if(e->id() == ID_FORM)
+ check = true;
+ break;
+ case DOC_LAYERS:
+ if(e->id() == ID_LAYER || e->id() == ID_ILAYER)
+ check = true;
+ break;
+ case TABLE_TBODIES:
+ if(e->id() == ID_TBODY)
+ check = true;
+ else if(e->id() == ID_TABLE)
+ deep = false;
+ break;
+ case TR_CELLS:
+ if(e->id() == ID_TD || e->id() == ID_TH)
+ check = true;
+ else if(e->id() == ID_TABLE)
+ deep = false;
+ break;
+ case TABLE_ROWS:
+ case TSECTION_ROWS:
+ if(e->id() == ID_TR)
+ check = true;
+ else if(e->id() == ID_TABLE)
+ deep = false;
+ break;
+ case SELECT_OPTIONS:
+ if(e->id() == ID_OPTION)
+ check = true;
+ break;
+ case MAP_AREAS:
+ if(e->id() == ID_AREA)
+ check = true;
+ break;
+ case DOC_APPLETS: // all OBJECT and APPLET elements
+ if(e->id() == ID_OBJECT || e->id() == ID_APPLET || e->id() == ID_EMBED)
+ check = true;
+ break;
+ case DOC_LINKS: // all A _and_ AREA elements with a value for href
+ if(e->id() == ID_A || e->id() == ID_AREA)
+ if(!e->getAttribute(ATTR_HREF).isNull())
+ check = true;
+ break;
+ case DOC_ANCHORS: // all A elements with a value for name and/or id
+ if(e->id() == ID_A) {
+ if(e->hasID() || !e->getAttribute(ATTR_NAME).isNull())
+ check = true;
+ }
+ break;
+ case DOC_ALL: // "all" elements
+ check = true;
+ break;
+ case NODE_CHILDREN: // first-level children
+ check = true;
+ deep = false;
+ break;
+ default:
+ kdDebug( 6030 ) << "Error in HTMLCollection, wrong tagId!" << endl;
+ }
+
+ return check;
+}
+
+bool HTMLCollectionImpl::checkForNameMatch(NodeImpl *node, const DOMString &name) const
+{
+ if ( node->nodeType() != Node::ELEMENT_NODE )
+ return false;
+
+ HTMLElementImpl *e = static_cast<HTMLElementImpl *>(node);
+
+ //If ID matches, this is definitely a match
+ if (e->getAttribute(ATTR_ID) == name)
+ return true;
+
+ //Despite what the DOM spec says, neither IE nor Gecko actually
+ //care to prefer IDs. Instead, they just match everything
+ //that has ID or a name for nodes that have a name.
+ //Except for the form elements collection, Gecko always returns
+ //just one item. IE is more complex: its namedItem
+ //and call notation access return everything that matches,
+ //but the subscript notation is sometimes different.
+ //For now, we try to match IE, but without the subscript
+ //oddness, which I don't understand -- Maks.
+
+ bool checkName;
+ switch (e->id())
+ {
+ case ID_A:
+ case ID_APPLET:
+ case ID_BUTTON:
+ case ID_EMBED:
+ case ID_FORM:
+ case ID_IMG:
+ case ID_INPUT:
+ case ID_MAP:
+ case ID_META:
+ case ID_OBJECT:
+ case ID_SELECT:
+ case ID_TEXTAREA:
+ case ID_FRAME:
+ case ID_IFRAME:
+ case ID_FRAMESET:
+ checkName = true;
+ break;
+ default:
+ checkName = false;
+ }
+
+ if (checkName)
+ return e->getAttribute(ATTR_NAME) == name;
+ else
+ return false;
+}
+
+NodeImpl *HTMLCollectionImpl::item ( unsigned long index ) const
+{
+ //Most of the time, we just go in normal document order
+ if (type != TABLE_ROWS)
+ return NodeListImpl::item(index);
+
+ //For table.rows, we first need to check header, then bodies, then footer.
+ //we pack any extra headers/footer with bodies. This matches IE, and
+ //means doing the usual thing with length is right
+ const HTMLTableElementImpl* table = static_cast<const HTMLTableElementImpl*>(m_refNode);
+
+ long sectionIndex;
+ HTMLTableSectionElementImpl* section;
+
+ NodeImpl* found = 0;
+ if (table->findRowSection(index, section, sectionIndex)) {
+ HTMLCollectionImpl rows(section, TSECTION_ROWS);
+ found = rows.item(sectionIndex);
+ }
+
+ m_cache->current.node = found; //namedItem needs this.
+ m_cache->position = index;
+ return found;
+}
+
+unsigned long HTMLCollectionImpl::calcLength(NodeImpl *start) const
+{
+ if (type != TABLE_ROWS)
+ return NodeListImpl::calcLength(start);
+
+ unsigned length = 0;
+ const HTMLTableElementImpl* table = static_cast<const HTMLTableElementImpl*>(m_refNode);
+ for (NodeImpl* kid = table->firstChild(); kid; kid = kid->nextSibling()) {
+ HTMLCollectionImpl rows(kid, TSECTION_ROWS);
+ length += rows.length();
+ }
+ return length;
+}
+
+NodeImpl *HTMLCollectionImpl::firstItem() const
+{
+ return item(0);
+}
+
+NodeImpl *HTMLCollectionImpl::nextItem() const
+{
+ //### this assumes this is called immediately after nextItem --
+ //it this sane?
+ return item(m_cache->position + 1);
+}
+
+NodeImpl *HTMLCollectionImpl::namedItem( const DOMString &name ) const
+{
+ //Reset the position. The invariant is that nextNamedItem will start looking
+ //from the current position.
+ firstItem();
+
+ return nextNamedItem(name);
+}
+
+NodeImpl *HTMLCollectionImpl::nextNamedItem( const DOMString &name ) const
+{
+ while (NodeImpl* candidate = m_cache->current.node)
+ {
+ //Always advance, for next call
+ nextItem();
+ if (checkForNameMatch(candidate, name))
+ return candidate;
+ }
+ return 0;
+}
+
+QValueList<NodeImpl*> HTMLCollectionImpl::namedItems( const DOMString &name ) const
+{
+ QString key = name.string();
+
+ //We use a work-conserving design for the name cache presently -- only
+ //remember stuff about elements we were asked for.
+ m_cache->updateNodeListInfo(m_refNode->getDocument());
+ CollectionCache* cache = static_cast<CollectionCache*>(m_cache);
+ if (QValueList<NodeImpl*>* info = cache->nameCache.find(key)) {
+ return *info;
+ }
+ else {
+ QValueList<NodeImpl*>* newInfo = new QValueList<NodeImpl*>;
+
+ NodeImpl* match = namedItem(name);
+ while (match) {
+ newInfo->append(match);
+ match = nextNamedItem(name);
+ }
+
+ cache->nameCache.insert(key, newInfo);
+ return *newInfo;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+HTMLFormCollectionImpl::HTMLFormCollectionImpl(NodeImpl* _base)
+ : HTMLCollectionImpl(_base, FORM_ELEMENTS), currentNamePos(0), currentNameImgPos(0)
+{}
+
+NodeImpl *HTMLFormCollectionImpl::item( unsigned long index ) const
+{
+ m_cache->updateNodeListInfo(m_refNode->getDocument());
+
+ unsigned int dist = index;
+ unsigned int strt = 0;
+ if (m_cache->current.index && m_cache->position <= index)
+ {
+ dist = index - m_cache->position;
+ strt = m_cache->current.index;
+ }
+
+ QPtrList<HTMLGenericFormElementImpl>& l = static_cast<HTMLFormElementImpl*>( m_refNode )->formElements;
+ for (unsigned i = strt; i < l.count(); i++)
+ {
+ if (l.at( i )->isEnumeratable())
+ {
+ if (dist == 0)
+ {
+ //Found it!
+ m_cache->position = index;
+ m_cache->current.index = i;
+ return l.at( i );
+ }
+ else
+ --dist;
+ }
+ }
+ return 0;
+}
+
+unsigned long HTMLFormCollectionImpl::calcLength(NodeImpl *start) const
+{
+ unsigned length = 0;
+ QPtrList<HTMLGenericFormElementImpl> l = static_cast<HTMLFormElementImpl*>( start )->formElements;
+ for ( unsigned i = 0; i < l.count(); i++ )
+ if ( l.at( i )->isEnumeratable() )
+ ++length;
+ return length;
+}
+
+NodeImpl *HTMLFormCollectionImpl::namedItem( const DOMString &name ) const
+{
+ currentNamePos = 0;
+ currentNameImgPos = 0;
+ foundInput = false;
+ return nextNamedItem(name);
+}
+
+NodeImpl *HTMLFormCollectionImpl::nextNamedItem( const DOMString &name ) const
+{
+ QPtrList<HTMLGenericFormElementImpl>& l = static_cast<HTMLFormElementImpl*>( m_refNode )->formElements;
+
+ //Go through the list, trying to find the appropriate named form element.
+ for ( ; currentNamePos < l.count(); ++currentNamePos )
+ {
+ HTMLGenericFormElementImpl* el = l.at(currentNamePos);
+ if (el->isEnumeratable() &&
+ ((el->getAttribute(ATTR_ID) == name) ||
+ (el->getAttribute(ATTR_NAME) == name)))
+ {
+ ++currentNamePos; //Make next call start after this
+ foundInput = true;//No need to look for img
+ return el;
+ }
+ }
+
+ //If we got this far, we may need to start looking through the images,
+ //but only if no input tags were matched
+ if (foundInput) return 0;
+
+ QPtrList<HTMLImageElementImpl>& il = static_cast<HTMLFormElementImpl*>( m_refNode )->imgElements;
+ for ( ; currentNameImgPos < il.count(); ++currentNameImgPos )
+ {
+ HTMLImageElementImpl* el = il.at(currentNameImgPos);
+ if ((el->getAttribute(ATTR_ID) == name) ||
+ (el->getAttribute(ATTR_NAME) == name))
+ {
+ ++currentNameImgPos; //Make next call start after this
+ return el;
+ }
+ }
+
+ return 0;
+}
+
+// -------------------------------------------------------------------------
+HTMLMappedNameCollectionImpl::HTMLMappedNameCollectionImpl(NodeImpl* _base, int _type, const DOMString& _name):
+ HTMLCollectionImpl(_base, NodeListImpl::UNCACHEABLE), name(_name)
+{
+ type = _type; //We pass uncacheable to collection, but need our own type internally.
+}
+
+bool HTMLMappedNameCollectionImpl::nodeMatches(NodeImpl *current, bool& deep) const
+{
+ if ( current->nodeType() != Node::ELEMENT_NODE )
+ {
+ deep = false;
+ return false;
+ }
+
+ HTMLElementImpl *e = static_cast<HTMLElementImpl *>(current);
+
+ return matchesName(e, type, name);
+}
+
+bool HTMLMappedNameCollectionImpl::matchesName( ElementImpl* el, int type, const DOMString& name )
+{
+ switch (el->id())
+ {
+ case ID_IMG:
+ case ID_FORM:
+ //Under document. these require non-empty name to see the element
+ if (type == DOCUMENT_NAMED_ITEMS && el->getAttribute(ATTR_NAME).isNull())
+ return false;
+ //Otherwise, fallthrough
+ case ID_OBJECT:
+ case ID_EMBED:
+ case ID_APPLET:
+ case ID_LAYER:
+ if (el->getAttribute(ATTR_NAME) == name || el->getAttribute(ATTR_ID) == name)
+ return true;
+ else
+ return false;
+ default:
+ return false;
+ }
+}