1 /* 2 * Copyright (C) 2010, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include "config.h" 26 #include "core/inspector/InspectorCSSAgent.h" 27 28 #include "CSSPropertyNames.h" 29 #include "InspectorTypeBuilder.h" 30 #include "StylePropertyShorthand.h" 31 #include "bindings/v8/ExceptionState.h" 32 #include "bindings/v8/ExceptionStatePlaceholder.h" 33 #include "core/css/CSSComputedStyleDeclaration.h" 34 #include "core/css/CSSImportRule.h" 35 #include "core/css/CSSMediaRule.h" 36 #include "core/css/CSSParser.h" 37 #include "core/css/CSSRule.h" 38 #include "core/css/CSSRuleList.h" 39 #include "core/css/CSSStyleRule.h" 40 #include "core/css/CSSStyleSheet.h" 41 #include "core/css/MediaList.h" 42 #include "core/css/StylePropertySet.h" 43 #include "core/css/StyleRule.h" 44 #include "core/css/StyleSheet.h" 45 #include "core/css/StyleSheetContents.h" 46 #include "core/css/StyleSheetList.h" 47 #include "core/css/resolver/StyleResolver.h" 48 #include "core/dom/NamedFlow.h" 49 #include "core/dom/NamedFlowCollection.h" 50 #include "core/dom/Node.h" 51 #include "core/dom/NodeList.h" 52 #include "core/html/HTMLHeadElement.h" 53 #include "core/inspector/InspectorDOMAgent.h" 54 #include "core/inspector/InspectorHistory.h" 55 #include "core/inspector/InspectorPageAgent.h" 56 #include "core/inspector/InspectorState.h" 57 #include "core/inspector/InstrumentingAgents.h" 58 #include "core/loader/DocumentLoader.h" 59 #include "core/page/ContentSecurityPolicy.h" 60 #include "core/platform/JSONValues.h" 61 #include "core/rendering/RenderRegion.h" 62 #include "wtf/CurrentTime.h" 63 #include "wtf/HashSet.h" 64 #include "wtf/Vector.h" 65 #include "wtf/text/CString.h" 66 #include "wtf/text/StringConcatenate.h" 67 68 namespace CSSAgentState { 69 static const char cssAgentEnabled[] = "cssAgentEnabled"; 70 } 71 72 namespace WebCore { 73 74 enum ForcePseudoClassFlags { 75 PseudoNone = 0, 76 PseudoHover = 1 << 0, 77 PseudoFocus = 1 << 1, 78 PseudoActive = 1 << 2, 79 PseudoVisited = 1 << 3 80 }; 81 82 class StyleSheetAppender { 83 public: 84 StyleSheetAppender(CSSStyleSheetToInspectorStyleSheet& cssStyleSheetToInspectorStyleSheet, Vector<CSSStyleSheet*>& result) 85 : m_cssStyleSheetToInspectorStyleSheet(cssStyleSheetToInspectorStyleSheet) 86 , m_result(result) { } 87 88 void run(CSSStyleSheet* styleSheet) 89 { 90 RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet); 91 // Avoid creating m_childRuleCSSOMWrappers in the stylesheet if it is in the process of re-parsing. 92 // Otherwise m_childRuleCSSOMWrappers size will be initialized only for a part of rules, resulting in an ASSERT failure in CSSStyleSheet::item(). 93 // Instead, wait for the RuleMutationScope destruction and handle the complete CSSStyleSheet. 94 if (inspectorStyleSheet && inspectorStyleSheet->isReparsing()) 95 return; 96 m_result.append(styleSheet); 97 for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) { 98 CSSRule* rule = styleSheet->item(i); 99 if (rule->type() == CSSRule::IMPORT_RULE) { 100 CSSStyleSheet* importedStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet(); 101 if (importedStyleSheet) 102 run(importedStyleSheet); 103 } 104 } 105 } 106 107 private: 108 CSSStyleSheetToInspectorStyleSheet& m_cssStyleSheetToInspectorStyleSheet; 109 Vector<CSSStyleSheet*>& m_result; 110 }; 111 112 static unsigned computePseudoClassMask(JSONArray* pseudoClassArray) 113 { 114 DEFINE_STATIC_LOCAL(String, active, ("active")); 115 DEFINE_STATIC_LOCAL(String, hover, ("hover")); 116 DEFINE_STATIC_LOCAL(String, focus, ("focus")); 117 DEFINE_STATIC_LOCAL(String, visited, ("visited")); 118 if (!pseudoClassArray || !pseudoClassArray->length()) 119 return PseudoNone; 120 121 unsigned result = PseudoNone; 122 for (size_t i = 0; i < pseudoClassArray->length(); ++i) { 123 RefPtr<JSONValue> pseudoClassValue = pseudoClassArray->get(i); 124 String pseudoClass; 125 bool success = pseudoClassValue->asString(&pseudoClass); 126 if (!success) 127 continue; 128 if (pseudoClass == active) 129 result |= PseudoActive; 130 else if (pseudoClass == hover) 131 result |= PseudoHover; 132 else if (pseudoClass == focus) 133 result |= PseudoFocus; 134 else if (pseudoClass == visited) 135 result |= PseudoVisited; 136 } 137 138 return result; 139 } 140 141 class UpdateRegionLayoutTask { 142 public: 143 UpdateRegionLayoutTask(InspectorCSSAgent*); 144 void scheduleFor(NamedFlow*, int documentNodeId); 145 void unschedule(NamedFlow*); 146 void reset(); 147 void onTimer(Timer<UpdateRegionLayoutTask>*); 148 149 private: 150 InspectorCSSAgent* m_cssAgent; 151 Timer<UpdateRegionLayoutTask> m_timer; 152 HashMap<NamedFlow*, int> m_namedFlows; 153 }; 154 155 UpdateRegionLayoutTask::UpdateRegionLayoutTask(InspectorCSSAgent* cssAgent) 156 : m_cssAgent(cssAgent) 157 , m_timer(this, &UpdateRegionLayoutTask::onTimer) 158 { 159 } 160 161 void UpdateRegionLayoutTask::scheduleFor(NamedFlow* namedFlow, int documentNodeId) 162 { 163 m_namedFlows.add(namedFlow, documentNodeId); 164 165 if (!m_timer.isActive()) 166 m_timer.startOneShot(0); 167 } 168 169 void UpdateRegionLayoutTask::unschedule(NamedFlow* namedFlow) 170 { 171 m_namedFlows.remove(namedFlow); 172 } 173 174 void UpdateRegionLayoutTask::reset() 175 { 176 m_timer.stop(); 177 m_namedFlows.clear(); 178 } 179 180 void UpdateRegionLayoutTask::onTimer(Timer<UpdateRegionLayoutTask>*) 181 { 182 // The timer is stopped on m_cssAgent destruction, so this method will never be called after m_cssAgent has been destroyed. 183 Vector<std::pair<NamedFlow*, int> > namedFlows; 184 185 for (HashMap<NamedFlow*, int>::iterator it = m_namedFlows.begin(), end = m_namedFlows.end(); it != end; ++it) 186 namedFlows.append(std::make_pair(it->key, it->value)); 187 188 for (unsigned i = 0, size = namedFlows.size(); i < size; ++i) { 189 NamedFlow* namedFlow = namedFlows.at(i).first; 190 int documentNodeId = namedFlows.at(i).second; 191 192 if (m_namedFlows.contains(namedFlow)) { 193 m_cssAgent->regionLayoutUpdated(namedFlow, documentNodeId); 194 m_namedFlows.remove(namedFlow); 195 } 196 } 197 198 if (!m_namedFlows.isEmpty() && !m_timer.isActive()) 199 m_timer.startOneShot(0); 200 } 201 202 class ChangeRegionOversetTask { 203 public: 204 ChangeRegionOversetTask(InspectorCSSAgent*); 205 void scheduleFor(NamedFlow*, int documentNodeId); 206 void unschedule(NamedFlow*); 207 void reset(); 208 void onTimer(Timer<ChangeRegionOversetTask>*); 209 210 private: 211 InspectorCSSAgent* m_cssAgent; 212 Timer<ChangeRegionOversetTask> m_timer; 213 HashMap<NamedFlow*, int> m_namedFlows; 214 }; 215 216 ChangeRegionOversetTask::ChangeRegionOversetTask(InspectorCSSAgent* cssAgent) 217 : m_cssAgent(cssAgent) 218 , m_timer(this, &ChangeRegionOversetTask::onTimer) 219 { 220 } 221 222 void ChangeRegionOversetTask::scheduleFor(NamedFlow* namedFlow, int documentNodeId) 223 { 224 m_namedFlows.add(namedFlow, documentNodeId); 225 226 if (!m_timer.isActive()) 227 m_timer.startOneShot(0); 228 } 229 230 void ChangeRegionOversetTask::unschedule(NamedFlow* namedFlow) 231 { 232 m_namedFlows.remove(namedFlow); 233 } 234 235 void ChangeRegionOversetTask::reset() 236 { 237 m_timer.stop(); 238 m_namedFlows.clear(); 239 } 240 241 void ChangeRegionOversetTask::onTimer(Timer<ChangeRegionOversetTask>*) 242 { 243 // The timer is stopped on m_cssAgent destruction, so this method will never be called after m_cssAgent has been destroyed. 244 for (HashMap<NamedFlow*, int>::iterator it = m_namedFlows.begin(), end = m_namedFlows.end(); it != end; ++it) 245 m_cssAgent->regionOversetChanged(it->key, it->value); 246 247 m_namedFlows.clear(); 248 } 249 250 class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action { 251 WTF_MAKE_NONCOPYABLE(StyleSheetAction); 252 public: 253 StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet) 254 : InspectorHistory::Action(name) 255 , m_styleSheet(styleSheet) 256 { 257 } 258 259 protected: 260 RefPtr<InspectorStyleSheet> m_styleSheet; 261 }; 262 263 class InspectorCSSAgent::SetStyleSheetTextAction : public InspectorCSSAgent::StyleSheetAction { 264 WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction); 265 public: 266 SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text) 267 : InspectorCSSAgent::StyleSheetAction("SetStyleSheetText", styleSheet) 268 , m_text(text) 269 { 270 } 271 272 virtual bool perform(ExceptionState& es) 273 { 274 if (!m_styleSheet->getText(&m_oldText)) 275 return false; 276 return redo(es); 277 } 278 279 virtual bool undo(ExceptionState& es) 280 { 281 if (m_styleSheet->setText(m_oldText, es)) { 282 m_styleSheet->reparseStyleSheet(m_oldText); 283 return true; 284 } 285 return false; 286 } 287 288 virtual bool redo(ExceptionState& es) 289 { 290 if (m_styleSheet->setText(m_text, es)) { 291 m_styleSheet->reparseStyleSheet(m_text); 292 return true; 293 } 294 return false; 295 } 296 297 virtual String mergeId() 298 { 299 return String::format("SetStyleSheetText %s", m_styleSheet->id().utf8().data()); 300 } 301 302 virtual void merge(PassOwnPtr<Action> action) 303 { 304 ASSERT(action->mergeId() == mergeId()); 305 306 SetStyleSheetTextAction* other = static_cast<SetStyleSheetTextAction*>(action.get()); 307 m_text = other->m_text; 308 } 309 310 private: 311 String m_text; 312 String m_oldText; 313 }; 314 315 class InspectorCSSAgent::SetStyleTextAction : public InspectorCSSAgent::StyleSheetAction { 316 WTF_MAKE_NONCOPYABLE(SetStyleTextAction); 317 public: 318 SetStyleTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& text) 319 : InspectorCSSAgent::StyleSheetAction("SetPropertyText", styleSheet) 320 , m_cssId(cssId) 321 , m_text(text) 322 { 323 } 324 325 virtual String toString() 326 { 327 return mergeId() + ": " + m_oldText + " -> " + m_text; 328 } 329 330 virtual bool perform(ExceptionState& es) 331 { 332 return redo(es); 333 } 334 335 virtual bool undo(ExceptionState& es) 336 { 337 String placeholder; 338 return m_styleSheet->setStyleText(m_cssId, m_oldText, &placeholder, es); 339 } 340 341 virtual bool redo(ExceptionState& es) 342 { 343 return m_styleSheet->setStyleText(m_cssId, m_text, &m_oldText, es); 344 } 345 346 virtual String mergeId() 347 { 348 return String::format("SetStyleText %s:%u", m_cssId.styleSheetId().utf8().data(), m_cssId.ordinal()); 349 } 350 351 virtual void merge(PassOwnPtr<Action> action) 352 { 353 ASSERT(action->mergeId() == mergeId()); 354 355 SetStyleTextAction* other = static_cast<SetStyleTextAction*>(action.get()); 356 m_text = other->m_text; 357 } 358 359 private: 360 InspectorCSSId m_cssId; 361 String m_text; 362 String m_oldText; 363 }; 364 365 class InspectorCSSAgent::SetPropertyTextAction : public InspectorCSSAgent::StyleSheetAction { 366 WTF_MAKE_NONCOPYABLE(SetPropertyTextAction); 367 public: 368 SetPropertyTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, const String& text, bool overwrite) 369 : InspectorCSSAgent::StyleSheetAction("SetPropertyText", styleSheet) 370 , m_cssId(cssId) 371 , m_propertyIndex(propertyIndex) 372 , m_text(text) 373 , m_overwrite(overwrite) 374 { 375 } 376 377 virtual String toString() 378 { 379 return mergeId() + ": " + m_oldText + " -> " + m_text; 380 } 381 382 virtual bool perform(ExceptionState& es) 383 { 384 return redo(es); 385 } 386 387 virtual bool undo(ExceptionState& es) 388 { 389 String placeholder; 390 return m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_overwrite ? m_oldText : "", true, &placeholder, es); 391 } 392 393 virtual bool redo(ExceptionState& es) 394 { 395 String oldText; 396 bool result = m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_text, m_overwrite, &oldText, es); 397 m_oldText = oldText.stripWhiteSpace(); 398 // FIXME: remove this once the model handles this case. 399 if (!m_oldText.endsWith(';')) 400 m_oldText.append(';'); 401 return result; 402 } 403 404 virtual String mergeId() 405 { 406 return String::format("SetPropertyText %s:%u:%s", m_styleSheet->id().utf8().data(), m_propertyIndex, m_overwrite ? "true" : "false"); 407 } 408 409 virtual void merge(PassOwnPtr<Action> action) 410 { 411 ASSERT(action->mergeId() == mergeId()); 412 413 SetPropertyTextAction* other = static_cast<SetPropertyTextAction*>(action.get()); 414 m_text = other->m_text; 415 } 416 417 private: 418 InspectorCSSId m_cssId; 419 unsigned m_propertyIndex; 420 String m_text; 421 String m_oldText; 422 bool m_overwrite; 423 }; 424 425 class InspectorCSSAgent::TogglePropertyAction : public InspectorCSSAgent::StyleSheetAction { 426 WTF_MAKE_NONCOPYABLE(TogglePropertyAction); 427 public: 428 TogglePropertyAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, bool disable) 429 : InspectorCSSAgent::StyleSheetAction("ToggleProperty", styleSheet) 430 , m_cssId(cssId) 431 , m_propertyIndex(propertyIndex) 432 , m_disable(disable) 433 { 434 } 435 436 virtual bool perform(ExceptionState& es) 437 { 438 return redo(es); 439 } 440 441 virtual bool undo(ExceptionState& es) 442 { 443 return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, !m_disable, es); 444 } 445 446 virtual bool redo(ExceptionState& es) 447 { 448 return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, m_disable, es); 449 } 450 451 private: 452 InspectorCSSId m_cssId; 453 unsigned m_propertyIndex; 454 bool m_disable; 455 }; 456 457 class InspectorCSSAgent::SetRuleSelectorAction : public InspectorCSSAgent::StyleSheetAction { 458 WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction); 459 public: 460 SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector) 461 : InspectorCSSAgent::StyleSheetAction("SetRuleSelector", styleSheet) 462 , m_cssId(cssId) 463 , m_selector(selector) 464 { 465 } 466 467 virtual bool perform(ExceptionState& es) 468 { 469 m_oldSelector = m_styleSheet->ruleSelector(m_cssId, es); 470 if (es.hadException()) 471 return false; 472 return redo(es); 473 } 474 475 virtual bool undo(ExceptionState& es) 476 { 477 return m_styleSheet->setRuleSelector(m_cssId, m_oldSelector, es); 478 } 479 480 virtual bool redo(ExceptionState& es) 481 { 482 return m_styleSheet->setRuleSelector(m_cssId, m_selector, es); 483 } 484 485 private: 486 InspectorCSSId m_cssId; 487 String m_selector; 488 String m_oldSelector; 489 }; 490 491 class InspectorCSSAgent::AddRuleAction : public InspectorCSSAgent::StyleSheetAction { 492 WTF_MAKE_NONCOPYABLE(AddRuleAction); 493 public: 494 AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector) 495 : InspectorCSSAgent::StyleSheetAction("AddRule", styleSheet) 496 , m_selector(selector) 497 { 498 } 499 500 virtual bool perform(ExceptionState& es) 501 { 502 return redo(es); 503 } 504 505 virtual bool undo(ExceptionState& es) 506 { 507 return m_styleSheet->deleteRule(m_newId, es); 508 } 509 510 virtual bool redo(ExceptionState& es) 511 { 512 CSSStyleRule* cssStyleRule = m_styleSheet->addRule(m_selector, es); 513 if (es.hadException()) 514 return false; 515 m_newId = m_styleSheet->ruleId(cssStyleRule); 516 return true; 517 } 518 519 InspectorCSSId newRuleId() { return m_newId; } 520 521 private: 522 InspectorCSSId m_newId; 523 String m_selector; 524 String m_oldSelector; 525 }; 526 527 // static 528 CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule* rule) 529 { 530 if (!rule || rule->type() != CSSRule::STYLE_RULE) 531 return 0; 532 return static_cast<CSSStyleRule*>(rule); 533 } 534 535 template <typename CharType, size_t bufferLength> 536 static size_t vendorPrefixLowerCase(const CharType* string, size_t stringLength, char (&buffer)[bufferLength]) 537 { 538 static const char lowerCaseOffset = 'a' - 'A'; 539 540 if (string[0] != '-') 541 return 0; 542 543 for (size_t i = 0; i < stringLength - 1; i++) { 544 CharType c = string[i + 1]; 545 if (c == '-') 546 return i; 547 if (i == bufferLength) 548 break; 549 if (c < 'A' || c > 'z') 550 break; 551 if (c >= 'a') 552 buffer[i] = c; 553 else if (c <= 'Z') 554 buffer[i] = c + lowerCaseOffset; 555 else 556 break; 557 } 558 return 0; 559 } 560 561 template <size_t patternLength> 562 static bool equals(const char* prefix, size_t prefixLength, const char (&pattern)[patternLength]) 563 { 564 if (prefixLength != patternLength - 1) 565 return false; 566 for (size_t i = 0; i < patternLength - 1; i++) { 567 if (prefix[i] != pattern[i]) 568 return false; 569 } 570 return true; 571 } 572 573 static bool hasNonWebkitVendorSpecificPrefix(const CSSParserString& string) 574 { 575 // Known prefixes: http://wiki.csswg.org/spec/vendor-prefixes 576 const size_t stringLength = string.length(); 577 if (stringLength < 4) 578 return false; 579 580 char buffer[6]; 581 size_t prefixLength = string.is8Bit() ? 582 vendorPrefixLowerCase(string.characters8(), stringLength, buffer) : 583 vendorPrefixLowerCase(string.characters16(), stringLength, buffer); 584 585 if (!prefixLength || prefixLength == stringLength - 2) 586 return false; 587 588 switch (buffer[0]) { 589 case 'a': 590 return (prefixLength == 2 && buffer[1] == 'h') || equals(buffer + 1, prefixLength - 1, "tsc"); 591 case 'e': 592 return equals(buffer + 1, prefixLength - 1, "pub"); 593 case 'h': 594 return prefixLength == 2 && buffer[1] == 'p'; 595 case 'i': 596 return equals(buffer + 1, prefixLength - 1, "books"); 597 case 'k': 598 return equals(buffer + 1, prefixLength - 1, "html"); 599 case 'm': 600 if (prefixLength == 2) 601 return buffer[1] == 's'; 602 if (prefixLength == 3) 603 return (buffer[1] == 'o' && buffer[2] == 'z') || (buffer[1] == 's' || buffer[2] == 'o'); 604 break; 605 case 'o': 606 return prefixLength == 1; 607 case 'p': 608 return equals(buffer + 1, prefixLength - 1, "rince"); 609 case 'r': 610 return (prefixLength == 2 && buffer[1] == 'o') || equals(buffer + 1, prefixLength - 1, "im"); 611 case 't': 612 return prefixLength == 2 && buffer[1] == 'c'; 613 case 'w': 614 return (prefixLength == 3 && buffer[1] == 'a' && buffer[2] == 'p') || equals(buffer + 1, prefixLength - 1, "easy"); 615 case 'x': 616 return prefixLength == 2 && buffer[1] == 'v'; 617 } 618 return false; 619 } 620 621 static bool isValidPropertyName(const CSSParserString& content) 622 { 623 if (content.equalIgnoringCase("animation") 624 || content.equalIgnoringCase("font-size-adjust") 625 || content.equalIgnoringCase("transform") 626 || content.equalIgnoringCase("user-select") 627 || content.equalIgnoringCase("-webkit-flex-pack") 628 || content.equalIgnoringCase("-webkit-text-size-adjust")) 629 return true; 630 631 return false; 632 } 633 634 // static 635 bool InspectorCSSAgent::cssErrorFilter(const CSSParserString& content, int propertyId, int errorType) 636 { 637 const size_t contentLength = content.length(); 638 639 switch (errorType) { 640 case CSSParser::PropertyDeclarationError: 641 // Ignore errors like "*property: value". This trick is used for IE7: http://stackoverflow.com/questions/4563651/what-does-an-asterisk-do-in-a-css-property-name 642 if (contentLength && content[0] == '*') 643 return false; 644 645 // The "filter" property is commonly used instead of "opacity" for IE9. 646 if (propertyId == CSSPropertyFilter) 647 return false; 648 649 break; 650 651 case CSSParser::InvalidPropertyValueError: 652 // The "filter" property is commonly used instead of "opacity" for IE9. 653 if (propertyId == CSSPropertyFilter) 654 return false; 655 656 // Value might be a vendor-specific function. 657 if (hasNonWebkitVendorSpecificPrefix(content)) 658 return false; 659 660 // IE-only "cursor: hand". 661 if (propertyId == CSSPropertyCursor && content.equalIgnoringCase("hand")) 662 return false; 663 664 // Ignore properties like "property: value \9" (common IE hack) or "property: value \0" (IE 8 hack). 665 if (contentLength > 2 && content[contentLength - 2] == '\\' && (content[contentLength - 1] == '9' || content[contentLength - 1] == '0')) 666 return false; 667 668 if (contentLength > 3) { 669 670 // property: value\0/; 671 if (content[contentLength - 3] == '\\' && content[contentLength - 2] == '0' && content[contentLength - 1] == '/') 672 return false; 673 674 // property: value !ie; 675 if (content[contentLength - 3] == '!' && content[contentLength - 2] == 'i' && content[contentLength - 1] == 'e') 676 return false; 677 } 678 679 // Popular value prefixes valid in other browsers. 680 if (content.startsWithIgnoringCase("linear-gradient")) 681 return false; 682 if (content.startsWithIgnoringCase("-webkit-flexbox")) 683 return false; 684 if (propertyId == CSSPropertyUnicodeBidi && content.startsWithIgnoringCase("isolate")) 685 return false; 686 687 break; 688 689 case CSSParser::InvalidPropertyError: 690 if (hasNonWebkitVendorSpecificPrefix(content)) 691 return false; 692 693 // Another hack to make IE-only property. 694 if (contentLength && content[0] == '_') 695 return false; 696 697 // IE-only set of properties. 698 if (content.startsWithIgnoringCase("scrollbar-")) 699 return false; 700 701 if (isValidPropertyName(content)) 702 return false; 703 704 break; 705 706 case CSSParser::InvalidRuleError: 707 // Block error reporting for @-rules for now to avoid noise. 708 if (contentLength > 4 && content[0] == '@') 709 return false; 710 return true; 711 712 case CSSParser::InvalidSelectorPseudoError: 713 if (hasNonWebkitVendorSpecificPrefix(content)) 714 return false; 715 } 716 return true; 717 } 718 719 InspectorCSSAgent::InspectorCSSAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InspectorDOMAgent* domAgent, InspectorPageAgent* pageAgent) 720 : InspectorBaseAgent<InspectorCSSAgent>("CSS", instrumentingAgents, state) 721 , m_frontend(0) 722 , m_domAgent(domAgent) 723 , m_pageAgent(pageAgent) 724 , m_lastStyleSheetId(1) 725 , m_creatingViaInspectorStyleSheet(false) 726 , m_isSettingStyleSheetText(false) 727 { 728 m_domAgent->setDOMListener(this); 729 } 730 731 InspectorCSSAgent::~InspectorCSSAgent() 732 { 733 ASSERT(!m_domAgent); 734 reset(); 735 } 736 737 void InspectorCSSAgent::setFrontend(InspectorFrontend* frontend) 738 { 739 ASSERT(!m_frontend); 740 m_frontend = frontend->css(); 741 } 742 743 void InspectorCSSAgent::clearFrontend() 744 { 745 ASSERT(m_frontend); 746 m_frontend = 0; 747 resetNonPersistentData(); 748 } 749 750 void InspectorCSSAgent::discardAgent() 751 { 752 m_domAgent->setDOMListener(0); 753 m_domAgent = 0; 754 } 755 756 void InspectorCSSAgent::restore() 757 { 758 if (m_state->getBoolean(CSSAgentState::cssAgentEnabled)) { 759 ErrorString error; 760 enable(&error); 761 } 762 } 763 764 void InspectorCSSAgent::reset() 765 { 766 m_idToInspectorStyleSheet.clear(); 767 m_cssStyleSheetToInspectorStyleSheet.clear(); 768 m_nodeToInspectorStyleSheet.clear(); 769 m_documentToInspectorStyleSheet.clear(); 770 resetNonPersistentData(); 771 } 772 773 void InspectorCSSAgent::resetNonPersistentData() 774 { 775 m_namedFlowCollectionsRequested.clear(); 776 if (m_updateRegionLayoutTask) 777 m_updateRegionLayoutTask->reset(); 778 if (m_changeRegionOversetTask) 779 m_changeRegionOversetTask->reset(); 780 resetPseudoStates(); 781 } 782 783 void InspectorCSSAgent::enable(ErrorString*) 784 { 785 m_state->setBoolean(CSSAgentState::cssAgentEnabled, true); 786 m_instrumentingAgents->setInspectorCSSAgent(this); 787 788 if (!m_frontend) 789 return; 790 Vector<InspectorStyleSheet*> styleSheets; 791 collectAllStyleSheets(styleSheets); 792 for (size_t i = 0; i < styleSheets.size(); ++i) 793 m_frontend->styleSheetAdded(styleSheets.at(i)->buildObjectForStyleSheetInfo()); 794 } 795 796 void InspectorCSSAgent::disable(ErrorString*) 797 { 798 m_instrumentingAgents->setInspectorCSSAgent(0); 799 m_state->setBoolean(CSSAgentState::cssAgentEnabled, false); 800 } 801 802 void InspectorCSSAgent::didCommitLoad(Frame* frame, DocumentLoader* loader) 803 { 804 if (loader->frame() != frame->page()->mainFrame()) 805 return; 806 807 reset(); 808 } 809 810 void InspectorCSSAgent::mediaQueryResultChanged() 811 { 812 if (m_frontend) 813 m_frontend->mediaQueryResultChanged(); 814 } 815 816 void InspectorCSSAgent::didCreateNamedFlow(Document* document, NamedFlow* namedFlow) 817 { 818 int documentNodeId = documentNodeWithRequestedFlowsId(document); 819 if (!documentNodeId) 820 return; 821 822 ErrorString errorString; 823 m_frontend->namedFlowCreated(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId)); 824 } 825 826 void InspectorCSSAgent::willRemoveNamedFlow(Document* document, NamedFlow* namedFlow) 827 { 828 int documentNodeId = documentNodeWithRequestedFlowsId(document); 829 if (!documentNodeId) 830 return; 831 832 if (m_updateRegionLayoutTask) 833 m_updateRegionLayoutTask->unschedule(namedFlow); 834 835 m_frontend->namedFlowRemoved(documentNodeId, namedFlow->name().string()); 836 } 837 838 void InspectorCSSAgent::didUpdateRegionLayout(Document* document, NamedFlow* namedFlow) 839 { 840 int documentNodeId = documentNodeWithRequestedFlowsId(document); 841 if (!documentNodeId) 842 return; 843 844 if (!m_updateRegionLayoutTask) 845 m_updateRegionLayoutTask = adoptPtr(new UpdateRegionLayoutTask(this)); 846 m_updateRegionLayoutTask->scheduleFor(namedFlow, documentNodeId); 847 } 848 849 void InspectorCSSAgent::regionLayoutUpdated(NamedFlow* namedFlow, int documentNodeId) 850 { 851 if (namedFlow->flowState() == NamedFlow::FlowStateNull) 852 return; 853 854 ErrorString errorString; 855 RefPtr<NamedFlow> protector(namedFlow); 856 857 m_frontend->regionLayoutUpdated(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId)); 858 } 859 860 void InspectorCSSAgent::didChangeRegionOverset(Document* document, NamedFlow* namedFlow) 861 { 862 int documentNodeId = documentNodeWithRequestedFlowsId(document); 863 if (!documentNodeId) 864 return; 865 866 if (!m_changeRegionOversetTask) 867 m_changeRegionOversetTask = adoptPtr(new ChangeRegionOversetTask(this)); 868 m_changeRegionOversetTask->scheduleFor(namedFlow, documentNodeId); 869 } 870 871 void InspectorCSSAgent::regionOversetChanged(NamedFlow* namedFlow, int documentNodeId) 872 { 873 if (namedFlow->flowState() == NamedFlow::FlowStateNull) 874 return; 875 876 ErrorString errorString; 877 RefPtr<NamedFlow> protector(namedFlow); 878 879 m_frontend->regionOversetChanged(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId)); 880 } 881 882 void InspectorCSSAgent::activeStyleSheetsUpdated(Document* document, const StyleSheetVector& newSheets) 883 { 884 if (m_isSettingStyleSheetText) 885 return; 886 HashSet<CSSStyleSheet*> removedSheets; 887 for (CSSStyleSheetToInspectorStyleSheet::iterator it = m_cssStyleSheetToInspectorStyleSheet.begin(); it != m_cssStyleSheetToInspectorStyleSheet.end(); ++it) { 888 if (it->value->canBind() && (!it->key->ownerDocument() || it->key->ownerDocument() == document)) 889 removedSheets.add(it->key); 890 } 891 892 Vector<CSSStyleSheet*> newSheetsVector; 893 for (size_t i = 0, size = newSheets.size(); i < size; ++i) { 894 StyleSheet* newSheet = newSheets.at(i).get(); 895 if (newSheet->isCSSStyleSheet()) { 896 StyleSheetAppender appender(m_cssStyleSheetToInspectorStyleSheet, newSheetsVector); 897 appender.run(static_cast<CSSStyleSheet*>(newSheet)); 898 } 899 } 900 901 HashSet<CSSStyleSheet*> addedSheets; 902 for (size_t i = 0; i < newSheetsVector.size(); ++i) { 903 CSSStyleSheet* newCSSSheet = newSheetsVector.at(i); 904 if (removedSheets.contains(newCSSSheet)) 905 removedSheets.remove(newCSSSheet); 906 else 907 addedSheets.add(newCSSSheet); 908 } 909 910 for (HashSet<CSSStyleSheet*>::iterator it = removedSheets.begin(); it != removedSheets.end(); ++it) { 911 RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(*it); 912 ASSERT(inspectorStyleSheet); 913 if (m_idToInspectorStyleSheet.contains(inspectorStyleSheet->id())) { 914 String id = unbindStyleSheet(inspectorStyleSheet.get()); 915 if (m_frontend) 916 m_frontend->styleSheetRemoved(id); 917 } 918 } 919 920 for (HashSet<CSSStyleSheet*>::iterator it = addedSheets.begin(); it != addedSheets.end(); ++it) { 921 if (!m_cssStyleSheetToInspectorStyleSheet.contains(*it)) { 922 InspectorStyleSheet* newStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(*it)); 923 if (m_frontend) 924 m_frontend->styleSheetAdded(newStyleSheet->buildObjectForStyleSheetInfo()); 925 } 926 } 927 } 928 929 void InspectorCSSAgent::frameDetachedFromParent(Frame* frame) 930 { 931 Document* document = frame->document(); 932 if (!document) 933 return; 934 StyleSheetVector newSheets; 935 activeStyleSheetsUpdated(document, newSheets); 936 } 937 938 bool InspectorCSSAgent::forcePseudoState(Element* element, CSSSelector::PseudoType pseudoType) 939 { 940 if (m_nodeIdToForcedPseudoState.isEmpty()) 941 return false; 942 943 int nodeId = m_domAgent->boundNodeId(element); 944 if (!nodeId) 945 return false; 946 947 NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId); 948 if (it == m_nodeIdToForcedPseudoState.end()) 949 return false; 950 951 unsigned forcedPseudoState = it->value; 952 switch (pseudoType) { 953 case CSSSelector::PseudoActive: 954 return forcedPseudoState & PseudoActive; 955 case CSSSelector::PseudoFocus: 956 return forcedPseudoState & PseudoFocus; 957 case CSSSelector::PseudoHover: 958 return forcedPseudoState & PseudoHover; 959 case CSSSelector::PseudoVisited: 960 return forcedPseudoState & PseudoVisited; 961 default: 962 return false; 963 } 964 } 965 966 void InspectorCSSAgent::getMatchedStylesForNode(ErrorString* errorString, int nodeId, const bool* includePseudo, const bool* includeInherited, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> >& matchedCSSRules, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches> >& pseudoIdMatches, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> >& inheritedEntries) 967 { 968 Element* element = elementForId(errorString, nodeId); 969 if (!element) 970 return; 971 972 // Matched rules. 973 StyleResolver* styleResolver = element->ownerDocument()->styleResolver(); 974 RefPtr<CSSRuleList> matchedRules = styleResolver->styleRulesForElement(element, StyleResolver::AllCSSRules); 975 matchedCSSRules = buildArrayForMatchedRuleList(matchedRules.get(), styleResolver, element); 976 977 // Pseudo elements. 978 if (!includePseudo || *includePseudo) { 979 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches> > pseudoElements = TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches>::create(); 980 for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) { 981 RefPtr<CSSRuleList> matchedRules = styleResolver->pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules); 982 if (matchedRules && matchedRules->length()) { 983 RefPtr<TypeBuilder::CSS::PseudoIdMatches> matches = TypeBuilder::CSS::PseudoIdMatches::create() 984 .setPseudoId(static_cast<int>(pseudoId)) 985 .setMatches(buildArrayForMatchedRuleList(matchedRules.get(), styleResolver, element)); 986 pseudoElements->addItem(matches.release()); 987 } 988 } 989 990 pseudoIdMatches = pseudoElements.release(); 991 } 992 993 // Inherited styles. 994 if (!includeInherited || *includeInherited) { 995 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> > entries = TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry>::create(); 996 Element* parentElement = element->parentElement(); 997 while (parentElement) { 998 StyleResolver* parentStyleResolver = parentElement->ownerDocument()->styleResolver(); 999 RefPtr<CSSRuleList> parentMatchedRules = parentStyleResolver->styleRulesForElement(parentElement, StyleResolver::AllCSSRules); 1000 RefPtr<TypeBuilder::CSS::InheritedStyleEntry> entry = TypeBuilder::CSS::InheritedStyleEntry::create() 1001 .setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules.get(), styleResolver, parentElement)); 1002 if (parentElement->style() && parentElement->style()->length()) { 1003 InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement); 1004 if (styleSheet) 1005 entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0)))); 1006 } 1007 1008 entries->addItem(entry.release()); 1009 parentElement = parentElement->parentElement(); 1010 } 1011 1012 inheritedEntries = entries.release(); 1013 } 1014 } 1015 1016 void InspectorCSSAgent::getInlineStylesForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::CSS::CSSStyle>& inlineStyle, RefPtr<TypeBuilder::CSS::CSSStyle>& attributesStyle) 1017 { 1018 Element* element = elementForId(errorString, nodeId); 1019 if (!element) 1020 return; 1021 1022 InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element); 1023 if (!styleSheet) 1024 return; 1025 1026 inlineStyle = styleSheet->buildObjectForStyle(element->style()); 1027 RefPtr<TypeBuilder::CSS::CSSStyle> attributes = buildObjectForAttributesStyle(element); 1028 attributesStyle = attributes ? attributes.release() : 0; 1029 } 1030 1031 void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> >& style) 1032 { 1033 Element* element = elementForId(errorString, nodeId); 1034 if (!element) 1035 return; 1036 1037 RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(element, true); 1038 RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0); 1039 style = inspectorStyle->buildArrayForComputedStyle(); 1040 } 1041 1042 void InspectorCSSAgent::getAllStyleSheets(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader> >& styleInfos) 1043 { 1044 styleInfos = TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader>::create(); 1045 Vector<InspectorStyleSheet*> styleSheets; 1046 collectAllStyleSheets(styleSheets); 1047 for (size_t i = 0; i < styleSheets.size(); ++i) 1048 styleInfos->addItem(styleSheets.at(i)->buildObjectForStyleSheetInfo()); 1049 } 1050 1051 void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<TypeBuilder::CSS::CSSStyleSheetBody>& styleSheetObject) 1052 { 1053 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId); 1054 if (!inspectorStyleSheet) 1055 return; 1056 1057 Document* doc = inspectorStyleSheet->pageStyleSheet() ? inspectorStyleSheet->pageStyleSheet()->ownerDocument() : 0; 1058 if (!doc || !doc->styleResolver()) 1059 return; 1060 1061 RefPtr<TypeBuilder::CSS::CSSStyleSheetBody> result = TypeBuilder::CSS::CSSStyleSheetBody::create() 1062 .setStyleSheetId(styleSheetId) 1063 .setRules(buildArrayForRuleList(inspectorStyleSheet->pageStyleSheet()->rules().get(), doc->styleResolver())); 1064 1065 bool success = inspectorStyleSheet->fillObjectForStyleSheet(result); 1066 if (success) 1067 styleSheetObject = result; 1068 } 1069 1070 void InspectorCSSAgent::getStyleSheetText(ErrorString* errorString, const String& styleSheetId, String* result) 1071 { 1072 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId); 1073 if (!inspectorStyleSheet) 1074 return; 1075 1076 inspectorStyleSheet->getText(result); 1077 } 1078 1079 void InspectorCSSAgent::setStyleSheetText(ErrorString* errorString, const String& styleSheetId, const String& text) 1080 { 1081 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId); 1082 if (!inspectorStyleSheet) 1083 return; 1084 1085 TrackExceptionState es; 1086 m_domAgent->history()->perform(adoptPtr(new SetStyleSheetTextAction(inspectorStyleSheet, text)), es); 1087 *errorString = InspectorDOMAgent::toErrorString(es); 1088 } 1089 1090 void InspectorCSSAgent::setStyleText(ErrorString* errorString, const RefPtr<JSONObject>& fullStyleId, const String& text, RefPtr<TypeBuilder::CSS::CSSStyle>& result) 1091 { 1092 InspectorCSSId compoundId(fullStyleId); 1093 ASSERT(!compoundId.isEmpty()); 1094 1095 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId()); 1096 if (!inspectorStyleSheet) 1097 return; 1098 1099 TrackExceptionState es; 1100 m_domAgent->history()->perform(adoptPtr(new SetStyleTextAction(inspectorStyleSheet, compoundId, text)), es); 1101 if (!es.hadException()) 1102 result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId)); 1103 *errorString = InspectorDOMAgent::toErrorString(es); 1104 } 1105 1106 void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<JSONObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<TypeBuilder::CSS::CSSStyle>& result) 1107 { 1108 InspectorCSSId compoundId(fullStyleId); 1109 ASSERT(!compoundId.isEmpty()); 1110 1111 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId()); 1112 if (!inspectorStyleSheet) 1113 return; 1114 1115 TrackExceptionState es; 1116 bool success = m_domAgent->history()->perform(adoptPtr(new SetPropertyTextAction(inspectorStyleSheet, compoundId, propertyIndex, text, overwrite)), es); 1117 if (success) 1118 result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId)); 1119 *errorString = InspectorDOMAgent::toErrorString(es); 1120 } 1121 1122 void InspectorCSSAgent::toggleProperty(ErrorString* errorString, const RefPtr<JSONObject>& fullStyleId, int propertyIndex, bool disable, RefPtr<TypeBuilder::CSS::CSSStyle>& result) 1123 { 1124 InspectorCSSId compoundId(fullStyleId); 1125 ASSERT(!compoundId.isEmpty()); 1126 1127 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId()); 1128 if (!inspectorStyleSheet) 1129 return; 1130 1131 TrackExceptionState es; 1132 bool success = m_domAgent->history()->perform(adoptPtr(new TogglePropertyAction(inspectorStyleSheet, compoundId, propertyIndex, disable)), es); 1133 if (success) 1134 result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId)); 1135 *errorString = InspectorDOMAgent::toErrorString(es); 1136 } 1137 1138 void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<JSONObject>& fullRuleId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result) 1139 { 1140 InspectorCSSId compoundId(fullRuleId); 1141 ASSERT(!compoundId.isEmpty()); 1142 1143 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId()); 1144 if (!inspectorStyleSheet) 1145 return; 1146 1147 TrackExceptionState es; 1148 bool success = m_domAgent->history()->perform(adoptPtr(new SetRuleSelectorAction(inspectorStyleSheet, compoundId, selector)), es); 1149 1150 if (success) { 1151 CSSStyleRule* rule = inspectorStyleSheet->ruleForId(compoundId); 1152 result = inspectorStyleSheet->buildObjectForRule(rule, buildMediaListChain(rule)); 1153 } 1154 *errorString = InspectorDOMAgent::toErrorString(es); 1155 } 1156 1157 void InspectorCSSAgent::addRule(ErrorString* errorString, const int contextNodeId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result) 1158 { 1159 Node* node = m_domAgent->assertNode(errorString, contextNodeId); 1160 if (!node) 1161 return; 1162 1163 InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(node->document(), true); 1164 if (!inspectorStyleSheet) { 1165 *errorString = "No target stylesheet found"; 1166 return; 1167 } 1168 1169 TrackExceptionState es; 1170 OwnPtr<AddRuleAction> action = adoptPtr(new AddRuleAction(inspectorStyleSheet, selector)); 1171 AddRuleAction* rawAction = action.get(); 1172 bool success = m_domAgent->history()->perform(action.release(), es); 1173 if (!success) { 1174 *errorString = InspectorDOMAgent::toErrorString(es); 1175 return; 1176 } 1177 1178 InspectorCSSId ruleId = rawAction->newRuleId(); 1179 CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId); 1180 result = inspectorStyleSheet->buildObjectForRule(rule, buildMediaListChain(rule)); 1181 } 1182 1183 void InspectorCSSAgent::getSupportedCSSProperties(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> >& cssProperties) 1184 { 1185 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> > properties = TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo>::create(); 1186 for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) { 1187 CSSPropertyID id = convertToCSSPropertyID(i); 1188 RefPtr<TypeBuilder::CSS::CSSPropertyInfo> property = TypeBuilder::CSS::CSSPropertyInfo::create() 1189 .setName(getPropertyNameString(id)); 1190 1191 const StylePropertyShorthand& shorthand = shorthandForProperty(id); 1192 if (!shorthand.length()) { 1193 properties->addItem(property.release()); 1194 continue; 1195 } 1196 RefPtr<TypeBuilder::Array<String> > longhands = TypeBuilder::Array<String>::create(); 1197 for (unsigned j = 0; j < shorthand.length(); ++j) { 1198 CSSPropertyID longhandID = shorthand.properties()[j]; 1199 longhands->addItem(getPropertyNameString(longhandID)); 1200 } 1201 property->setLonghands(longhands); 1202 properties->addItem(property.release()); 1203 } 1204 cssProperties = properties.release(); 1205 } 1206 1207 void InspectorCSSAgent::forcePseudoState(ErrorString* errorString, int nodeId, const RefPtr<JSONArray>& forcedPseudoClasses) 1208 { 1209 Element* element = m_domAgent->assertElement(errorString, nodeId); 1210 if (!element) 1211 return; 1212 1213 unsigned forcedPseudoState = computePseudoClassMask(forcedPseudoClasses.get()); 1214 NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId); 1215 unsigned currentForcedPseudoState = it == m_nodeIdToForcedPseudoState.end() ? 0 : it->value; 1216 bool needStyleRecalc = forcedPseudoState != currentForcedPseudoState; 1217 if (!needStyleRecalc) 1218 return; 1219 1220 if (forcedPseudoState) 1221 m_nodeIdToForcedPseudoState.set(nodeId, forcedPseudoState); 1222 else 1223 m_nodeIdToForcedPseudoState.remove(nodeId); 1224 element->ownerDocument()->setNeedsStyleRecalc(); 1225 } 1226 1227 void InspectorCSSAgent::getNamedFlowCollection(ErrorString* errorString, int documentNodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::NamedFlow> >& result) 1228 { 1229 Document* document = m_domAgent->assertDocument(errorString, documentNodeId); 1230 if (!document) 1231 return; 1232 1233 m_namedFlowCollectionsRequested.add(documentNodeId); 1234 1235 Vector<RefPtr<NamedFlow> > namedFlowsVector = document->namedFlows()->namedFlows(); 1236 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::NamedFlow> > namedFlows = TypeBuilder::Array<TypeBuilder::CSS::NamedFlow>::create(); 1237 1238 for (Vector<RefPtr<NamedFlow> >::iterator it = namedFlowsVector.begin(); it != namedFlowsVector.end(); ++it) 1239 namedFlows->addItem(buildObjectForNamedFlow(errorString, it->get(), documentNodeId)); 1240 1241 result = namedFlows.release(); 1242 } 1243 1244 PassRefPtr<TypeBuilder::CSS::CSSMedia> InspectorCSSAgent::buildMediaObject(const MediaList* media, MediaListSource mediaListSource, const String& sourceURL, CSSStyleSheet* parentStyleSheet) 1245 { 1246 // Make certain compilers happy by initializing |source| up-front. 1247 TypeBuilder::CSS::CSSMedia::Source::Enum source = TypeBuilder::CSS::CSSMedia::Source::InlineSheet; 1248 switch (mediaListSource) { 1249 case MediaListSourceMediaRule: 1250 source = TypeBuilder::CSS::CSSMedia::Source::MediaRule; 1251 break; 1252 case MediaListSourceImportRule: 1253 source = TypeBuilder::CSS::CSSMedia::Source::ImportRule; 1254 break; 1255 case MediaListSourceLinkedSheet: 1256 source = TypeBuilder::CSS::CSSMedia::Source::LinkedSheet; 1257 break; 1258 case MediaListSourceInlineSheet: 1259 source = TypeBuilder::CSS::CSSMedia::Source::InlineSheet; 1260 break; 1261 } 1262 1263 RefPtr<TypeBuilder::CSS::CSSMedia> mediaObject = TypeBuilder::CSS::CSSMedia::create() 1264 .setText(media->mediaText()) 1265 .setSource(source); 1266 1267 if (parentStyleSheet && mediaListSource != MediaListSourceLinkedSheet) { 1268 if (InspectorStyleSheet* inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(parentStyleSheet)) 1269 mediaObject->setParentStyleSheetId(inspectorStyleSheet->id()); 1270 } 1271 if (!sourceURL.isEmpty()) { 1272 mediaObject->setSourceURL(sourceURL); 1273 1274 CSSRule* parentRule = media->parentRule(); 1275 if (!parentRule) 1276 return mediaObject.release(); 1277 InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(parentRule->parentStyleSheet()); 1278 RefPtr<TypeBuilder::CSS::SourceRange> mediaRange = inspectorStyleSheet->ruleHeaderSourceRange(parentRule); 1279 if (mediaRange) 1280 mediaObject->setRange(mediaRange); 1281 } 1282 return mediaObject.release(); 1283 } 1284 1285 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSMedia> > InspectorCSSAgent::buildMediaListChain(CSSRule* rule) 1286 { 1287 if (!rule) 1288 return 0; 1289 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSMedia> > mediaArray = TypeBuilder::Array<TypeBuilder::CSS::CSSMedia>::create(); 1290 bool hasItems = false; 1291 MediaList* mediaList; 1292 CSSRule* parentRule = rule; 1293 String sourceURL; 1294 while (parentRule) { 1295 CSSStyleSheet* parentStyleSheet = 0; 1296 bool isMediaRule = true; 1297 if (parentRule->type() == CSSRule::MEDIA_RULE) { 1298 CSSMediaRule* mediaRule = static_cast<CSSMediaRule*>(parentRule); 1299 mediaList = mediaRule->media(); 1300 parentStyleSheet = mediaRule->parentStyleSheet(); 1301 } else if (parentRule->type() == CSSRule::IMPORT_RULE) { 1302 CSSImportRule* importRule = static_cast<CSSImportRule*>(parentRule); 1303 mediaList = importRule->media(); 1304 parentStyleSheet = importRule->parentStyleSheet(); 1305 isMediaRule = false; 1306 } else { 1307 mediaList = 0; 1308 } 1309 1310 if (parentStyleSheet) { 1311 sourceURL = parentStyleSheet->contents()->baseURL(); 1312 if (sourceURL.isEmpty()) 1313 sourceURL = InspectorDOMAgent::documentURLString(parentStyleSheet->ownerDocument()); 1314 } else { 1315 sourceURL = ""; 1316 } 1317 1318 if (mediaList && mediaList->length()) { 1319 mediaArray->addItem(buildMediaObject(mediaList, isMediaRule ? MediaListSourceMediaRule : MediaListSourceImportRule, sourceURL, parentStyleSheet)); 1320 hasItems = true; 1321 } 1322 1323 if (parentRule->parentRule()) { 1324 parentRule = parentRule->parentRule(); 1325 } else { 1326 CSSStyleSheet* styleSheet = parentRule->parentStyleSheet(); 1327 while (styleSheet) { 1328 mediaList = styleSheet->media(); 1329 if (mediaList && mediaList->length()) { 1330 Document* doc = styleSheet->ownerDocument(); 1331 if (doc) 1332 sourceURL = doc->url(); 1333 else if (!styleSheet->contents()->baseURL().isEmpty()) 1334 sourceURL = styleSheet->contents()->baseURL(); 1335 else 1336 sourceURL = ""; 1337 mediaArray->addItem(buildMediaObject(mediaList, styleSheet->ownerNode() ? MediaListSourceLinkedSheet : MediaListSourceInlineSheet, sourceURL, styleSheet)); 1338 hasItems = true; 1339 } 1340 parentRule = styleSheet->ownerRule(); 1341 if (parentRule) 1342 break; 1343 styleSheet = styleSheet->parentStyleSheet(); 1344 } 1345 } 1346 } 1347 return hasItems ? mediaArray : 0; 1348 } 1349 1350 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element) 1351 { 1352 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element); 1353 if (it != m_nodeToInspectorStyleSheet.end()) 1354 return it->value.get(); 1355 1356 CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0; 1357 if (!style) 1358 return 0; 1359 1360 String newStyleSheetId = String::number(m_lastStyleSheetId++); 1361 RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(m_pageAgent, newStyleSheetId, element, TypeBuilder::CSS::StyleSheetOrigin::Regular, this); 1362 m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet); 1363 m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet); 1364 return inspectorStyleSheet.get(); 1365 } 1366 1367 Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId) 1368 { 1369 Node* node = m_domAgent->nodeForId(nodeId); 1370 if (!node) { 1371 *errorString = "No node with given id found"; 1372 return 0; 1373 } 1374 if (!node->isElementNode()) { 1375 *errorString = "Not an element node"; 1376 return 0; 1377 } 1378 return toElement(node); 1379 } 1380 1381 int InspectorCSSAgent::documentNodeWithRequestedFlowsId(Document* document) 1382 { 1383 int documentNodeId = m_domAgent->boundNodeId(document); 1384 if (!documentNodeId || !m_namedFlowCollectionsRequested.contains(documentNodeId)) 1385 return 0; 1386 1387 return documentNodeId; 1388 } 1389 1390 void InspectorCSSAgent::collectAllStyleSheets(Vector<InspectorStyleSheet*>& result) 1391 { 1392 Vector<Document*> documents = m_domAgent->documents(); 1393 for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) { 1394 StyleSheetList* list = (*it)->styleSheets(); 1395 for (unsigned i = 0; i < list->length(); ++i) { 1396 StyleSheet* styleSheet = list->item(i); 1397 if (styleSheet->isCSSStyleSheet()) 1398 collectStyleSheets(static_cast<CSSStyleSheet*>(styleSheet), result); 1399 } 1400 } 1401 } 1402 1403 void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, Vector<InspectorStyleSheet*>& result) 1404 { 1405 InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(styleSheet)); 1406 result.append(inspectorStyleSheet); 1407 for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) { 1408 CSSRule* rule = styleSheet->item(i); 1409 if (rule->type() == CSSRule::IMPORT_RULE) { 1410 CSSStyleSheet* importedStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet(); 1411 if (importedStyleSheet) 1412 collectStyleSheets(importedStyleSheet, result); 1413 } 1414 } 1415 } 1416 1417 InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet) 1418 { 1419 RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet); 1420 if (!inspectorStyleSheet) { 1421 String id = String::number(m_lastStyleSheetId++); 1422 Document* document = styleSheet->ownerDocument(); 1423 inspectorStyleSheet = InspectorStyleSheet::create(m_pageAgent, id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this); 1424 m_idToInspectorStyleSheet.set(id, inspectorStyleSheet); 1425 m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet); 1426 if (m_creatingViaInspectorStyleSheet) 1427 m_documentToInspectorStyleSheet.add(document, inspectorStyleSheet); 1428 } 1429 return inspectorStyleSheet.get(); 1430 } 1431 1432 String InspectorCSSAgent::unbindStyleSheet(InspectorStyleSheet* inspectorStyleSheet) 1433 { 1434 String id = inspectorStyleSheet->id(); 1435 m_idToInspectorStyleSheet.remove(id); 1436 if (inspectorStyleSheet->pageStyleSheet()) 1437 m_cssStyleSheetToInspectorStyleSheet.remove(inspectorStyleSheet->pageStyleSheet()); 1438 return id; 1439 } 1440 1441 InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent) 1442 { 1443 if (!document) { 1444 ASSERT(!createIfAbsent); 1445 return 0; 1446 } 1447 1448 if (!document->isHTMLDocument() && !document->isSVGDocument()) 1449 return 0; 1450 1451 RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document); 1452 if (inspectorStyleSheet || !createIfAbsent) 1453 return inspectorStyleSheet.get(); 1454 1455 TrackExceptionState es; 1456 RefPtr<Element> styleElement = document->createElement("style", es); 1457 if (!es.hadException()) 1458 styleElement->setAttribute("type", "text/css", es); 1459 if (!es.hadException()) { 1460 ContainerNode* targetNode; 1461 // HEAD is absent in ImageDocuments, for example. 1462 if (document->head()) 1463 targetNode = document->head(); 1464 else if (document->body()) 1465 targetNode = document->body(); 1466 else 1467 return 0; 1468 1469 InlineStyleOverrideScope overrideScope(document); 1470 m_creatingViaInspectorStyleSheet = true; 1471 targetNode->appendChild(styleElement, es, AttachLazily); 1472 // At this point the added stylesheet will get bound through the updateActiveStyleSheets() invocation. 1473 // We just need to pick the respective InspectorStyleSheet from m_documentToInspectorStyleSheet. 1474 m_creatingViaInspectorStyleSheet = false; 1475 } 1476 if (es.hadException()) 1477 return 0; 1478 1479 return m_documentToInspectorStyleSheet.get(document); 1480 } 1481 1482 InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId) 1483 { 1484 IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId); 1485 if (it == m_idToInspectorStyleSheet.end()) { 1486 *errorString = "No style sheet with given id found"; 1487 return 0; 1488 } 1489 return it->value.get(); 1490 } 1491 1492 TypeBuilder::CSS::StyleSheetOrigin::Enum InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument) 1493 { 1494 if (m_creatingViaInspectorStyleSheet) 1495 return TypeBuilder::CSS::StyleSheetOrigin::Inspector; 1496 1497 TypeBuilder::CSS::StyleSheetOrigin::Enum origin = TypeBuilder::CSS::StyleSheetOrigin::Regular; 1498 if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty()) 1499 origin = TypeBuilder::CSS::StyleSheetOrigin::User_agent; 1500 else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document") 1501 origin = TypeBuilder::CSS::StyleSheetOrigin::User; 1502 else { 1503 InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false); 1504 if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet()) 1505 origin = TypeBuilder::CSS::StyleSheetOrigin::Inspector; 1506 } 1507 return origin; 1508 } 1509 1510 PassRefPtr<TypeBuilder::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule, StyleResolver* styleResolver) 1511 { 1512 if (!rule) 1513 return 0; 1514 1515 // CSSRules returned by StyleResolver::styleRulesForElement lack parent pointers since that infomation is not cheaply available. 1516 // Since the inspector wants to walk the parent chain, we construct the full wrappers here. 1517 // FIXME: This could be factored better. StyleResolver::styleRulesForElement should return a StyleRule vector, not a CSSRuleList. 1518 if (!rule->parentStyleSheet()) { 1519 rule = styleResolver->inspectorCSSOMWrappers().getWrapperForRuleInSheets(rule->styleRule(), styleResolver->document()->styleSheetCollection()); 1520 if (!rule) 1521 return 0; 1522 } 1523 return bindStyleSheet(rule->parentStyleSheet())->buildObjectForRule(rule, buildMediaListChain(rule)); 1524 } 1525 1526 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList, StyleResolver* styleResolver) 1527 { 1528 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > result = TypeBuilder::Array<TypeBuilder::CSS::CSSRule>::create(); 1529 if (!ruleList) 1530 return result.release(); 1531 1532 RefPtr<CSSRuleList> refRuleList = ruleList; 1533 CSSRuleVector rules; 1534 InspectorStyleSheet::collectFlatRules(refRuleList, &rules); 1535 1536 for (unsigned i = 0, size = rules.size(); i < size; ++i) { 1537 CSSStyleRule* styleRule = asCSSStyleRule(rules.at(i).get()); 1538 if (!styleRule) 1539 continue; 1540 result->addItem(buildObjectForRule(styleRule, styleResolver)); 1541 } 1542 1543 return result.release(); 1544 } 1545 1546 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > InspectorCSSAgent::buildArrayForMatchedRuleList(CSSRuleList* ruleList, StyleResolver* styleResolver, Element* element) 1547 { 1548 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > result = TypeBuilder::Array<TypeBuilder::CSS::RuleMatch>::create(); 1549 if (!ruleList) 1550 return result.release(); 1551 1552 for (unsigned i = 0, size = ruleList->length(); i < size; ++i) { 1553 CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i)); 1554 RefPtr<TypeBuilder::CSS::CSSRule> ruleObject = buildObjectForRule(rule, styleResolver); 1555 if (!ruleObject) 1556 continue; 1557 RefPtr<TypeBuilder::Array<int> > matchingSelectors = TypeBuilder::Array<int>::create(); 1558 const CSSSelectorList& selectorList = rule->styleRule()->selectorList(); 1559 long index = 0; 1560 for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) { 1561 bool matched = element->webkitMatchesSelector(selector->selectorText(), IGNORE_EXCEPTION); 1562 if (matched) 1563 matchingSelectors->addItem(index); 1564 ++index; 1565 } 1566 RefPtr<TypeBuilder::CSS::RuleMatch> match = TypeBuilder::CSS::RuleMatch::create() 1567 .setRule(ruleObject) 1568 .setMatchingSelectors(matchingSelectors); 1569 result->addItem(match); 1570 } 1571 1572 return result; 1573 } 1574 1575 PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element) 1576 { 1577 if (!element->isStyledElement()) 1578 return 0; 1579 1580 // FIXME: Ugliness below. 1581 StylePropertySet* attributeStyle = const_cast<StylePropertySet*>(element->presentationAttributeStyle()); 1582 if (!attributeStyle) 1583 return 0; 1584 1585 ASSERT(attributeStyle->isMutable()); 1586 MutableStylePropertySet* mutableAttributeStyle = static_cast<MutableStylePropertySet*>(attributeStyle); 1587 1588 RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), mutableAttributeStyle->ensureCSSStyleDeclaration(), 0); 1589 return inspectorStyle->buildObjectForStyle(); 1590 } 1591 1592 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::Region> > InspectorCSSAgent::buildArrayForRegions(ErrorString* errorString, PassRefPtr<NodeList> regionList, int documentNodeId) 1593 { 1594 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::Region> > regions = TypeBuilder::Array<TypeBuilder::CSS::Region>::create(); 1595 1596 for (unsigned i = 0; i < regionList->length(); ++i) { 1597 TypeBuilder::CSS::Region::RegionOverset::Enum regionOverset; 1598 1599 switch (toElement(regionList->item(i))->renderRegion()->regionOversetState()) { 1600 case RegionFit: 1601 regionOverset = TypeBuilder::CSS::Region::RegionOverset::Fit; 1602 break; 1603 case RegionEmpty: 1604 regionOverset = TypeBuilder::CSS::Region::RegionOverset::Empty; 1605 break; 1606 case RegionOverset: 1607 regionOverset = TypeBuilder::CSS::Region::RegionOverset::Overset; 1608 break; 1609 case RegionUndefined: 1610 continue; 1611 default: 1612 ASSERT_NOT_REACHED(); 1613 continue; 1614 } 1615 1616 RefPtr<TypeBuilder::CSS::Region> region = TypeBuilder::CSS::Region::create() 1617 .setRegionOverset(regionOverset) 1618 // documentNodeId was previously asserted 1619 .setNodeId(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, regionList->item(i))); 1620 1621 regions->addItem(region); 1622 } 1623 1624 return regions.release(); 1625 } 1626 1627 PassRefPtr<TypeBuilder::CSS::NamedFlow> InspectorCSSAgent::buildObjectForNamedFlow(ErrorString* errorString, NamedFlow* webkitNamedFlow, int documentNodeId) 1628 { 1629 RefPtr<NodeList> contentList = webkitNamedFlow->getContent(); 1630 RefPtr<TypeBuilder::Array<int> > content = TypeBuilder::Array<int>::create(); 1631 1632 for (unsigned i = 0; i < contentList->length(); ++i) { 1633 // documentNodeId was previously asserted 1634 content->addItem(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, contentList->item(i))); 1635 } 1636 1637 RefPtr<TypeBuilder::CSS::NamedFlow> namedFlow = TypeBuilder::CSS::NamedFlow::create() 1638 .setDocumentNodeId(documentNodeId) 1639 .setName(webkitNamedFlow->name().string()) 1640 .setOverset(webkitNamedFlow->overset()) 1641 .setContent(content) 1642 .setRegions(buildArrayForRegions(errorString, webkitNamedFlow->getRegions(), documentNodeId)); 1643 1644 return namedFlow.release(); 1645 } 1646 1647 void InspectorCSSAgent::didRemoveDocument(Document* document) 1648 { 1649 if (document) 1650 m_documentToInspectorStyleSheet.remove(document); 1651 } 1652 1653 void InspectorCSSAgent::didRemoveDOMNode(Node* node) 1654 { 1655 if (!node) 1656 return; 1657 1658 int nodeId = m_domAgent->boundNodeId(node); 1659 if (nodeId) 1660 m_nodeIdToForcedPseudoState.remove(nodeId); 1661 1662 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node); 1663 if (it == m_nodeToInspectorStyleSheet.end()) 1664 return; 1665 1666 m_idToInspectorStyleSheet.remove(it->value->id()); 1667 m_nodeToInspectorStyleSheet.remove(node); 1668 } 1669 1670 void InspectorCSSAgent::didModifyDOMAttr(Element* element) 1671 { 1672 if (!element) 1673 return; 1674 1675 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element); 1676 if (it == m_nodeToInspectorStyleSheet.end()) 1677 return; 1678 1679 it->value->didModifyElementAttribute(); 1680 } 1681 1682 void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet) 1683 { 1684 if (m_frontend) 1685 m_frontend->styleSheetChanged(styleSheet->id()); 1686 } 1687 1688 void InspectorCSSAgent::willReparseStyleSheet() 1689 { 1690 ASSERT(!m_isSettingStyleSheetText); 1691 m_isSettingStyleSheetText = true; 1692 } 1693 1694 void InspectorCSSAgent::didReparseStyleSheet() 1695 { 1696 ASSERT(m_isSettingStyleSheetText); 1697 m_isSettingStyleSheetText = false; 1698 } 1699 1700 void InspectorCSSAgent::resetPseudoStates() 1701 { 1702 HashSet<Document*> documentsToChange; 1703 for (NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.begin(), end = m_nodeIdToForcedPseudoState.end(); it != end; ++it) { 1704 Element* element = toElement(m_domAgent->nodeForId(it->key)); 1705 if (element && element->ownerDocument()) 1706 documentsToChange.add(element->ownerDocument()); 1707 } 1708 1709 m_nodeIdToForcedPseudoState.clear(); 1710 for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = documentsToChange.end(); it != end; ++it) 1711 (*it)->setNeedsStyleRecalc(); 1712 } 1713 1714 } // namespace WebCore 1715 1716