css_base.cpp00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <assert.h>
00030 #include <kdebug.h>
00031
00032 #include "css_base.h"
00033
00034 #ifdef CSS_DEBUG
00035 #include "cssproperties.h"
00036 #endif
00037
00038 #include "css_stylesheetimpl.h"
00039 #include "xml/dom_docimpl.h"
00040 #include "misc/htmlhashes.h"
00041 #include "css_valueimpl.h"
00042 using namespace DOM;
00043
00044 void StyleBaseImpl::checkLoaded() const
00045 {
00046 if(m_parent) m_parent->checkLoaded();
00047 }
00048
00049 StyleSheetImpl* StyleBaseImpl::stylesheet()
00050 {
00051 StyleBaseImpl* b = this;
00052 while(b && !b->isStyleSheet())
00053 b = b->m_parent;
00054 return static_cast<StyleSheetImpl *>(b);
00055 }
00056
00057 KURL StyleBaseImpl::baseURL()
00058 {
00059
00060
00061
00062
00063 StyleSheetImpl *sheet = stylesheet();
00064
00065 if(!sheet) return KURL();
00066
00067 if(!sheet->href().isNull())
00068 return KURL( sheet->href().string() );
00069
00070
00071 if(sheet->parent()) return sheet->parent()->baseURL();
00072
00073 if(!sheet->ownerNode()) return KURL();
00074
00075 return sheet->ownerNode()->getDocument()->baseURL();
00076 }
00077
00078 void StyleBaseImpl::setParsedValue(int propId, const CSSValueImpl *parsedValue,
00079 bool important, bool nonCSSHint, QPtrList<CSSProperty> *propList)
00080 {
00081 QPtrListIterator<CSSProperty> propIt(*propList);
00082 propIt.toLast();
00083 while (propIt.current() &&
00084 ( propIt.current()->m_id != propId || propIt.current()->nonCSSHint != nonCSSHint ||
00085 propIt.current()->m_bImportant != important) )
00086 --propIt;
00087 if (propIt.current())
00088 propList->removeRef(propIt.current());
00089
00090 CSSProperty *prop = new CSSProperty();
00091 prop->m_id = propId;
00092 prop->setValue((CSSValueImpl *) parsedValue);
00093 prop->m_bImportant = important;
00094 prop->nonCSSHint = nonCSSHint;
00095
00096 propList->append(prop);
00097 #ifdef CSS_DEBUG
00098 kdDebug( 6080 ) << "added property: " << getPropertyName(propId).string()
00099
00100 << " important: " << prop->m_bImportant
00101 << " nonCSS: " << prop->nonCSSHint << endl;
00102 #endif
00103 }
00104
00105
00106
00107 StyleListImpl::~StyleListImpl()
00108 {
00109 StyleBaseImpl *n;
00110
00111 if(!m_lstChildren) return;
00112
00113 for( n = m_lstChildren->first(); n != 0; n = m_lstChildren->next() )
00114 {
00115 n->setParent(0);
00116 if( !n->refCount() ) delete n;
00117 }
00118 delete m_lstChildren;
00119 }
00120
00121
00122
00123 void CSSSelector::print(void)
00124 {
00125 kdDebug( 6080 ) << "[Selector: tag = " << QString::number(tag,16) << ", attr = \"" << attr << "\", match = \"" << match
00126 << "\" value = \"" << value.string().latin1() << "\" relation = " << (int)relation
00127 << "]" << endl;
00128 if ( tagHistory )
00129 tagHistory->print();
00130 kdDebug( 6080 ) << " specificity = " << specificity() << endl;
00131 }
00132
00133 unsigned int CSSSelector::specificity() const
00134 {
00135 if ( nonCSSHint )
00136 return 0;
00137
00138 int s = ((localNamePart(tag) == anyLocalName) ? 0 : 1);
00139 switch(match)
00140 {
00141 case Id:
00142 s += 0x10000;
00143 break;
00144 case Exact:
00145 case Set:
00146 case List:
00147 case Class:
00148 case Hyphen:
00149 case PseudoClass:
00150 case PseudoElement:
00151 case Contain:
00152 case Begin:
00153 case End:
00154 s += 0x100;
00155 case None:
00156 break;
00157 }
00158 if(tagHistory)
00159 s += tagHistory->specificity();
00160
00161 return s & 0xffffff;
00162 }
00163
00164 void CSSSelector::extractPseudoType() const
00165 {
00166 if (match != PseudoClass && match != PseudoElement)
00167 return;
00168 _pseudoType = PseudoOther;
00169 bool element = false;
00170 bool compat = false;
00171 if (!value.isEmpty()) {
00172 value = value.lower();
00173 switch (value[0]) {
00174 case 'a':
00175 if (value == "active")
00176 _pseudoType = PseudoActive;
00177 else if (value == "after") {
00178 _pseudoType = PseudoAfter;
00179 element = compat = true;
00180 }
00181 break;
00182 case 'b':
00183 if (value == "before") {
00184 _pseudoType = PseudoBefore;
00185 element = compat = true;
00186 }
00187 break;
00188 case 'c':
00189 if (value == "checked")
00190 _pseudoType = PseudoChecked;
00191 else if (value == "contains(")
00192 _pseudoType = PseudoContains;
00193 break;
00194 case 'd':
00195 if (value == "disabled")
00196 _pseudoType = PseudoDisabled;
00197 break;
00198 case 'e':
00199 if (value == "empty")
00200 _pseudoType = PseudoEmpty;
00201 else if (value == "enabled")
00202 _pseudoType = PseudoEnabled;
00203 break;
00204 case 'f':
00205 if (value == "first-child")
00206 _pseudoType = PseudoFirstChild;
00207 else if (value == "first-letter") {
00208 _pseudoType = PseudoFirstLetter;
00209 element = compat = true;
00210 }
00211 else if (value == "first-line") {
00212 _pseudoType = PseudoFirstLine;
00213 element = compat = true;
00214 }
00215 else if (value == "first-of-type")
00216 _pseudoType = PseudoFirstOfType;
00217 else if (value == "focus")
00218 _pseudoType = PseudoFocus;
00219 break;
00220 case 'h':
00221 if (value == "hover")
00222 _pseudoType = PseudoHover;
00223 break;
00224 case 'i':
00225 if (value == "indeterminate")
00226 _pseudoType = PseudoIndeterminate;
00227 break;
00228 case 'l':
00229 if (value == "link")
00230 _pseudoType = PseudoLink;
00231 else if (value == "lang(")
00232 _pseudoType = PseudoLang;
00233 else if (value == "last-child")
00234 _pseudoType = PseudoLastChild;
00235 else if (value == "last-of-type")
00236 _pseudoType = PseudoLastOfType;
00237 break;
00238 case 'n':
00239 if (value == "not(")
00240 _pseudoType = PseudoNot;
00241 else if (value == "nth-child(")
00242 _pseudoType = PseudoNthChild;
00243 else if (value == "nth-last-child(")
00244 _pseudoType = PseudoNthLastChild;
00245 else if (value == "nth-of-type(")
00246 _pseudoType = PseudoNthOfType;
00247 else if (value == "nth-last-of-type(")
00248 _pseudoType = PseudoNthLastOfType;
00249 break;
00250 case 'o':
00251 if (value == "only-child")
00252 _pseudoType = PseudoOnlyChild;
00253 else if (value == "only-of-type")
00254 _pseudoType = PseudoOnlyOfType;
00255 break;
00256 case 'r':
00257 if (value == "root")
00258 _pseudoType = PseudoRoot;
00259 break;
00260 case 's':
00261 if (value == "selection") {
00262 _pseudoType = PseudoSelection;
00263 element = true;
00264 }
00265 break;
00266 case 't':
00267 if (value == "target")
00268 _pseudoType = PseudoTarget;
00269 break;
00270 case 'v':
00271 if (value == "visited")
00272 _pseudoType = PseudoVisited;
00273 break;
00274 }
00275 }
00276 if (match == PseudoClass && element)
00277 if (!compat) _pseudoType = PseudoOther;
00278 else match = PseudoElement;
00279 else
00280 if (match == PseudoElement && !element)
00281 _pseudoType = PseudoOther;
00282 }
00283
00284
00285 bool CSSSelector::operator == ( const CSSSelector &other ) const
00286 {
00287 const CSSSelector *sel1 = this;
00288 const CSSSelector *sel2 = &other;
00289
00290 while ( sel1 && sel2 ) {
00291
00292
00293 if ( sel1->tag != sel2->tag || sel1->attr != sel2->attr ||
00294 sel1->relation != sel2->relation || sel1->match != sel2->match ||
00295 sel1->nonCSSHint != sel2->nonCSSHint ||
00296 sel1->value != sel2->value ||
00297 sel1->pseudoType() != sel2->pseudoType() ||
00298 sel1->string_arg != sel2->string_arg)
00299 return false;
00300 sel1 = sel1->tagHistory;
00301 sel2 = sel2->tagHistory;
00302 }
00303 if ( sel1 || sel2 )
00304 return false;
00305 return true;
00306 }
00307
00308 DOMString CSSSelector::selectorText() const
00309 {
00310
00311
00312 DOMString str;
00313 const CSSSelector* cs = this;
00314 Q_UINT16 tag = localNamePart(cs->tag);
00315 if (tag == anyLocalName && cs->match == CSSSelector::None)
00316 str = "*";
00317 else if (tag != anyLocalName)
00318 str = getTagName( cs->tag );
00319
00320 const CSSSelector* op = 0;
00321 while (true) {
00322 if ( cs->attr == ATTR_ID && cs->match == CSSSelector::Id )
00323 {
00324 str += "#";
00325 str += cs->value;
00326 }
00327 else if ( cs->match == CSSSelector::Class )
00328 {
00329 str += ".";
00330 str += cs->value;
00331 }
00332 else if ( cs->match == CSSSelector::PseudoClass )
00333 {
00334 str += ":";
00335 str += cs->value;
00336 if (!cs->string_arg.isEmpty()) {
00337 str += cs->string_arg;
00338 str += ")";
00339 } else if (cs->simpleSelector && !op) {
00340 op = cs;
00341 cs = cs->simpleSelector;
00342 continue;
00343 }
00344 }
00345 else if ( cs->match == CSSSelector::PseudoElement )
00346 {
00347 str += "::";
00348 str += cs->value;
00349 }
00350
00351 else if ( cs->attr ) {
00352 DOMString attrName = getAttrName( cs->attr );
00353 str += "[";
00354 str += attrName;
00355 switch (cs->match) {
00356 case CSSSelector::Exact:
00357 str += "=";
00358 break;
00359 case CSSSelector::Set:
00360 break;
00361 case CSSSelector::List:
00362 str += "~=";
00363 break;
00364 case CSSSelector::Hyphen:
00365 str += "|=";
00366 break;
00367 case CSSSelector::Begin:
00368 str += "^=";
00369 break;
00370 case CSSSelector::End:
00371 str += "$=";
00372 break;
00373 case CSSSelector::Contain:
00374 str += "*=";
00375 break;
00376 default:
00377 kdWarning(6080) << "Unhandled case in CSSStyleRuleImpl::selectorText : match=" << cs->match << endl;
00378 }
00379 if (cs->match != CSSSelector::Set) {
00380 str += "\"";
00381 str += cs->value;
00382 str += "\"";
00383 }
00384 str += "]";
00385 }
00386 if (op && !cs->tagHistory) {
00387 cs=op;
00388 op=0;
00389 str += ")";
00390 }
00391
00392 if ((cs->relation != CSSSelector::SubSelector && !op) || !cs->tagHistory)
00393 break;
00394 cs = cs->tagHistory;
00395 }
00396
00397 if ( cs->tagHistory ) {
00398 DOMString tagHistoryText = cs->tagHistory->selectorText();
00399 if ( cs->relation == DirectAdjacent )
00400 str = tagHistoryText + " + " + str;
00401 else if ( cs->relation == IndirectAdjacent )
00402 str = tagHistoryText + " ~ " + str;
00403 else if ( cs->relation == Child )
00404 str = tagHistoryText + " > " + str;
00405 else
00406 str = tagHistoryText + " " + str;
00407 }
00408 return str;
00409 }
00410
00411
|