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_important != 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_important = 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_important
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 '-':
00175 if (value == "-khtml-replaced")
00176 _pseudoType = PseudoReplaced;
00177 else
00178 if (value == "-khtml-marker")
00179 _pseudoType = PseudoMarker;
00180 element = true;
00181 break;
00182 case 'a':
00183 if (value == "active")
00184 _pseudoType = PseudoActive;
00185 else if (value == "after") {
00186 _pseudoType = PseudoAfter;
00187 element = compat = true;
00188 }
00189 break;
00190 case 'b':
00191 if (value == "before") {
00192 _pseudoType = PseudoBefore;
00193 element = compat = true;
00194 }
00195 break;
00196 case 'c':
00197 if (value == "checked")
00198 _pseudoType = PseudoChecked;
00199 else if (value == "contains(")
00200 _pseudoType = PseudoContains;
00201 break;
00202 case 'd':
00203 if (value == "disabled")
00204 _pseudoType = PseudoDisabled;
00205 break;
00206 case 'e':
00207 if (value == "empty")
00208 _pseudoType = PseudoEmpty;
00209 else if (value == "enabled")
00210 _pseudoType = PseudoEnabled;
00211 break;
00212 case 'f':
00213 if (value == "first-child")
00214 _pseudoType = PseudoFirstChild;
00215 else if (value == "first-letter") {
00216 _pseudoType = PseudoFirstLetter;
00217 element = compat = true;
00218 }
00219 else if (value == "first-line") {
00220 _pseudoType = PseudoFirstLine;
00221 element = compat = true;
00222 }
00223 else if (value == "first-of-type")
00224 _pseudoType = PseudoFirstOfType;
00225 else if (value == "focus")
00226 _pseudoType = PseudoFocus;
00227 break;
00228 case 'h':
00229 if (value == "hover")
00230 _pseudoType = PseudoHover;
00231 break;
00232 case 'i':
00233 if (value == "indeterminate")
00234 _pseudoType = PseudoIndeterminate;
00235 break;
00236 case 'l':
00237 if (value == "link")
00238 _pseudoType = PseudoLink;
00239 else if (value == "lang(")
00240 _pseudoType = PseudoLang;
00241 else if (value == "last-child")
00242 _pseudoType = PseudoLastChild;
00243 else if (value == "last-of-type")
00244 _pseudoType = PseudoLastOfType;
00245 break;
00246 case 'n':
00247 if (value == "not(")
00248 _pseudoType = PseudoNot;
00249 else if (value == "nth-child(")
00250 _pseudoType = PseudoNthChild;
00251 else if (value == "nth-last-child(")
00252 _pseudoType = PseudoNthLastChild;
00253 else if (value == "nth-of-type(")
00254 _pseudoType = PseudoNthOfType;
00255 else if (value == "nth-last-of-type(")
00256 _pseudoType = PseudoNthLastOfType;
00257 break;
00258 case 'o':
00259 if (value == "only-child")
00260 _pseudoType = PseudoOnlyChild;
00261 else if (value == "only-of-type")
00262 _pseudoType = PseudoOnlyOfType;
00263 break;
00264 case 'r':
00265 if (value == "root")
00266 _pseudoType = PseudoRoot;
00267 break;
00268 case 's':
00269 if (value == "selection") {
00270 _pseudoType = PseudoSelection;
00271 element = true;
00272 }
00273 break;
00274 case 't':
00275 if (value == "target")
00276 _pseudoType = PseudoTarget;
00277 break;
00278 case 'v':
00279 if (value == "visited")
00280 _pseudoType = PseudoVisited;
00281 break;
00282 }
00283 }
00284 if (match == PseudoClass && element)
00285 if (!compat) _pseudoType = PseudoOther;
00286 else match = PseudoElement;
00287 else
00288 if (match == PseudoElement && !element)
00289 _pseudoType = PseudoOther;
00290 }
00291
00292
00293 bool CSSSelector::operator == ( const CSSSelector &other ) const
00294 {
00295 const CSSSelector *sel1 = this;
00296 const CSSSelector *sel2 = &other;
00297
00298 while ( sel1 && sel2 ) {
00299
00300
00301 if ( sel1->tag != sel2->tag || sel1->attr != sel2->attr ||
00302 sel1->relation != sel2->relation || sel1->match != sel2->match ||
00303 sel1->nonCSSHint != sel2->nonCSSHint ||
00304 sel1->value != sel2->value ||
00305 sel1->pseudoType() != sel2->pseudoType() ||
00306 sel1->string_arg != sel2->string_arg)
00307 return false;
00308 sel1 = sel1->tagHistory;
00309 sel2 = sel2->tagHistory;
00310 }
00311 if ( sel1 || sel2 )
00312 return false;
00313 return true;
00314 }
00315
00316 DOMString CSSSelector::selectorText() const
00317 {
00318
00319
00320 DOMString str;
00321 const CSSSelector* cs = this;
00322 Q_UINT16 tag = localNamePart(cs->tag);
00323 if (tag == anyLocalName && cs->match == CSSSelector::None)
00324 str = "*";
00325 else if (tag != anyLocalName)
00326 str = getTagName( cs->tag );
00327
00328 const CSSSelector* op = 0;
00329 while (true) {
00330 if ( cs->attr == ATTR_ID && cs->match == CSSSelector::Id )
00331 {
00332 str += "#";
00333 str += cs->value;
00334 }
00335 else if ( cs->match == CSSSelector::Class )
00336 {
00337 str += ".";
00338 str += cs->value;
00339 }
00340 else if ( cs->match == CSSSelector::PseudoClass )
00341 {
00342 str += ":";
00343 str += cs->value;
00344 if (!cs->string_arg.isEmpty()) {
00345 str += cs->string_arg;
00346 str += ")";
00347 } else if (cs->simpleSelector && !op) {
00348 op = cs;
00349 cs = cs->simpleSelector;
00350 continue;
00351 }
00352 }
00353 else if ( cs->match == CSSSelector::PseudoElement )
00354 {
00355 str += "::";
00356 str += cs->value;
00357 }
00358
00359 else if ( cs->attr ) {
00360 DOMString attrName = getAttrName( cs->attr );
00361 str += "[";
00362 str += attrName;
00363 switch (cs->match) {
00364 case CSSSelector::Exact:
00365 str += "=";
00366 break;
00367 case CSSSelector::Set:
00368 break;
00369 case CSSSelector::List:
00370 str += "~=";
00371 break;
00372 case CSSSelector::Hyphen:
00373 str += "|=";
00374 break;
00375 case CSSSelector::Begin:
00376 str += "^=";
00377 break;
00378 case CSSSelector::End:
00379 str += "$=";
00380 break;
00381 case CSSSelector::Contain:
00382 str += "*=";
00383 break;
00384 default:
00385 kdWarning(6080) << "Unhandled case in CSSStyleRuleImpl::selectorText : match=" << cs->match << endl;
00386 }
00387 if (cs->match != CSSSelector::Set) {
00388 str += "\"";
00389 str += cs->value;
00390 str += "\"";
00391 }
00392 str += "]";
00393 }
00394 if (op && !cs->tagHistory) {
00395 cs=op;
00396 op=0;
00397 str += ")";
00398 }
00399
00400 if ((cs->relation != CSSSelector::SubSelector && !op) || !cs->tagHistory)
00401 break;
00402 cs = cs->tagHistory;
00403 }
00404
00405 if ( cs->tagHistory ) {
00406 DOMString tagHistoryText = cs->tagHistory->selectorText();
00407 if ( cs->relation == DirectAdjacent )
00408 str = tagHistoryText + " + " + str;
00409 else if ( cs->relation == IndirectAdjacent )
00410 str = tagHistoryText + " ~ " + str;
00411 else if ( cs->relation == Child )
00412 str = tagHistoryText + " > " + str;
00413 else
00414 str = tagHistoryText + " " + str;
00415 }
00416 return str;
00417 }
00418
00419
|