diff options
Diffstat (limited to 'tdehtml/css/css_base.cpp')
-rw-r--r-- | tdehtml/css/css_base.cpp | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/tdehtml/css/css_base.cpp b/tdehtml/css/css_base.cpp new file mode 100644 index 000000000..a4dda95a0 --- /dev/null +++ b/tdehtml/css/css_base.cpp @@ -0,0 +1,419 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * 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) + * 2002 Apple Computer, Inc. + * 2004 Allan Sandfeld Jensen (kde@carewolf.com) + * + * 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. + */ + +//#define CSS_DEBUG + +#include <assert.h> +#include <kdebug.h> + +#include "css_base.h" + +#ifdef CSS_DEBUG +#include "cssproperties.h" +#endif + +#include "css_stylesheetimpl.h" +#include "xml/dom_docimpl.h" +#include "misc/htmlhashes.h" +#include "css_valueimpl.h" +using namespace DOM; + +void StyleBaseImpl::checkLoaded() const +{ + if(m_parent) m_parent->checkLoaded(); +} + +StyleSheetImpl* StyleBaseImpl::stylesheet() +{ + StyleBaseImpl* b = this; + while(b && !b->isStyleSheet()) + b = b->m_parent; + return static_cast<StyleSheetImpl *>(b); +} + +KURL StyleBaseImpl::baseURL() +{ + // try to find the style sheet. If found look for its url. + // If it has none, look for the parentsheet, or the parentNode and + // try to find out about their url + + StyleSheetImpl *sheet = stylesheet(); + + if(!sheet) return KURL(); + + if(!sheet->href().isNull()) + return KURL( sheet->href().string() ); + + // find parent + if(sheet->parent()) return sheet->parent()->baseURL(); + + if(!sheet->ownerNode()) return KURL(); + + return sheet->ownerNode()->getDocument()->baseURL(); +} + +void StyleBaseImpl::setParsedValue(int propId, const CSSValueImpl *parsedValue, + bool important, bool nonCSSHint, TQPtrList<CSSProperty> *propList) +{ + TQPtrListIterator<CSSProperty> propIt(*propList); + propIt.toLast(); // just remove the top one - not sure what should happen if we have multiple instances of the property + while (propIt.current() && + ( propIt.current()->m_id != propId || propIt.current()->nonCSSHint != nonCSSHint || + propIt.current()->m_important != important) ) + --propIt; + if (propIt.current()) + propList->removeRef(propIt.current()); + + CSSProperty *prop = new CSSProperty(); + prop->m_id = propId; + prop->setValue((CSSValueImpl *) parsedValue); + prop->m_important = important; + prop->nonCSSHint = nonCSSHint; + + propList->append(prop); +#ifdef CSS_DEBUG + kdDebug( 6080 ) << "added property: " << getPropertyName(propId).string() + // non implemented yet << ", value: " << parsedValue->cssText().string() + << " important: " << prop->m_important + << " nonCSS: " << prop->nonCSSHint << endl; +#endif +} + +// ------------------------------------------------------------------------------ + +StyleListImpl::~StyleListImpl() +{ + StyleBaseImpl *n; + + if(!m_lstChildren) return; + + for( n = m_lstChildren->first(); n != 0; n = m_lstChildren->next() ) + { + n->setParent(0); + if( !n->refCount() ) delete n; + } + delete m_lstChildren; +} + +// -------------------------------------------------------------------------------- + +void CSSSelector::print(void) +{ + kdDebug( 6080 ) << "[Selector: tag = " << TQString::number(tag,16) << ", attr = \"" << attr << "\", match = \"" << match + << "\" value = \"" << value.string().latin1() << "\" relation = " << (int)relation + << "]" << endl; + if ( tagHistory ) + tagHistory->print(); + kdDebug( 6080 ) << " specificity = " << specificity() << endl; +} + +unsigned int CSSSelector::specificity() const +{ + if ( nonCSSHint ) + return 0; + + int s = ((localNamePart(tag) == anyLocalName) ? 0 : 1); + switch(match) + { + case Id: + s += 0x10000; + break; + case Exact: + case Set: + case List: + case Class: + case Hyphen: + case PseudoClass: + case PseudoElement: + case Contain: + case Begin: + case End: + s += 0x100; + case None: + break; + } + if(tagHistory) + s += tagHistory->specificity(); + // make sure it doesn't overflow + return s & 0xffffff; +} + +void CSSSelector::extractPseudoType() const +{ + if (match != PseudoClass && match != PseudoElement) + return; + _pseudoType = PseudoOther; + bool element = false; + bool compat = false; + if (!value.isEmpty()) { + value = value.lower(); + switch (value[0]) { + case '-': + if (value == "-tdehtml-replaced") + _pseudoType = PseudoReplaced; + else + if (value == "-tdehtml-marker") + _pseudoType = PseudoMarker; + element = true; + break; + case 'a': + if (value == "active") + _pseudoType = PseudoActive; + else if (value == "after") { + _pseudoType = PseudoAfter; + element = compat = true; + } + break; + case 'b': + if (value == "before") { + _pseudoType = PseudoBefore; + element = compat = true; + } + break; + case 'c': + if (value == "checked") + _pseudoType = PseudoChecked; + else if (value == "contains(") + _pseudoType = PseudoContains; + break; + case 'd': + if (value == "disabled") + _pseudoType = PseudoDisabled; + break; + case 'e': + if (value == "empty") + _pseudoType = PseudoEmpty; + else if (value == "enabled") + _pseudoType = PseudoEnabled; + break; + case 'f': + if (value == "first-child") + _pseudoType = PseudoFirstChild; + else if (value == "first-letter") { + _pseudoType = PseudoFirstLetter; + element = compat = true; + } + else if (value == "first-line") { + _pseudoType = PseudoFirstLine; + element = compat = true; + } + else if (value == "first-of-type") + _pseudoType = PseudoFirstOfType; + else if (value == "focus") + _pseudoType = PseudoFocus; + break; + case 'h': + if (value == "hover") + _pseudoType = PseudoHover; + break; + case 'i': + if (value == "indeterminate") + _pseudoType = PseudoIndeterminate; + break; + case 'l': + if (value == "link") + _pseudoType = PseudoLink; + else if (value == "lang(") + _pseudoType = PseudoLang; + else if (value == "last-child") + _pseudoType = PseudoLastChild; + else if (value == "last-of-type") + _pseudoType = PseudoLastOfType; + break; + case 'n': + if (value == "not(") + _pseudoType = PseudoNot; + else if (value == "nth-child(") + _pseudoType = PseudoNthChild; + else if (value == "nth-last-child(") + _pseudoType = PseudoNthLastChild; + else if (value == "nth-of-type(") + _pseudoType = PseudoNthOfType; + else if (value == "nth-last-of-type(") + _pseudoType = PseudoNthLastOfType; + break; + case 'o': + if (value == "only-child") + _pseudoType = PseudoOnlyChild; + else if (value == "only-of-type") + _pseudoType = PseudoOnlyOfType; + break; + case 'r': + if (value == "root") + _pseudoType = PseudoRoot; + break; + case 's': + if (value == "selection") { + _pseudoType = PseudoSelection; + element = true; + } + break; + case 't': + if (value == "target") + _pseudoType = PseudoTarget; + break; + case 'v': + if (value == "visited") + _pseudoType = PseudoVisited; + break; + } + } + if (match == PseudoClass && element) + if (!compat) _pseudoType = PseudoOther; + else match = PseudoElement; + else + if (match == PseudoElement && !element) + _pseudoType = PseudoOther; +} + + +bool CSSSelector::operator == ( const CSSSelector &other ) const +{ + const CSSSelector *sel1 = this; + const CSSSelector *sel2 = &other; + + while ( sel1 && sel2 ) { + //assert(sel1->_pseudoType != PseudoNotParsed); + //assert(sel2->_pseudoType != PseudoNotParsed); + if ( sel1->tag != sel2->tag || sel1->attr != sel2->attr || + sel1->relation != sel2->relation || sel1->match != sel2->match || + sel1->nonCSSHint != sel2->nonCSSHint || + sel1->value != sel2->value || + sel1->pseudoType() != sel2->pseudoType() || + sel1->string_arg != sel2->string_arg) + return false; + sel1 = sel1->tagHistory; + sel2 = sel2->tagHistory; + } + if ( sel1 || sel2 ) + return false; + return true; +} + +DOMString CSSSelector::selectorText() const +{ + // FIXME: Support namespaces when dumping the selector text. This requires preserving + // the original namespace prefix used. Ugh. -dwh + DOMString str; + const CSSSelector* cs = this; + TQ_UINT16 tag = localNamePart(cs->tag); + if (tag == anyLocalName && cs->match == CSSSelector::None) + str = "*"; + else if (tag != anyLocalName) + str = getTagName( cs->tag ); + + const CSSSelector* op = 0; + while (true) { + if ( cs->attr == ATTR_ID && 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; + if (!cs->string_arg.isEmpty()) { // e.g :nth-child(...) + str += cs->string_arg; + str += ")"; + } else if (cs->simpleSelector && !op) { // :not(...) + op = cs; + cs = cs->simpleSelector; + continue; + } + } + else if ( cs->match == CSSSelector::PseudoElement ) + { + str += "::"; + str += cs->value; + } + // optional attribute + else if ( cs->attr ) { + DOMString attrName = getAttrName( cs->attr ); + str += "["; + str += attrName; + switch (cs->match) { + case CSSSelector::Exact: + str += "="; + break; + case CSSSelector::Set: + 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: + kdWarning(6080) << "Unhandled case in CSSStyleRuleImpl::selectorText : match=" << cs->match << endl; + } + if (cs->match != CSSSelector::Set) { + str += "\""; + str += cs->value; + str += "\""; + } + str += "]"; + } + if (op && !cs->tagHistory) { + cs=op; + op=0; + str += ")"; + } + + if ((cs->relation != CSSSelector::SubSelector && !op) || !cs->tagHistory) + break; + cs = cs->tagHistory; + } + + if ( cs->tagHistory ) { + DOMString tagHistoryText = cs->tagHistory->selectorText(); + if ( cs->relation == DirectAdjacent ) + str = tagHistoryText + " + " + str; + else if ( cs->relation == IndirectAdjacent ) + str = tagHistoryText + " ~ " + str; + else if ( cs->relation == Child ) + str = tagHistoryText + " > " + str; + else // Descendant + str = tagHistoryText + " " + str; + } + return str; +} + +// ---------------------------------------------------------------------------- |