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/CSSImportRule.h" | 9 #include "core/css/CSSImportRule.h" |
10 #include "core/css/CSSMediaRule.h" | 10 #include "core/css/CSSMediaRule.h" |
11 #include "core/css/CSSRuleList.h" | 11 #include "core/css/CSSStyleRule.h" |
12 #include "core/css/MediaList.h" | 12 #include "core/css/MediaList.h" |
13 #include "core/dom/NodeComputedStyle.h" | 13 #include "core/dom/NodeComputedStyle.h" |
14 #include "core/dom/StaticNodeList.h" | 14 #include "core/dom/StaticNodeList.h" |
15 #include "core/frame/FrameView.h" | 15 #include "core/frame/FrameView.h" |
16 #include "core/inspector/InspectorCSSAgent.h" | 16 #include "core/inspector/InspectorCSSAgent.h" |
17 #include "core/inspector/InspectorDOMAgent.h" | 17 #include "core/inspector/InspectorDOMAgent.h" |
18 #include "core/inspector/InspectorHighlight.h" | 18 #include "core/inspector/InspectorHighlight.h" |
19 #include "core/layout/LayoutBox.h" | 19 #include "core/layout/LayoutBox.h" |
20 #include "core/layout/LayoutInline.h" | 20 #include "core/layout/LayoutInline.h" |
21 #include "core/layout/LayoutObject.h" | 21 #include "core/layout/LayoutObject.h" |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 } | 138 } |
139 | 139 |
140 float toValidValue(CSSPropertyID propertyId, float newValue) | 140 float toValidValue(CSSPropertyID propertyId, float newValue) |
141 { | 141 { |
142 if (CSSPropertyPaddingBottom <= propertyId && propertyId <= CSSPropertyPaddi
ngTop) | 142 if (CSSPropertyPaddingBottom <= propertyId && propertyId <= CSSPropertyPaddi
ngTop) |
143 return newValue >= 0 ? newValue : 0; | 143 return newValue >= 0 ? newValue : 0; |
144 | 144 |
145 return newValue; | 145 return newValue; |
146 } | 146 } |
147 | 147 |
148 bool comparePairs(const std::pair<unsigned, CSSStyleRule*>& lhs, const std::pair
<unsigned, CSSStyleRule*>& rhs) | |
149 { | |
150 return lhs.first < rhs.first; | |
151 } | |
152 | |
153 InspectorHighlightConfig affectedNodesHighlightConfig() | 148 InspectorHighlightConfig affectedNodesHighlightConfig() |
154 { | 149 { |
155 // TODO: find a better color | 150 // TODO: find a better color |
156 InspectorHighlightConfig config; | 151 InspectorHighlightConfig config; |
157 config.content = Color(95, 127, 162, 100); | 152 config.content = Color(95, 127, 162, 100); |
158 config.padding = Color(95, 127, 162, 100); | 153 config.padding = Color(95, 127, 162, 100); |
159 config.margin = Color(95, 127, 162, 100); | 154 config.margin = Color(95, 127, 162, 100); |
160 return config; | 155 return config; |
161 } | 156 } |
162 | 157 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 | 197 |
203 } // namespace | 198 } // namespace |
204 | 199 |
205 LayoutEditor::LayoutEditor(InspectorCSSAgent* cssAgent, InspectorDOMAgent* domAg
ent) | 200 LayoutEditor::LayoutEditor(InspectorCSSAgent* cssAgent, InspectorDOMAgent* domAg
ent) |
206 : m_element(nullptr) | 201 : m_element(nullptr) |
207 , m_cssAgent(cssAgent) | 202 , m_cssAgent(cssAgent) |
208 , m_domAgent(domAgent) | 203 , m_domAgent(domAgent) |
209 , m_changingProperty(CSSPropertyInvalid) | 204 , m_changingProperty(CSSPropertyInvalid) |
210 , m_propertyInitialValue(0) | 205 , m_propertyInitialValue(0) |
211 , m_isDirty(false) | 206 , m_isDirty(false) |
212 , m_currentRuleIndex(-1) | 207 , m_matchedRules(StaticCSSRuleList::create()) |
| 208 , m_currentRuleIndex(0) |
213 { | 209 { |
214 } | 210 } |
215 | 211 |
216 DEFINE_TRACE(LayoutEditor) | 212 DEFINE_TRACE(LayoutEditor) |
217 { | 213 { |
218 visitor->trace(m_element); | 214 visitor->trace(m_element); |
219 visitor->trace(m_cssAgent); | 215 visitor->trace(m_cssAgent); |
220 visitor->trace(m_domAgent); | 216 visitor->trace(m_domAgent); |
221 visitor->trace(m_matchedRules); | 217 visitor->trace(m_matchedRules); |
222 } | 218 } |
223 | 219 |
224 void LayoutEditor::selectNode(Node* node) | 220 void LayoutEditor::selectNode(Node* node) |
225 { | 221 { |
226 Element* element = node && node->isElementNode() ? toElement(node) : nullptr
; | 222 Element* element = node && node->isElementNode() ? toElement(node) : nullptr
; |
227 if (element == m_element) | 223 if (element == m_element) |
228 return; | 224 return; |
229 | 225 |
230 ASSERT(!m_isDirty); | 226 ASSERT(!m_isDirty); |
231 m_element = element; | 227 m_element = element; |
232 m_changingProperty = CSSPropertyInvalid; | 228 m_changingProperty = CSSPropertyInvalid; |
233 m_propertyInitialValue = 0; | 229 m_propertyInitialValue = 0; |
234 initializeCSSRules(); | 230 m_matchedRules = m_cssAgent->matchedRulesList(m_element.get()); |
| 231 m_currentRuleIndex = m_matchedRules->length(); |
235 } | 232 } |
236 | 233 |
237 PassRefPtr<JSONObject> LayoutEditor::buildJSONInfo() const | 234 PassRefPtr<JSONObject> LayoutEditor::buildJSONInfo() const |
238 { | 235 { |
239 if (!m_element) | 236 if (!m_element) |
240 return nullptr; | 237 return nullptr; |
241 | 238 |
242 FloatQuad content, padding, border, margin; | 239 FloatQuad content, padding, border, margin; |
243 InspectorHighlight::buildNodeQuads(m_element.get(), &content, &padding, &bor
der, &margin); | 240 InspectorHighlight::buildNodeQuads(m_element.get(), &content, &padding, &bor
der, &margin); |
244 FloatQuad orthogonals = orthogonalVectors(padding); | 241 FloatQuad orthogonals = orthogonalVectors(padding); |
(...skipping 13 matching lines...) Expand all Loading... |
258 appendAnchorFor(anchors.get(), "margin", "margin-right", marginHandles.p2(),
orthogonals.p2()); | 255 appendAnchorFor(anchors.get(), "margin", "margin-right", marginHandles.p2(),
orthogonals.p2()); |
259 appendAnchorFor(anchors.get(), "margin", "margin-bottom", marginHandles.p3()
, orthogonals.p3()); | 256 appendAnchorFor(anchors.get(), "margin", "margin-bottom", marginHandles.p3()
, orthogonals.p3()); |
260 appendAnchorFor(anchors.get(), "margin", "margin-left", marginHandles.p4(),
orthogonals.p4()); | 257 appendAnchorFor(anchors.get(), "margin", "margin-left", marginHandles.p4(),
orthogonals.p4()); |
261 | 258 |
262 object->setArray("anchors", anchors.release()); | 259 object->setArray("anchors", anchors.release()); |
263 return object.release(); | 260 return object.release(); |
264 } | 261 } |
265 | 262 |
266 RefPtrWillBeRawPtr<CSSPrimitiveValue> LayoutEditor::getPropertyCSSValue(CSSPrope
rtyID property) const | 263 RefPtrWillBeRawPtr<CSSPrimitiveValue> LayoutEditor::getPropertyCSSValue(CSSPrope
rtyID property) const |
267 { | 264 { |
268 RefPtrWillBeRawPtr<CSSStyleDeclaration> style = m_cssAgent->findEffectiveDec
laration(m_element.get(), property); | 265 RefPtrWillBeRawPtr<CSSStyleDeclaration> style = m_cssAgent->findEffectiveDec
laration(property, m_matchedRules.get(), m_element->style()); |
269 if (!style) | 266 if (!style) |
270 return nullptr; | 267 return nullptr; |
271 | 268 |
272 RefPtrWillBeRawPtr<CSSValue> cssValue = style->getPropertyCSSValueInternal(p
roperty); | 269 RefPtrWillBeRawPtr<CSSValue> cssValue = style->getPropertyCSSValueInternal(p
roperty); |
273 if (!cssValue || !cssValue->isPrimitiveValue()) | 270 if (!cssValue || !cssValue->isPrimitiveValue()) |
274 return nullptr; | 271 return nullptr; |
275 | 272 |
276 return toCSSPrimitiveValue(cssValue.get()); | 273 return toCSSPrimitiveValue(cssValue.get()); |
277 } | 274 } |
278 | 275 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 default: | 322 default: |
326 ASSERT_NOT_REACHED(); | 323 ASSERT_NOT_REACHED(); |
327 break; | 324 break; |
328 } | 325 } |
329 m_propertyInitialValue = cssValue ? cssValue->getFloatValue() : 0; | 326 m_propertyInitialValue = cssValue ? cssValue->getFloatValue() : 0; |
330 } | 327 } |
331 | 328 |
332 void LayoutEditor::overlayPropertyChanged(float cssDelta) | 329 void LayoutEditor::overlayPropertyChanged(float cssDelta) |
333 { | 330 { |
334 if (m_changingProperty && m_factor) { | 331 if (m_changingProperty && m_factor) { |
335 String errorString; | |
336 float newValue = toValidValue(m_changingProperty, cssDelta / m_factor +
m_propertyInitialValue); | 332 float newValue = toValidValue(m_changingProperty, cssDelta / m_factor +
m_propertyInitialValue); |
337 m_cssAgent->setCSSPropertyValue(&errorString, m_element.get(), m_changin
gProperty, truncateZeroes(String::format("%.2f", newValue)) + CSSPrimitiveValue:
:unitTypeToString(m_valueUnitType)); | 333 m_isDirty |= setCSSPropertyValueInCurrentRule(truncateZeroes(String::for
mat("%.2f", newValue)) + CSSPrimitiveValue::unitTypeToString(m_valueUnitType)); |
338 if (!errorString) | |
339 m_isDirty = true; | |
340 } | 334 } |
341 } | 335 } |
342 | 336 |
343 void LayoutEditor::overlayEndedPropertyChange() | 337 void LayoutEditor::overlayEndedPropertyChange() |
344 { | 338 { |
345 m_changingProperty = CSSPropertyInvalid; | 339 m_changingProperty = CSSPropertyInvalid; |
346 m_propertyInitialValue = 0; | 340 m_propertyInitialValue = 0; |
347 m_factor = 0; | 341 m_factor = 0; |
348 m_valueUnitType = CSSPrimitiveValue::UnitType::Unknown; | 342 m_valueUnitType = CSSPrimitiveValue::UnitType::Unknown; |
349 } | 343 } |
350 | 344 |
351 void LayoutEditor::clearSelection(bool commitChanges) | 345 void LayoutEditor::clearSelection(bool commitChanges) |
352 { | 346 { |
353 ErrorString errorString; | 347 ErrorString errorString; |
354 if (commitChanges) | 348 if (commitChanges) |
355 m_domAgent->markUndoableState(&errorString); | 349 m_domAgent->markUndoableState(&errorString); |
356 else if (m_isDirty) | 350 else if (m_isDirty) |
357 m_domAgent->undo(&errorString); | 351 m_domAgent->undo(&errorString); |
358 | 352 |
359 m_element.clear(); | 353 m_element.clear(); |
360 m_isDirty = false; | 354 m_isDirty = false; |
361 m_matchedRules.clear(); | 355 m_matchedRules = StaticCSSRuleList::create(); |
362 m_currentRuleIndex = -1; | 356 m_currentRuleIndex = 0; |
363 } | 357 } |
364 | 358 |
365 void LayoutEditor::initializeCSSRules() | 359 bool LayoutEditor::currentStyleIsInline() |
366 { | 360 { |
367 if (!m_element) | 361 return m_currentRuleIndex == m_matchedRules->length(); |
368 return; | 362 } |
369 | |
370 Document* ownerDocument = m_element->ownerDocument(); | |
371 // A non-active document has no styles. | |
372 if (!ownerDocument->isActive()) | |
373 return; | |
374 | |
375 // Matched rules. | |
376 StyleResolver& styleResolver = ownerDocument->ensureStyleResolver(); | |
377 PseudoId elementPseudoId = m_element->pseudoId(); | |
378 m_element->updateDistribution(); | |
379 RefPtrWillBeRawPtr<CSSRuleList> matchedRules = styleResolver.pseudoCSSRulesF
orElement(m_element.get(), elementPseudoId, StyleResolver::AllCSSRules); | |
380 if (!matchedRules) | |
381 return; | |
382 | |
383 HashSet<CSSStyleRule*> uniqRulesSet; | |
384 Vector<CSSStyleRule*> uniqRules; | |
385 for (unsigned i = matchedRules->length(); i > 0; --i) { | |
386 CSSRule* rule = matchedRules->item(i); | |
387 if (!rule || rule->type() != CSSRule::STYLE_RULE || !rule->parentStyleSh
eet()) | |
388 continue; | |
389 | |
390 CSSStyleRule* styleRule = toCSSStyleRule(rule); | |
391 | |
392 if (uniqRulesSet.contains(styleRule)) | |
393 continue; | |
394 uniqRulesSet.add(styleRule); | |
395 uniqRules.append(styleRule); | |
396 } | |
397 Vector<std::pair<unsigned, CSSStyleRule*>> selectors; | |
398 for (unsigned i = 0; i < uniqRules.size(); ++i) { | |
399 TrackExceptionState exceptionState; | |
400 RefPtrWillBeRawPtr<StaticElementList> elements = ownerDocument->querySel
ectorAll(AtomicString(uniqRules[i]->selectorText()), exceptionState); | |
401 unsigned length = exceptionState.hadException() ? 0: elements->length(); | |
402 selectors.append(std::make_pair(length, uniqRules[i])); | |
403 } | |
404 | |
405 std::sort(selectors.begin(), selectors.end(), &comparePairs); | |
406 for (size_t i = 0; i < selectors.size(); ++i) | |
407 m_matchedRules.append(selectors[i].second); | |
408 }; | |
409 | 363 |
410 void LayoutEditor::nextSelector() | 364 void LayoutEditor::nextSelector() |
411 { | 365 { |
412 if (static_cast<size_t>(m_currentRuleIndex + 1) == m_matchedRules.size()) | 366 if (m_currentRuleIndex == 0) |
| 367 return; |
| 368 |
| 369 m_currentRuleIndex--; |
| 370 } |
| 371 |
| 372 void LayoutEditor::previousSelector() |
| 373 { |
| 374 if (currentStyleIsInline()) |
413 return; | 375 return; |
414 | 376 |
415 m_currentRuleIndex++; | 377 m_currentRuleIndex++; |
416 } | 378 } |
417 | 379 |
418 void LayoutEditor::previousSelector() | |
419 { | |
420 if (m_currentRuleIndex == -1) | |
421 return; | |
422 | |
423 m_currentRuleIndex--; | |
424 } | |
425 | |
426 String LayoutEditor::currentSelectorInfo() | 380 String LayoutEditor::currentSelectorInfo() |
427 { | 381 { |
428 if (!m_element) | 382 if (!m_element) |
429 return String(); | 383 return String(); |
430 | 384 |
431 RefPtr<JSONObject> object = JSONObject::create(); | 385 RefPtr<JSONObject> object = JSONObject::create(); |
432 String currentSelectorText = m_currentRuleIndex == -1 ? "inline style" : m_m
atchedRules[m_currentRuleIndex]->selectorText(); | 386 String currentSelectorText = currentStyleIsInline() ? "inline style" : toCSS
StyleRule(m_matchedRules->item(m_currentRuleIndex))->selectorText(); |
433 object->setString("selector", currentSelectorText); | 387 object->setString("selector", currentSelectorText); |
434 | 388 |
435 Document* ownerDocument = m_element->ownerDocument(); | 389 Document* ownerDocument = m_element->ownerDocument(); |
436 if (!ownerDocument->isActive() || m_currentRuleIndex == -1) | 390 if (!ownerDocument->isActive() || currentStyleIsInline()) |
437 return object->toJSONString(); | 391 return object->toJSONString(); |
438 | 392 |
439 if (m_currentRuleIndex != -1) { | 393 bool hasSameSelectors = false; |
440 bool hasSameSelectors = false; | 394 for (unsigned i = 0; i < m_matchedRules->length(); i++) { |
441 for (size_t i = 0; i < m_matchedRules.size(); i++) { | 395 if (i != m_currentRuleIndex && toCSSStyleRule(m_matchedRules->item(i))->
selectorText() == currentSelectorText) { |
442 if (i != static_cast<unsigned>(m_currentRuleIndex) && m_matchedRules
[i]->selectorText() == currentSelectorText) { | 396 hasSameSelectors = true; |
443 hasSameSelectors = true; | 397 break; |
444 break; | |
445 } | |
446 } | |
447 | |
448 if (hasSameSelectors) { | |
449 Vector<String> medias; | |
450 buildMediaListChain(m_matchedRules[m_currentRuleIndex].get(), medias
); | |
451 RefPtr<JSONArray> mediasJSONArray = JSONArray::create(); | |
452 for (size_t i = 0; i < medias.size(); ++i) | |
453 mediasJSONArray->pushString(medias[i]); | |
454 | |
455 object->setArray("medias", mediasJSONArray.release()); | |
456 } | 398 } |
457 } | 399 } |
458 | 400 |
| 401 if (hasSameSelectors) { |
| 402 Vector<String> medias; |
| 403 buildMediaListChain(m_matchedRules->item(m_currentRuleIndex), medias); |
| 404 RefPtr<JSONArray> mediasJSONArray = JSONArray::create(); |
| 405 for (size_t i = 0; i < medias.size(); ++i) |
| 406 mediasJSONArray->pushString(medias[i]); |
| 407 |
| 408 object->setArray("medias", mediasJSONArray.release()); |
| 409 } |
| 410 |
459 TrackExceptionState exceptionState; | 411 TrackExceptionState exceptionState; |
460 RefPtrWillBeRawPtr<StaticElementList> elements = ownerDocument->querySelecto
rAll(AtomicString(m_matchedRules[m_currentRuleIndex]->selectorText()), exception
State); | 412 RefPtrWillBeRawPtr<StaticElementList> elements = ownerDocument->querySelecto
rAll(AtomicString(currentSelectorText), exceptionState); |
461 | 413 |
462 if (!elements || exceptionState.hadException()) | 414 if (!elements || exceptionState.hadException()) |
463 return object->toJSONString(); | 415 return object->toJSONString(); |
464 | 416 |
465 RefPtr<JSONArray> highlights = JSONArray::create(); | 417 RefPtr<JSONArray> highlights = JSONArray::create(); |
466 InspectorHighlightConfig config = affectedNodesHighlightConfig(); | 418 InspectorHighlightConfig config = affectedNodesHighlightConfig(); |
467 for (unsigned i = 0; i < elements->length(); ++i) { | 419 for (unsigned i = 0; i < elements->length(); ++i) { |
468 Element* element = elements->item(i); | 420 Element* element = elements->item(i); |
469 if (element == m_element) | 421 if (element == m_element) |
470 continue; | 422 continue; |
471 | 423 |
472 InspectorHighlight highlight(element, config, false); | 424 InspectorHighlight highlight(element, config, false); |
473 highlights->pushObject(highlight.asJSONObject()); | 425 highlights->pushObject(highlight.asJSONObject()); |
474 } | 426 } |
475 | 427 |
476 object->setArray("nodes", highlights.release()); | 428 object->setArray("nodes", highlights.release()); |
477 return object->toJSONString(); | 429 return object->toJSONString(); |
478 } | 430 } |
479 | 431 |
| 432 bool LayoutEditor::setCSSPropertyValueInCurrentRule(const String& value) |
| 433 { |
| 434 if (!m_element) |
| 435 return false; |
| 436 |
| 437 RefPtrWillBeRawPtr<CSSStyleDeclaration> effectiveDeclaration = m_cssAgent->f
indEffectiveDeclaration(m_changingProperty, m_matchedRules.get(), m_element->sty
le()); |
| 438 bool forceImportant = false; |
| 439 |
| 440 if (effectiveDeclaration) { |
| 441 CSSStyleRule* effectiveRule = nullptr; |
| 442 if (effectiveDeclaration->parentRule() && effectiveDeclaration->parentRu
le()->type() == CSSRule::STYLE_RULE) |
| 443 effectiveRule = toCSSStyleRule(effectiveDeclaration->parentRule()); |
| 444 |
| 445 unsigned effectiveRuleIndex = m_matchedRules->length(); |
| 446 for (unsigned i = 0; i < m_matchedRules->length(); ++i) { |
| 447 if (m_matchedRules->item(i) == effectiveRule) { |
| 448 effectiveRuleIndex = i; |
| 449 break; |
| 450 } |
| 451 } |
| 452 forceImportant = effectiveDeclaration->getPropertyPriority(getPropertyNa
meString(m_changingProperty)) == "important"; |
| 453 forceImportant |= effectiveRuleIndex > m_currentRuleIndex; |
| 454 } |
| 455 |
| 456 CSSStyleDeclaration* style = currentStyleIsInline() ? m_element->style() : t
oCSSStyleRule(m_matchedRules->item(m_currentRuleIndex))->style(); |
| 457 |
| 458 String errorString; |
| 459 m_cssAgent->setCSSPropertyValue(&errorString, m_element.get(), style, m_chan
gingProperty, value, forceImportant); |
| 460 return errorString.isEmpty(); |
| 461 } |
| 462 |
480 } // namespace blink | 463 } // namespace blink |
OLD | NEW |