| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010, Google Inc. All rights reserved. | 2 * Copyright (C) 2010, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 #include "core/platform/JSONValues.h" | 59 #include "core/platform/JSONValues.h" |
| 60 #include "core/rendering/RenderRegion.h" | 60 #include "core/rendering/RenderRegion.h" |
| 61 #include "wtf/CurrentTime.h" | 61 #include "wtf/CurrentTime.h" |
| 62 #include "wtf/HashSet.h" | 62 #include "wtf/HashSet.h" |
| 63 #include "wtf/Vector.h" | 63 #include "wtf/Vector.h" |
| 64 #include "wtf/text/CString.h" | 64 #include "wtf/text/CString.h" |
| 65 #include "wtf/text/StringConcatenate.h" | 65 #include "wtf/text/StringConcatenate.h" |
| 66 | 66 |
| 67 namespace CSSAgentState { | 67 namespace CSSAgentState { |
| 68 static const char cssAgentEnabled[] = "cssAgentEnabled"; | 68 static const char cssAgentEnabled[] = "cssAgentEnabled"; |
| 69 static const char isSelectorProfiling[] = "isSelectorProfiling"; | |
| 70 } | 69 } |
| 71 | 70 |
| 72 namespace WebCore { | 71 namespace WebCore { |
| 73 | 72 |
| 74 enum ForcePseudoClassFlags { | 73 enum ForcePseudoClassFlags { |
| 75 PseudoNone = 0, | 74 PseudoNone = 0, |
| 76 PseudoHover = 1 << 0, | 75 PseudoHover = 1 << 0, |
| 77 PseudoFocus = 1 << 1, | 76 PseudoFocus = 1 << 1, |
| 78 PseudoActive = 1 << 2, | 77 PseudoActive = 1 << 2, |
| 79 PseudoVisited = 1 << 3 | 78 PseudoVisited = 1 << 3 |
| 80 }; | 79 }; |
| 81 | 80 |
| 82 struct RuleMatchData { | |
| 83 String selector; | |
| 84 String url; | |
| 85 unsigned lineNumber; | |
| 86 double startTime; | |
| 87 }; | |
| 88 | |
| 89 struct RuleMatchingStats { | |
| 90 RuleMatchingStats() | |
| 91 : lineNumber(0), totalTime(0.0), hits(0), matches(0) | |
| 92 { | |
| 93 } | |
| 94 RuleMatchingStats(const RuleMatchData& data, double totalTime, unsigned hits
, unsigned matches) | |
| 95 : selector(data.selector), url(data.url), lineNumber(data.lineNumber), t
otalTime(totalTime), hits(hits), matches(matches) | |
| 96 { | |
| 97 } | |
| 98 | |
| 99 String selector; | |
| 100 String url; | |
| 101 unsigned lineNumber; | |
| 102 double totalTime; | |
| 103 unsigned hits; | |
| 104 unsigned matches; | |
| 105 }; | |
| 106 | |
| 107 class SelectorProfile { | |
| 108 WTF_MAKE_FAST_ALLOCATED; | |
| 109 public: | |
| 110 SelectorProfile() | |
| 111 : m_totalMatchingTimeMs(0.0) | |
| 112 { | |
| 113 } | |
| 114 virtual ~SelectorProfile() | |
| 115 { | |
| 116 } | |
| 117 | |
| 118 double totalMatchingTimeMs() const { return m_totalMatchingTimeMs; } | |
| 119 | |
| 120 String makeKey(); | |
| 121 void startSelector(const CSSStyleRule*); | |
| 122 void commitSelector(bool); | |
| 123 void commitSelectorTime(); | |
| 124 PassRefPtr<TypeBuilder::CSS::SelectorProfile> toInspectorObject() const; | |
| 125 | |
| 126 private: | |
| 127 | |
| 128 // Key is "selector?url:line". | |
| 129 typedef HashMap<String, RuleMatchingStats> RuleMatchingStatsMap; | |
| 130 | |
| 131 double m_totalMatchingTimeMs; | |
| 132 RuleMatchingStatsMap m_ruleMatchingStats; | |
| 133 RuleMatchData m_currentMatchData; | |
| 134 }; | |
| 135 | |
| 136 class StyleSheetAppender { | 81 class StyleSheetAppender { |
| 137 public: | 82 public: |
| 138 StyleSheetAppender(CSSStyleSheetToInspectorStyleSheet& cssStyleSheetToInspec
torStyleSheet, Vector<CSSStyleSheet*>& result) | 83 StyleSheetAppender(CSSStyleSheetToInspectorStyleSheet& cssStyleSheetToInspec
torStyleSheet, Vector<CSSStyleSheet*>& result) |
| 139 : m_cssStyleSheetToInspectorStyleSheet(cssStyleSheetToInspectorStyleShee
t) | 84 : m_cssStyleSheetToInspectorStyleSheet(cssStyleSheetToInspectorStyleShee
t) |
| 140 , m_result(result) { } | 85 , m_result(result) { } |
| 141 | 86 |
| 142 void run(CSSStyleSheet* styleSheet) | 87 void run(CSSStyleSheet* styleSheet) |
| 143 { | 88 { |
| 144 RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspe
ctorStyleSheet.get(styleSheet); | 89 RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspe
ctorStyleSheet.get(styleSheet); |
| 145 // Avoid creating m_childRuleCSSOMWrappers in the stylesheet if it is in
the process of re-parsing. | 90 // Avoid creating m_childRuleCSSOMWrappers in the stylesheet if it is in
the process of re-parsing. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 result |= PseudoHover; | 130 result |= PseudoHover; |
| 186 else if (pseudoClass == focus) | 131 else if (pseudoClass == focus) |
| 187 result |= PseudoFocus; | 132 result |= PseudoFocus; |
| 188 else if (pseudoClass == visited) | 133 else if (pseudoClass == visited) |
| 189 result |= PseudoVisited; | 134 result |= PseudoVisited; |
| 190 } | 135 } |
| 191 | 136 |
| 192 return result; | 137 return result; |
| 193 } | 138 } |
| 194 | 139 |
| 195 inline String SelectorProfile::makeKey() | |
| 196 { | |
| 197 return m_currentMatchData.selector + "?" + m_currentMatchData.url + ":" + St
ring::number(m_currentMatchData.lineNumber); | |
| 198 } | |
| 199 | |
| 200 inline void SelectorProfile::startSelector(const CSSStyleRule* rule) | |
| 201 { | |
| 202 m_currentMatchData.selector = rule->selectorText(); | |
| 203 CSSStyleSheet* styleSheet = rule->parentStyleSheet(); | |
| 204 String url = emptyString(); | |
| 205 if (styleSheet) { | |
| 206 url = InspectorStyleSheet::styleSheetURL(styleSheet); | |
| 207 if (url.isEmpty()) | |
| 208 url = InspectorDOMAgent::documentURLString(styleSheet->ownerDocument
()); | |
| 209 } | |
| 210 m_currentMatchData.url = url; | |
| 211 m_currentMatchData.lineNumber = rule->styleRule()->sourceLine(); | |
| 212 m_currentMatchData.startTime = WTF::currentTimeMS(); | |
| 213 } | |
| 214 | |
| 215 inline void SelectorProfile::commitSelector(bool matched) | |
| 216 { | |
| 217 double matchTimeMs = WTF::currentTimeMS() - m_currentMatchData.startTime; | |
| 218 m_totalMatchingTimeMs += matchTimeMs; | |
| 219 | |
| 220 RuleMatchingStatsMap::AddResult result = m_ruleMatchingStats.add(makeKey(),
RuleMatchingStats(m_currentMatchData, matchTimeMs, 1, matched ? 1 : 0)); | |
| 221 if (!result.isNewEntry) { | |
| 222 result.iterator->value.totalTime += matchTimeMs; | |
| 223 result.iterator->value.hits += 1; | |
| 224 if (matched) | |
| 225 result.iterator->value.matches += 1; | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 inline void SelectorProfile::commitSelectorTime() | |
| 230 { | |
| 231 double processingTimeMs = WTF::currentTimeMS() - m_currentMatchData.startTim
e; | |
| 232 m_totalMatchingTimeMs += processingTimeMs; | |
| 233 | |
| 234 RuleMatchingStatsMap::iterator it = m_ruleMatchingStats.find(makeKey()); | |
| 235 if (it == m_ruleMatchingStats.end()) | |
| 236 return; | |
| 237 | |
| 238 it->value.totalTime += processingTimeMs; | |
| 239 } | |
| 240 | |
| 241 PassRefPtr<TypeBuilder::CSS::SelectorProfile> SelectorProfile::toInspectorObject
() const | |
| 242 { | |
| 243 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::SelectorProfileEntry> > selector
ProfileData = TypeBuilder::Array<TypeBuilder::CSS::SelectorProfileEntry>::create
(); | |
| 244 for (RuleMatchingStatsMap::const_iterator it = m_ruleMatchingStats.begin();
it != m_ruleMatchingStats.end(); ++it) { | |
| 245 RefPtr<TypeBuilder::CSS::SelectorProfileEntry> entry = TypeBuilder::CSS:
:SelectorProfileEntry::create() | |
| 246 .setSelector(it->value.selector) | |
| 247 .setUrl(it->value.url) | |
| 248 .setLineNumber(it->value.lineNumber) | |
| 249 .setTime(it->value.totalTime) | |
| 250 .setHitCount(it->value.hits) | |
| 251 .setMatchCount(it->value.matches); | |
| 252 selectorProfileData->addItem(entry.release()); | |
| 253 } | |
| 254 | |
| 255 RefPtr<TypeBuilder::CSS::SelectorProfile> result = TypeBuilder::CSS::Selecto
rProfile::create() | |
| 256 .setTotalTime(totalMatchingTimeMs()) | |
| 257 .setData(selectorProfileData); | |
| 258 return result.release(); | |
| 259 } | |
| 260 | |
| 261 class UpdateRegionLayoutTask { | 140 class UpdateRegionLayoutTask { |
| 262 public: | 141 public: |
| 263 UpdateRegionLayoutTask(InspectorCSSAgent*); | 142 UpdateRegionLayoutTask(InspectorCSSAgent*); |
| 264 void scheduleFor(NamedFlow*, int documentNodeId); | 143 void scheduleFor(NamedFlow*, int documentNodeId); |
| 265 void unschedule(NamedFlow*); | 144 void unschedule(NamedFlow*); |
| 266 void reset(); | 145 void reset(); |
| 267 void onTimer(Timer<UpdateRegionLayoutTask>*); | 146 void onTimer(Timer<UpdateRegionLayoutTask>*); |
| 268 | 147 |
| 269 private: | 148 private: |
| 270 InspectorCSSAgent* m_cssAgent; | 149 InspectorCSSAgent* m_cssAgent; |
| (...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 858 { | 737 { |
| 859 ASSERT(!m_frontend); | 738 ASSERT(!m_frontend); |
| 860 m_frontend = frontend->css(); | 739 m_frontend = frontend->css(); |
| 861 } | 740 } |
| 862 | 741 |
| 863 void InspectorCSSAgent::clearFrontend() | 742 void InspectorCSSAgent::clearFrontend() |
| 864 { | 743 { |
| 865 ASSERT(m_frontend); | 744 ASSERT(m_frontend); |
| 866 m_frontend = 0; | 745 m_frontend = 0; |
| 867 resetNonPersistentData(); | 746 resetNonPersistentData(); |
| 868 stopSelectorProfilerImpl(0, false); | |
| 869 } | 747 } |
| 870 | 748 |
| 871 void InspectorCSSAgent::discardAgent() | 749 void InspectorCSSAgent::discardAgent() |
| 872 { | 750 { |
| 873 m_domAgent->setDOMListener(0); | 751 m_domAgent->setDOMListener(0); |
| 874 m_domAgent = 0; | 752 m_domAgent = 0; |
| 875 } | 753 } |
| 876 | 754 |
| 877 void InspectorCSSAgent::restore() | 755 void InspectorCSSAgent::restore() |
| 878 { | 756 { |
| 879 if (m_state->getBoolean(CSSAgentState::cssAgentEnabled)) { | 757 if (m_state->getBoolean(CSSAgentState::cssAgentEnabled)) { |
| 880 ErrorString error; | 758 ErrorString error; |
| 881 enable(&error); | 759 enable(&error); |
| 882 } | 760 } |
| 883 if (m_state->getBoolean(CSSAgentState::isSelectorProfiling)) { | |
| 884 String errorString; | |
| 885 startSelectorProfiler(&errorString); | |
| 886 } | |
| 887 } | 761 } |
| 888 | 762 |
| 889 void InspectorCSSAgent::reset() | 763 void InspectorCSSAgent::reset() |
| 890 { | 764 { |
| 891 m_idToInspectorStyleSheet.clear(); | 765 m_idToInspectorStyleSheet.clear(); |
| 892 m_cssStyleSheetToInspectorStyleSheet.clear(); | 766 m_cssStyleSheetToInspectorStyleSheet.clear(); |
| 893 m_nodeToInspectorStyleSheet.clear(); | 767 m_nodeToInspectorStyleSheet.clear(); |
| 894 m_documentToInspectorStyleSheet.clear(); | 768 m_documentToInspectorStyleSheet.clear(); |
| 895 resetNonPersistentData(); | 769 resetNonPersistentData(); |
| 896 } | 770 } |
| (...skipping 568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1465 parentRule = styleSheet->ownerRule(); | 1339 parentRule = styleSheet->ownerRule(); |
| 1466 if (parentRule) | 1340 if (parentRule) |
| 1467 break; | 1341 break; |
| 1468 styleSheet = styleSheet->parentStyleSheet(); | 1342 styleSheet = styleSheet->parentStyleSheet(); |
| 1469 } | 1343 } |
| 1470 } | 1344 } |
| 1471 } | 1345 } |
| 1472 return hasItems ? mediaArray : 0; | 1346 return hasItems ? mediaArray : 0; |
| 1473 } | 1347 } |
| 1474 | 1348 |
| 1475 void InspectorCSSAgent::startSelectorProfiler(ErrorString*) | |
| 1476 { | |
| 1477 m_currentSelectorProfile = adoptPtr(new SelectorProfile()); | |
| 1478 m_state->setBoolean(CSSAgentState::isSelectorProfiling, true); | |
| 1479 } | |
| 1480 | |
| 1481 void InspectorCSSAgent::stopSelectorProfiler(ErrorString* errorString, RefPtr<Ty
peBuilder::CSS::SelectorProfile>& result) | |
| 1482 { | |
| 1483 result = stopSelectorProfilerImpl(errorString, true); | |
| 1484 } | |
| 1485 | |
| 1486 PassRefPtr<TypeBuilder::CSS::SelectorProfile> InspectorCSSAgent::stopSelectorPro
filerImpl(ErrorString*, bool needProfile) | |
| 1487 { | |
| 1488 if (!m_state->getBoolean(CSSAgentState::isSelectorProfiling)) | |
| 1489 return 0; | |
| 1490 m_state->setBoolean(CSSAgentState::isSelectorProfiling, false); | |
| 1491 RefPtr<TypeBuilder::CSS::SelectorProfile> result; | |
| 1492 if (m_frontend && needProfile) | |
| 1493 result = m_currentSelectorProfile->toInspectorObject(); | |
| 1494 m_currentSelectorProfile.clear(); | |
| 1495 return result.release(); | |
| 1496 } | |
| 1497 | |
| 1498 void InspectorCSSAgent::willMatchRule(StyleRule* rule, InspectorCSSOMWrappers& i
nspectorCSSOMWrappers, DocumentStyleSheetCollection* styleSheetCollection) | |
| 1499 { | |
| 1500 if (m_currentSelectorProfile) | |
| 1501 m_currentSelectorProfile->startSelector(inspectorCSSOMWrappers.getWrappe
rForRuleInSheets(rule, styleSheetCollection)); | |
| 1502 } | |
| 1503 | |
| 1504 void InspectorCSSAgent::didMatchRule(bool matched) | |
| 1505 { | |
| 1506 if (m_currentSelectorProfile) | |
| 1507 m_currentSelectorProfile->commitSelector(matched); | |
| 1508 } | |
| 1509 | |
| 1510 void InspectorCSSAgent::willProcessRule(StyleRule* rule, StyleResolver* styleRes
olver) | |
| 1511 { | |
| 1512 if (m_currentSelectorProfile) | |
| 1513 m_currentSelectorProfile->startSelector(styleResolver->inspectorCSSOMWra
ppers().getWrapperForRuleInSheets(rule, styleResolver->document()->styleSheetCol
lection())); | |
| 1514 } | |
| 1515 | |
| 1516 void InspectorCSSAgent::didProcessRule() | |
| 1517 { | |
| 1518 if (m_currentSelectorProfile) | |
| 1519 m_currentSelectorProfile->commitSelectorTime(); | |
| 1520 } | |
| 1521 | |
| 1522 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Elem
ent* element) | 1349 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Elem
ent* element) |
| 1523 { | 1350 { |
| 1524 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(el
ement); | 1351 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(el
ement); |
| 1525 if (it != m_nodeToInspectorStyleSheet.end()) | 1352 if (it != m_nodeToInspectorStyleSheet.end()) |
| 1526 return it->value.get(); | 1353 return it->value.get(); |
| 1527 | 1354 |
| 1528 CSSStyleDeclaration* style = element->isStyledElement() ? element->style() :
0; | 1355 CSSStyleDeclaration* style = element->isStyledElement() ? element->style() :
0; |
| 1529 if (!style) | 1356 if (!style) |
| 1530 return 0; | 1357 return 0; |
| 1531 | 1358 |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1878 documentsToChange.add(element->ownerDocument()); | 1705 documentsToChange.add(element->ownerDocument()); |
| 1879 } | 1706 } |
| 1880 | 1707 |
| 1881 m_nodeIdToForcedPseudoState.clear(); | 1708 m_nodeIdToForcedPseudoState.clear(); |
| 1882 for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = docu
mentsToChange.end(); it != end; ++it) | 1709 for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = docu
mentsToChange.end(); it != end; ++it) |
| 1883 (*it)->setNeedsStyleRecalc(); | 1710 (*it)->setNeedsStyleRecalc(); |
| 1884 } | 1711 } |
| 1885 | 1712 |
| 1886 } // namespace WebCore | 1713 } // namespace WebCore |
| 1887 | 1714 |
| OLD | NEW |