#include "config.h"
#include "CSSSelector.h"
namespace WebCore {
void CSSSelector::print()
{
if (tagHistory)
tagHistory->print();
}
unsigned int CSSSelector::specificity()
{
int s = (tag.localName() == starAtom ? 0 : 1);
switch(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 (tagHistory)
s += tagHistory->specificity();
return s & 0xffffff;
}
void CSSSelector::extractPseudoType() const
{
if (match != PseudoClass && 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 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 lastChild("last-child");
static AtomicString lastOfType("last-of-type");
static AtomicString notStr("not(");
static AtomicString onlyChild("only-child");
static AtomicString onlyOfType("only-of-type");
static AtomicString root("root");
static AtomicString selection("selection");
static AtomicString target("target");
static AtomicString visited("visited");
bool element = false; bool compat = false;
_pseudoType = PseudoUnknown;
if (value == active)
_pseudoType = PseudoActive;
else if (value == after) {
_pseudoType = PseudoAfter;
element = compat = true;
} else if (value == anyLink)
_pseudoType = PseudoAnyLink;
else if (value == autofill)
_pseudoType = PseudoAutofill;
else if (value == before) {
_pseudoType = PseudoBefore;
element = compat = true;
} else if (value == checked)
_pseudoType = PseudoChecked;
else if (value == fileUploadButton) {
_pseudoType = PseudoFileUploadButton;
element = true;
} else if (value == disabled)
_pseudoType = PseudoDisabled;
else if (value == drag)
_pseudoType = PseudoDrag;
else if (value == enabled)
_pseudoType = PseudoEnabled;
else if (value == empty)
_pseudoType = PseudoEmpty;
else if (value == firstChild)
_pseudoType = PseudoFirstChild;
else if (value == firstLetter) {
_pseudoType = PseudoFirstLetter;
element = compat = true;
} else if (value == firstLine) {
_pseudoType = PseudoFirstLine;
element = compat = true;
} else if (value == firstOfType)
_pseudoType = PseudoFirstOfType;
else if (value == focus)
_pseudoType = PseudoFocus;
else if (value == hover)
_pseudoType = PseudoHover;
else if (value == indeterminate)
_pseudoType = PseudoIndeterminate;
else if (value == link)
_pseudoType = PseudoLink;
else if (value == lang)
_pseudoType = PseudoLang;
else if (value == lastChild)
_pseudoType = PseudoLastChild;
else if (value == lastOfType)
_pseudoType = PseudoLastOfType;
else if (value == notStr)
_pseudoType = PseudoNot;
else if (value == onlyChild)
_pseudoType = PseudoOnlyChild;
else if (value == onlyOfType)
_pseudoType = PseudoOnlyOfType;
else if (value == root)
_pseudoType = PseudoRoot;
else if (value == selection) {
_pseudoType = PseudoSelection;
element = true;
} else if (value == target)
_pseudoType = PseudoTarget;
else if (value == visited)
_pseudoType = PseudoVisited;
if (match == PseudoClass && element)
if (!compat)
_pseudoType = PseudoUnknown;
else
match = PseudoElement;
else if (match == PseudoElement && !element)
_pseudoType = PseudoUnknown;
}
bool CSSSelector::operator == (const CSSSelector &other)
{
const CSSSelector *sel1 = this;
const CSSSelector *sel2 = &other;
while (sel1 && sel2) {
if (sel1->tag != sel2->tag || sel1->attr != sel2->attr ||
sel1->relation() != sel2->relation() || sel1->match != sel2->match ||
sel1->value != sel2->value ||
sel1->pseudoType() != sel2->pseudoType() ||
sel1->argument != sel2->argument)
return false;
sel1 = sel1->tagHistory;
sel2 = sel2->tagHistory;
}
if (sel1 || sel2)
return false;
return true;
}
String CSSSelector::selectorText() const
{
String str;
const CSSSelector* cs = this;
const AtomicString& localName = cs->tag.localName();
if (cs->match == CSSSelector::None || localName != starAtom)
str = localName;
while (true) {
if (cs->match == CSSSelector::Id) {
str += "#";
str += cs->value;
} else if (cs->match == CSSSelector::Class) {
str += ".";
str += cs->value;
} else if (cs->match == CSSSelector::PseudoClass) {
str += ":";
str += cs->value;
} else if (cs->match == CSSSelector::PseudoElement) {
str += "::";
str += cs->value;
} else if (cs->hasAttribute()) {
String attrName = cs->attr.localName();
str += "[";
str += attrName;
switch (cs->match) {
case CSSSelector::Exact:
str += "=";
break;
case CSSSelector::Set:
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->match != CSSSelector::Set) {
str += "\"";
str += cs->value;
str += "\"]";
}
}
if (cs->relation() != CSSSelector::SubSelector || !cs->tagHistory)
break;
cs = cs->tagHistory;
}
if (cs->tagHistory) {
String tagHistoryText = cs->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 str = tagHistoryText + " " + str;
}
return str;
}
}