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