OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (C) 2013 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 are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 #include "config.h" | |
32 #include "core/dom/CSSSelectorWatch.h" | |
33 | |
34 #include "core/css/CSSParser.h" | |
35 #include "core/css/CSSSelectorList.h" | |
36 #include "core/css/StylePropertySet.h" | |
37 #include "core/dom/Document.h" | |
38 #include "core/dom/ScriptExecutionContext.h" | |
39 #include "core/loader/FrameLoaderClient.h" | |
40 #include "core/page/Frame.h" | |
41 #include "core/rendering/style/StyleRareNonInheritedData.h" | |
42 | |
43 namespace WebCore { | |
44 | |
45 // The address of this string is important; its value is just documentation. | |
46 static const char kSupplementName[] = "CSSSelectorWatch"; | |
47 | |
48 CSSSelectorWatch::CSSSelectorWatch(Document* document) | |
49 : m_document(document) | |
50 , m_callbackSelectorChangeTimer(this, &CSSSelectorWatch::callbackSelectorCha ngeTimerFired) | |
51 , m_timerExpirations(0) | |
52 { | |
53 } | |
54 | |
55 CSSSelectorWatch* CSSSelectorWatch::from(Document* document) | |
56 { | |
57 CSSSelectorWatch* watch = static_cast<CSSSelectorWatch*>(Supplement<ScriptEx ecutionContext>::from(document, kSupplementName)); | |
58 if (!watch) { | |
59 watch = new CSSSelectorWatch(document); | |
60 Supplement<ScriptExecutionContext>::provideTo(document, kSupplementName, adoptPtr(watch)); | |
61 } | |
62 return watch; | |
63 } | |
64 | |
65 void CSSSelectorWatch::restartTimer() | |
66 { | |
67 if (m_callbackSelectorChangeTimer.isActive()) | |
68 m_timerExpirations = 0; | |
69 else | |
70 m_callbackSelectorChangeTimer.startOneShot(0); | |
71 } | |
72 | |
73 void CSSSelectorWatch::callbackSelectorChangeTimerFired(Timer<CSSSelectorWatch>* ) | |
74 { | |
75 if (m_addedSelectors.isEmpty() && m_removedSelectors.isEmpty()) { | |
76 m_timerExpirations = 0; | |
77 return; | |
78 } | |
79 if (m_timerExpirations < 1) { | |
80 m_timerExpirations++; | |
81 m_callbackSelectorChangeTimer.startOneShot(0); | |
82 return; | |
83 } | |
84 if (m_document->frame()) { | |
85 Vector<String> addedSelectors, removedSelectors; | |
esprehn
2013/09/04 06:08:28
We usually do one declaration per line.
Jeffrey Yasskin
2013/09/12 22:09:59
Ah, sure.
| |
86 copyToVector(m_addedSelectors, addedSelectors); | |
87 copyToVector(m_removedSelectors, removedSelectors); | |
88 m_document->frame()->loader()->client()->selectorMatchChanged(addedSelec tors, removedSelectors); | |
89 } | |
90 m_addedSelectors.clear(); | |
91 m_removedSelectors.clear(); | |
92 m_timerExpirations = 0; | |
93 } | |
94 | |
95 void CSSSelectorWatch::addSelectorMatches(const Vector<String>& selectors) | |
96 { | |
97 for (unsigned i = 0; i < selectors.size(); ++i) { | |
98 const String& selector = selectors[i]; | |
99 HashMap<String, int>::iterator count = m_matchingCallbackSelectors.find( selector); | |
100 if (count != m_matchingCallbackSelectors.end()) { | |
101 ++count->value; | |
102 continue; | |
103 } | |
104 restartTimer(); | |
105 | |
106 m_matchingCallbackSelectors.set(selector, 1); | |
107 if (m_removedSelectors.contains(selector)) | |
108 m_removedSelectors.remove(selector); | |
109 else | |
110 m_addedSelectors.add(selector); | |
111 } | |
112 } | |
113 | |
114 void CSSSelectorWatch::removeSelectorMatches(const Vector<String>& selectors) | |
115 { | |
116 for (unsigned i = 0; i < selectors.size(); ++i) { | |
117 const String& selector = selectors[i]; | |
118 HashMap<String, int>::iterator count = m_matchingCallbackSelectors.find( selector); | |
119 if (count == m_matchingCallbackSelectors.end()) | |
120 continue; | |
121 --count->value; | |
122 if (!count->value) { | |
123 restartTimer(); | |
124 | |
125 m_matchingCallbackSelectors.remove(count); | |
126 if (m_addedSelectors.contains(selector)) | |
127 m_addedSelectors.remove(selector); | |
128 else | |
129 m_removedSelectors.add(selector); | |
130 } | |
131 } | |
132 } | |
133 | |
134 static bool allCompound(const CSSSelectorList& selectorList) | |
135 { | |
136 for (const CSSSelector* selector = selectorList.first(); selector; selector = selectorList.next(selector)) { | |
137 if (!selector->isCompound()) | |
138 return false; | |
139 } | |
140 return true; | |
141 } | |
142 | |
143 void CSSSelectorWatch::watchCSSSelectors(const Vector<String>& selectors) | |
144 { | |
145 m_watchedCallbackSelectors.clear(); | |
146 CSSParserContext context(UASheetMode); | |
147 CSSParser parser(context); | |
148 | |
149 const CSSProperty callbackProperty(CSSPropertyInternalCallback, CSSPrimitive Value::createIdentifier(CSSValueInternalPresence)); | |
150 const RefPtr<StylePropertySet> callbackPropertySet = ImmutableStylePropertyS et::create(&callbackProperty, 1, UASheetMode); | |
151 | |
152 CSSSelectorList selectorList; | |
153 for (unsigned i = 0; i < selectors.size(); ++i) { | |
154 parser.parseSelector(selectors[i], selectorList); | |
155 if (!selectorList.isValid()) | |
156 continue; | |
157 | |
158 // Only accept Compound Selectors, since they're cheaper to match. | |
159 if (!allCompound(selectorList)) | |
160 continue; | |
161 | |
162 RefPtr<StyleRule> rule = StyleRule::create(); | |
163 rule->wrapperAdoptSelectorList(selectorList); | |
164 rule->setProperties(callbackPropertySet); | |
165 m_watchedCallbackSelectors.append(rule.release()); | |
166 } | |
167 m_document->styleResolverChanged(RecalcStyleDeferred); | |
esprehn
2013/09/04 06:08:28
You should really be calling m_document->modifiedS
Jeffrey Yasskin
2013/09/12 22:09:59
It turned out to be complicated to create an actua
| |
168 } | |
169 | |
170 } // namespace WebCore | |
OLD | NEW |