2 * This file is part of the DOM implementation for KDE.
4 * Copyright 1999-2003 Lars Knoll (knoll@kde.org)
5 * Copyright 1999 Waldo Bastian (bastian@kde.org)
6 * Copyright 2001 Andreas Schlapbach (schlpbch@iam.unibe.ch)
7 * Copyright 2001-2003 Dirk Mueller (mueller@kde.org)
8 * Copyright 2002 Apple Computer, Inc.
9 * Copyright 2004 Allan Sandfeld Jensen (kde@carewolf.com)
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
35 #include "cssproperties.h"
38 #include "css_stylesheetimpl.h"
39 #include <xml/dom_docimpl.h>
40 #include <misc/htmlhashes.h>
41 #include "css_valueimpl.h"
44 void StyleBaseImpl::checkLoaded() const
46 if(m_parent
) m_parent
->checkLoaded();
49 void StyleBaseImpl::checkPending() const
51 if(m_parent
) m_parent
->checkPending();
54 StyleSheetImpl
* StyleBaseImpl::stylesheet()
56 StyleBaseImpl
* b
= this;
57 while(b
&& !b
->isStyleSheet())
59 return static_cast<StyleSheetImpl
*>(b
);
62 KUrl
StyleBaseImpl::baseURL()
64 // try to find the style sheet. If found look for its url.
65 // If it has none, look for the parentsheet, or the parentNode and
66 // try to find out about their url
68 StyleSheetImpl
*sheet
= stylesheet();
70 if(!sheet
) return KUrl();
72 if(!sheet
->href().isNull())
73 return KUrl( sheet
->href().string() );
76 if(sheet
->parent()) return sheet
->parent()->baseURL();
78 if(!sheet
->ownerNode()) return KUrl();
80 return sheet
->ownerNode()->document()->baseURL();
83 void StyleBaseImpl::setParsedValue(int propId
, const CSSValueImpl
*parsedValue
,
84 bool important
, QList
<CSSProperty
*> *propList
)
86 QMutableListIterator
<CSSProperty
*> propIt(*propList
);
87 propIt
.toBack(); // just remove the top one - not sure what should happen if we have multiple instances of the property
89 while (propIt
.hasPrevious()) {
90 p
= propIt
.previous();
91 if (p
->m_id
== propId
&& p
->m_important
== important
) {
92 delete propIt
.value();
98 CSSProperty
*prop
= new CSSProperty();
100 prop
->setValue((CSSValueImpl
*) parsedValue
);
101 prop
->m_important
= important
;
103 propList
->append(prop
);
105 kDebug( 6080 ) << "added property: " << getPropertyName(propId
).string()
106 // non implemented yet << ", value: " << parsedValue->cssText().string()
107 << " important: " << prop
->m_important
;
111 // ------------------------------------------------------------------------------
113 StyleListImpl::~StyleListImpl()
117 if(!m_lstChildren
) return;
119 QListIterator
<StyleBaseImpl
*> it( *m_lstChildren
);
120 while ( it
.hasNext() )
124 if( !n
->refCount() ) delete n
;
126 delete m_lstChildren
;
129 // --------------------------------------------------------------------------------
131 void CSSSelector::print(void)
133 kDebug( 6080 ) << "[Selector: tag = " << QString::number(makeId(tagNamespace
.id(), tagLocalName
.id()),16) << ", attr = \"" << makeId(attrNamespace
.id(), attrLocalName
.id()) << "\", match = \"" << match
134 << "\" value = \"" << value
.string().string().toLatin1().constData() << "\" relation = " << (int)relation
138 kDebug( 6080 ) << " specificity = " << specificity();
141 unsigned int CSSSelector::specificity() const
144 int s
= ((tagLocalName
.id() == anyLocalName
) ? 0 : 1);
165 s
+= tagHistory
->specificity();
166 // make sure it doesn't overflow
170 void CSSSelector::extractPseudoType() const
172 if (match
!= PseudoClass
&& match
!= PseudoElement
)
174 _pseudoType
= PseudoOther
;
175 bool element
= false;
177 if (!value
.isEmpty()) {
178 value
= value
.string().lower();
179 switch (value
[0].unicode()) {
181 if (value
== "-khtml-replaced")
182 _pseudoType
= PseudoReplaced
;
184 if (value
== "-khtml-marker")
185 _pseudoType
= PseudoMarker
;
189 if (value
== "active")
190 _pseudoType
= PseudoActive
;
191 else if (value
== "after") {
192 _pseudoType
= PseudoAfter
;
193 element
= compat
= true;
197 if (value
== "before") {
198 _pseudoType
= PseudoBefore
;
199 element
= compat
= true;
203 if (value
== "checked")
204 _pseudoType
= PseudoChecked
;
205 else if (value
== "contains(")
206 _pseudoType
= PseudoContains
;
209 if (value
== "disabled")
210 _pseudoType
= PseudoDisabled
;
211 if (value
== "default")
212 _pseudoType
= PseudoDefault
;
215 if (value
== "empty")
216 _pseudoType
= PseudoEmpty
;
217 else if (value
== "enabled")
218 _pseudoType
= PseudoEnabled
;
221 if (value
== "first-child")
222 _pseudoType
= PseudoFirstChild
;
223 else if (value
== "first-letter") {
224 _pseudoType
= PseudoFirstLetter
;
225 element
= compat
= true;
227 else if (value
== "first-line") {
228 _pseudoType
= PseudoFirstLine
;
229 element
= compat
= true;
231 else if (value
== "first-of-type")
232 _pseudoType
= PseudoFirstOfType
;
233 else if (value
== "focus")
234 _pseudoType
= PseudoFocus
;
237 if (value
== "hover")
238 _pseudoType
= PseudoHover
;
241 if (value
== "indeterminate")
242 _pseudoType
= PseudoIndeterminate
;
246 _pseudoType
= PseudoLink
;
247 else if (value
== "lang(")
248 _pseudoType
= PseudoLang
;
249 else if (value
== "last-child")
250 _pseudoType
= PseudoLastChild
;
251 else if (value
== "last-of-type")
252 _pseudoType
= PseudoLastOfType
;
256 _pseudoType
= PseudoNot
;
257 else if (value
== "nth-child(")
258 _pseudoType
= PseudoNthChild
;
259 else if (value
== "nth-last-child(")
260 _pseudoType
= PseudoNthLastChild
;
261 else if (value
== "nth-of-type(")
262 _pseudoType
= PseudoNthOfType
;
263 else if (value
== "nth-last-of-type(")
264 _pseudoType
= PseudoNthLastOfType
;
267 if (value
== "only-child")
268 _pseudoType
= PseudoOnlyChild
;
269 else if (value
== "only-of-type")
270 _pseudoType
= PseudoOnlyOfType
;
274 _pseudoType
= PseudoRoot
;
275 else if (value
== "read-only")
276 _pseudoType
= PseudoReadOnly
;
277 else if (value
== "read-write")
278 _pseudoType
= PseudoReadWrite
;
281 if (value
== "selection") {
282 _pseudoType
= PseudoSelection
;
287 if (value
== "target")
288 _pseudoType
= PseudoTarget
;
291 if (value
== "visited")
292 _pseudoType
= PseudoVisited
;
296 if (match
== PseudoClass
&& element
)
297 if (!compat
) _pseudoType
= PseudoOther
;
298 else match
= PseudoElement
;
300 if (match
== PseudoElement
&& !element
)
301 _pseudoType
= PseudoOther
;
305 bool CSSSelector::operator == ( const CSSSelector
&other
) const
307 const CSSSelector
*sel1
= this;
308 const CSSSelector
*sel2
= &other
;
310 while ( sel1
&& sel2
) {
311 //assert(sel1->_pseudoType != PseudoNotParsed);
312 //assert(sel2->_pseudoType != PseudoNotParsed);
313 if ( sel1
->tagLocalName
.id() != sel2
->tagLocalName
.id() || sel1
->attrLocalName
.id() != sel2
->attrLocalName
.id() ||
314 sel1
->tagNamespace
.id() != sel2
->tagNamespace
.id() || sel1
->attrNamespace
.id() != sel2
->attrNamespace
.id() ||
315 sel1
->relation
!= sel2
->relation
|| sel1
->match
!= sel2
->match
||
316 sel1
->value
!= sel2
->value
||
317 sel1
->pseudoType() != sel2
->pseudoType() ||
318 sel1
->string_arg
!= sel2
->string_arg
)
320 sel1
= sel1
->tagHistory
;
321 sel2
= sel2
->tagHistory
;
328 DOMString
CSSSelector::selectorText() const
330 // FIXME: Support namespaces when dumping the selector text. This requires preserving
331 // the original namespace prefix used. Ugh. -dwh
333 const CSSSelector
* cs
= this;
334 quint16 tag
= cs
->tagLocalName
.id();
335 if (tag
== anyLocalName
&& cs
->match
== CSSSelector::None
)
337 else if (tag
!= anyLocalName
)
338 str
= LocalName::fromId(tag
).toString();
340 const CSSSelector
* op
= 0;
342 if ( makeId(cs
->attrNamespace
.id(), cs
->attrLocalName
.id()) == ATTR_ID
&& cs
->match
== CSSSelector::Id
)
347 else if ( cs
->match
== CSSSelector::Class
)
352 else if ( cs
->match
== CSSSelector::PseudoClass
)
356 if (!cs
->string_arg
.isEmpty()) { // e.g :nth-child(...)
357 str
+= cs
->string_arg
;
359 } else if (cs
->simpleSelector
&& !op
) { // :not(...)
361 cs
= cs
->simpleSelector
;
365 else if ( cs
->match
== CSSSelector::PseudoElement
)
370 // optional attribute
371 else if ( cs
->attrLocalName
.id() ) {
372 DOMString attrName
= LocalName::fromId(cs
->attrLocalName
.id()).toString();
376 case CSSSelector::Exact
:
379 case CSSSelector::Set
:
381 case CSSSelector::List
:
384 case CSSSelector::Hyphen
:
387 case CSSSelector::Begin
:
390 case CSSSelector::End
:
393 case CSSSelector::Contain
:
397 kWarning(6080) << "Unhandled case in CSSStyleRuleImpl::selectorText : match=" << cs
->match
;
399 if (cs
->match
!= CSSSelector::Set
) {
406 if (op
&& !cs
->tagHistory
) {
412 if ((cs
->relation
!= CSSSelector::SubSelector
&& !op
) || !cs
->tagHistory
)
417 if ( cs
->tagHistory
) {
418 DOMString tagHistoryText
= cs
->tagHistory
->selectorText();
419 if ( cs
->relation
== DirectAdjacent
)
420 str
= tagHistoryText
+ " + " + str
;
421 else if ( cs
->relation
== IndirectAdjacent
)
422 str
= tagHistoryText
+ " ~ " + str
;
423 else if ( cs
->relation
== Child
)
424 str
= tagHistoryText
+ " > " + str
;
426 str
= tagHistoryText
+ " " + str
;
431 // ----------------------------------------------------------------------------