Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) | 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) |
| 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) | 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) |
| 5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. | 5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. |
| 6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> | 6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> |
| 7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> | 7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> |
| 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t orchmobile.com/) | 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t orchmobile.com/) |
| 9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | 9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. |
| 10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. | 10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 71 ShadowRoot* root = element->containingShadowRoot(); | 71 ShadowRoot* root = element->containingShadowRoot(); |
| 72 if (!root || root->type() != ShadowRoot::UserAgentShadowRoot) | 72 if (!root || root->type() != ShadowRoot::UserAgentShadowRoot) |
| 73 return false; | 73 return false; |
| 74 | 74 |
| 75 if (element->shadowPseudoId() != selector.value()) | 75 if (element->shadowPseudoId() != selector.value()) |
| 76 return false; | 76 return false; |
| 77 | 77 |
| 78 return true; | 78 return true; |
| 79 } | 79 } |
| 80 | 80 |
| 81 Element* SelectorChecker::parentElement(const SelectorCheckingContext& context, bool allowToCrossBoundary) const | 81 static Element* parentElement(const SelectorChecker::SelectorCheckingContext& co ntext) |
| 82 { | 82 { |
| 83 // CrossesBoundary means we don't care any context.scope. So we can walk up from a shadow root to its shadow host. | 83 // If context.scope is a shadow root, we should walk up to its shadow host. |
| 84 if (allowToCrossBoundary) | 84 if (context.scope && context.scope == context.element->containingShadowRoot( )) |
|
esprehn
2014/06/27 08:05:51
Why don't we need the ScopeIsShadowRoot stuff anym
kochi
2014/06/30 02:44:06
The flag used to mean that a context's scope was s
| |
| 85 return context.element->parentOrShadowHostElement(); | 85 return context.element->parentOrShadowHostElement(); |
| 86 | 86 |
| 87 // If context.scope is a shadow root, we should walk up to its shadow host. | |
| 88 if ((context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowRoot) && con text.scope == context.element->containingShadowRoot()) | |
| 89 return context.element->parentOrShadowHostElement(); | |
| 90 | |
| 91 if ((context.behaviorAtBoundary & SelectorChecker::BoundaryBehaviorMask) != SelectorChecker::StaysWithinTreeScope) | |
|
esprehn
2014/06/27 08:05:51
Why is this not needed now?
kochi
2014/06/30 02:44:06
Now the condition will never be met.
This conditi
| |
| 92 return context.element->parentElement(); | |
| 93 | |
| 94 // If context.scope is some element in some shadow tree and querySelector in itialized the context, | 87 // If context.scope is some element in some shadow tree and querySelector in itialized the context, |
| 95 // e.g. shadowRoot.querySelector(':host *'), | 88 // e.g. shadowRoot.querySelector(':host *'), |
| 96 // (a) context.element has the same treescope as context.scope, need to walk up to its shadow host. | 89 // (a) context.element has the same treescope as context.scope, need to walk up to its shadow host. |
| 97 // (b) Otherwise, should not walk up from a shadow root to a shadow host. | 90 // (b) Otherwise, should not walk up from a shadow root to a shadow host. |
| 98 if (context.scope && context.scope->treeScope() == context.element->treeScop e()) | 91 if (context.scope && context.scope->treeScope() == context.element->treeScop e()) |
| 99 return context.element->parentOrShadowHostElement(); | 92 return context.element->parentOrShadowHostElement(); |
| 100 | 93 |
| 101 return context.element->parentElement(); | 94 return context.element->parentElement(); |
| 102 } | 95 } |
| 103 | 96 |
| 104 bool SelectorChecker::scopeContainsLastMatchedElement(const SelectorCheckingCont ext& context) const | 97 static bool scopeContainsLastMatchedElement(const SelectorChecker::SelectorCheck ingContext& context) |
| 105 { | 98 { |
| 106 if (!(context.behaviorAtBoundary & SelectorChecker::ScopeContainsLastMatched Element)) | 99 if (!(context.contextFlags & SelectorChecker::ScopeContainsLastMatchedElemen t)) |
| 107 return true; | 100 return true; |
| 108 | 101 |
| 109 ASSERT(context.scope); | 102 ASSERT(context.scope); |
| 110 // If behaviorAtBoundary is not ScopeIsShadowRoot, we can use "contains". | 103 // If the scope is not a Shadow root, we can use "contains". |
| 111 if (!(context.behaviorAtBoundary & SelectorChecker::ScopeIsShadowRoot)) | 104 if (!context.scope->isShadowRoot()) |
| 112 return context.scope->contains(context.element); | 105 return context.scope->contains(context.element); |
| 113 | 106 |
| 114 // If a given element is scope, i.e. shadow host, matches. | 107 // If a given element is scope, i.e. shadow host, matches. |
| 115 if (context.element == context.scope->shadowHost() && (!context.previousElem ent || context.previousElement->isInDescendantTreeOf(context.element))) | 108 if (context.element == context.scope->shadowHost() && (!context.previousElem ent || context.previousElement->isInDescendantTreeOf(context.element))) |
| 116 return true; | 109 return true; |
| 117 | 110 |
| 118 ShadowRoot* root = context.element->containingShadowRoot(); | 111 // If the containing shadow root is scope, matches. |
| 119 if (!root) | 112 return context.element->containingShadowRoot() == context.scope; |
| 120 return false; | |
| 121 | |
| 122 // If a host of the containing shadow root is scope, matches. | |
| 123 return root == context.scope; | |
| 124 } | 113 } |
| 125 | 114 |
| 126 static inline bool nextSelectorExceedsScope(const SelectorChecker::SelectorCheck ingContext& context) | 115 static inline bool nextSelectorExceedsScope(const SelectorChecker::SelectorCheck ingContext& context) |
| 127 { | 116 { |
| 128 if (context.scope && context.scope->isInShadowTree()) | 117 if (context.scope && context.scope->isInShadowTree()) |
| 129 return context.element == context.scope->shadowHost(); | 118 return context.element == context.scope->shadowHost(); |
| 130 | 119 |
| 131 return false; | 120 return false; |
| 132 } | 121 } |
| 133 | 122 |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 334 for (; nextContext.element; nextContext.element = ElementTraversal::prev iousSibling(*nextContext.element)) { | 323 for (; nextContext.element; nextContext.element = ElementTraversal::prev iousSibling(*nextContext.element)) { |
| 335 Match match = this->match(nextContext, siblingTraversalStrategy, res ult); | 324 Match match = this->match(nextContext, siblingTraversalStrategy, res ult); |
| 336 if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely) | 325 if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely) |
| 337 return match; | 326 return match; |
| 338 }; | 327 }; |
| 339 return SelectorFailsAllSiblings; | 328 return SelectorFailsAllSiblings; |
| 340 | 329 |
| 341 case CSSSelector::ShadowPseudo: | 330 case CSSSelector::ShadowPseudo: |
| 342 { | 331 { |
| 343 // If we're in the same tree-scope as the scoping element, then foll owing a shadow descendant combinator would escape that and thus the scope. | 332 // If we're in the same tree-scope as the scoping element, then foll owing a shadow descendant combinator would escape that and thus the scope. |
| 344 if (context.scope && context.scope->shadowHost() && context.scope->s hadowHost()->treeScope() == context.element->treeScope() && (context.behaviorAtB oundary & BoundaryBehaviorMask) != StaysWithinTreeScope) | 333 if (context.scope && context.scope->shadowHost() && context.scope->s hadowHost()->treeScope() == context.element->treeScope()) |
| 345 return SelectorFailsCompletely; | 334 return SelectorFailsCompletely; |
| 346 | 335 |
| 347 Element* shadowHost = context.element->shadowHost(); | 336 Element* shadowHost = context.element->shadowHost(); |
| 348 if (!shadowHost) | 337 if (!shadowHost) |
| 349 return SelectorFailsCompletely; | 338 return SelectorFailsCompletely; |
| 350 nextContext.element = shadowHost; | 339 nextContext.element = shadowHost; |
| 351 nextContext.isSubSelector = false; | 340 nextContext.isSubSelector = false; |
| 352 nextContext.elementStyle = 0; | 341 nextContext.elementStyle = 0; |
| 353 return this->match(nextContext, siblingTraversalStrategy, result); | 342 return this->match(nextContext, siblingTraversalStrategy, result); |
| 354 } | 343 } |
| 355 | 344 |
| 356 case CSSSelector::ShadowDeep: | 345 case CSSSelector::ShadowDeep: |
| 357 { | 346 { |
| 358 nextContext.isSubSelector = false; | 347 nextContext.isSubSelector = false; |
| 359 nextContext.elementStyle = 0; | 348 nextContext.elementStyle = 0; |
| 360 for (nextContext.element = parentElement(context, true); nextContext .element; nextContext.element = parentElement(nextContext, true)) { | 349 for (nextContext.element = context.element->parentOrShadowHostElemen t(); nextContext.element; nextContext.element = nextContext.element->parentOrSha dowHostElement()) { |
| 361 Match match = this->match(nextContext, siblingTraversalStrategy, result); | 350 Match match = this->match(nextContext, siblingTraversalStrategy, result); |
| 362 if (match == SelectorMatches || match == SelectorFailsCompletely ) | 351 if (match == SelectorMatches || match == SelectorFailsCompletely ) |
| 363 return match; | 352 return match; |
| 364 if (nextSelectorExceedsScope(nextContext)) | 353 if (nextSelectorExceedsScope(nextContext)) |
| 365 return SelectorFailsCompletely; | 354 return SelectorFailsCompletely; |
| 366 } | 355 } |
| 367 return SelectorFailsCompletely; | 356 return SelectorFailsCompletely; |
| 368 } | 357 } |
| 369 | 358 |
| 370 case CSSSelector::SubSelector: | 359 case CSSSelector::SubSelector: |
| 371 ASSERT_NOT_REACHED(); | 360 ASSERT_NOT_REACHED(); |
| 372 } | 361 } |
| 373 | 362 |
| 374 ASSERT_NOT_REACHED(); | 363 ASSERT_NOT_REACHED(); |
| 375 return SelectorFailsCompletely; | 364 return SelectorFailsCompletely; |
| 376 } | 365 } |
| 377 | 366 |
| 378 template<typename SiblingTraversalStrategy> | 367 template<typename SiblingTraversalStrategy> |
| 379 SelectorChecker::Match SelectorChecker::matchForShadowDistributed(const Element* element, const SiblingTraversalStrategy& siblingTraversalStrategy, SelectorChec kingContext& nextContext, MatchResult* result) const | 368 SelectorChecker::Match SelectorChecker::matchForShadowDistributed(const Element* element, const SiblingTraversalStrategy& siblingTraversalStrategy, SelectorChec kingContext& nextContext, MatchResult* result) const |
| 380 { | 369 { |
| 381 ASSERT(element); | 370 ASSERT(element); |
| 382 WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints; | 371 WillBeHeapVector<RawPtrWillBeMember<InsertionPoint>, 8> insertionPoints; |
| 383 | |
| 384 const ContainerNode* scope = nextContext.scope; | |
| 385 BehaviorAtBoundary behaviorAtBoundary = nextContext.behaviorAtBoundary; | |
| 386 | |
| 387 collectDestinationInsertionPoints(*element, insertionPoints); | 372 collectDestinationInsertionPoints(*element, insertionPoints); |
| 388 for (size_t i = 0; i < insertionPoints.size(); ++i) { | 373 for (size_t i = 0; i < insertionPoints.size(); ++i) { |
| 389 nextContext.element = insertionPoints[i]; | 374 nextContext.element = insertionPoints[i]; |
| 390 | 375 if (m_mode == SharingRules) |
| 391 // If a given scope is a shadow host of an insertion point but behaviorA tBoundary doesn't have ScopeIsShadowRoot, | |
| 392 // we need to update behaviorAtBoundary to make selectors like ":host > ::content" work correctly. | |
| 393 if (m_mode == SharingRules) { | |
| 394 nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(beh aviorAtBoundary | ScopeIsShadowRoot); | |
| 395 nextContext.scope = insertionPoints[i]->containingShadowRoot(); | 376 nextContext.scope = insertionPoints[i]->containingShadowRoot(); |
| 396 } else if (scope == insertionPoints[i]->containingShadowRoot() && !(beha viorAtBoundary & ScopeIsShadowRoot)) { | |
| 397 nextContext.behaviorAtBoundary = static_cast<BehaviorAtBoundary>(beh aviorAtBoundary | ScopeIsShadowRoot); | |
| 398 } else { | |
| 399 nextContext.behaviorAtBoundary = behaviorAtBoundary; | |
| 400 } | |
| 401 | |
| 402 nextContext.isSubSelector = false; | 377 nextContext.isSubSelector = false; |
| 403 nextContext.elementStyle = 0; | 378 nextContext.elementStyle = 0; |
| 404 if (match(nextContext, siblingTraversalStrategy, result) == SelectorMatc hes) | 379 if (match(nextContext, siblingTraversalStrategy, result) == SelectorMatc hes) |
| 405 return SelectorMatches; | 380 return SelectorMatches; |
| 406 } | 381 } |
| 407 return SelectorFailsLocally; | 382 return SelectorFailsLocally; |
| 408 } | 383 } |
| 409 | 384 |
| 410 template<typename CharType> | 385 template<typename CharType> |
| 411 static inline bool containsHTMLSpaceTemplate(const CharType* string, unsigned le ngth) | 386 static inline bool containsHTMLSpaceTemplate(const CharType* string, unsigned le ngth) |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 527 } | 502 } |
| 528 | 503 |
| 529 template<typename SiblingTraversalStrategy> | 504 template<typename SiblingTraversalStrategy> |
| 530 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib lingTraversalStrategy& siblingTraversalStrategy, unsigned* specificity) const | 505 bool SelectorChecker::checkOne(const SelectorCheckingContext& context, const Sib lingTraversalStrategy& siblingTraversalStrategy, unsigned* specificity) const |
| 531 { | 506 { |
| 532 ASSERT(context.element); | 507 ASSERT(context.element); |
| 533 Element& element = *context.element; | 508 Element& element = *context.element; |
| 534 ASSERT(context.selector); | 509 ASSERT(context.selector); |
| 535 const CSSSelector& selector = *context.selector; | 510 const CSSSelector& selector = *context.selector; |
| 536 | 511 |
| 537 bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.b ehaviorAtBoundary, context.scope); | 512 bool elementIsHostInItsShadowTree = isHostInItsShadowTree(element, context.s cope); |
| 538 | 513 |
| 539 // Only :host and :ancestor should match the host: http://drafts.csswg.org/c ss-scoping/#host-element | 514 // Only :host and :ancestor should match the host: http://drafts.csswg.org/c ss-scoping/#host-element |
| 540 if (elementIsHostInItsShadowTree && !selector.isHostPseudoClass() | 515 if (elementIsHostInItsShadowTree && !selector.isHostPseudoClass() |
| 541 && !(context.behaviorAtBoundary & TreatShadowHostAsNormalScope)) | 516 && !(context.contextFlags & TreatShadowHostAsNormalScope)) |
| 542 return false; | 517 return false; |
| 543 | 518 |
| 544 if (selector.match() == CSSSelector::Tag) | 519 if (selector.match() == CSSSelector::Tag) |
| 545 return SelectorChecker::tagMatches(element, selector.tagQName()); | 520 return SelectorChecker::tagMatches(element, selector.tagQName()); |
| 546 | 521 |
| 547 if (selector.match() == CSSSelector::Class) | 522 if (selector.match() == CSSSelector::Class) |
| 548 return element.hasClass() && element.classNames().contains(selector.valu e()); | 523 return element.hasClass() && element.classNames().contains(selector.valu e()); |
| 549 | 524 |
| 550 if (selector.match() == CSSSelector::Id) | 525 if (selector.match() == CSSSelector::Id) |
| 551 return element.hasID() && element.idForStyleResolution() == selector.val ue(); | 526 return element.hasID() && element.idForStyleResolution() == selector.val ue(); |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 940 return true; | 915 return true; |
| 941 | 916 |
| 942 SelectorCheckingContext subContext(context); | 917 SelectorCheckingContext subContext(context); |
| 943 subContext.isSubSelector = true; | 918 subContext.isSubSelector = true; |
| 944 | 919 |
| 945 bool matched = false; | 920 bool matched = false; |
| 946 unsigned maxSpecificity = 0; | 921 unsigned maxSpecificity = 0; |
| 947 | 922 |
| 948 // If one of simple selectors matches an element, returns Select orMatches. Just "OR". | 923 // If one of simple selectors matches an element, returns Select orMatches. Just "OR". |
| 949 for (subContext.selector = selector.selectorList()->first(); sub Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select or)) { | 924 for (subContext.selector = selector.selectorList()->first(); sub Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select or)) { |
| 950 subContext.behaviorAtBoundary = ScopeIsShadowHostInPseudoHos tParameter; | 925 subContext.contextFlags = TreatShadowHostAsNormalScope; |
| 951 subContext.scope = context.scope; | 926 subContext.scope = context.scope; |
| 952 // Use NodeRenderingTraversal to traverse a composed ancesto r list of a given element. | 927 // Use NodeRenderingTraversal to traverse a composed ancesto r list of a given element. |
| 953 Element* nextElement = &element; | 928 Element* nextElement = &element; |
| 954 SelectorCheckingContext hostContext(subContext); | 929 SelectorCheckingContext hostContext(subContext); |
| 955 do { | 930 do { |
| 956 MatchResult subResult; | 931 MatchResult subResult; |
| 957 hostContext.element = nextElement; | 932 hostContext.element = nextElement; |
| 958 if (match(hostContext, siblingTraversalStrategy, &subRes ult) == SelectorMatches) { | 933 if (match(hostContext, siblingTraversalStrategy, &subRes ult) == SelectorMatches) { |
| 959 matched = true; | 934 matched = true; |
| 960 // Consider div:host(div:host(div:host(div:host...)) ). | 935 // Consider div:host(div:host(div:host(div:host...)) ). |
| 961 maxSpecificity = std::max(maxSpecificity, hostContex t.selector->specificity() + subResult.specificity); | 936 maxSpecificity = std::max(maxSpecificity, hostContex t.selector->specificity() + subResult.specificity); |
| 962 break; | 937 break; |
| 963 } | 938 } |
| 964 hostContext.behaviorAtBoundary = DoesNotCrossBoundary; | 939 hostContext.contextFlags = DefaultBehavior; |
| 965 hostContext.scope = 0; | 940 hostContext.scope = 0; |
| 966 | 941 |
| 967 if (selector.pseudoType() == CSSSelector::PseudoHost) | 942 if (selector.pseudoType() == CSSSelector::PseudoHost) |
| 968 break; | 943 break; |
| 969 | 944 |
| 970 hostContext.elementStyle = 0; | 945 hostContext.elementStyle = 0; |
| 971 nextElement = NodeRenderingTraversal::parentElement(next Element); | 946 nextElement = NodeRenderingTraversal::parentElement(next Element); |
| 972 } while (nextElement); | 947 } while (nextElement); |
| 973 } | 948 } |
| 974 if (matched) { | 949 if (matched) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 994 case CSSSelector::PseudoUnknown: | 969 case CSSSelector::PseudoUnknown: |
| 995 case CSSSelector::PseudoNotParsed: | 970 case CSSSelector::PseudoNotParsed: |
| 996 default: | 971 default: |
| 997 ASSERT_NOT_REACHED(); | 972 ASSERT_NOT_REACHED(); |
| 998 break; | 973 break; |
| 999 } | 974 } |
| 1000 return false; | 975 return false; |
| 1001 } else if (selector.match() == CSSSelector::PseudoElement && selector.pseudo Type() == CSSSelector::PseudoCue) { | 976 } else if (selector.match() == CSSSelector::PseudoElement && selector.pseudo Type() == CSSSelector::PseudoCue) { |
| 1002 SelectorCheckingContext subContext(context); | 977 SelectorCheckingContext subContext(context); |
| 1003 subContext.isSubSelector = true; | 978 subContext.isSubSelector = true; |
| 1004 subContext.behaviorAtBoundary = StaysWithinTreeScope; | 979 subContext.contextFlags = DefaultBehavior; |
| 1005 | 980 |
| 1006 const CSSSelector* contextSelector = context.selector; | 981 const CSSSelector* contextSelector = context.selector; |
| 1007 ASSERT(contextSelector); | 982 ASSERT(contextSelector); |
| 1008 for (subContext.selector = contextSelector->selectorList()->first(); sub Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select or)) { | 983 for (subContext.selector = contextSelector->selectorList()->first(); sub Context.selector; subContext.selector = CSSSelectorList::next(*subContext.select or)) { |
| 1009 if (match(subContext, siblingTraversalStrategy) == SelectorMatches) | 984 if (match(subContext, siblingTraversalStrategy) == SelectorMatches) |
| 1010 return true; | 985 return true; |
| 1011 } | 986 } |
| 1012 return false; | 987 return false; |
| 1013 } | 988 } |
| 1014 // ### add the rest of the checks... | 989 // ### add the rest of the checks... |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1150 return element.focused() && isFrameFocused(element); | 1125 return element.focused() && isFrameFocused(element); |
| 1151 } | 1126 } |
| 1152 | 1127 |
| 1153 template | 1128 template |
| 1154 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co nst DOMSiblingTraversalStrategy&, MatchResult*) const; | 1129 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co nst DOMSiblingTraversalStrategy&, MatchResult*) const; |
| 1155 | 1130 |
| 1156 template | 1131 template |
| 1157 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co nst ShadowDOMSiblingTraversalStrategy&, MatchResult*) const; | 1132 SelectorChecker::Match SelectorChecker::match(const SelectorCheckingContext&, co nst ShadowDOMSiblingTraversalStrategy&, MatchResult*) const; |
| 1158 | 1133 |
| 1159 } | 1134 } |
| OLD | NEW |