WebCore/html/HTMLFormCollection.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
       
     3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
       
     4  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
       
     5  *
       
     6  * This library is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Library General Public
       
     8  * License as published by the Free Software Foundation; either
       
     9  * version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This library is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * Library General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Library General Public License
       
    17  * along with this library; see the file COPYING.LIB.  If not, write to
       
    18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    19  * Boston, MA 02110-1301, USA.
       
    20  *
       
    21  */
       
    22 
       
    23 #include "config.h"
       
    24 #include "HTMLFormCollection.h"
       
    25 
       
    26 #include "CollectionCache.h"
       
    27 #include "HTMLFormControlElement.h"
       
    28 #include "HTMLFormElement.h"
       
    29 #include "HTMLImageElement.h"
       
    30 #include "HTMLNames.h"
       
    31 
       
    32 namespace WebCore {
       
    33 
       
    34 using namespace HTMLNames;
       
    35 
       
    36 // Since the collections are to be "live", we have to do the
       
    37 // calculation every time if anything has changed.
       
    38 
       
    39 inline CollectionCache* HTMLFormCollection::formCollectionInfo(HTMLFormElement* form)
       
    40 {
       
    41     if (!form->m_collectionCache)
       
    42         form->m_collectionCache.set(new CollectionCache);
       
    43     return form->m_collectionCache.get();
       
    44 }
       
    45 
       
    46 HTMLFormCollection::HTMLFormCollection(PassRefPtr<HTMLFormElement> form)
       
    47     : HTMLCollection(form.get(), OtherCollection, formCollectionInfo(form.get()))
       
    48 {
       
    49 }
       
    50 
       
    51 PassRefPtr<HTMLFormCollection> HTMLFormCollection::create(PassRefPtr<HTMLFormElement> form)
       
    52 {
       
    53     return adoptRef(new HTMLFormCollection(form));
       
    54 }
       
    55 
       
    56 HTMLFormCollection::~HTMLFormCollection()
       
    57 {
       
    58 }
       
    59 
       
    60 unsigned HTMLFormCollection::calcLength() const
       
    61 {
       
    62     return static_cast<HTMLFormElement*>(base())->length();
       
    63 }
       
    64 
       
    65 Node* HTMLFormCollection::item(unsigned index) const
       
    66 {
       
    67     resetCollectionInfo();
       
    68 
       
    69     if (info()->current && info()->position == index)
       
    70         return info()->current;
       
    71 
       
    72     if (info()->hasLength && info()->length <= index)
       
    73         return 0;
       
    74 
       
    75     if (!info()->current || info()->position > index) {
       
    76         info()->current = 0;
       
    77         info()->position = 0;
       
    78         info()->elementsArrayPosition = 0;
       
    79     }
       
    80 
       
    81     Vector<HTMLFormControlElement*>& elementsArray = static_cast<HTMLFormElement*>(base())->m_associatedElements;
       
    82     unsigned currentIndex = info()->position;
       
    83     
       
    84     for (unsigned i = info()->elementsArrayPosition; i < elementsArray.size(); i++) {
       
    85         HTMLFormControlElement* element = elementsArray[i];
       
    86         if (element->isEnumeratable()) {
       
    87             if (index == currentIndex) {
       
    88                 info()->position = index;
       
    89                 info()->current = element;
       
    90                 info()->elementsArrayPosition = i;
       
    91                 return element;
       
    92             }
       
    93 
       
    94             currentIndex++;
       
    95         }
       
    96     }
       
    97 
       
    98     return 0;
       
    99 }
       
   100 
       
   101 Element* HTMLFormCollection::getNamedItem(const QualifiedName& attrName, const AtomicString& name) const
       
   102 {
       
   103     info()->position = 0;
       
   104     return getNamedFormItem(attrName, name, 0);
       
   105 }
       
   106 
       
   107 Element* HTMLFormCollection::getNamedFormItem(const QualifiedName& attrName, const String& name, int duplicateNumber) const
       
   108 {
       
   109     HTMLFormElement* form = static_cast<HTMLFormElement*>(base());
       
   110 
       
   111     bool foundInputElements = false;
       
   112     for (unsigned i = 0; i < form->m_associatedElements.size(); ++i) {
       
   113         HTMLFormControlElement* e = form->m_associatedElements[i];
       
   114         if (e->isEnumeratable() && e->getAttribute(attrName) == name) {
       
   115             foundInputElements = true;
       
   116             if (!duplicateNumber)
       
   117                 return e;
       
   118             --duplicateNumber;
       
   119         }
       
   120     }
       
   121 
       
   122     if (!foundInputElements) {
       
   123         for (unsigned i = 0; i < form->m_imageElements.size(); ++i) {
       
   124             HTMLImageElement* e = form->m_imageElements[i];
       
   125             if (e->getAttribute(attrName) == name) {
       
   126                 if (!duplicateNumber)
       
   127                     return e;
       
   128                 --duplicateNumber;
       
   129             }
       
   130         }
       
   131     }
       
   132 
       
   133     return 0;
       
   134 }
       
   135 
       
   136 Node* HTMLFormCollection::nextItem() const
       
   137 {
       
   138     return item(info()->position + 1);
       
   139 }
       
   140 
       
   141 Element* HTMLFormCollection::nextNamedItemInternal(const String &name) const
       
   142 {
       
   143     Element* retval = getNamedFormItem(m_idsDone ? nameAttr : idAttr, name, ++info()->position);
       
   144     if (retval)
       
   145         return retval;
       
   146     if (m_idsDone) // we're done
       
   147         return 0;
       
   148     // After doing id, do name
       
   149     m_idsDone = true;
       
   150     return getNamedItem(nameAttr, name);
       
   151 }
       
   152 
       
   153 Node* HTMLFormCollection::namedItem(const AtomicString& name) const
       
   154 {
       
   155     // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/nameditem.asp
       
   156     // This method first searches for an object with a matching id
       
   157     // attribute. If a match is not found, the method then searches for an
       
   158     // object with a matching name attribute, but only on those elements
       
   159     // that are allowed a name attribute.
       
   160     resetCollectionInfo();
       
   161     m_idsDone = false;
       
   162     info()->current = getNamedItem(idAttr, name);
       
   163     if (info()->current)
       
   164         return info()->current;
       
   165     m_idsDone = true;
       
   166     info()->current = getNamedItem(nameAttr, name);
       
   167     return info()->current;
       
   168 }
       
   169 
       
   170 Node* HTMLFormCollection::nextNamedItem(const AtomicString& name) const
       
   171 {
       
   172     // The nextNamedItemInternal function can return the same item twice if it has
       
   173     // both an id and name that are equal to the name parameter. So this function
       
   174     // checks if we are on the nameAttr half of the iteration and skips over any
       
   175     // that also have the same idAttributeName.
       
   176     Element* impl = nextNamedItemInternal(name);
       
   177     if (m_idsDone) {
       
   178         while (impl && impl->getIdAttribute() == name)
       
   179             impl = nextNamedItemInternal(name);
       
   180     }
       
   181     return impl;
       
   182 }
       
   183 
       
   184 void HTMLFormCollection::updateNameCache() const
       
   185 {
       
   186     if (info()->hasNameCache)
       
   187         return;
       
   188 
       
   189     HashSet<AtomicStringImpl*> foundInputElements;
       
   190 
       
   191     HTMLFormElement* f = static_cast<HTMLFormElement*>(base());
       
   192 
       
   193     for (unsigned i = 0; i < f->m_associatedElements.size(); ++i) {
       
   194         HTMLFormControlElement* e = f->m_associatedElements[i];
       
   195         if (e->isEnumeratable()) {
       
   196             const AtomicString& idAttrVal = e->getIdAttribute();
       
   197             const AtomicString& nameAttrVal = e->getAttribute(nameAttr);
       
   198             if (!idAttrVal.isEmpty()) {
       
   199                 // add to id cache
       
   200                 Vector<Element*>* idVector = info()->idCache.get(idAttrVal.impl());
       
   201                 if (!idVector) {
       
   202                     idVector = new Vector<Element*>;
       
   203                     info()->idCache.add(idAttrVal.impl(), idVector);
       
   204                 }
       
   205                 idVector->append(e);
       
   206                 foundInputElements.add(idAttrVal.impl());
       
   207             }
       
   208             if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal) {
       
   209                 // add to name cache
       
   210                 Vector<Element*>* nameVector = info()->nameCache.get(nameAttrVal.impl());
       
   211                 if (!nameVector) {
       
   212                     nameVector = new Vector<Element*>;
       
   213                     info()->nameCache.add(nameAttrVal.impl(), nameVector);
       
   214                 }
       
   215                 nameVector->append(e);
       
   216                 foundInputElements.add(nameAttrVal.impl());
       
   217             }
       
   218         }
       
   219     }
       
   220 
       
   221     for (unsigned i = 0; i < f->m_imageElements.size(); ++i) {
       
   222         HTMLImageElement* e = f->m_imageElements[i];
       
   223         const AtomicString& idAttrVal = e->getIdAttribute();
       
   224         const AtomicString& nameAttrVal = e->getAttribute(nameAttr);
       
   225         if (!idAttrVal.isEmpty() && !foundInputElements.contains(idAttrVal.impl())) {
       
   226             // add to id cache
       
   227             Vector<Element*>* idVector = info()->idCache.get(idAttrVal.impl());
       
   228             if (!idVector) {
       
   229                 idVector = new Vector<Element*>;
       
   230                 info()->idCache.add(idAttrVal.impl(), idVector);
       
   231             }
       
   232             idVector->append(e);
       
   233         }
       
   234         if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal && !foundInputElements.contains(nameAttrVal.impl())) {
       
   235             // add to name cache
       
   236             Vector<Element*>* nameVector = info()->nameCache.get(nameAttrVal.impl());
       
   237             if (!nameVector) {
       
   238                 nameVector = new Vector<Element*>;
       
   239                 info()->nameCache.add(nameAttrVal.impl(), nameVector);
       
   240             }
       
   241             nameVector->append(e);
       
   242         }
       
   243     }
       
   244 
       
   245     info()->hasNameCache = true;
       
   246 }
       
   247 
       
   248 }