OLD | NEW |
1 /* | 1 /* |
2 * (C) 1999-2003 Lars Knoll (knoll@kde.org) | 2 * (C) 1999-2003 Lars Knoll (knoll@kde.org) |
3 * Copyright (C) 2004, 2006, 2007, 2012 Apple Inc. All rights reserved. | 3 * Copyright (C) 2004, 2006, 2007, 2012 Apple Inc. All rights reserved. |
4 * | 4 * |
5 * This library is free software; you can redistribute it and/or | 5 * This library is free software; you can redistribute it and/or |
6 * modify it under the terms of the GNU Library General Public | 6 * modify it under the terms of the GNU Library General Public |
7 * License as published by the Free Software Foundation; either | 7 * License as published by the Free Software Foundation; either |
8 * version 2 of the License, or (at your option) any later version. | 8 * version 2 of the License, or (at your option) any later version. |
9 * | 9 * |
10 * This library is distributed in the hope that it will be useful, | 10 * This library is distributed in the hope that it will be useful, |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 m_hasSyntacticallyValidCSSHeader(o.m_hasSyntacticallyValidCSSHeader), | 94 m_hasSyntacticallyValidCSSHeader(o.m_hasSyntacticallyValidCSSHeader), |
95 m_didLoadErrorOccur(false), | 95 m_didLoadErrorOccur(false), |
96 m_isMutable(false), | 96 m_isMutable(false), |
97 m_hasFontFaceRule(o.m_hasFontFaceRule), | 97 m_hasFontFaceRule(o.m_hasFontFaceRule), |
98 m_hasViewportRule(o.m_hasViewportRule), | 98 m_hasViewportRule(o.m_hasViewportRule), |
99 m_hasMediaQueries(o.m_hasMediaQueries), | 99 m_hasMediaQueries(o.m_hasMediaQueries), |
100 m_hasSingleOwnerDocument(true), | 100 m_hasSingleOwnerDocument(true), |
101 m_isUsedFromTextCache(false), | 101 m_isUsedFromTextCache(false), |
102 m_parserContext(o.m_parserContext) { | 102 m_parserContext(o.m_parserContext) { |
103 // FIXME: Copy import rules. | 103 // FIXME: Copy import rules. |
104 ASSERT(o.m_importRules.isEmpty()); | 104 DCHECK(o.m_importRules.isEmpty()); |
105 | 105 |
106 for (unsigned i = 0; i < m_namespaceRules.size(); ++i) { | 106 for (unsigned i = 0; i < m_namespaceRules.size(); ++i) { |
107 m_namespaceRules[i] = | 107 m_namespaceRules[i] = |
108 static_cast<StyleRuleNamespace*>(o.m_namespaceRules[i]->copy()); | 108 static_cast<StyleRuleNamespace*>(o.m_namespaceRules[i]->copy()); |
109 } | 109 } |
110 | 110 |
111 // LazyParseCSS: Copying child rules is a strict point for lazy parsing, so | 111 // LazyParseCSS: Copying child rules is a strict point for lazy parsing, so |
112 // there is no need to copy lazy parsing state here. | 112 // there is no need to copy lazy parsing state here. |
113 for (unsigned i = 0; i < m_childRules.size(); ++i) | 113 for (unsigned i = 0; i < m_childRules.size(); ++i) |
114 m_childRules[i] = o.m_childRules[i]->copy(); | 114 m_childRules[i] = o.m_childRules[i]->copy(); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 if (isMutable()) | 161 if (isMutable()) |
162 return false; | 162 return false; |
163 if (!hasSyntacticallyValidCSSHeader()) | 163 if (!hasSyntacticallyValidCSSHeader()) |
164 return false; | 164 return false; |
165 return true; | 165 return true; |
166 } | 166 } |
167 | 167 |
168 void StyleSheetContents::parserAppendRule(StyleRuleBase* rule) { | 168 void StyleSheetContents::parserAppendRule(StyleRuleBase* rule) { |
169 if (rule->isImportRule()) { | 169 if (rule->isImportRule()) { |
170 // Parser enforces that @import rules come before anything else | 170 // Parser enforces that @import rules come before anything else |
171 ASSERT(m_childRules.isEmpty()); | 171 DCHECK(m_childRules.isEmpty()); |
172 StyleRuleImport* importRule = toStyleRuleImport(rule); | 172 StyleRuleImport* importRule = toStyleRuleImport(rule); |
173 if (importRule->mediaQueries()) | 173 if (importRule->mediaQueries()) |
174 setHasMediaQueries(); | 174 setHasMediaQueries(); |
175 m_importRules.push_back(importRule); | 175 m_importRules.push_back(importRule); |
176 m_importRules.back()->setParentStyleSheet(this); | 176 m_importRules.back()->setParentStyleSheet(this); |
177 m_importRules.back()->requestStyleSheet(); | 177 m_importRules.back()->requestStyleSheet(); |
178 return; | 178 return; |
179 } | 179 } |
180 | 180 |
181 if (rule->isNamespaceRule()) { | 181 if (rule->isNamespaceRule()) { |
182 // Parser enforces that @namespace rules come before all rules other than | 182 // Parser enforces that @namespace rules come before all rules other than |
183 // import/charset rules | 183 // import/charset rules |
184 ASSERT(m_childRules.isEmpty()); | 184 DCHECK(m_childRules.isEmpty()); |
185 StyleRuleNamespace& namespaceRule = toStyleRuleNamespace(*rule); | 185 StyleRuleNamespace& namespaceRule = toStyleRuleNamespace(*rule); |
186 parserAddNamespace(namespaceRule.prefix(), namespaceRule.uri()); | 186 parserAddNamespace(namespaceRule.prefix(), namespaceRule.uri()); |
187 m_namespaceRules.push_back(&namespaceRule); | 187 m_namespaceRules.push_back(&namespaceRule); |
188 return; | 188 return; |
189 } | 189 } |
190 | 190 |
191 m_childRules.push_back(rule); | 191 m_childRules.push_back(rule); |
192 } | 192 } |
193 | 193 |
194 void StyleSheetContents::setHasMediaQueries() { | 194 void StyleSheetContents::setHasMediaQueries() { |
(...skipping 17 matching lines...) Expand all Loading... |
212 | 212 |
213 return m_childRules[index].get(); | 213 return m_childRules[index].get(); |
214 } | 214 } |
215 | 215 |
216 unsigned StyleSheetContents::ruleCount() const { | 216 unsigned StyleSheetContents::ruleCount() const { |
217 return m_importRules.size() + m_namespaceRules.size() + m_childRules.size(); | 217 return m_importRules.size() + m_namespaceRules.size() + m_childRules.size(); |
218 } | 218 } |
219 | 219 |
220 void StyleSheetContents::clearRules() { | 220 void StyleSheetContents::clearRules() { |
221 for (unsigned i = 0; i < m_importRules.size(); ++i) { | 221 for (unsigned i = 0; i < m_importRules.size(); ++i) { |
222 ASSERT(m_importRules.at(i)->parentStyleSheet() == this); | 222 DCHECK_EQ(m_importRules.at(i)->parentStyleSheet(), this); |
223 m_importRules[i]->clearParentStyleSheet(); | 223 m_importRules[i]->clearParentStyleSheet(); |
224 } | 224 } |
225 m_importRules.clear(); | 225 m_importRules.clear(); |
226 m_namespaceRules.clear(); | 226 m_namespaceRules.clear(); |
227 m_childRules.clear(); | 227 m_childRules.clear(); |
228 } | 228 } |
229 | 229 |
230 bool StyleSheetContents::wrapperInsertRule(StyleRuleBase* rule, | 230 bool StyleSheetContents::wrapperInsertRule(StyleRuleBase* rule, |
231 unsigned index) { | 231 unsigned index) { |
232 ASSERT(m_isMutable); | 232 DCHECK(m_isMutable); |
233 SECURITY_DCHECK(index <= ruleCount()); | 233 SECURITY_DCHECK(index <= ruleCount()); |
234 | 234 |
235 if (index < m_importRules.size() || | 235 if (index < m_importRules.size() || |
236 (index == m_importRules.size() && rule->isImportRule())) { | 236 (index == m_importRules.size() && rule->isImportRule())) { |
237 // Inserting non-import rule before @import is not allowed. | 237 // Inserting non-import rule before @import is not allowed. |
238 if (!rule->isImportRule()) | 238 if (!rule->isImportRule()) |
239 return false; | 239 return false; |
240 | 240 |
241 StyleRuleImport* importRule = toStyleRuleImport(rule); | 241 StyleRuleImport* importRule = toStyleRuleImport(rule); |
242 if (importRule->mediaQueries()) | 242 if (importRule->mediaQueries()) |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 if (rule->isNamespaceRule()) | 282 if (rule->isNamespaceRule()) |
283 return false; | 283 return false; |
284 | 284 |
285 index -= m_namespaceRules.size(); | 285 index -= m_namespaceRules.size(); |
286 | 286 |
287 m_childRules.insert(index, rule); | 287 m_childRules.insert(index, rule); |
288 return true; | 288 return true; |
289 } | 289 } |
290 | 290 |
291 bool StyleSheetContents::wrapperDeleteRule(unsigned index) { | 291 bool StyleSheetContents::wrapperDeleteRule(unsigned index) { |
292 ASSERT(m_isMutable); | 292 DCHECK(m_isMutable); |
293 SECURITY_DCHECK(index < ruleCount()); | 293 SECURITY_DCHECK(index < ruleCount()); |
294 | 294 |
295 if (index < m_importRules.size()) { | 295 if (index < m_importRules.size()) { |
296 m_importRules[index]->clearParentStyleSheet(); | 296 m_importRules[index]->clearParentStyleSheet(); |
297 if (m_importRules[index]->isFontFaceRule()) | 297 if (m_importRules[index]->isFontFaceRule()) |
298 notifyRemoveFontFaceRule(toStyleRuleFontFace(m_importRules[index].get())); | 298 notifyRemoveFontFaceRule(toStyleRuleFontFace(m_importRules[index].get())); |
299 m_importRules.erase(index); | 299 m_importRules.erase(index); |
300 return true; | 300 return true; |
301 } | 301 } |
302 index -= m_importRules.size(); | 302 index -= m_importRules.size(); |
303 | 303 |
304 if (index < m_namespaceRules.size()) { | 304 if (index < m_namespaceRules.size()) { |
305 if (!m_childRules.isEmpty()) | 305 if (!m_childRules.isEmpty()) |
306 return false; | 306 return false; |
307 m_namespaceRules.erase(index); | 307 m_namespaceRules.erase(index); |
308 return true; | 308 return true; |
309 } | 309 } |
310 index -= m_namespaceRules.size(); | 310 index -= m_namespaceRules.size(); |
311 | 311 |
312 if (m_childRules[index]->isFontFaceRule()) | 312 if (m_childRules[index]->isFontFaceRule()) |
313 notifyRemoveFontFaceRule(toStyleRuleFontFace(m_childRules[index].get())); | 313 notifyRemoveFontFaceRule(toStyleRuleFontFace(m_childRules[index].get())); |
314 m_childRules.erase(index); | 314 m_childRules.erase(index); |
315 return true; | 315 return true; |
316 } | 316 } |
317 | 317 |
318 void StyleSheetContents::parserAddNamespace(const AtomicString& prefix, | 318 void StyleSheetContents::parserAddNamespace(const AtomicString& prefix, |
319 const AtomicString& uri) { | 319 const AtomicString& uri) { |
320 ASSERT(!uri.isNull()); | 320 DCHECK(!uri.isNull()); |
321 if (prefix.isNull()) { | 321 if (prefix.isNull()) { |
322 m_defaultNamespace = uri; | 322 m_defaultNamespace = uri; |
323 return; | 323 return; |
324 } | 324 } |
325 PrefixNamespaceURIMap::AddResult result = m_namespaces.insert(prefix, uri); | 325 PrefixNamespaceURIMap::AddResult result = m_namespaces.insert(prefix, uri); |
326 if (result.isNewEntry) | 326 if (result.isNewEntry) |
327 return; | 327 return; |
328 result.storedValue->value = uri; | 328 result.storedValue->value = uri; |
329 } | 329 } |
330 | 330 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 void StyleSheetContents::checkLoaded() { | 416 void StyleSheetContents::checkLoaded() { |
417 if (isLoading()) | 417 if (isLoading()) |
418 return; | 418 return; |
419 | 419 |
420 StyleSheetContents* parentSheet = parentStyleSheet(); | 420 StyleSheetContents* parentSheet = parentStyleSheet(); |
421 if (parentSheet) { | 421 if (parentSheet) { |
422 parentSheet->checkLoaded(); | 422 parentSheet->checkLoaded(); |
423 return; | 423 return; |
424 } | 424 } |
425 | 425 |
426 ASSERT(this == rootStyleSheet()); | 426 DCHECK_EQ(this, rootStyleSheet()); |
427 if (m_loadingClients.isEmpty()) | 427 if (m_loadingClients.isEmpty()) |
428 return; | 428 return; |
429 | 429 |
430 // Avoid |CSSSStyleSheet| and |ownerNode| being deleted by scripts that run | 430 // Avoid |CSSSStyleSheet| and |ownerNode| being deleted by scripts that run |
431 // via ScriptableDocumentParser::executeScriptsWaitingForResources(). Also | 431 // via ScriptableDocumentParser::executeScriptsWaitingForResources(). Also |
432 // protect the |CSSStyleSheet| from being deleted during iteration via the | 432 // protect the |CSSStyleSheet| from being deleted during iteration via the |
433 // |sheetLoaded| method. | 433 // |sheetLoaded| method. |
434 // | 434 // |
435 // When a sheet is loaded it is moved from the set of loading clients | 435 // When a sheet is loaded it is moved from the set of loading clients |
436 // to the set of completed clients. We therefore need the copy in order to | 436 // to the set of completed clients. We therefore need the copy in order to |
(...skipping 10 matching lines...) Expand all Loading... |
447 if (Node* ownerNode = loadingClients[i]->ownerNode()) { | 447 if (Node* ownerNode = loadingClients[i]->ownerNode()) { |
448 if (loadingClients[i]->sheetLoaded()) | 448 if (loadingClients[i]->sheetLoaded()) |
449 ownerNode->notifyLoadedSheetAndAllCriticalSubresources( | 449 ownerNode->notifyLoadedSheetAndAllCriticalSubresources( |
450 m_didLoadErrorOccur ? Node::ErrorOccurredLoadingSubresource | 450 m_didLoadErrorOccur ? Node::ErrorOccurredLoadingSubresource |
451 : Node::NoErrorLoadingSubresource); | 451 : Node::NoErrorLoadingSubresource); |
452 } | 452 } |
453 } | 453 } |
454 } | 454 } |
455 | 455 |
456 void StyleSheetContents::notifyLoadedSheet(const CSSStyleSheetResource* sheet) { | 456 void StyleSheetContents::notifyLoadedSheet(const CSSStyleSheetResource* sheet) { |
457 ASSERT(sheet); | 457 DCHECK(sheet); |
458 m_didLoadErrorOccur |= sheet->errorOccurred(); | 458 m_didLoadErrorOccur |= sheet->errorOccurred(); |
459 // updateLayoutIgnorePendingStyleSheets can cause us to create the RuleSet on | 459 // updateLayoutIgnorePendingStyleSheets can cause us to create the RuleSet on |
460 // this sheet before its imports have loaded. So clear the RuleSet when the | 460 // this sheet before its imports have loaded. So clear the RuleSet when the |
461 // imports load since the import's subrules are flattened into its parent | 461 // imports load since the import's subrules are flattened into its parent |
462 // sheet's RuleSet. | 462 // sheet's RuleSet. |
463 clearRuleSet(); | 463 clearRuleSet(); |
464 } | 464 } |
465 | 465 |
466 void StyleSheetContents::startLoadingDynamicSheet() { | 466 void StyleSheetContents::startLoadingDynamicSheet() { |
467 StyleSheetContents* root = rootStyleSheet(); | 467 StyleSheetContents* root = rootStyleSheet(); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
523 return true; | 523 return true; |
524 break; | 524 break; |
525 case StyleRuleBase::Media: | 525 case StyleRuleBase::Media: |
526 if (childRulesHaveFailedOrCanceledSubresources( | 526 if (childRulesHaveFailedOrCanceledSubresources( |
527 toStyleRuleMedia(rule)->childRules())) | 527 toStyleRuleMedia(rule)->childRules())) |
528 return true; | 528 return true; |
529 break; | 529 break; |
530 case StyleRuleBase::Charset: | 530 case StyleRuleBase::Charset: |
531 case StyleRuleBase::Import: | 531 case StyleRuleBase::Import: |
532 case StyleRuleBase::Namespace: | 532 case StyleRuleBase::Namespace: |
533 ASSERT_NOT_REACHED(); | 533 NOTREACHED(); |
534 case StyleRuleBase::Page: | 534 case StyleRuleBase::Page: |
535 case StyleRuleBase::Keyframes: | 535 case StyleRuleBase::Keyframes: |
536 case StyleRuleBase::Keyframe: | 536 case StyleRuleBase::Keyframe: |
537 case StyleRuleBase::Supports: | 537 case StyleRuleBase::Supports: |
538 case StyleRuleBase::Viewport: | 538 case StyleRuleBase::Viewport: |
539 break; | 539 break; |
540 } | 540 } |
541 } | 541 } |
542 return false; | 542 return false; |
543 } | 543 } |
544 | 544 |
545 bool StyleSheetContents::hasFailedOrCanceledSubresources() const { | 545 bool StyleSheetContents::hasFailedOrCanceledSubresources() const { |
546 ASSERT(isCacheableForResource()); | 546 DCHECK(isCacheableForResource()); |
547 return childRulesHaveFailedOrCanceledSubresources(m_childRules); | 547 return childRulesHaveFailedOrCanceledSubresources(m_childRules); |
548 } | 548 } |
549 | 549 |
550 Document* StyleSheetContents::clientAnyOwnerDocument() const { | 550 Document* StyleSheetContents::clientAnyOwnerDocument() const { |
551 if (clientSize() <= 0) | 551 if (clientSize() <= 0) |
552 return nullptr; | 552 return nullptr; |
553 if (m_loadingClients.size()) | 553 if (m_loadingClients.size()) |
554 return (*m_loadingClients.begin())->ownerDocument(); | 554 return (*m_loadingClients.begin())->ownerDocument(); |
555 return (*m_completedClients.begin())->ownerDocument(); | 555 return (*m_completedClients.begin())->ownerDocument(); |
556 } | 556 } |
557 | 557 |
558 Document* StyleSheetContents::clientSingleOwnerDocument() const { | 558 Document* StyleSheetContents::clientSingleOwnerDocument() const { |
559 return m_hasSingleOwnerDocument ? clientAnyOwnerDocument() : nullptr; | 559 return m_hasSingleOwnerDocument ? clientAnyOwnerDocument() : nullptr; |
560 } | 560 } |
561 | 561 |
562 StyleSheetContents* StyleSheetContents::parentStyleSheet() const { | 562 StyleSheetContents* StyleSheetContents::parentStyleSheet() const { |
563 return m_ownerRule ? m_ownerRule->parentStyleSheet() : nullptr; | 563 return m_ownerRule ? m_ownerRule->parentStyleSheet() : nullptr; |
564 } | 564 } |
565 | 565 |
566 void StyleSheetContents::registerClient(CSSStyleSheet* sheet) { | 566 void StyleSheetContents::registerClient(CSSStyleSheet* sheet) { |
567 ASSERT(!m_loadingClients.contains(sheet) && | 567 DCHECK(!m_loadingClients.contains(sheet)); |
568 !m_completedClients.contains(sheet)); | 568 DCHECK(!m_completedClients.contains(sheet)); |
569 | 569 |
570 // InspectorCSSAgent::buildObjectForRule creates CSSStyleSheet without any | 570 // InspectorCSSAgent::buildObjectForRule creates CSSStyleSheet without any |
571 // owner node. | 571 // owner node. |
572 if (!sheet->ownerDocument()) | 572 if (!sheet->ownerDocument()) |
573 return; | 573 return; |
574 | 574 |
575 if (Document* document = clientSingleOwnerDocument()) { | 575 if (Document* document = clientSingleOwnerDocument()) { |
576 if (sheet->ownerDocument() != document) | 576 if (sheet->ownerDocument() != document) |
577 m_hasSingleOwnerDocument = false; | 577 m_hasSingleOwnerDocument = false; |
578 } | 578 } |
579 m_loadingClients.insert(sheet); | 579 m_loadingClients.insert(sheet); |
580 } | 580 } |
581 | 581 |
582 void StyleSheetContents::unregisterClient(CSSStyleSheet* sheet) { | 582 void StyleSheetContents::unregisterClient(CSSStyleSheet* sheet) { |
583 m_loadingClients.erase(sheet); | 583 m_loadingClients.erase(sheet); |
584 m_completedClients.erase(sheet); | 584 m_completedClients.erase(sheet); |
585 | 585 |
586 if (!sheet->ownerDocument() || !m_loadingClients.isEmpty() || | 586 if (!sheet->ownerDocument() || !m_loadingClients.isEmpty() || |
587 !m_completedClients.isEmpty()) | 587 !m_completedClients.isEmpty()) |
588 return; | 588 return; |
589 | 589 |
590 m_hasSingleOwnerDocument = true; | 590 m_hasSingleOwnerDocument = true; |
591 } | 591 } |
592 | 592 |
593 void StyleSheetContents::clientLoadCompleted(CSSStyleSheet* sheet) { | 593 void StyleSheetContents::clientLoadCompleted(CSSStyleSheet* sheet) { |
594 ASSERT(m_loadingClients.contains(sheet) || !sheet->ownerDocument()); | 594 DCHECK(m_loadingClients.contains(sheet) || !sheet->ownerDocument()); |
595 m_loadingClients.erase(sheet); | 595 m_loadingClients.erase(sheet); |
596 // In m_ownerNode->sheetLoaded, the CSSStyleSheet might be detached. | 596 // In m_ownerNode->sheetLoaded, the CSSStyleSheet might be detached. |
597 // (i.e. clearOwnerNode was invoked.) | 597 // (i.e. clearOwnerNode was invoked.) |
598 // In this case, we don't need to add the stylesheet to completed clients. | 598 // In this case, we don't need to add the stylesheet to completed clients. |
599 if (!sheet->ownerDocument()) | 599 if (!sheet->ownerDocument()) |
600 return; | 600 return; |
601 m_completedClients.insert(sheet); | 601 m_completedClients.insert(sheet); |
602 } | 602 } |
603 | 603 |
604 void StyleSheetContents::clientLoadStarted(CSSStyleSheet* sheet) { | 604 void StyleSheetContents::clientLoadStarted(CSSStyleSheet* sheet) { |
605 ASSERT(m_completedClients.contains(sheet)); | 605 DCHECK(m_completedClients.contains(sheet)); |
606 m_completedClients.erase(sheet); | 606 m_completedClients.erase(sheet); |
607 m_loadingClients.insert(sheet); | 607 m_loadingClients.insert(sheet); |
608 } | 608 } |
609 | 609 |
610 void StyleSheetContents::setReferencedFromResource( | 610 void StyleSheetContents::setReferencedFromResource( |
611 CSSStyleSheetResource* resource) { | 611 CSSStyleSheetResource* resource) { |
612 DCHECK(resource); | 612 DCHECK(resource); |
613 DCHECK(!isReferencedFromResource()); | 613 DCHECK(!isReferencedFromResource()); |
614 DCHECK(isCacheableForResource()); | 614 DCHECK(isCacheableForResource()); |
615 m_referencedFromResource = resource; | 615 m_referencedFromResource = resource; |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
703 visitor->trace(m_namespaceRules); | 703 visitor->trace(m_namespaceRules); |
704 visitor->trace(m_childRules); | 704 visitor->trace(m_childRules); |
705 visitor->trace(m_loadingClients); | 705 visitor->trace(m_loadingClients); |
706 visitor->trace(m_completedClients); | 706 visitor->trace(m_completedClients); |
707 visitor->trace(m_ruleSet); | 707 visitor->trace(m_ruleSet); |
708 visitor->trace(m_referencedFromResource); | 708 visitor->trace(m_referencedFromResource); |
709 visitor->trace(m_parserContext); | 709 visitor->trace(m_parserContext); |
710 } | 710 } |
711 | 711 |
712 } // namespace blink | 712 } // namespace blink |
OLD | NEW |