📄 cssparser.cpp
字号:
/** * This file is part of the DOM implementation for KDE. * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * 1999 Waldo Bastian (bastian@kde.org) * * 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * $Id: cssparser.cpp,v 1.2 2002/01/28 04:31:02 leon Exp $ *///#define CSS_DEBUG#include "render_interface.h"#include "render_style.h"#include "css_stylesheetimpl.h"#include "css_stylesheet.h"#include "css_rule.h"#include "css_ruleimpl.h"#include "css_valueimpl.h"#include "csshelper.h"#include "dom_string.h"#include "dom_nodeimpl.h"#include "html_documentimpl.h"#include "dom_exception.h"#include "kdebug.h"#include "htmlhashes.h"#include "cssproperties.h"#include "cssvalues.h"using namespace DOM;//// The following file defines the function// const struct props *findProp(const char *word, int len)//// with 'props->id' a CSS property in the range from CSS_PROP_MIN to// (and including) CSS_PROP_TOTAL-1#include "cssproperties.c"#include "cssvalues.c"int DOM::getPropertyID(const char *tagStr, int len){ const struct props *propsPtr = findProp(tagStr, len); if (!propsPtr) return 0; return propsPtr->id;}// ------------------------------------------------------------------------------------------------------bool StyleBaseImpl::deleteMe(){ if(!m_parent && _ref <= 0) return true; return false;}void StyleBaseImpl::setParent(StyleBaseImpl *parent){ m_parent = parent;}void StyleBaseImpl::checkLoaded(){ if(m_parent) m_parent->checkLoaded();}DOMString StyleBaseImpl::baseUrl(){ // try to find the style sheet. If found look for it's url. // If it has none, look for the parentsheet, or the parentNode and // try to find out about their url StyleBaseImpl *b = this; while(b && !b->isStyleSheet()) b = b->parent(); if(!b) return 0; StyleSheetImpl *sheet = static_cast<StyleSheetImpl *>(b); if(!sheet->href().isNull()) return sheet->href(); // find parent if(sheet->parent()) return sheet->parent()->baseUrl(); if(!sheet->ownerNode()) return 0; DocumentImpl *doc = static_cast<DocumentImpl*>(sheet->ownerNode()->nodeType() == Node::DOCUMENT_NODE ? sheet->ownerNode() : sheet->ownerNode()->ownerDocument()); if(!doc->isHTMLDocument()) return 0; HTMLDocumentImpl *htmldoc = static_cast<HTMLDocumentImpl *>(doc); return htmldoc->baseURL();}/* * parsing functions for stylesheets */inline bool isspace(const QChar &c){ return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == QChar(0xa0));}const QChar *StyleBaseImpl::parseSpace(const QChar *curP, const QChar *endP){ bool sc = false; // possible start comment? bool ec = false; // possible end comment? bool ic = false; // in comment? while (curP < endP) { if (ic) { if (ec && (*curP == '/')) ic = false; else if (*curP == '*') ec = true; else ec = false; } else if (sc && (*curP == '*')) { ic = true; } else if (*curP == '/') { sc = true; } else if (!isspace(*curP)) { return(curP); } else { sc = false; } curP++; } return(0);}/* * ParseToChar * * Search for an expected character. Deals with escaped characters, * quoted strings, and pairs of braces/parens/brackets. */const QChar *StyleBaseImpl::parseToChar(const QChar *curP, const QChar *endP, QChar c, bool chkws, bool endAtBlock){ //kdDebug( 6080 ) << "parsetochar: \"" << QString(curP, endP-curP) << "\" searching " << c << " ws=" << chkws << endl; bool sq = false; /* in single quote? */ bool dq = false; /* in double quote? */ bool esc = false; /* escape mode? */ while (curP < endP) { if (esc) esc = false; else if (*curP == '\\') esc = true; else if (!sq && (*curP == '"')) dq = !dq; else if (!dq && (*curP == '\'')) sq = !sq; else if (!sq && !dq && *curP == c) return(curP); else if (!sq && !dq && chkws && isspace(*curP)) return(curP); else if(!sq && !dq ) { if (*curP == '{') { if(endAtBlock) return curP; curP = parseToChar(curP + 1, endP, '}', false); if (!curP) return(0); } else if (*curP == '(') { curP = parseToChar(curP + 1, endP, ')', false); if (!curP) return(0); } else if (*curP == '[') { curP = parseToChar(curP + 1, endP, ']', false); if (!curP) return(0); } } curP++; } return(0);}CSSRuleImpl *StyleBaseImpl::parseAtRule(const QChar *&curP, const QChar *endP){ curP++; const QChar *startP = curP; while( *curP != ' ' && *curP != '{' && *curP != '\'') curP++; QString rule(startP, curP-startP); rule = rule.lower(); //kdDebug( 6080 ) << "rule = '" << rule << "'" << endl; if(rule == "import") { // load stylesheet and pass it over curP = parseSpace(curP, endP); if(!curP) return 0; startP = curP++; curP = parseToChar(startP, endP, ';', true); // Do not allow @import statements after explicity inlined // declarations. They should simply be ignored per CSS-1 // specification section 3.0. if( !curP || hasInlinedDecl ) return 0; DOMString url = khtml::parseURL(DOMString(startP, curP - startP)); startP = curP; if(*curP != ';') curP = parseToChar(startP, endP, ';', false, true); if(!curP) return 0; QString media(startP, curP - startP); // ### check if at the beginning of the stylesheet (no style rule // before the import rule)#ifdef CSS_DEBUG// kdDebug( 6080 ) << "at rule: url = " << url.string() << " media = " << media << endl;#endif // ignore block following @import rule if( *curP == '{' ) { curP++; curP = parseToChar(curP, endP, '}', false); if(curP) curP++; } // ### only media="", "screen and "all" are imported for the moment... if( !media.isEmpty() && !(media.contains("all") || media.contains("screen")) ) return 0; if(!this->isCSSStyleSheet()) return 0; return new CSSImportRuleImpl(this, url, 0); } else if(rule == "charset") { // ### invoke decoder startP = curP++; curP = parseToChar(startP, endP, ';', false);#ifdef CSS_DEBUG// kdDebug( 6080 ) << "charset = " << QString(startP, curP - startP) << endl;#endif } else if(rule == "font-face") { startP = curP++; curP = parseToChar(startP, endP, '}', false);#ifdef CSS_DEBUG// kdDebug( 6080 ) << "font rule = " << QString(startP, curP - startP) << endl;#endif } else if(rule == "media") { startP = curP++; curP = parseToChar(startP, endP, '}', false);#ifdef CSS_DEBUG// kdDebug( 6080 ) << "media rule = " << QString(startP, curP - startP) << endl;#endif } else if(rule == "page") { startP = curP++; curP = parseToChar(startP, endP, '}', false);#ifdef CSS_DEBUG// kdDebug( 6080 ) << "page rule = " << QString(startP, curP - startP) << endl;#endif } return 0;}static DOMString getValue( const QChar *curP, const QChar *endP, const QChar *&endVal){ //QString selecString( curP, endP - curP ); //kdDebug( 6080 ) << "getValue = \"" << selecString << "\"" << endl; endVal = curP; endVal++; // ignore first char (could be the ':' form the pseudo classes) while( endVal < endP && *endVal != '.' && *endVal != ':' && *endVal != '[' ) endVal++; const QChar *end = endVal; if(endVal == endP) endVal = 0; return DOMString( curP, end - curP);}CSSSelector *StyleBaseImpl::parseSelector2(const QChar *curP, const QChar *endP, CSSSelector *stack, CSSSelector::Relation relation){ CSSSelector *cs = new CSSSelector();#ifdef CSS_DEBUG QString selecString( curP, endP - curP );// kdDebug( 6080 ) << "selectString = \"" << selecString << "\"" << endl;#endif const QChar *endVal = 0; if (*curP == '#' && (curP < endP && !((*(curP+1)).isDigit()))) { cs->tag = -1; cs->attr = ATTR_ID; cs->match = CSSSelector::Exact; cs->value = getValue( curP+1, endP, endVal); } else if (*curP == '.' && (curP < endP && !((*(curP+1)).isDigit()))) { cs->tag = -1; cs->attr = ATTR_CLASS; cs->match = CSSSelector::List; cs->value = getValue( curP+1, endP, endVal); } else if (*curP == ':') { cs->tag = -1; cs->value = getValue(curP, endP, endVal); cs->match = CSSSelector::Pseudo; } else { const QChar *startP = curP; QString tag; while (curP < endP) { if (*curP =='#' && (curP < endP && !((*(curP+1)).isDigit()))) { tag = QString( startP, curP-startP ); cs->attr = ATTR_ID; cs->match = CSSSelector::Exact; cs->value = getValue(curP+1, endP, endVal); break; } else if (*curP == '.' && (curP < endP && !((*(curP+1)).isDigit()))) { tag = QString( startP, curP - startP ); cs->attr = ATTR_CLASS; cs->match = CSSSelector::List; cs->value = getValue(curP+1, endP, endVal); break; } else if (*curP == ':') { // pseudo attributes (:link, :hover, ...) tag = QString( startP, curP - startP ); cs->value = getValue(curP, endP, endVal); cs->match = CSSSelector::Pseudo; break; } else if (*curP == '[') { tag = QString( startP, curP - startP ); curP++; if ( curP >= endP ) { delete cs; return 0; }#ifdef CSS_DEBUG// kdDebug( 6080 ) << "tag = " << tag << endl;#endif const QChar *equal = parseToChar(curP, endP, '=', false); QString attr; if(!equal) { attr = QString( curP, endP - curP - 1 ); attr = attr.stripWhiteSpace();#ifdef CSS_DEBUG// kdDebug( 6080 ) << "attr = '" << attr << "'" << endl;#endif cs->match = CSSSelector::Set; } else { // check relation: = / ~= / |= if(*(equal-1) == '~') { attr = QString( curP, equal - curP - 1 ); cs->match = CSSSelector::List; } else if(*(equal-1) == '|') { attr = QString( curP, equal - curP - 1 ); cs->match = CSSSelector::Hyphen; } else { attr = QString(curP, equal - curP ); cs->match = CSSSelector::Exact; } } attr = attr.stripWhiteSpace(); cs->attr = khtml::getAttrID(attr.ascii(), attr.length()); if(equal) { equal++; while(equal < endP && *equal == ' ') equal++; if(equal >= endP ) { delete cs; return 0; } endVal = equal; bool hasQuote = false; if(*equal == '\'') { equal++; endVal++; while(endVal < endP && *endVal != '\'') endVal++; hasQuote = true; } else if(*equal == '\"') { equal++; endVal++; while(endVal < endP && *endVal != '\"') endVal++; hasQuote = true; } else { while(endVal < endP && *endVal != ']') endVal++; } cs->value = DOMString(equal, endVal - equal); if ( hasQuote ) { while( endVal < endP - 1 && *endVal != ']' ) endVal++; } endVal++; // ### fixme we ignore everything after [..] if( endVal == endP ) endVal = 0; } break; } else { curP++; } } if (curP == endP) { tag = QString( startP, curP - startP ); } if(tag == "*") { //kdDebug( 6080 ) << "found '*' selector" << endl; cs->tag = -1; } else cs->tag = khtml::getTagID(tag.lower().ascii(), tag.length()); } if (cs->tag == 0) { delete cs; delete stack; return(0); }#ifdef CSS_DEBUG// kdDebug( 6080 ) << "[Selector: tag=" << cs->tag << " Attribute=" << cs->attr << " match=" << (int)cs->match << " value=" << cs->value.string() << " specificity=" << cs->specificity() << "]" << endl;#endif cs->tagHistory = stack; cs->relation = relation; relation = CSSSelector::SubSelector; stack = cs; //stack->print(); if( endVal ) { // lets be recursive stack = parseSelector2(endVal, endP, stack, relation); } return(stack);}CSSSelector *StyleBaseImpl::parseSelector1(const QChar *curP, const QChar *endP){#ifdef CSS_DEBUG// kdDebug( 6080 ) << "selector1 is \'" << QString(curP, endP-curP) << "\'" << endl;#endif CSSSelector *selecStack=0; curP = parseSpace(curP, endP); if (!curP) return(0); CSSSelector::Relation relation = CSSSelector::Descendant; const QChar *startP = curP; while (curP <= endP) { if ((curP == endP) || isspace(*curP) || *curP == '+' || *curP == '>') { selecStack = parseSelector2(startP, curP, selecStack, relation); if (!selecStack) return 0; curP = parseSpace(curP, endP); if (!curP) return(selecStack); relation = CSSSelector::Descendant; if(*curP == '+') { relation = CSSSelector::Sibling; curP++; curP = parseSpace(curP, endP); } else if(*curP == '>') {#ifdef CSS_DEBUG// kdDebug( 6080 ) << "child selector" << endl;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -