📄 qcssparser.cpp
字号:
return result;}Parser::Parser(QString css, bool isFile){ if (isFile) { QFile file(css); if (file.open(QFile::ReadOnly)) { sourcePath = QFileInfo(css).absolutePath() + QLatin1String("/"); QTextStream stream(&file); css = stream.readAll(); } else { qWarning() << "QCss::Parser - Failed to load file " << css; css.clear(); } } init(css);}Parser::Parser(){ index = 0; errorIndex = -1; hasEscapeSequences = false;}void Parser::init(const QString &css){ symbols.resize(0); Scanner::scan(Scanner::preprocess(css, &hasEscapeSequences), &symbols); index = 0; errorIndex = -1; symbols.reserve(qMax(symbols.capacity(), symbols.size()));}bool Parser::parse(StyleSheet *styleSheet){ if (testTokenAndEndsWith(ATKEYWORD_SYM, QLatin1String("charset"))) { if (!next(STRING)) return false; if (!next(SEMICOLON)) return false; } while (test(S) || test(CDO) || test(CDC)); while (testImport()) { ImportRule rule; if (!parseImport(&rule)) return false; styleSheet->importRules.append(rule); while (test(S) || test(CDO) || test(CDC)); } do { if (testMedia()) { MediaRule rule; if (!parseMedia(&rule)) return false; styleSheet->mediaRules.append(rule); } else if (testPage()) { PageRule rule; if (!parsePage(&rule)) return false; styleSheet->pageRules.append(rule); } else if (testRuleset()) { StyleRule rule; if (!parseRuleset(&rule)) return false; styleSheet->styleRules.append(rule); } else if (test(ATKEYWORD_SYM)) { if (!until(RBRACE)) return false; } else if (hasNext()) { return false; } while (test(S) || test(CDO) || test(CDC)); } while (hasNext()); return true;}Symbol Parser::errorSymbol(){ if (errorIndex == -1) return Symbol(); return symbols.at(errorIndex);}static inline void removeOptionalQuotes(QString *str){ if (!str->startsWith(QLatin1Char('\'')) && !str->startsWith(QLatin1Char('\"'))) return; str->remove(0, 1); str->chop(1);}bool Parser::parseImport(ImportRule *importRule){ skipSpace(); if (test(STRING)) { importRule->href = lexem(); } else { if (!testAndParseUri(&importRule->href)) return false; } removeOptionalQuotes(&importRule->href); skipSpace(); if (testMedium()) { if (!parseMedium(&importRule->media)) return false; while (test(COMMA)) { skipSpace(); if (!parseNextMedium(&importRule->media)) return false; } } if (!next(SEMICOLON)) return false; skipSpace(); return true;}bool Parser::parseMedia(MediaRule *mediaRule){ do { skipSpace(); if (!parseNextMedium(&mediaRule->media)) return false; } while (test(COMMA)); if (!next(LBRACE)) return false; skipSpace(); while (testRuleset()) { StyleRule rule; if (!parseRuleset(&rule)) return false; mediaRule->styleRules.append(rule); } if (!next(RBRACE)) return false; skipSpace(); return true;}bool Parser::parseMedium(QStringList *media){ media->append(lexem()); skipSpace(); return true;}bool Parser::parsePage(PageRule *pageRule){ skipSpace(); if (testPseudoPage()) if (!parsePseudoPage(&pageRule->selector)) return false; skipSpace(); if (!next(LBRACE)) return false; do { skipSpace(); Declaration decl; if (!parseNextDeclaration(&decl)) return false; if (!decl.isEmpty()) pageRule->declarations.append(decl); } while (test(SEMICOLON)); if (!next(RBRACE)) return false; skipSpace(); return true;}bool Parser::parsePseudoPage(QString *selector){ if (!next(IDENT)) return false; *selector = lexem(); return true;}bool Parser::parseNextOperator(Value *value){ if (!hasNext()) return true; switch (next()) { case SLASH: value->type = Value::TermOperatorSlash; skipSpace(); break; case COMMA: value->type = Value::TermOperatorComma; skipSpace(); break; default: prev(); break; } return true;}bool Parser::parseCombinator(BasicSelector::Relation *relation){ *relation = BasicSelector::NoRelation; if (lookup() == S) { *relation = BasicSelector::MatchNextSelectorIfAncestor; skipSpace(); } else { prev(); } if (test(PLUS)) { *relation = BasicSelector::MatchNextSelectorIfPreceeds; } else if (test(GREATER)) { *relation = BasicSelector::MatchNextSelectorIfParent; } skipSpace(); return true;}bool Parser::parseProperty(Declaration *decl){ decl->property = lexem(); decl->propertyId = static_cast<Property>(findKnownValue(decl->property, properties, NumProperties)); skipSpace(); return true;}bool Parser::parseRuleset(StyleRule *styleRule){ Selector sel; if (!parseSelector(&sel)) return false; styleRule->selectors.append(sel); while (test(COMMA)) { skipSpace(); Selector sel; if (!parseNextSelector(&sel)) return false; styleRule->selectors.append(sel); } skipSpace(); if (!next(LBRACE)) return false; const int declarationStart = index; do { skipSpace(); Declaration decl; const int rewind = index; if (!parseNextDeclaration(&decl)) { index = rewind; const bool foundSemicolon = until(SEMICOLON); const int semicolonIndex = index; index = declarationStart; const bool foundRBrace = until(RBRACE); if (foundSemicolon && semicolonIndex < index) { decl = Declaration(); index = semicolonIndex - 1; } else { skipSpace(); return foundRBrace; } } if (!decl.isEmpty()) styleRule->declarations.append(decl); } while (test(SEMICOLON)); if (!next(RBRACE)) return false; skipSpace(); return true;}bool Parser::parseSelector(Selector *sel){ BasicSelector basicSel; if (!parseSimpleSelector(&basicSel)) return false; while (testCombinator()) { if (!parseCombinator(&basicSel.relationToNext)) return false; if (!testSimpleSelector()) break; sel->basicSelectors.append(basicSel); basicSel = BasicSelector(); if (!parseSimpleSelector(&basicSel)) return false; } sel->basicSelectors.append(basicSel); return true;}bool Parser::parseSimpleSelector(BasicSelector *basicSel){ int minCount = 0; if (lookupElementName()) { if (!parseElementName(&basicSel->elementName)) return false; } else { prev(); minCount = 1; } bool onceMore; int count = 0; do { onceMore = false; if (test(HASH)) { QString id = lexem(); // chop off leading # id.remove(0, 1); basicSel->ids.append(id); onceMore = true; } else if (testClass()) { onceMore = true; AttributeSelector a; a.name = QLatin1String("class"); a.valueMatchCriterium = AttributeSelector::MatchContains; if (!parseClass(&a.value)) return false; basicSel->attributeSelectors.append(a); } else if (testAttrib()) { onceMore = true; AttributeSelector a; if (!parseAttrib(&a)) return false; basicSel->attributeSelectors.append(a); } else if (testPseudo()) { onceMore = true; Pseudo ps; if (!parsePseudo(&ps)) return false; basicSel->pseudos.append(ps); } if (onceMore) ++count; } while (onceMore); return count >= minCount;}bool Parser::parseClass(QString *name){ if (!next(IDENT)) return false; *name = lexem(); return true;}bool Parser::parseElementName(QString *name){ switch (lookup()) { case STAR: name->clear(); break; case IDENT: *name = lexem(); break; default: return false; } return true;}bool Parser::parseAttrib(AttributeSelector *attr){ skipSpace(); if (!next(IDENT)) return false; attr->name = lexem(); skipSpace(); if (test(EQUAL)) { attr->valueMatchCriterium = AttributeSelector::MatchEqual; } else if (test(INCLUDES)) { attr->valueMatchCriterium = AttributeSelector::MatchContains; } else if (test(DASHMATCH)) { attr->valueMatchCriterium = AttributeSelector::MatchBeginsWith; } else { return next(RBRACKET); } skipSpace(); if (!test(IDENT) && !test(STRING)) return false; attr->value = unquotedLexem(); skipSpace(); return next(RBRACKET);}bool Parser::parsePseudo(Pseudo *pseudo){ test(COLON); pseudo->negated = test(EXCLAMATION_SYM); if (test(IDENT)) { pseudo->name = lexem(); pseudo->type = static_cast<PseudoClass>(findKnownValue(pseudo->name, pseudos, NumPseudos)); return true; } if (!next(FUNCTION)) return false; pseudo->function = lexem(); // chop off trailing parenthesis pseudo->function.chop(1); skipSpace(); if (!test(IDENT)) return false; pseudo->name = lexem(); skipSpace(); return next(RPAREN);}bool Parser::parseNextDeclaration(Declaration *decl){ if (!testProperty()) return true; // not an error! if (!parseProperty(decl)) return false; if (!next(COLON)) return false; skipSpace(); if (!parseNextExpr(&decl->values)) return false; if (testPrio()) if (!parsePrio(decl)) return false; return true;}bool Parser::testPrio(){ const int rewind = index; if (!test(EXCLAMATION_SYM)) return false; skipSpace(); if (!test(IDENT)) { index = rewind; return false; } if (lexem().compare(QLatin1String("important"), Qt::CaseInsensitive) != 0) { index = rewind; return false; } return true;}bool Parser::parsePrio(Declaration *declaration){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -