webengine/osswebengine/WebCore/css/CSSSelector.cpp
changeset 0 dd21522fd290
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/css/CSSSelector.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
+ *               1999 Waldo Bastian (bastian@kde.org)
+ *               2001 Andreas Schlapbach (schlpbch@iam.unibe.ch)
+ *               2001-2003 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2002, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * 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 "config.h"
+#include "CSSSelector.h"
+
+namespace WebCore {
+
+void CSSSelector::print()
+{
+    if (m_tagHistory)
+        m_tagHistory->print();
+}
+
+unsigned int CSSSelector::specificity()
+{
+    // FIXME: Pseudo-elements and pseudo-classes do not have the same specificity. This function
+    // isn't quite correct.
+    int s = (m_tag.localName() == starAtom ? 0 : 1);
+    switch (m_match) {
+        case Id:
+            s += 0x10000;
+            break;
+        case Exact:
+        case Class:
+        case Set:
+        case List:
+        case Hyphen:
+        case PseudoClass:
+        case PseudoElement:
+        case Contain:
+        case Begin:
+        case End:
+            s += 0x100;
+        case None:
+            break;
+    }
+
+    if (m_tagHistory)
+        s += m_tagHistory->specificity();
+
+    // make sure it doesn't overflow
+    return s & 0xffffff;
+}
+
+void CSSSelector::extractPseudoType() const
+{
+    if (m_match != PseudoClass && m_match != PseudoElement)
+        return;
+
+    static AtomicString active("active");
+    static AtomicString after("after");
+    static AtomicString anyLink("-webkit-any-link");
+    static AtomicString autofill("-webkit-autofill");
+    static AtomicString before("before");
+    static AtomicString checked("checked");
+    static AtomicString fileUploadButton("-webkit-file-upload-button");
+    static AtomicString disabled("disabled");
+    static AtomicString drag("-webkit-drag");
+    static AtomicString dragAlias("-khtml-drag"); // was documented with this name in Apple documentation, so keep an alias
+    static AtomicString empty("empty");
+    static AtomicString enabled("enabled");
+    static AtomicString firstChild("first-child");
+    static AtomicString firstLetter("first-letter");
+    static AtomicString firstLine("first-line");
+    static AtomicString firstOfType("first-of-type");
+    static AtomicString focus("focus");
+    static AtomicString hover("hover");
+    static AtomicString indeterminate("indeterminate");
+    static AtomicString link("link");
+    static AtomicString lang("lang(");
+    static AtomicString notStr("not(");
+    static AtomicString root("root");
+    static AtomicString searchCancelButton("-webkit-search-cancel-button");
+    static AtomicString searchDecoration("-webkit-search-decoration");
+    static AtomicString searchResultsDecoration("-webkit-search-results-decoration");
+    static AtomicString searchResultsButton("-webkit-search-results-button");
+    static AtomicString selection("selection");
+    static AtomicString sliderThumb("-webkit-slider-thumb");
+    static AtomicString target("target");
+    static AtomicString visited("visited");
+
+    bool element = false; // pseudo-element
+    bool compat = false; // single colon compatbility mode
+
+    m_pseudoType = PseudoUnknown;
+    if (m_value == active)
+        m_pseudoType = PseudoActive;
+    else if (m_value == after) {
+        m_pseudoType = PseudoAfter;
+        element = true;
+        compat = true;
+    } else if (m_value == anyLink)
+        m_pseudoType = PseudoAnyLink;
+    else if (m_value == autofill)
+        m_pseudoType = PseudoAutofill;
+    else if (m_value == before) {
+        m_pseudoType = PseudoBefore;
+        element = true;
+        compat = true;
+    } else if (m_value == checked)
+        m_pseudoType = PseudoChecked;
+    else if (m_value == fileUploadButton) {
+        m_pseudoType = PseudoFileUploadButton;
+        element = true;
+    } else if (m_value == disabled)
+        m_pseudoType = PseudoDisabled;
+    else if (m_value == drag || m_value == dragAlias)
+        m_pseudoType = PseudoDrag;
+    else if (m_value == enabled)
+        m_pseudoType = PseudoEnabled;
+    else if (m_value == empty)
+        m_pseudoType = PseudoEmpty;
+    else if (m_value == firstChild)
+        m_pseudoType = PseudoFirstChild;
+    else if (m_value == firstLetter) {
+        m_pseudoType = PseudoFirstLetter;
+        element = true;
+        compat = true;
+    } else if (m_value == firstLine) {
+        m_pseudoType = PseudoFirstLine;
+        element = true;
+        compat = true;
+    } else if (m_value == firstOfType)
+        m_pseudoType = PseudoFirstOfType;
+    else if (m_value == focus)
+        m_pseudoType = PseudoFocus;
+    else if (m_value == hover)
+        m_pseudoType = PseudoHover;
+    else if (m_value == indeterminate)
+        m_pseudoType = PseudoIndeterminate;
+    else if (m_value == link)
+        m_pseudoType = PseudoLink;
+    else if (m_value == lang)
+        m_pseudoType = PseudoLang;
+    else if (m_value == notStr)
+        m_pseudoType = PseudoNot;
+    else if (m_value == root)
+        m_pseudoType = PseudoRoot;
+    else if (m_value == searchCancelButton) {
+        m_pseudoType = PseudoSearchCancelButton;
+        element = true;
+    } else if (m_value == searchDecoration) {
+        m_pseudoType = PseudoSearchDecoration;
+        element = true;
+    } else if (m_value == searchResultsDecoration) {
+        m_pseudoType = PseudoSearchResultsDecoration;
+        element = true;
+    } else if (m_value == searchResultsButton) {
+        m_pseudoType = PseudoSearchResultsButton;
+        element = true;
+    }  else if (m_value == selection) {
+        m_pseudoType = PseudoSelection;
+        element = true;
+    } else if (m_value == sliderThumb) {
+        m_pseudoType = PseudoSliderThumb;
+        element = true;
+    } else if (m_value == target)
+        m_pseudoType = PseudoTarget;
+    else if (m_value == visited)
+        m_pseudoType = PseudoVisited;
+
+    if (m_match == PseudoClass && element) {
+        if (!compat) 
+            m_pseudoType = PseudoUnknown;
+        else 
+           m_match = PseudoElement;
+    } else if (m_match == PseudoElement && !element)
+        m_pseudoType = PseudoUnknown;
+}
+
+bool CSSSelector::operator==(const CSSSelector& other)
+{
+    const CSSSelector* sel1 = this;
+    const CSSSelector* sel2 = &other;
+
+    while (sel1 && sel2) {
+        if (sel1->m_tag != sel2->m_tag || sel1->m_attr != sel2->m_attr ||
+             sel1->relation() != sel2->relation() || sel1->m_match != sel2->m_match ||
+             sel1->m_value != sel2->m_value ||
+             sel1->pseudoType() != sel2->pseudoType() ||
+             sel1->m_argument != sel2->m_argument)
+            return false;
+        sel1 = sel1->m_tagHistory;
+        sel2 = sel2->m_tagHistory;
+    }
+
+    if (sel1 || sel2)
+        return false;
+
+    return true;
+}
+
+String CSSSelector::selectorText() const
+{
+    String str = "";
+
+    const AtomicString& prefix = m_tag.prefix();
+    const AtomicString& localName = m_tag.localName();
+    if (m_match == CSSSelector::None || !prefix.isNull() || localName != starAtom) {
+        if (prefix.isNull())
+            str = localName;
+        else
+            str = prefix + "|" + localName;
+    }
+
+    const CSSSelector* cs = this;
+    while (true) {
+        if (cs->m_match == CSSSelector::Id) {
+            str += "#";
+            str += cs->m_value;
+        } else if (cs->m_match == CSSSelector::Class) {
+            str += ".";
+            str += cs->m_value;
+        } else if (cs->m_match == CSSSelector::PseudoClass) {
+            str += ":";
+            str += cs->m_value;
+            if (cs->pseudoType() == PseudoNot) {
+                if (CSSSelector* subSel = cs->m_simpleSelector)
+                    str += subSel->selectorText();
+                str += ")";
+            } else if (cs->pseudoType() == PseudoLang) {
+                str += cs->m_argument;
+                str += ")";
+            }
+        } else if (cs->m_match == CSSSelector::PseudoElement) {
+            str += "::";
+            str += cs->m_value;
+        } else if (cs->hasAttribute()) {
+            str += "[";
+            const AtomicString& prefix = cs->m_attr.prefix();
+            if (!prefix.isNull())
+                str += prefix + "|";
+            str += cs->m_attr.localName();
+            switch (cs->m_match) {
+                case CSSSelector::Exact:
+                    str += "=";
+                    break;
+                case CSSSelector::Set:
+                    // set has no operator or value, just the attrName
+                    str += "]";
+                    break;
+                case CSSSelector::List:
+                    str += "~=";
+                    break;
+                case CSSSelector::Hyphen:
+                    str += "|=";
+                    break;
+                case CSSSelector::Begin:
+                    str += "^=";
+                    break;
+                case CSSSelector::End:
+                    str += "$=";
+                    break;
+                case CSSSelector::Contain:
+                    str += "*=";
+                    break;
+                default:
+                    break;
+            }
+            if (cs->m_match != CSSSelector::Set) {
+                str += "\"";
+                str += cs->m_value;
+                str += "\"]";
+            }
+        }
+        if (cs->relation() != CSSSelector::SubSelector || !cs->m_tagHistory)
+            break;
+        cs = cs->m_tagHistory;
+    }
+
+    if (cs->m_tagHistory) {
+        String tagHistoryText = cs->m_tagHistory->selectorText();
+        if (cs->relation() == CSSSelector::DirectAdjacent)
+            str = tagHistoryText + " + " + str;
+        else if (cs->relation() == CSSSelector::IndirectAdjacent)
+            str = tagHistoryText + " ~ " + str;
+        else if (cs->relation() == CSSSelector::Child)
+            str = tagHistoryText + " > " + str;
+        else
+            // Descendant
+            str = tagHistoryText + " " + str;
+    }
+
+    return str;
+}
+
+} // namespace WebCore