OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/css/parser/CSSPropertyParser.h" | 5 #include "core/css/parser/CSSPropertyParser.h" |
6 | 6 |
7 #include "core/StylePropertyShorthand.h" | 7 #include "core/StylePropertyShorthand.h" |
8 #include "core/css/CSSBasicShapeValues.h" | 8 #include "core/css/CSSBasicShapeValues.h" |
9 #include "core/css/CSSBorderImage.h" | 9 #include "core/css/CSSBorderImage.h" |
10 #include "core/css/CSSContentDistributionValue.h" | 10 #include "core/css/CSSContentDistributionValue.h" |
(...skipping 24 matching lines...) Expand all Loading... |
35 #include "core/css/CSSValuePair.h" | 35 #include "core/css/CSSValuePair.h" |
36 #include "core/css/CSSVariableReferenceValue.h" | 36 #include "core/css/CSSVariableReferenceValue.h" |
37 #include "core/css/FontFace.h" | 37 #include "core/css/FontFace.h" |
38 #include "core/css/HashTools.h" | 38 #include "core/css/HashTools.h" |
39 #include "core/css/parser/CSSParserFastPaths.h" | 39 #include "core/css/parser/CSSParserFastPaths.h" |
40 #include "core/css/parser/CSSParserIdioms.h" | 40 #include "core/css/parser/CSSParserIdioms.h" |
41 #include "core/css/parser/CSSPropertyParserHelpers.h" | 41 #include "core/css/parser/CSSPropertyParserHelpers.h" |
42 #include "core/css/parser/CSSVariableParser.h" | 42 #include "core/css/parser/CSSVariableParser.h" |
43 #include "core/css/parser/FontVariantLigaturesParser.h" | 43 #include "core/css/parser/FontVariantLigaturesParser.h" |
44 #include "core/css/properties/CSSPropertyAlignmentUtils.h" | 44 #include "core/css/properties/CSSPropertyAlignmentUtils.h" |
| 45 #include "core/css/properties/CSSPropertyBackgroundComponentUtils.h" |
45 #include "core/css/properties/CSSPropertyColumnUtils.h" | 46 #include "core/css/properties/CSSPropertyColumnUtils.h" |
46 #include "core/css/properties/CSSPropertyDescriptor.h" | 47 #include "core/css/properties/CSSPropertyDescriptor.h" |
47 #include "core/css/properties/CSSPropertyLengthUtils.h" | 48 #include "core/css/properties/CSSPropertyLengthUtils.h" |
48 #include "core/css/properties/CSSPropertyPositionUtils.h" | 49 #include "core/css/properties/CSSPropertyPositionUtils.h" |
49 #include "core/css/properties/CSSPropertyShapeUtils.h" | 50 #include "core/css/properties/CSSPropertyShapeUtils.h" |
50 #include "core/frame/UseCounter.h" | 51 #include "core/frame/UseCounter.h" |
51 #include "core/layout/LayoutTheme.h" | 52 #include "core/layout/LayoutTheme.h" |
52 #include "core/svg/SVGPathUtilities.h" | 53 #include "core/svg/SVGPathUtilities.h" |
53 #include "wtf/text/StringBuilder.h" | 54 #include "wtf/text/StringBuilder.h" |
54 #include <memory> | 55 #include <memory> |
(...skipping 1573 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1628 if (range.peek().id() == CSSValueFromImage) | 1629 if (range.peek().id() == CSSValueFromImage) |
1629 return consumeIdent(range); | 1630 return consumeIdent(range); |
1630 if (range.peek().type() != NumberToken) { | 1631 if (range.peek().type() != NumberToken) { |
1631 CSSPrimitiveValue* angle = consumeAngle(range); | 1632 CSSPrimitiveValue* angle = consumeAngle(range); |
1632 if (angle && angle->getDoubleValue() == 0) | 1633 if (angle && angle->getDoubleValue() == 0) |
1633 return angle; | 1634 return angle; |
1634 } | 1635 } |
1635 return nullptr; | 1636 return nullptr; |
1636 } | 1637 } |
1637 | 1638 |
1638 static CSSValue* consumeBackgroundBlendMode(CSSParserTokenRange& range) { | |
1639 CSSValueID id = range.peek().id(); | |
1640 if (id == CSSValueNormal || id == CSSValueOverlay || | |
1641 (id >= CSSValueMultiply && id <= CSSValueLuminosity)) | |
1642 return consumeIdent(range); | |
1643 return nullptr; | |
1644 } | |
1645 | |
1646 static CSSValue* consumeBackgroundAttachment(CSSParserTokenRange& range) { | |
1647 return consumeIdent<CSSValueScroll, CSSValueFixed, CSSValueLocal>(range); | |
1648 } | |
1649 | |
1650 static CSSValue* consumeBackgroundBox(CSSParserTokenRange& range) { | |
1651 return consumeIdent<CSSValueBorderBox, CSSValuePaddingBox, | |
1652 CSSValueContentBox>(range); | |
1653 } | |
1654 | |
1655 static CSSValue* consumeBackgroundComposite(CSSParserTokenRange& range) { | |
1656 return consumeIdentRange(range, CSSValueClear, CSSValuePlusLighter); | |
1657 } | |
1658 | |
1659 static CSSValue* consumeMaskSourceType(CSSParserTokenRange& range) { | |
1660 ASSERT(RuntimeEnabledFeatures::cssMaskSourceTypeEnabled()); | |
1661 return consumeIdent<CSSValueAuto, CSSValueAlpha, CSSValueLuminance>(range); | |
1662 } | |
1663 | |
1664 static CSSValue* consumePrefixedBackgroundBox(CSSPropertyID property, | |
1665 CSSParserTokenRange& range, | |
1666 const CSSParserContext* context) { | |
1667 // The values 'border', 'padding' and 'content' are deprecated and do not | |
1668 // apply to the version of the property that has the -webkit- prefix removed. | |
1669 if (CSSValue* value = | |
1670 consumeIdentRange(range, CSSValueBorder, CSSValuePaddingBox)) | |
1671 return value; | |
1672 if ((property == CSSPropertyWebkitBackgroundClip || | |
1673 property == CSSPropertyWebkitMaskClip) && | |
1674 range.peek().id() == CSSValueText) | |
1675 return consumeIdent(range); | |
1676 return nullptr; | |
1677 } | |
1678 | |
1679 static CSSValue* consumeBackgroundSize(CSSPropertyID unresolvedProperty, | |
1680 CSSParserTokenRange& range, | |
1681 CSSParserMode cssParserMode) { | |
1682 if (identMatches<CSSValueContain, CSSValueCover>(range.peek().id())) | |
1683 return consumeIdent(range); | |
1684 | |
1685 CSSValue* horizontal = consumeIdent<CSSValueAuto>(range); | |
1686 if (!horizontal) | |
1687 horizontal = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, | |
1688 UnitlessQuirk::Forbid); | |
1689 | |
1690 CSSValue* vertical = nullptr; | |
1691 if (!range.atEnd()) { | |
1692 if (range.peek().id() == CSSValueAuto) // `auto' is the default | |
1693 range.consumeIncludingWhitespace(); | |
1694 else | |
1695 vertical = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, | |
1696 UnitlessQuirk::Forbid); | |
1697 } else if (unresolvedProperty == CSSPropertyAliasWebkitBackgroundSize) { | |
1698 // Legacy syntax: "-webkit-background-size: 10px" is equivalent to | |
1699 // "background-size: 10px 10px". | |
1700 vertical = horizontal; | |
1701 } | |
1702 if (!vertical) | |
1703 return horizontal; | |
1704 return CSSValuePair::create(horizontal, vertical, | |
1705 CSSValuePair::KeepIdenticalValues); | |
1706 } | |
1707 | |
1708 static CSSValue* consumeBackgroundComponent(CSSPropertyID unresolvedProperty, | |
1709 CSSParserTokenRange& range, | |
1710 const CSSParserContext* context) { | |
1711 switch (unresolvedProperty) { | |
1712 case CSSPropertyBackgroundClip: | |
1713 return consumeBackgroundBox(range); | |
1714 case CSSPropertyBackgroundBlendMode: | |
1715 return consumeBackgroundBlendMode(range); | |
1716 case CSSPropertyBackgroundAttachment: | |
1717 return consumeBackgroundAttachment(range); | |
1718 case CSSPropertyBackgroundOrigin: | |
1719 return consumeBackgroundBox(range); | |
1720 case CSSPropertyWebkitMaskComposite: | |
1721 return consumeBackgroundComposite(range); | |
1722 case CSSPropertyMaskSourceType: | |
1723 return consumeMaskSourceType(range); | |
1724 case CSSPropertyWebkitBackgroundClip: | |
1725 case CSSPropertyWebkitBackgroundOrigin: | |
1726 case CSSPropertyWebkitMaskClip: | |
1727 case CSSPropertyWebkitMaskOrigin: | |
1728 return consumePrefixedBackgroundBox(unresolvedProperty, range, context); | |
1729 case CSSPropertyBackgroundImage: | |
1730 case CSSPropertyWebkitMaskImage: | |
1731 return consumeImageOrNone(range, context); | |
1732 case CSSPropertyBackgroundPositionX: | |
1733 case CSSPropertyWebkitMaskPositionX: | |
1734 return CSSPropertyPositionUtils::consumePositionLonghand<CSSValueLeft, | |
1735 CSSValueRight>( | |
1736 range, context->mode()); | |
1737 case CSSPropertyBackgroundPositionY: | |
1738 case CSSPropertyWebkitMaskPositionY: | |
1739 return CSSPropertyPositionUtils::consumePositionLonghand<CSSValueTop, | |
1740 CSSValueBottom>( | |
1741 range, context->mode()); | |
1742 case CSSPropertyBackgroundSize: | |
1743 case CSSPropertyAliasWebkitBackgroundSize: | |
1744 case CSSPropertyWebkitMaskSize: | |
1745 return consumeBackgroundSize(unresolvedProperty, range, context->mode()); | |
1746 case CSSPropertyBackgroundColor: | |
1747 return consumeColor(range, context->mode()); | |
1748 default: | |
1749 break; | |
1750 }; | |
1751 return nullptr; | |
1752 } | |
1753 | |
1754 static void addBackgroundValue(CSSValue*& list, CSSValue* value) { | |
1755 if (list) { | |
1756 if (!list->isBaseValueList()) { | |
1757 CSSValue* firstValue = list; | |
1758 list = CSSValueList::createCommaSeparated(); | |
1759 toCSSValueList(list)->append(*firstValue); | |
1760 } | |
1761 toCSSValueList(list)->append(*value); | |
1762 } else { | |
1763 // To conserve memory we don't actually wrap a single value in a list. | |
1764 list = value; | |
1765 } | |
1766 } | |
1767 | |
1768 static CSSValue* consumeCommaSeparatedBackgroundComponent( | 1639 static CSSValue* consumeCommaSeparatedBackgroundComponent( |
1769 CSSPropertyID unresolvedProperty, | 1640 CSSPropertyID unresolvedProperty, |
1770 CSSParserTokenRange& range, | 1641 CSSParserTokenRange& range, |
1771 const CSSParserContext* context) { | 1642 const CSSParserContext* context) { |
1772 CSSValue* result = nullptr; | 1643 CSSValue* result = nullptr; |
1773 do { | 1644 do { |
1774 CSSValue* value = | 1645 CSSValue* value = |
1775 consumeBackgroundComponent(unresolvedProperty, range, context); | 1646 CSSPropertyBackgroundComponentUtils::consumeBackgroundComponent( |
| 1647 unresolvedProperty, range, context); |
1776 if (!value) | 1648 if (!value) |
1777 return nullptr; | 1649 return nullptr; |
1778 addBackgroundValue(result, value); | 1650 CSSPropertyBackgroundComponentUtils::addBackgroundValue(result, value); |
1779 } while (consumeCommaIncludingWhitespace(range)); | 1651 } while (consumeCommaIncludingWhitespace(range)); |
1780 return result; | 1652 return result; |
1781 } | 1653 } |
1782 | 1654 |
1783 static CSSValue* consumeAlignItems(CSSParserTokenRange& range) { | 1655 static CSSValue* consumeAlignItems(CSSParserTokenRange& range) { |
1784 // align-items property does not allow the 'auto' value. | 1656 // align-items property does not allow the 'auto' value. |
1785 if (identMatches<CSSValueAuto>(range.peek().id())) | 1657 if (identMatches<CSSValueAuto>(range.peek().id())) |
1786 return nullptr; | 1658 return nullptr; |
1787 return CSSPropertyAlignmentUtils::consumeSelfPositionOverflowPosition(range); | 1659 return CSSPropertyAlignmentUtils::consumeSelfPositionOverflowPosition(range); |
1788 } | 1660 } |
(...skipping 1589 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3378 const CSSParserContext* context, | 3250 const CSSParserContext* context, |
3379 UnitlessQuirk unitless, | 3251 UnitlessQuirk unitless, |
3380 CSSValue*& resultX, | 3252 CSSValue*& resultX, |
3381 CSSValue*& resultY) { | 3253 CSSValue*& resultY) { |
3382 do { | 3254 do { |
3383 CSSValue* positionX = nullptr; | 3255 CSSValue* positionX = nullptr; |
3384 CSSValue* positionY = nullptr; | 3256 CSSValue* positionY = nullptr; |
3385 if (!consumePosition(range, context->mode(), unitless, positionX, | 3257 if (!consumePosition(range, context->mode(), unitless, positionX, |
3386 positionY)) | 3258 positionY)) |
3387 return false; | 3259 return false; |
3388 addBackgroundValue(resultX, positionX); | 3260 CSSPropertyBackgroundComponentUtils::addBackgroundValue(resultX, positionX); |
3389 addBackgroundValue(resultY, positionY); | 3261 CSSPropertyBackgroundComponentUtils::addBackgroundValue(resultY, positionY); |
3390 } while (consumeCommaIncludingWhitespace(range)); | 3262 } while (consumeCommaIncludingWhitespace(range)); |
3391 return true; | 3263 return true; |
3392 } | 3264 } |
3393 | 3265 |
3394 static bool consumeRepeatStyleComponent(CSSParserTokenRange& range, | 3266 static bool consumeRepeatStyleComponent(CSSParserTokenRange& range, |
3395 CSSValue*& value1, | 3267 CSSValue*& value1, |
3396 CSSValue*& value2, | 3268 CSSValue*& value2, |
3397 bool& implicit) { | 3269 bool& implicit) { |
3398 if (consumeIdent<CSSValueRepeatX>(range)) { | 3270 if (consumeIdent<CSSValueRepeatX>(range)) { |
3399 value1 = CSSIdentifierValue::create(CSSValueRepeat); | 3271 value1 = CSSIdentifierValue::create(CSSValueRepeat); |
(...skipping 23 matching lines...) Expand all Loading... |
3423 | 3295 |
3424 static bool consumeRepeatStyle(CSSParserTokenRange& range, | 3296 static bool consumeRepeatStyle(CSSParserTokenRange& range, |
3425 CSSValue*& resultX, | 3297 CSSValue*& resultX, |
3426 CSSValue*& resultY, | 3298 CSSValue*& resultY, |
3427 bool& implicit) { | 3299 bool& implicit) { |
3428 do { | 3300 do { |
3429 CSSValue* repeatX = nullptr; | 3301 CSSValue* repeatX = nullptr; |
3430 CSSValue* repeatY = nullptr; | 3302 CSSValue* repeatY = nullptr; |
3431 if (!consumeRepeatStyleComponent(range, repeatX, repeatY, implicit)) | 3303 if (!consumeRepeatStyleComponent(range, repeatX, repeatY, implicit)) |
3432 return false; | 3304 return false; |
3433 addBackgroundValue(resultX, repeatX); | 3305 CSSPropertyBackgroundComponentUtils::addBackgroundValue(resultX, repeatX); |
3434 addBackgroundValue(resultY, repeatY); | 3306 CSSPropertyBackgroundComponentUtils::addBackgroundValue(resultY, repeatY); |
3435 } while (consumeCommaIncludingWhitespace(range)); | 3307 } while (consumeCommaIncludingWhitespace(range)); |
3436 return true; | 3308 return true; |
3437 } | 3309 } |
3438 | 3310 |
3439 // Note: consumeBackgroundShorthand assumes y properties (for example | 3311 // Note: consumeBackgroundShorthand assumes y properties (for example |
3440 // background-position-y) follow the x properties in the shorthand array. | 3312 // background-position-y) follow the x properties in the shorthand array. |
3441 bool CSSPropertyParser::consumeBackgroundShorthand( | 3313 bool CSSPropertyParser::consumeBackgroundShorthand( |
3442 const StylePropertyShorthand& shorthand, | 3314 const StylePropertyShorthand& shorthand, |
3443 bool important) { | 3315 bool important) { |
3444 const unsigned longhandCount = shorthand.length(); | 3316 const unsigned longhandCount = shorthand.length(); |
(...skipping 18 matching lines...) Expand all Loading... |
3463 consumeRepeatStyleComponent(m_range, value, valueY, implicit); | 3335 consumeRepeatStyleComponent(m_range, value, valueY, implicit); |
3464 } else if (property == CSSPropertyBackgroundPositionX || | 3336 } else if (property == CSSPropertyBackgroundPositionX || |
3465 property == CSSPropertyWebkitMaskPositionX) { | 3337 property == CSSPropertyWebkitMaskPositionX) { |
3466 if (!consumePosition(m_range, m_context->mode(), | 3338 if (!consumePosition(m_range, m_context->mode(), |
3467 UnitlessQuirk::Forbid, value, valueY)) | 3339 UnitlessQuirk::Forbid, value, valueY)) |
3468 continue; | 3340 continue; |
3469 } else if (property == CSSPropertyBackgroundSize || | 3341 } else if (property == CSSPropertyBackgroundSize || |
3470 property == CSSPropertyWebkitMaskSize) { | 3342 property == CSSPropertyWebkitMaskSize) { |
3471 if (!consumeSlashIncludingWhitespace(m_range)) | 3343 if (!consumeSlashIncludingWhitespace(m_range)) |
3472 continue; | 3344 continue; |
3473 value = consumeBackgroundSize(property, m_range, m_context->mode()); | 3345 value = CSSPropertyBackgroundComponentUtils::consumeBackgroundSize( |
| 3346 property, m_range, m_context->mode()); |
3474 if (!value || !parsedLonghand[i - 1]) // Position must have been | 3347 if (!value || !parsedLonghand[i - 1]) // Position must have been |
3475 // parsed in the current layer. | 3348 // parsed in the current layer. |
3476 return false; | 3349 return false; |
3477 } else if (property == CSSPropertyBackgroundPositionY || | 3350 } else if (property == CSSPropertyBackgroundPositionY || |
3478 property == CSSPropertyBackgroundRepeatY || | 3351 property == CSSPropertyBackgroundRepeatY || |
3479 property == CSSPropertyWebkitMaskPositionY || | 3352 property == CSSPropertyWebkitMaskPositionY || |
3480 property == CSSPropertyWebkitMaskRepeatY) { | 3353 property == CSSPropertyWebkitMaskRepeatY) { |
3481 continue; | 3354 continue; |
3482 } else { | 3355 } else { |
3483 value = consumeBackgroundComponent(property, m_range, m_context); | 3356 value = |
| 3357 CSSPropertyBackgroundComponentUtils::consumeBackgroundComponent( |
| 3358 property, m_range, m_context); |
3484 } | 3359 } |
3485 if (value) { | 3360 if (value) { |
3486 if (property == CSSPropertyBackgroundOrigin || | 3361 if (property == CSSPropertyBackgroundOrigin || |
3487 property == CSSPropertyWebkitMaskOrigin) | 3362 property == CSSPropertyWebkitMaskOrigin) |
3488 originValue = value; | 3363 originValue = value; |
3489 parsedLonghand[i] = true; | 3364 parsedLonghand[i] = true; |
3490 foundProperty = true; | 3365 foundProperty = true; |
3491 addBackgroundValue(longhands[i], value); | 3366 CSSPropertyBackgroundComponentUtils::addBackgroundValue(longhands[i], |
| 3367 value); |
3492 if (valueY) { | 3368 if (valueY) { |
3493 parsedLonghand[i + 1] = true; | 3369 parsedLonghand[i + 1] = true; |
3494 addBackgroundValue(longhands[i + 1], valueY); | 3370 CSSPropertyBackgroundComponentUtils::addBackgroundValue( |
| 3371 longhands[i + 1], valueY); |
3495 } | 3372 } |
3496 } | 3373 } |
3497 } | 3374 } |
3498 if (!foundProperty) | 3375 if (!foundProperty) |
3499 return false; | 3376 return false; |
3500 } while (!m_range.atEnd() && m_range.peek().type() != CommaToken); | 3377 } while (!m_range.atEnd() && m_range.peek().type() != CommaToken); |
3501 | 3378 |
3502 // TODO(timloh): This will make invalid longhands, see crbug.com/386459 | 3379 // TODO(timloh): This will make invalid longhands, see crbug.com/386459 |
3503 for (size_t i = 0; i < longhandCount; ++i) { | 3380 for (size_t i = 0; i < longhandCount; ++i) { |
3504 CSSPropertyID property = shorthand.properties()[i]; | 3381 CSSPropertyID property = shorthand.properties()[i]; |
3505 if (property == CSSPropertyBackgroundColor && !m_range.atEnd()) { | 3382 if (property == CSSPropertyBackgroundColor && !m_range.atEnd()) { |
3506 if (parsedLonghand[i]) | 3383 if (parsedLonghand[i]) |
3507 return false; // Colors are only allowed in the last layer. | 3384 return false; // Colors are only allowed in the last layer. |
3508 continue; | 3385 continue; |
3509 } | 3386 } |
3510 if ((property == CSSPropertyBackgroundClip || | 3387 if ((property == CSSPropertyBackgroundClip || |
3511 property == CSSPropertyWebkitMaskClip) && | 3388 property == CSSPropertyWebkitMaskClip) && |
3512 !parsedLonghand[i] && originValue) { | 3389 !parsedLonghand[i] && originValue) { |
3513 addBackgroundValue(longhands[i], originValue); | 3390 CSSPropertyBackgroundComponentUtils::addBackgroundValue(longhands[i], |
| 3391 originValue); |
3514 continue; | 3392 continue; |
3515 } | 3393 } |
3516 if (!parsedLonghand[i]) | 3394 if (!parsedLonghand[i]) { |
3517 addBackgroundValue(longhands[i], CSSInitialValue::create()); | 3395 CSSPropertyBackgroundComponentUtils::addBackgroundValue( |
| 3396 longhands[i], CSSInitialValue::create()); |
| 3397 } |
3518 } | 3398 } |
3519 } while (consumeCommaIncludingWhitespace(m_range)); | 3399 } while (consumeCommaIncludingWhitespace(m_range)); |
3520 if (!m_range.atEnd()) | 3400 if (!m_range.atEnd()) |
3521 return false; | 3401 return false; |
3522 | 3402 |
3523 for (size_t i = 0; i < longhandCount; ++i) { | 3403 for (size_t i = 0; i < longhandCount; ++i) { |
3524 CSSPropertyID property = shorthand.properties()[i]; | 3404 CSSPropertyID property = shorthand.properties()[i]; |
3525 if (property == CSSPropertyBackgroundSize && longhands[i] && | 3405 if (property == CSSPropertyBackgroundSize && longhands[i] && |
3526 m_context->useLegacyBackgroundSizeShorthandBehavior()) | 3406 m_context->useLegacyBackgroundSizeShorthandBehavior()) |
3527 continue; | 3407 continue; |
(...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4073 case CSSPropertyGridTemplate: | 3953 case CSSPropertyGridTemplate: |
4074 return consumeGridTemplateShorthand(CSSPropertyGridTemplate, important); | 3954 return consumeGridTemplateShorthand(CSSPropertyGridTemplate, important); |
4075 case CSSPropertyGrid: | 3955 case CSSPropertyGrid: |
4076 return consumeGridShorthand(important); | 3956 return consumeGridShorthand(important); |
4077 default: | 3957 default: |
4078 return false; | 3958 return false; |
4079 } | 3959 } |
4080 } | 3960 } |
4081 | 3961 |
4082 } // namespace blink | 3962 } // namespace blink |
OLD | NEW |