| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library csslib.parser; | 5 library csslib.parser; |
| 6 | 6 |
| 7 import 'dart:math' as math; | 7 import 'dart:math' as math; |
| 8 | 8 |
| 9 import 'package:source_span/source_span.dart'; | 9 import 'package:source_span/source_span.dart'; |
| 10 | 10 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 | 57 |
| 58 _createMessages(errors: errors, options: options); | 58 _createMessages(errors: errors, options: options); |
| 59 | 59 |
| 60 var file = new SourceFile(source); | 60 var file = new SourceFile(source); |
| 61 | 61 |
| 62 var tree = new _Parser(file, source).parse(); | 62 var tree = new _Parser(file, source).parse(); |
| 63 | 63 |
| 64 analyze([tree], errors: errors, options: options); | 64 analyze([tree], errors: errors, options: options); |
| 65 | 65 |
| 66 if (polyfill) { | 66 if (polyfill) { |
| 67 var processCss = new PolyFill(messages, true); | 67 var processCss = new PolyFill(messages); |
| 68 processCss.process(tree, includes: includes); | 68 processCss.process(tree, includes: includes); |
| 69 } | 69 } |
| 70 | 70 |
| 71 return tree; | 71 return tree; |
| 72 } | 72 } |
| 73 | 73 |
| 74 /** Analyze the CSS file. */ | 74 /** Analyze the CSS file. */ |
| 75 void analyze(List<StyleSheet> styleSheets, | 75 void analyze(List<StyleSheet> styleSheets, |
| 76 {List<Message> errors, PreprocessorOptions options}) { | 76 {List<Message> errors, PreprocessorOptions options}) { |
| 77 _createMessages(errors: errors, options: options); | 77 _createMessages(errors: errors, options: options); |
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 andOp = TokenKind.matchMediaOperator(op, 0, opLen) == | 423 andOp = TokenKind.matchMediaOperator(op, 0, opLen) == |
| 424 TokenKind.MEDIA_OP_AND; | 424 TokenKind.MEDIA_OP_AND; |
| 425 if (!andOp) break; | 425 if (!andOp) break; |
| 426 _next(); | 426 _next(); |
| 427 } | 427 } |
| 428 } | 428 } |
| 429 | 429 |
| 430 if (unaryOp != -1 || type != null || exprs.length > 0) { | 430 if (unaryOp != -1 || type != null || exprs.length > 0) { |
| 431 return new MediaQuery(unaryOp, type, exprs, _makeSpan(start)); | 431 return new MediaQuery(unaryOp, type, exprs, _makeSpan(start)); |
| 432 } | 432 } |
| 433 return null; |
| 433 } | 434 } |
| 434 | 435 |
| 435 MediaExpression processMediaExpression([bool andOperator = false]) { | 436 MediaExpression processMediaExpression([bool andOperator = false]) { |
| 436 var start = _peekToken.span; | 437 var start = _peekToken.span; |
| 437 | 438 |
| 438 // Grammar: '(' S* media_feature S* [ ':' S* expr ]? ')' S* | 439 // Grammar: '(' S* media_feature S* [ ':' S* expr ]? ')' S* |
| 439 if (_maybeEat(TokenKind.LPAREN)) { | 440 if (_maybeEat(TokenKind.LPAREN)) { |
| 440 if (_peekIdentifier()) { | 441 if (_peekIdentifier()) { |
| 441 var feature = identifier(); // Media feature. | 442 var feature = identifier(); // Media feature. |
| 442 while (_maybeEat(TokenKind.COLON)) { | 443 while (_maybeEat(TokenKind.COLON)) { |
| 443 var startExpr = _peekToken.span; | 444 var startExpr = _peekToken.span; |
| 444 var exprs = processExpr(); | 445 var exprs = processExpr(); |
| 445 if (_maybeEat(TokenKind.RPAREN)) { | 446 if (_maybeEat(TokenKind.RPAREN)) { |
| 446 return new MediaExpression( | 447 return new MediaExpression( |
| 447 andOperator, feature, exprs, _makeSpan(startExpr)); | 448 andOperator, feature, exprs, _makeSpan(startExpr)); |
| 448 } else if (isChecked) { | 449 } else if (isChecked) { |
| 449 _warning("Missing parenthesis around media expression", | 450 _warning("Missing parenthesis around media expression", |
| 450 _makeSpan(start)); | 451 _makeSpan(start)); |
| 451 return null; | 452 return null; |
| 452 } | 453 } |
| 453 } | 454 } |
| 454 } else if (isChecked) { | 455 } else if (isChecked) { |
| 455 _warning("Missing media feature in media expression", _makeSpan(start)); | 456 _warning("Missing media feature in media expression", _makeSpan(start)); |
| 456 return null; | |
| 457 } | 457 } |
| 458 } | 458 } |
| 459 return null; |
| 459 } | 460 } |
| 460 | 461 |
| 461 /** | 462 /** |
| 462 * Directive grammar: | 463 * Directive grammar: |
| 463 * | 464 * |
| 464 * import: '@import' [string | URI] media_list? | 465 * import: '@import' [string | URI] media_list? |
| 465 * media: '@media' media_query_list '{' ruleset '}' | 466 * media: '@media' media_query_list '{' ruleset '}' |
| 466 * page: '@page' [':' IDENT]? '{' declarations '}' | 467 * page: '@page' [':' IDENT]? '{' declarations '}' |
| 467 * stylet: '@stylet' IDENT '{' ruleset '}' | 468 * stylet: '@stylet' IDENT '{' ruleset '}' |
| 468 * media_query_list: IDENT [',' IDENT] | 469 * media_query_list: IDENT [',' IDENT] |
| (...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 791 mustHaveParam = true; | 792 mustHaveParam = true; |
| 792 continue; | 793 continue; |
| 793 } | 794 } |
| 794 keepGoing = !_maybeEat(TokenKind.RPAREN); | 795 keepGoing = !_maybeEat(TokenKind.RPAREN); |
| 795 } | 796 } |
| 796 } | 797 } |
| 797 | 798 |
| 798 _eat(TokenKind.LBRACE); | 799 _eat(TokenKind.LBRACE); |
| 799 | 800 |
| 800 List<TreeNode> productions = []; | 801 List<TreeNode> productions = []; |
| 801 List<TreeNode> declarations = []; | |
| 802 var mixinDirective; | 802 var mixinDirective; |
| 803 | 803 |
| 804 var start = _peekToken.span; | 804 var start = _peekToken.span; |
| 805 while (!_maybeEat(TokenKind.END_OF_FILE)) { | 805 while (!_maybeEat(TokenKind.END_OF_FILE)) { |
| 806 var directive = processDirective(); | 806 var directive = processDirective(); |
| 807 if (directive != null) { | 807 if (directive != null) { |
| 808 productions.add(directive); | 808 productions.add(directive); |
| 809 continue; | 809 continue; |
| 810 } | 810 } |
| 811 | 811 |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 977 } | 977 } |
| 978 | 978 |
| 979 RuleSet processRuleSet([SelectorGroup selectorGroup]) { | 979 RuleSet processRuleSet([SelectorGroup selectorGroup]) { |
| 980 if (selectorGroup == null) { | 980 if (selectorGroup == null) { |
| 981 selectorGroup = processSelectorGroup(); | 981 selectorGroup = processSelectorGroup(); |
| 982 } | 982 } |
| 983 if (selectorGroup != null) { | 983 if (selectorGroup != null) { |
| 984 return new RuleSet( | 984 return new RuleSet( |
| 985 selectorGroup, processDeclarations(), selectorGroup.span); | 985 selectorGroup, processDeclarations(), selectorGroup.span); |
| 986 } | 986 } |
| 987 return null; |
| 987 } | 988 } |
| 988 | 989 |
| 989 /** | 990 /** |
| 990 * Look ahead to see if what should be a declaration is really a selector. | 991 * Look ahead to see if what should be a declaration is really a selector. |
| 991 * If it's a selector than it's a nested selector. This support's Less' | 992 * If it's a selector than it's a nested selector. This support's Less' |
| 992 * nested selector syntax (requires a look ahead). E.g., | 993 * nested selector syntax (requires a look ahead). E.g., |
| 993 * | 994 * |
| 994 * div { | 995 * div { |
| 995 * width : 20px; | 996 * width : 20px; |
| 996 * span { | 997 * span { |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1184 do { | 1185 do { |
| 1185 Selector selector = processSelector(); | 1186 Selector selector = processSelector(); |
| 1186 if (selector != null) { | 1187 if (selector != null) { |
| 1187 selectors.add(selector); | 1188 selectors.add(selector); |
| 1188 } | 1189 } |
| 1189 } while (_maybeEat(TokenKind.COMMA)); | 1190 } while (_maybeEat(TokenKind.COMMA)); |
| 1190 | 1191 |
| 1191 if (selectors.length > 0) { | 1192 if (selectors.length > 0) { |
| 1192 return new SelectorGroup(selectors, _makeSpan(start)); | 1193 return new SelectorGroup(selectors, _makeSpan(start)); |
| 1193 } | 1194 } |
| 1195 return null; |
| 1194 } | 1196 } |
| 1195 | 1197 |
| 1196 /** | 1198 /** |
| 1197 * Return list of selectors | 1199 * Return list of selectors |
| 1198 */ | 1200 */ |
| 1199 Selector processSelector() { | 1201 Selector processSelector() { |
| 1200 var simpleSequences = <SimpleSelectorSequence>[]; | 1202 var simpleSequences = <SimpleSelectorSequence>[]; |
| 1201 var start = _peekToken.span; | 1203 var start = _peekToken.span; |
| 1202 while (true) { | 1204 while (true) { |
| 1203 // First item is never descendant make sure it's COMBINATOR_NONE. | 1205 // First item is never descendant make sure it's COMBINATOR_NONE. |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1595 | 1597 |
| 1596 if (value == null) { | 1598 if (value == null) { |
| 1597 _error('expected attribute value string or ident', _peekToken.span); | 1599 _error('expected attribute value string or ident', _peekToken.span); |
| 1598 } | 1600 } |
| 1599 } | 1601 } |
| 1600 | 1602 |
| 1601 _eat(TokenKind.RBRACK); | 1603 _eat(TokenKind.RBRACK); |
| 1602 | 1604 |
| 1603 return new AttributeSelector(attrName, op, value, _makeSpan(start)); | 1605 return new AttributeSelector(attrName, op, value, _makeSpan(start)); |
| 1604 } | 1606 } |
| 1607 return null; |
| 1605 } | 1608 } |
| 1606 | 1609 |
| 1607 // Declaration grammar: | 1610 // Declaration grammar: |
| 1608 // | 1611 // |
| 1609 // declaration: property ':' expr prio? | 1612 // declaration: property ':' expr prio? |
| 1610 // | 1613 // |
| 1611 // property: IDENT [or IE hacks] | 1614 // property: IDENT [or IE hacks] |
| 1612 // prio: !important | 1615 // prio: !important |
| 1613 // expr: (see processExpr) | 1616 // expr: (see processExpr) |
| 1614 // | 1617 // |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1756 }; | 1759 }; |
| 1757 | 1760 |
| 1758 static int _findStyle(String styleName) => _stylesToDart[styleName]; | 1761 static int _findStyle(String styleName) => _stylesToDart[styleName]; |
| 1759 | 1762 |
| 1760 DartStyleExpression _styleForDart( | 1763 DartStyleExpression _styleForDart( |
| 1761 Identifier property, Expressions exprs, List dartStyles) { | 1764 Identifier property, Expressions exprs, List dartStyles) { |
| 1762 var styleType = _findStyle(property.name.toLowerCase()); | 1765 var styleType = _findStyle(property.name.toLowerCase()); |
| 1763 if (styleType != null) { | 1766 if (styleType != null) { |
| 1764 return buildDartStyleNode(styleType, exprs, dartStyles); | 1767 return buildDartStyleNode(styleType, exprs, dartStyles); |
| 1765 } | 1768 } |
| 1769 return null; |
| 1766 } | 1770 } |
| 1767 | 1771 |
| 1768 FontExpression _mergeFontStyles(FontExpression fontExpr, List dartStyles) { | 1772 FontExpression _mergeFontStyles(FontExpression fontExpr, List dartStyles) { |
| 1769 // Merge all font styles for this class selector. | 1773 // Merge all font styles for this class selector. |
| 1770 for (var dartStyle in dartStyles) { | 1774 for (var dartStyle in dartStyles) { |
| 1771 if (dartStyle.isFont) { | 1775 if (dartStyle.isFont) { |
| 1772 fontExpr = new FontExpression.merge(dartStyle, fontExpr); | 1776 fontExpr = new FontExpression.merge(dartStyle, fontExpr); |
| 1773 } | 1777 } |
| 1774 } | 1778 } |
| 1775 | 1779 |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1903 case _heightPart: | 1907 case _heightPart: |
| 1904 case _widthPart: | 1908 case _widthPart: |
| 1905 case _paddingPartLeft: | 1909 case _paddingPartLeft: |
| 1906 case _paddingPartTop: | 1910 case _paddingPartTop: |
| 1907 case _paddingPartRight: | 1911 case _paddingPartRight: |
| 1908 case _paddingPartBottom: | 1912 case _paddingPartBottom: |
| 1909 if (exprs.expressions.length > 0) { | 1913 if (exprs.expressions.length > 0) { |
| 1910 return processOneNumber(exprs, styleType); | 1914 return processOneNumber(exprs, styleType); |
| 1911 } | 1915 } |
| 1912 break; | 1916 break; |
| 1913 default: | |
| 1914 // Don't handle it. | |
| 1915 return null; | |
| 1916 } | 1917 } |
| 1918 return null; |
| 1917 } | 1919 } |
| 1918 | 1920 |
| 1919 // TODO(terry): Look at handling width of thin, thick, etc. any none numbers | 1921 // TODO(terry): Look at handling width of thin, thick, etc. any none numbers |
| 1920 // to convert to a number. | 1922 // to convert to a number. |
| 1921 DartStyleExpression processOneNumber(Expressions exprs, int part) { | 1923 DartStyleExpression processOneNumber(Expressions exprs, int part) { |
| 1922 var value = marginValue(exprs.expressions[0]); | 1924 var value = marginValue(exprs.expressions[0]); |
| 1923 if (value != null) { | 1925 if (value != null) { |
| 1924 switch (part) { | 1926 switch (part) { |
| 1925 case _marginPartLeft: | 1927 case _marginPartLeft: |
| 1926 return new MarginExpression(exprs.span, left: value); | 1928 return new MarginExpression(exprs.span, left: value); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1949 case _paddingPartLeft: | 1951 case _paddingPartLeft: |
| 1950 return new PaddingExpression(exprs.span, left: value); | 1952 return new PaddingExpression(exprs.span, left: value); |
| 1951 case _paddingPartTop: | 1953 case _paddingPartTop: |
| 1952 return new PaddingExpression(exprs.span, top: value); | 1954 return new PaddingExpression(exprs.span, top: value); |
| 1953 case _paddingPartRight: | 1955 case _paddingPartRight: |
| 1954 return new PaddingExpression(exprs.span, right: value); | 1956 return new PaddingExpression(exprs.span, right: value); |
| 1955 case _paddingPartBottom: | 1957 case _paddingPartBottom: |
| 1956 return new PaddingExpression(exprs.span, bottom: value); | 1958 return new PaddingExpression(exprs.span, bottom: value); |
| 1957 } | 1959 } |
| 1958 } | 1960 } |
| 1961 return null; |
| 1959 } | 1962 } |
| 1960 | 1963 |
| 1961 /** | 1964 /** |
| 1962 * Margins are of the format: | 1965 * Margins are of the format: |
| 1963 * | 1966 * |
| 1964 * top,right,bottom,left (4 parameters) | 1967 * top,right,bottom,left (4 parameters) |
| 1965 * top,right/left, bottom (3 parameters) | 1968 * top,right/left, bottom (3 parameters) |
| 1966 * top/bottom,right/left (2 parameters) | 1969 * top/bottom,right/left (2 parameters) |
| 1967 * top/right/bottom/left (1 parameter) | 1970 * top/right/bottom/left (1 parameter) |
| 1968 * | 1971 * |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2178 _error('Expecting a positive number', _makeSpan(start)); | 2181 _error('Expecting a positive number', _makeSpan(start)); |
| 2179 } | 2182 } |
| 2180 | 2183 |
| 2181 _eat(TokenKind.RBRACK); | 2184 _eat(TokenKind.RBRACK); |
| 2182 | 2185 |
| 2183 return new ItemTerm(term.value, term.text, _makeSpan(start)); | 2186 return new ItemTerm(term.value, term.text, _makeSpan(start)); |
| 2184 case TokenKind.IDENTIFIER: | 2187 case TokenKind.IDENTIFIER: |
| 2185 var nameValue = identifier(); // Snarf up the ident we'll remap, maybe. | 2188 var nameValue = identifier(); // Snarf up the ident we'll remap, maybe. |
| 2186 | 2189 |
| 2187 if (!ieFilter && _maybeEat(TokenKind.LPAREN)) { | 2190 if (!ieFilter && _maybeEat(TokenKind.LPAREN)) { |
| 2191 var calc = processCalc(nameValue); |
| 2192 if (calc != null) return calc; |
| 2188 // FUNCTION | 2193 // FUNCTION |
| 2189 return processFunction(nameValue); | 2194 return processFunction(nameValue); |
| 2190 } | 2195 } |
| 2191 if (ieFilter) { | 2196 if (ieFilter) { |
| 2192 if (_maybeEat(TokenKind.COLON) && | 2197 if (_maybeEat(TokenKind.COLON) && |
| 2193 nameValue.name.toLowerCase() == 'progid') { | 2198 nameValue.name.toLowerCase() == 'progid') { |
| 2194 // IE filter:progid: | 2199 // IE filter:progid: |
| 2195 return processIEFilter(start); | 2200 return processIEFilter(start); |
| 2196 } else { | 2201 } else { |
| 2197 // Handle filter:<name> where name is any filter e.g., alpha, chroma
, | 2202 // Handle filter:<name> where name is any filter e.g., alpha, chroma
, |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2432 startAfterProgidColon.start.offset, _peekToken.start); | 2437 startAfterProgidColon.start.offset, _peekToken.start); |
| 2433 return new LiteralTerm(tok.text, tok.text, tok.span); | 2438 return new LiteralTerm(tok.text, tok.text, tok.span); |
| 2434 } | 2439 } |
| 2435 break; | 2440 break; |
| 2436 default: | 2441 default: |
| 2437 _eat(_peek()); | 2442 _eat(_peek()); |
| 2438 } | 2443 } |
| 2439 } | 2444 } |
| 2440 } | 2445 } |
| 2441 | 2446 |
| 2447 // TODO(terry): Hack to gobble up the calc expression as a string looking |
| 2448 // for the matching RPAREN the expression is not parsed into the |
| 2449 // AST. |
| 2450 // |
| 2451 // grammar should be: |
| 2452 // |
| 2453 // <calc()> = calc( <calc-sum> ) |
| 2454 // <calc-sum> = <calc-product> [ [ '+' | '-' ] <calc-product> ]* |
| 2455 // <calc-product> = <calc-value> [ '*' <calc-value> | '/' <number> ]* |
| 2456 // <calc-value> = <number> | <dimension> | <percentage> | ( <calc-sum> ) |
| 2457 // |
| 2458 String processCalcExpression() { |
| 2459 var inString = tokenizer._inString; |
| 2460 tokenizer._inString = false; |
| 2461 |
| 2462 // Gobble up everything until we hit our stop token. |
| 2463 var stringValue = new StringBuffer(); |
| 2464 var left = 1; |
| 2465 var matchingParens = false; |
| 2466 while (_peek() != TokenKind.END_OF_FILE && !matchingParens) { |
| 2467 var token = _peek(); |
| 2468 if (token == TokenKind.LPAREN) |
| 2469 left++; |
| 2470 else if (token == TokenKind.RPAREN) |
| 2471 left--; |
| 2472 |
| 2473 matchingParens = left == 0; |
| 2474 if (!matchingParens) stringValue.write(_next().text); |
| 2475 } |
| 2476 |
| 2477 if (!matchingParens) { |
| 2478 _error("problem parsing function expected ), ", _peekToken.span); |
| 2479 } |
| 2480 |
| 2481 tokenizer._inString = inString; |
| 2482 |
| 2483 return stringValue.toString(); |
| 2484 } |
| 2485 |
| 2486 CalcTerm processCalc(Identifier func) { |
| 2487 var start = _peekToken.span; |
| 2488 |
| 2489 var name = func.name; |
| 2490 if (name == 'calc') { |
| 2491 // TODO(terry): Implement expression parsing properly. |
| 2492 String expression = processCalcExpression(); |
| 2493 var calcExpr = new LiteralTerm(expression, expression, _makeSpan(start)); |
| 2494 |
| 2495 if (!_maybeEat(TokenKind.RPAREN)) { |
| 2496 _error("problem parsing function expected ), ", _peekToken.span); |
| 2497 } |
| 2498 |
| 2499 return new CalcTerm(name, name, calcExpr, _makeSpan(start)); |
| 2500 } |
| 2501 |
| 2502 return null; |
| 2503 } |
| 2504 |
| 2442 // Function grammar: | 2505 // Function grammar: |
| 2443 // | 2506 // |
| 2444 // function: IDENT '(' expr ')' | 2507 // function: IDENT '(' expr ')' |
| 2445 // | 2508 // |
| 2446 processFunction(Identifier func) { | 2509 processFunction(Identifier func) { |
| 2447 var start = _peekToken.span; | 2510 var start = _peekToken.span; |
| 2448 | 2511 |
| 2449 var name = func.name; | 2512 var name = func.name; |
| 2450 | 2513 |
| 2451 switch (name) { | 2514 switch (name) { |
| 2452 case 'url': | 2515 case 'url': |
| 2453 // URI term sucks up everything inside of quotes(' or ") or between pare
ns | 2516 // URI term sucks up everything inside of quotes(' or ") or between pare
ns |
| 2454 var urlParam = processQuotedString(true); | 2517 var urlParam = processQuotedString(true); |
| 2455 | 2518 |
| 2456 // TODO(terry): Better error messge and checking for mismatched quotes. | 2519 // TODO(terry): Better error messge and checking for mismatched quotes. |
| 2457 if (_peek() == TokenKind.END_OF_FILE) { | 2520 if (_peek() == TokenKind.END_OF_FILE) { |
| 2458 _error("problem parsing URI", _peekToken.span); | 2521 _error("problem parsing URI", _peekToken.span); |
| 2459 } | 2522 } |
| 2460 | 2523 |
| 2461 if (_peek() == TokenKind.RPAREN) { | 2524 if (_peek() == TokenKind.RPAREN) { |
| 2462 _next(); | 2525 _next(); |
| 2463 } | 2526 } |
| 2464 | 2527 |
| 2465 return new UriTerm(urlParam, _makeSpan(start)); | 2528 return new UriTerm(urlParam, _makeSpan(start)); |
| 2466 case 'calc': | |
| 2467 // TODO(terry): Implement expression handling... | |
| 2468 break; | |
| 2469 case 'var': | 2529 case 'var': |
| 2470 // TODO(terry): Consider handling var in IE specific filter/progid. Thi
s | 2530 // TODO(terry): Consider handling var in IE specific filter/progid. Thi
s |
| 2471 // will require parsing entire IE specific syntax e.g., | 2531 // will require parsing entire IE specific syntax e.g., |
| 2472 // param = value or progid:com_id, etc. for example: | 2532 // param = value or progid:com_id, etc. for example: |
| 2473 // | 2533 // |
| 2474 // var-blur: Blur(Add = 0, Direction = 225, Strength = 10); | 2534 // var-blur: Blur(Add = 0, Direction = 225, Strength = 10); |
| 2475 // var-gradient: progid:DXImageTransform.Microsoft.gradient" | 2535 // var-gradient: progid:DXImageTransform.Microsoft.gradient" |
| 2476 // (GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670'); | 2536 // (GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670'); |
| 2477 var expr = processExpr(); | 2537 var expr = processExpr(); |
| 2478 if (!_maybeEat(TokenKind.RPAREN)) { | 2538 if (!_maybeEat(TokenKind.RPAREN)) { |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2686 | 2746 |
| 2687 if (replace != null && result == null) { | 2747 if (replace != null && result == null) { |
| 2688 result = new StringBuffer(text.substring(0, i)); | 2748 result = new StringBuffer(text.substring(0, i)); |
| 2689 } | 2749 } |
| 2690 | 2750 |
| 2691 if (result != null) result.write(replace != null ? replace : text[i]); | 2751 if (result != null) result.write(replace != null ? replace : text[i]); |
| 2692 } | 2752 } |
| 2693 | 2753 |
| 2694 return result == null ? text : result.toString(); | 2754 return result == null ? text : result.toString(); |
| 2695 } | 2755 } |
| OLD | NEW |