Index: third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp |
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp |
index 5aec74b02a33daba88c42957303e5647a7751414..0b3b7fba906bad22771334b34e3f17ba062c66eb 100644 |
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp |
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp |
@@ -313,6 +313,17 @@ public: |
} |
}; |
+class InspectorCSSAgent::StyleEditAction : public InspectorCSSAgent::StyleSheetAction { |
+ WTF_MAKE_NONCOPYABLE(StyleEditAction); |
+public: |
+ StyleEditAction(const String& name) |
+ : InspectorCSSAgent::StyleSheetAction(name) |
+ { |
+ } |
+ |
+ virtual PassRefPtr<protocol::TypeBuilder::CSS::CSSStyle> takeSerializedStyle() = 0; |
+}; |
+ |
class InspectorCSSAgent::SetStyleSheetTextAction final : public InspectorCSSAgent::StyleSheetAction { |
WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction); |
public: |
@@ -365,7 +376,92 @@ private: |
String m_oldText; |
}; |
-class InspectorCSSAgent::ModifyRuleAction final : public InspectorCSSAgent::StyleSheetAction { |
+int getMultipleStyleTextsActionId() |
+{ |
+ static int lastId = 0; |
+ return ++lastId; |
+} |
+ |
+class InspectorCSSAgent::SetMultipleStyleTextsAction final : public InspectorCSSAgent::StyleSheetAction { |
+ WTF_MAKE_NONCOPYABLE(SetMultipleStyleTextsAction); |
+public: |
+ SetMultipleStyleTextsAction(HeapVector<RefPtrWillBeMember<StyleEditAction>>& actions) |
+ : InspectorCSSAgent::StyleSheetAction("SetMultipleStyleTextsAction") |
+ , m_id(getMultipleStyleTextsActionId()) |
+ , m_actions(actions) |
+ { |
+ } |
+ |
+ bool perform(ExceptionState& exceptionState) override |
+ { |
+ return redo(exceptionState); |
+ } |
+ |
+ bool undo(ExceptionState& exceptionState) override |
+ { |
+ for (size_t i = 0; i < m_actions.size(); ++i) { |
+ RefPtrWillBeMember<StyleEditAction> action = m_actions.at(m_actions.size() - i - 1); |
+ bool success = action->undo(exceptionState); |
+ if (!success) { |
+ for (size_t j = i + 1; j < m_actions.size(); ++j) { |
+ RefPtrWillBeMember<StyleSheetAction> revert = m_actions.at(j); |
+ TrackExceptionState undoExceptionState; |
+ revert->redo(undoExceptionState); |
+ } |
+ return false; |
+ } |
+ } |
+ return true; |
+ } |
+ |
+ bool redo(ExceptionState& exceptionState) override |
+ { |
+ for (size_t i = 0; i < m_actions.size(); ++i) { |
+ RefPtrWillBeMember<StyleEditAction> action = m_actions.at(i); |
+ bool success = action->redo(exceptionState); |
+ if (!success) { |
+ for (size_t j = 0; j < i; ++j) { |
+ RefPtrWillBeMember<StyleSheetAction> revert = m_actions.at(i - j - 1); |
+ TrackExceptionState undoExceptionState; |
+ revert->undo(undoExceptionState); |
dgozman
2016/02/16 18:14:05
ASSERT undo was successful? Or propagate exception
lushnikov
2016/02/17 20:26:49
Done.
|
+ } |
+ return false; |
+ } |
+ } |
+ |
+ return true; |
+ } |
+ |
+ String mergeId() override |
+ { |
+ return String::format("SetStyleSheetText %d", m_id); |
+ } |
+ |
+ void merge(PassRefPtrWillBeRawPtr<Action> action) override |
+ { |
+ ASSERT_NOT_REACHED(); |
dgozman
2016/02/16 18:14:05
Why don't you support merge?
lushnikov
2016/02/17 20:26:49
In order to keep things simple ATM.
|
+ } |
+ |
+ PassRefPtr<protocol::TypeBuilder::Array<protocol::TypeBuilder::CSS::CSSStyle>> takeSerializedStyles() |
+ { |
+ RefPtr<protocol::TypeBuilder::Array<protocol::TypeBuilder::CSS::CSSStyle>> result = protocol::TypeBuilder::Array<protocol::TypeBuilder::CSS::CSSStyle>::create(); |
+ for (size_t i = 0; i < m_actions.size(); ++i) |
+ result->addItem(m_actions.at(i)->takeSerializedStyle()); |
+ return result; |
+ } |
+ |
+ DEFINE_INLINE_VIRTUAL_TRACE() |
+ { |
+ visitor->trace(m_actions); |
+ InspectorCSSAgent::StyleSheetAction::trace(visitor); |
+ } |
+ |
+private: |
+ int m_id; |
+ HeapVector<RefPtrWillBeMember<StyleEditAction>> m_actions; |
+}; |
+ |
+class InspectorCSSAgent::ModifyRuleAction final : public InspectorCSSAgent::StyleEditAction { |
WTF_MAKE_NONCOPYABLE(ModifyRuleAction); |
public: |
enum Type { |
@@ -376,7 +472,7 @@ public: |
}; |
ModifyRuleAction(Type type, InspectorStyleSheet* styleSheet, const SourceRange& range, const String& text) |
- : InspectorCSSAgent::StyleSheetAction("ModifyRuleAction") |
+ : InspectorCSSAgent::StyleEditAction("ModifyRuleAction") |
, m_styleSheet(styleSheet) |
, m_type(type) |
, m_newText(text) |
@@ -435,6 +531,15 @@ public: |
return result; |
} |
+ PassRefPtr<protocol::TypeBuilder::CSS::CSSStyle> takeSerializedStyle() override |
+ { |
+ if (m_type != SetStyleText) |
+ return nullptr; |
+ RefPtrWillBeRawPtr<CSSStyleRule> styleRule = asCSSStyleRule(m_cssRule.get()); |
+ m_cssRule = nullptr; |
+ return m_styleSheet->buildObjectForStyle(styleRule->style()); |
+ } |
+ |
DEFINE_INLINE_VIRTUAL_TRACE() |
{ |
visitor->trace(m_styleSheet); |
@@ -471,11 +576,11 @@ private: |
RefPtrWillBeMember<CSSRule> m_cssRule; |
}; |
-class InspectorCSSAgent::SetElementStyleAction final : public InspectorCSSAgent::StyleSheetAction { |
+class InspectorCSSAgent::SetElementStyleAction final : public InspectorCSSAgent::StyleEditAction { |
WTF_MAKE_NONCOPYABLE(SetElementStyleAction); |
public: |
SetElementStyleAction(InspectorStyleSheetForInlineStyle* styleSheet, const String& text) |
- : InspectorCSSAgent::StyleSheetAction("SetElementStyleAction") |
+ : InspectorCSSAgent::StyleEditAction("SetElementStyleAction") |
, m_styleSheet(styleSheet) |
, m_text(text) |
{ |
@@ -509,6 +614,11 @@ public: |
return String::format("SetElementStyleAction:%s", m_styleSheet->id().utf8().data()); |
} |
+ PassRefPtr<protocol::TypeBuilder::CSS::CSSStyle> takeSerializedStyle() override |
+ { |
+ return m_styleSheet->buildObjectForStyle(m_styleSheet->inlineStyle()); |
+ } |
+ |
void merge(PassRefPtrWillBeRawPtr<Action> action) override |
{ |
ASSERT(action->mergeId() == mergeId()); |
@@ -1211,15 +1321,89 @@ void InspectorCSSAgent::setStyleText(ErrorString* errorString, const String& sty |
*errorString = "Stylesheet not found"; |
return; |
} |
- SourceRange selectorRange; |
- if (!jsonRangeToSourceRange(errorString, inspectorStyleSheet, range, &selectorRange)) |
+ SourceRange styleRange; |
+ if (!jsonRangeToSourceRange(errorString, inspectorStyleSheet, range, &styleRange)) |
return; |
- CSSStyleDeclaration* style = setStyleText(errorString, inspectorStyleSheet, selectorRange, text); |
+ CSSStyleDeclaration* style = setStyleText(errorString, inspectorStyleSheet, styleRange, text); |
if (style) |
result = inspectorStyleSheet->buildObjectForStyle(style); |
} |
+bool InspectorCSSAgent::multipleStyleTextsToActions(ErrorString* errorString, const RefPtr<JSONArray>& styleSheetIds, const RefPtr<JSONArray>& ranges, const RefPtr<JSONArray>& texts, HeapVector<RefPtrWillBeMember<StyleEditAction>>& actions) |
dgozman
2016/02/16 18:14:05
HeapVector<...>* actions
lushnikov
2016/02/17 20:26:49
Done.
|
+{ |
+ size_t n = styleSheetIds->length(); |
+ if (ranges->length() != n || texts->length() != n) { |
+ *errorString = "Arrays should be of equal length"; |
+ return false; |
+ } |
+ if (n == 0) { |
+ *errorString = "Arrays should not be empty"; |
+ return false; |
+ } |
+ |
+ for (size_t i = 0; i < n; ++i) { |
+ RefPtr<JSONValue> styleSheetIdValue = styleSheetIds->get(i); |
+ String styleSheetId; |
+ bool success = styleSheetIdValue->asString(&styleSheetId); |
+ if (!success) { |
+ *errorString = "Could not parse styleSheetId"; |
+ return false; |
+ } |
+ InspectorStyleSheetBase* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId); |
+ if (!inspectorStyleSheet) { |
+ *errorString = "StyleSheet not found"; |
+ return false; |
+ } |
+ |
+ RefPtr<JSONValue> rangeValue = ranges->get(i); |
+ RefPtr<JSONObject> rangeObject = rangeValue->asObject(); |
+ if (!rangeObject) { |
+ *errorString = "Could not parse range object"; |
+ return false; |
+ } |
+ |
+ SourceRange range; |
+ if (!jsonRangeToSourceRange(errorString, inspectorStyleSheet, rangeObject, &range)) |
+ return false; |
+ |
+ RefPtr<JSONValue> textValue = texts->get(i); |
+ String text; |
+ success = textValue->asString(&text); |
+ if (!success) { |
+ *errorString = "Could not parse text"; |
+ return false; |
+ } |
+ |
+ if (inspectorStyleSheet->isInlineStyle()) { |
+ InspectorStyleSheetForInlineStyle* inlineStyleSheet = static_cast<InspectorStyleSheetForInlineStyle*>(inspectorStyleSheet); |
+ RefPtrWillBeRawPtr<SetElementStyleAction> action = adoptRefWillBeNoop(new SetElementStyleAction(inlineStyleSheet, text)); |
+ actions.append(action); |
+ } else { |
+ RefPtrWillBeRawPtr<ModifyRuleAction> action = adoptRefWillBeNoop(new ModifyRuleAction(ModifyRuleAction::SetStyleText, static_cast<InspectorStyleSheet*>(inspectorStyleSheet), range, text)); |
+ actions.append(action); |
+ } |
+ } |
+ return true; |
+} |
+ |
+void InspectorCSSAgent::setMultipleStyleTexts(ErrorString* errorString, const RefPtr<JSONArray>& styleSheetIds, const RefPtr<JSONArray>& ranges, const RefPtr<JSONArray>& texts, RefPtr<protocol::TypeBuilder::Array<protocol::TypeBuilder::CSS::CSSStyle>>& result) |
+{ |
+ FrontendOperationScope scope; |
+ HeapVector<RefPtrWillBeMember<StyleEditAction>> actions; |
+ if (!multipleStyleTextsToActions(errorString, styleSheetIds, ranges, texts, actions)) |
+ return; |
+ |
+ TrackExceptionState exceptionState; |
+ RefPtrWillBeRawPtr<SetMultipleStyleTextsAction> batchAction = adoptRefWillBeNoop(new SetMultipleStyleTextsAction(actions)); |
+ bool success = m_domAgent->history()->perform(batchAction, exceptionState); |
+ if (!success) { |
+ *errorString = InspectorDOMAgent::toErrorString(exceptionState); |
+ return; |
+ } |
+ result = batchAction->takeSerializedStyles(); |
+} |
+ |
CSSStyleDeclaration* InspectorCSSAgent::setStyleText(ErrorString* errorString, InspectorStyleSheetBase* inspectorStyleSheet, const SourceRange& range, const String& text) |
{ |
TrackExceptionState exceptionState; |