OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 #include "core/inspector/LayoutEditor.h" | 6 #include "core/inspector/LayoutEditor.h" |
7 | 7 |
8 #include "core/css/CSSComputedStyleDeclaration.h" | 8 #include "core/css/CSSComputedStyleDeclaration.h" |
| 9 #include "core/css/CSSRuleList.h" |
9 #include "core/dom/NodeComputedStyle.h" | 10 #include "core/dom/NodeComputedStyle.h" |
| 11 #include "core/dom/StaticNodeList.h" |
10 #include "core/frame/FrameView.h" | 12 #include "core/frame/FrameView.h" |
11 #include "core/inspector/InspectorCSSAgent.h" | 13 #include "core/inspector/InspectorCSSAgent.h" |
12 #include "core/inspector/InspectorDOMAgent.h" | 14 #include "core/inspector/InspectorDOMAgent.h" |
13 #include "core/inspector/InspectorHighlight.h" | 15 #include "core/inspector/InspectorHighlight.h" |
14 #include "core/layout/LayoutBox.h" | 16 #include "core/layout/LayoutBox.h" |
15 #include "core/layout/LayoutInline.h" | 17 #include "core/layout/LayoutInline.h" |
16 #include "core/layout/LayoutObject.h" | 18 #include "core/layout/LayoutObject.h" |
17 #include "core/style/ComputedStyle.h" | 19 #include "core/style/ComputedStyle.h" |
18 #include "platform/JSONValues.h" | 20 #include "platform/JSONValues.h" |
19 | 21 |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 return number.left(number.length() - removeCount); | 134 return number.left(number.length() - removeCount); |
133 } | 135 } |
134 | 136 |
135 float toValidValue(CSSPropertyID propertyId, float newValue) | 137 float toValidValue(CSSPropertyID propertyId, float newValue) |
136 { | 138 { |
137 if (CSSPropertyPaddingBottom <= propertyId && propertyId <= CSSPropertyPaddi
ngTop) | 139 if (CSSPropertyPaddingBottom <= propertyId && propertyId <= CSSPropertyPaddi
ngTop) |
138 return newValue >= 0 ? newValue : 0; | 140 return newValue >= 0 ? newValue : 0; |
139 | 141 |
140 return newValue; | 142 return newValue; |
141 } | 143 } |
| 144 |
| 145 bool comparePairs(const std::pair<unsigned, CSSStyleRule*>& lhs, const std::pair
<unsigned, CSSStyleRule*>& rhs) |
| 146 { |
| 147 return lhs.first < rhs.first; |
| 148 } |
| 149 |
| 150 InspectorHighlightConfig affectedNodesHighlightConfig() |
| 151 { |
| 152 // TODO: find a better color |
| 153 InspectorHighlightConfig config; |
| 154 config.content = Color(95, 127, 162, 100); |
| 155 config.padding = Color(95, 127, 162, 100); |
| 156 config.margin = Color(95, 127, 162, 100); |
| 157 return config; |
| 158 } |
| 159 |
142 } // namespace | 160 } // namespace |
143 | 161 |
144 LayoutEditor::LayoutEditor(InspectorCSSAgent* cssAgent, InspectorDOMAgent* domAg
ent) | 162 LayoutEditor::LayoutEditor(InspectorCSSAgent* cssAgent, InspectorDOMAgent* domAg
ent) |
145 : m_element(nullptr) | 163 : m_element(nullptr) |
146 , m_cssAgent(cssAgent) | 164 , m_cssAgent(cssAgent) |
147 , m_domAgent(domAgent) | 165 , m_domAgent(domAgent) |
148 , m_changingProperty(CSSPropertyInvalid) | 166 , m_changingProperty(CSSPropertyInvalid) |
149 , m_propertyInitialValue(0) | 167 , m_propertyInitialValue(0) |
150 , m_isDirty(false) | 168 , m_isDirty(false) |
151 { | 169 { |
152 } | 170 } |
153 | 171 |
154 DEFINE_TRACE(LayoutEditor) | 172 DEFINE_TRACE(LayoutEditor) |
155 { | 173 { |
156 visitor->trace(m_element); | 174 visitor->trace(m_element); |
157 visitor->trace(m_cssAgent); | 175 visitor->trace(m_cssAgent); |
158 visitor->trace(m_domAgent); | 176 visitor->trace(m_domAgent); |
| 177 visitor->trace(m_matchedRules); |
159 } | 178 } |
160 | 179 |
161 void LayoutEditor::selectNode(Node* node) | 180 void LayoutEditor::selectNode(Node* node) |
162 { | 181 { |
163 Element* element = node && node->isElementNode() ? toElement(node) : nullptr
; | 182 Element* element = node && node->isElementNode() ? toElement(node) : nullptr
; |
164 if (element == m_element) | 183 if (element == m_element) |
165 return; | 184 return; |
166 | 185 |
167 ASSERT(!m_isDirty); | 186 ASSERT(!m_isDirty); |
168 m_element = element; | 187 m_element = element; |
169 m_changingProperty = CSSPropertyInvalid; | 188 m_changingProperty = CSSPropertyInvalid; |
170 m_propertyInitialValue = 0; | 189 m_propertyInitialValue = 0; |
171 | 190 initializeCSSRules(); |
172 } | 191 } |
173 | 192 |
174 PassRefPtr<JSONObject> LayoutEditor::buildJSONInfo() const | 193 PassRefPtr<JSONObject> LayoutEditor::buildJSONInfo() const |
175 { | 194 { |
176 if (!m_element) | 195 if (!m_element) |
177 return nullptr; | 196 return nullptr; |
178 | 197 |
179 FloatQuad content, padding, border, margin; | 198 FloatQuad content, padding, border, margin; |
180 InspectorHighlight::buildNodeQuads(m_element.get(), &content, &padding, &bor
der, &margin); | 199 InspectorHighlight::buildNodeQuads(m_element.get(), &content, &padding, &bor
der, &margin); |
181 FloatQuad orthogonals = orthogonalVectors(padding); | 200 FloatQuad orthogonals = orthogonalVectors(padding); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 PassRefPtr<JSONObject> LayoutEditor::createValueDescription(const String& proper
tyName) const | 235 PassRefPtr<JSONObject> LayoutEditor::createValueDescription(const String& proper
tyName) const |
217 { | 236 { |
218 RefPtrWillBeRawPtr<CSSPrimitiveValue> cssValue = getPropertyCSSValue(cssProp
ertyID(propertyName)); | 237 RefPtrWillBeRawPtr<CSSPrimitiveValue> cssValue = getPropertyCSSValue(cssProp
ertyID(propertyName)); |
219 if (cssValue && !(cssValue->isLength() || cssValue->isPercentage())) | 238 if (cssValue && !(cssValue->isLength() || cssValue->isPercentage())) |
220 return nullptr; | 239 return nullptr; |
221 | 240 |
222 RefPtr<JSONObject> object = JSONObject::create(); | 241 RefPtr<JSONObject> object = JSONObject::create(); |
223 object->setNumber("value", cssValue ? cssValue->getFloatValue() : 0); | 242 object->setNumber("value", cssValue ? cssValue->getFloatValue() : 0); |
224 CSSPrimitiveValue::UnitType unitType = cssValue ? cssValue->typeWithCalcReso
lved() : CSSPrimitiveValue::UnitType::Pixels; | 243 CSSPrimitiveValue::UnitType unitType = cssValue ? cssValue->typeWithCalcReso
lved() : CSSPrimitiveValue::UnitType::Pixels; |
225 object->setString("unit", CSSPrimitiveValue::unitTypeToString(unitType)); | 244 object->setString("unit", CSSPrimitiveValue::unitTypeToString(unitType)); |
226 // TODO: Support an editing of other popular units like: em, rem | |
227 object->setBoolean("mutable", isMutableUnitType(unitType)); | 245 object->setBoolean("mutable", isMutableUnitType(unitType)); |
228 return object.release(); | 246 return object.release(); |
229 } | 247 } |
230 | 248 |
231 void LayoutEditor::appendAnchorFor(JSONArray* anchors, const String& type, const
String& propertyName, const FloatPoint& position, const FloatPoint& orthogonalV
ector) const | 249 void LayoutEditor::appendAnchorFor(JSONArray* anchors, const String& type, const
String& propertyName, const FloatPoint& position, const FloatPoint& orthogonalV
ector) const |
232 { | 250 { |
233 RefPtr<JSONObject> description = createValueDescription(propertyName); | 251 RefPtr<JSONObject> description = createValueDescription(propertyName); |
234 if (description) | 252 if (description) |
235 anchors->pushObject(createAnchor(position, type, propertyName, orthogona
lVector, description.release())); | 253 anchors->pushObject(createAnchor(position, type, propertyName, orthogona
lVector, description.release())); |
236 } | 254 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 void LayoutEditor::clearSelection(bool commitChanges) | 307 void LayoutEditor::clearSelection(bool commitChanges) |
290 { | 308 { |
291 ErrorString errorString; | 309 ErrorString errorString; |
292 if (commitChanges) | 310 if (commitChanges) |
293 m_domAgent->markUndoableState(&errorString); | 311 m_domAgent->markUndoableState(&errorString); |
294 else if (m_isDirty) | 312 else if (m_isDirty) |
295 m_domAgent->undo(&errorString); | 313 m_domAgent->undo(&errorString); |
296 | 314 |
297 m_element.clear(); | 315 m_element.clear(); |
298 m_isDirty = false; | 316 m_isDirty = false; |
| 317 m_matchedRules.clear(); |
| 318 m_cachedSelectorsInfo.clear(); |
| 319 m_currentRuleIndex = -1; |
299 } | 320 } |
300 | 321 |
| 322 void LayoutEditor::initializeCSSRules() |
| 323 { |
| 324 if (!m_element) |
| 325 return; |
301 | 326 |
| 327 Document* ownerDocument = m_element->ownerDocument(); |
| 328 // A non-active document has no styles. |
| 329 if (!ownerDocument->isActive()) |
| 330 return; |
| 331 |
| 332 // Matched rules. |
| 333 StyleResolver& styleResolver = ownerDocument->ensureStyleResolver(); |
| 334 PseudoId elementPseudoId = m_element->pseudoId(); |
| 335 m_element->updateDistribution(); |
| 336 RefPtrWillBeRawPtr<CSSRuleList> matchedRules = styleResolver.pseudoCSSRulesF
orElement(m_element.get(), elementPseudoId, StyleResolver::AllCSSRules); |
| 337 if (!matchedRules) |
| 338 return; |
| 339 |
| 340 HashSet<CSSStyleRule*> uniqRulesSet; |
| 341 Vector<CSSStyleRule*> uniqRules; |
| 342 for (unsigned i = matchedRules->length(); i > 0; --i) { |
| 343 CSSRule* rule = matchedRules->item(i); |
| 344 if (!rule || rule->type() != CSSRule::STYLE_RULE || !rule->parentStyleSh
eet()) |
| 345 continue; |
| 346 |
| 347 CSSStyleRule* styleRule = toCSSStyleRule(rule); |
| 348 |
| 349 if (uniqRulesSet.contains(styleRule)) |
| 350 continue; |
| 351 uniqRulesSet.add(styleRule); |
| 352 uniqRules.append(styleRule); |
| 353 } |
| 354 Vector<std::pair<unsigned, CSSStyleRule*>> selectors; |
| 355 for (unsigned i = 0; i < uniqRules.size(); ++i) { |
| 356 TrackExceptionState exceptionState; |
| 357 RefPtrWillBeRawPtr<StaticElementList> elements = ownerDocument->querySel
ectorAll(AtomicString(uniqRules[i]->selectorText()), exceptionState); |
| 358 unsigned length = exceptionState.hadException() ? 0: elements->length(); |
| 359 selectors.append(std::make_pair(length, uniqRules[i])); |
| 360 } |
| 361 |
| 362 std::sort(selectors.begin(), selectors.end(), &comparePairs); |
| 363 for (size_t i = 0; i < selectors.size(); ++i) |
| 364 m_matchedRules.append(selectors[i].second); |
| 365 }; |
| 366 |
| 367 void LayoutEditor::nextSelector() |
| 368 { |
| 369 if (static_cast<size_t>(m_currentRuleIndex + 1) == m_matchedRules.size()) |
| 370 return; |
| 371 |
| 372 m_currentRuleIndex++; |
| 373 } |
| 374 |
| 375 void LayoutEditor::previousSelector() |
| 376 { |
| 377 if (m_currentRuleIndex == -1) |
| 378 return; |
| 379 |
| 380 m_currentRuleIndex--; |
| 381 } |
| 382 |
| 383 String LayoutEditor::currentSelectorInfo() |
| 384 { |
| 385 if (!m_element) |
| 386 return String(); |
| 387 |
| 388 if (m_cachedSelectorsInfo.contains(m_currentRuleIndex)) |
| 389 return m_cachedSelectorsInfo.get(m_currentRuleIndex); |
| 390 |
| 391 RefPtr<JSONObject> object = JSONObject::create(); |
| 392 String currentSelectorText = m_currentRuleIndex == -1 ? "inline style" : m_m
atchedRules[m_currentRuleIndex]->selectorText(); |
| 393 object->setString("selector", currentSelectorText); |
| 394 |
| 395 Document* ownerDocument = m_element->ownerDocument(); |
| 396 if (!ownerDocument->isActive() || m_currentRuleIndex == -1) |
| 397 return object->toJSONString(); |
| 398 |
| 399 TrackExceptionState exceptionState; |
| 400 RefPtrWillBeRawPtr<StaticElementList> elements = ownerDocument->querySelecto
rAll(AtomicString(m_matchedRules[m_currentRuleIndex]->selectorText()), exception
State); |
| 401 |
| 402 if (!elements || exceptionState.hadException()) |
| 403 return object->toJSONString(); |
| 404 |
| 405 RefPtr<JSONArray> highlights = JSONArray::create(); |
| 406 InspectorHighlightConfig config = affectedNodesHighlightConfig(); |
| 407 for (unsigned i = 0; i < elements->length(); ++i) { |
| 408 Element* element = elements->item(i); |
| 409 if (element == m_element) |
| 410 continue; |
| 411 |
| 412 InspectorHighlight highlight(element, config, false); |
| 413 highlights->pushObject(highlight.asJSONObject()); |
| 414 } |
| 415 |
| 416 object->setArray("nodes", highlights.release()); |
| 417 m_cachedSelectorsInfo.add(m_currentRuleIndex, object->toJSONString()); |
| 418 return m_cachedSelectorsInfo.get(m_currentRuleIndex); |
| 419 } |
302 | 420 |
303 } // namespace blink | 421 } // namespace blink |
OLD | NEW |