| 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 |