Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(714)

Side by Side Diff: Source/core/inspector/InspectorStyleSheet.cpp

Issue 441873010: DevTools: [SSP] Implement adding new rule in user stylesheet (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: minor changes Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2010, Google Inc. All rights reserved. 2 * Copyright (C) 2010, Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 setSourceData(result.release()); 422 setSourceData(result.release());
423 return hasSourceData(); 423 return hasSourceData();
424 } 424 }
425 425
426 void ParsedStyleSheet::setSourceData(PassOwnPtrWillBeRawPtr<RuleSourceDataList> sourceData) 426 void ParsedStyleSheet::setSourceData(PassOwnPtrWillBeRawPtr<RuleSourceDataList> sourceData)
427 { 427 {
428 if (!sourceData) { 428 if (!sourceData) {
429 m_sourceData.clear(); 429 m_sourceData.clear();
430 return; 430 return;
431 } 431 }
432
433 m_sourceData = adoptPtrWillBeNoop(new RuleSourceDataList()); 432 m_sourceData = adoptPtrWillBeNoop(new RuleSourceDataList());
434 433
435 // FIXME: This is a temporary solution to retain the original flat sourceDat a structure 434 // FIXME: This is a temporary solution to retain the original flat sourceDat a structure
436 // containing only style rules, even though BisonCSSParser now provides the full rule source data tree. 435 // containing only style rules, even though BisonCSSParser now provides the full rule source data tree.
437 // Normally, we should just assign m_sourceData = sourceData; 436 // Normally, we should just assign m_sourceData = sourceData;
438 flattenSourceData(sourceData.get()); 437 flattenSourceData(sourceData.get());
439 } 438 }
440 439
441 PassRefPtrWillBeRawPtr<blink::CSSRuleSourceData> ParsedStyleSheet::ruleSourceDat aAt(unsigned index) const 440 PassRefPtrWillBeRawPtr<blink::CSSRuleSourceData> ParsedStyleSheet::ruleSourceDat aAt(unsigned index) const
442 { 441 {
(...skipping 606 matching lines...) Expand 10 before | Expand all | Expand 10 after
1049 return false; 1048 return false;
1050 } 1049 }
1051 1050
1052 String sheetText = m_parsedStyleSheet->text(); 1051 String sheetText = m_parsedStyleSheet->text();
1053 sheetText.replace(sourceData->ruleHeaderRange.start, sourceData->ruleHeaderR ange.length(), selector); 1052 sheetText.replace(sourceData->ruleHeaderRange.start, sourceData->ruleHeaderR ange.length(), selector);
1054 updateText(sheetText); 1053 updateText(sheetText);
1055 fireStyleSheetChanged(); 1054 fireStyleSheetChanged();
1056 return true; 1055 return true;
1057 } 1056 }
1058 1057
1059 static bool checkStyleRuleSelector(Document* document, const String& selector) 1058 unsigned InspectorStyleSheet::ruleIndexBySourceRange(const CSSMediaRule* parentM ediaRule, const SourceRange& sourceRange)
1060 { 1059 {
1061 CSSSelectorList selectorList; 1060 unsigned index = 0;
1062 BisonCSSParser(parserContextForDocument(document)).parseSelector(selector, s electorList); 1061 for (size_t i = 0; i < m_flatRules.size(); ++i) {
1063 return selectorList.isValid(); 1062 RefPtrWillBeRawPtr<CSSRule> rule = m_flatRules.at(i);
1063 if (rule->parentRule() != parentMediaRule)
1064 continue;
1065 RefPtrWillBeRawPtr<CSSRuleSourceData> ruleSourceData = m_parsedStyleShee t->ruleSourceDataAt(i);
1066 if (ruleSourceData->ruleBodyRange.end < sourceRange.start)
1067 ++index;
1068 }
1069 return index;
1064 } 1070 }
1065 1071
1066 CSSStyleRule* InspectorStyleSheet::addRule(const String& selector, ExceptionStat e& exceptionState) 1072 CSSStyleRule* InspectorStyleSheet::insertCSSOMRuleInStyleSheet(const SourceRange & sourceRange, const String& ruleText, ExceptionState& exceptionState)
1067 { 1073 {
1068 if (!checkStyleRuleSelector(m_pageStyleSheet->ownerDocument(), selector)) { 1074 unsigned index = ruleIndexBySourceRange(nullptr, sourceRange);
1069 exceptionState.throwDOMException(SyntaxError, "The selector '" + selecto r + "' could not be added."); 1075 m_pageStyleSheet->insertRule(ruleText, index, exceptionState);
1076 CSSRule* rule = m_pageStyleSheet->item(index);
1077 CSSStyleRule* styleRule = InspectorCSSAgent::asCSSStyleRule(rule);
1078 if (!styleRule) {
1079 m_pageStyleSheet->deleteRule(index, ASSERT_NO_EXCEPTION);
1080 exceptionState.throwDOMException(SyntaxError, "The rule '" + ruleText + "' could not be added in style sheet.");
1081 return 0;
1082 }
1083 return styleRule;
1084 }
1085
1086 CSSStyleRule* InspectorStyleSheet::insertCSSOMRuleInMediaRule(CSSMediaRule* medi aRule, const SourceRange& sourceRange, const String& ruleText, ExceptionState& e xceptionState)
1087 {
1088 unsigned index = ruleIndexBySourceRange(mediaRule, sourceRange);
1089 mediaRule->insertRule(ruleText, index, exceptionState);
1090 CSSRule* rule = mediaRule->item(index);
1091 CSSStyleRule* styleRule = InspectorCSSAgent::asCSSStyleRule(rule);
1092 if (!styleRule) {
1093 mediaRule->deleteRule(index, ASSERT_NO_EXCEPTION);
1094 exceptionState.throwDOMException(SyntaxError, "The rule '" + ruleText + "' could not be added in media rule.");
1095 return 0;
1096 }
1097 return styleRule;
1098 }
1099
1100 CSSStyleRule* InspectorStyleSheet::insertCSSOMRuleBySourceRange(const SourceRang e& sourceRange, const String& ruleText, ExceptionState& exceptionState)
1101 {
1102 int containingRuleIndex = -1;
1103 unsigned containingRuleLength = 0;
1104 for (size_t i = 0; i < m_parsedStyleSheet->ruleCount(); ++i) {
1105 RefPtrWillBeRawPtr<CSSRuleSourceData> ruleSourceData = m_parsedStyleShee t->ruleSourceDataAt(i);
1106 if (ruleSourceData->ruleHeaderRange.start < sourceRange.start && sourceR ange.start < ruleSourceData->ruleBodyRange.start) {
1107 exceptionState.throwDOMException(NotFoundError, "Cannot insert rule inside rule selector.");
1108 return 0;
1109 }
1110 if (sourceRange.start < ruleSourceData->ruleBodyRange.start || ruleSourc eData->ruleBodyRange.end < sourceRange.start)
1111 continue;
1112 if (containingRuleIndex == -1 || containingRuleLength > ruleSourceData-> ruleBodyRange.length()) {
1113 containingRuleIndex = i;
1114 containingRuleLength = ruleSourceData->ruleBodyRange.length();
1115 }
1116 }
1117 if (containingRuleIndex == -1)
1118 return insertCSSOMRuleInStyleSheet(sourceRange, ruleText, exceptionState );
1119 RefPtrWillBeRawPtr<CSSRule> rule = m_flatRules.at(containingRuleIndex);
1120 if (rule->type() != CSSRule::MEDIA_RULE) {
1121 exceptionState.throwDOMException(NotFoundError, "Cannot insert rule in n on-media rule.");
1122 return 0;
1123 }
1124 return insertCSSOMRuleInMediaRule(toCSSMediaRule(rule.get()), sourceRange, r uleText, exceptionState);
1125 }
1126
1127 bool InspectorStyleSheet::verifyRuleText(const String& ruleText)
1128 {
1129 DEFINE_STATIC_LOCAL(String, bogusPropertyName, ("-webkit-boguz-propertee"));
1130 RefPtrWillBeRawPtr<MutableStylePropertySet> tempMutableStyle = MutableStyleP ropertySet::create();
1131 RuleSourceDataList sourceData;
1132 RefPtrWillBeRawPtr<StyleSheetContents> styleSheetContents = StyleSheetConten ts::create(strictCSSParserContext());
1133 String text = ruleText + " div { " + bogusPropertyName + ": none; }";
1134 StyleSheetHandler handler(text, ownerDocument(), styleSheetContents.get(), & sourceData);
1135 BisonCSSParser(parserContextForDocument(ownerDocument())).parseSheet(styleSh eetContents.get(), text, TextPosition::minimumPosition(), &handler);
1136 unsigned ruleCount = sourceData.size();
1137
1138 // Exactly two rules should be parsed.
1139 if (ruleCount != 2)
1140 return false;
1141
1142 // Added rule must be style rule.
1143 if (!sourceData.at(0)->styleSourceData)
1144 return false;
1145
1146 WillBeHeapVector<CSSPropertySourceData>& propertyData = sourceData.at(1)->st yleSourceData->propertyData;
1147 unsigned propertyCount = propertyData.size();
1148
1149 // Exactly one property should be in rule.
1150 if (propertyCount != 1)
1151 return false;
1152
1153 // Check for the property name.
1154 if (propertyData.at(0).name != bogusPropertyName)
1155 return false;
1156
1157 return true;
1158 }
1159
1160 CSSStyleRule* InspectorStyleSheet::addRule(const String& ruleText, const SourceR ange& location, ExceptionState& exceptionState)
1161 {
1162 if (!ensureParsedDataReady()) {
1163 exceptionState.throwDOMException(NotFoundError, "Cannot parse style shee t.");
1164 return 0;
1165 }
1166
1167 if (location.start != location.end) {
1168 exceptionState.throwDOMException(NotFoundError, "Source range must be co llapsed.");
1169 return 0;
1170 }
1171
1172 if (!verifyRuleText(ruleText)) {
1173 exceptionState.throwDOMException(SyntaxError, "Rule text is not valid.") ;
1070 return 0; 1174 return 0;
1071 } 1175 }
1072 1176
1073 String text; 1177 String text;
1074 bool success = getText(&text); 1178 bool success = getText(&text);
1075 if (!success) { 1179 if (!success) {
1076 exceptionState.throwDOMException(NotFoundError, "The selector '" + selec tor + "' could not be added."); 1180 exceptionState.throwDOMException(NotFoundError, "The rule '" + ruleText + "' could not be added.");
1077 return 0;
1078 }
1079 StringBuilder styleSheetText;
1080 styleSheetText.append(text);
1081
1082 m_pageStyleSheet->addRule(selector, "", exceptionState);
1083 if (exceptionState.hadException())
1084 return 0;
1085 ASSERT(m_pageStyleSheet->length());
1086 unsigned lastRuleIndex = m_pageStyleSheet->length() - 1;
1087 CSSRule* rule = m_pageStyleSheet->item(lastRuleIndex);
1088 ASSERT(rule);
1089
1090 CSSStyleRule* styleRule = InspectorCSSAgent::asCSSStyleRule(rule);
1091 if (!styleRule) {
1092 // What we just added has to be a CSSStyleRule - we cannot handle other types of rules yet.
1093 // If it is not a style rule, pretend we never touched the stylesheet.
1094 m_pageStyleSheet->deleteRule(lastRuleIndex, ASSERT_NO_EXCEPTION);
1095 exceptionState.throwDOMException(SyntaxError, "The selector '" + selecto r + "' could not be added.");
1096 return 0; 1181 return 0;
1097 } 1182 }
1098 1183
1099 if (!styleSheetText.isEmpty()) 1184 ensureFlatRules();
1100 styleSheetText.append('\n'); 1185 CSSStyleRule* styleRule = insertCSSOMRuleBySourceRange(location, ruleText, e xceptionState);
1186 if (exceptionState.hadException())
1187 return 0;
1101 1188
1102 styleSheetText.append(selector); 1189 text.insert(ruleText, location.start);
1103 styleSheetText.appendLiteral(" {}"); 1190
1104 m_parsedStyleSheet->setText(styleSheetText.toString()); 1191 m_parsedStyleSheet->setText(text);
1105 m_flatRules.clear(); 1192 m_flatRules.clear();
1106 1193
1107 fireStyleSheetChanged(); 1194 fireStyleSheetChanged();
1108
1109 return styleRule; 1195 return styleRule;
1110 } 1196 }
1111 1197
1112 bool InspectorStyleSheet::deleteRule(const InspectorCSSId& id, ExceptionState& e xceptionState) 1198 bool InspectorStyleSheet::deleteRule(const InspectorCSSId& id, const String& old Text, ExceptionState& exceptionState)
1113 { 1199 {
1114 RefPtrWillBeRawPtr<CSSStyleRule> rule = ruleForId(id); 1200 RefPtrWillBeRawPtr<CSSStyleRule> rule = ruleForId(id);
1115 if (!rule) { 1201 if (!rule) {
1116 exceptionState.throwDOMException(NotFoundError, "No style rule could be found for the provided ID."); 1202 exceptionState.throwDOMException(NotFoundError, "No style rule could be found for the provided ID.");
1117 return false; 1203 return false;
1118 } 1204 }
1119 CSSStyleSheet* styleSheet = rule->parentStyleSheet(); 1205 CSSStyleSheet* styleSheet = rule->parentStyleSheet();
1120 if (!styleSheet || !ensureParsedDataReady()) { 1206 if (!styleSheet || !ensureParsedDataReady()) {
1121 exceptionState.throwDOMException(NotFoundError, "No parent stylesheet co uld be found."); 1207 exceptionState.throwDOMException(NotFoundError, "No parent stylesheet co uld be found.");
1122 return false; 1208 return false;
1123 } 1209 }
1124 1210
1125 RefPtrWillBeRawPtr<CSSRuleSourceData> sourceData = ruleSourceDataAt(id.ordin al()); 1211 RefPtrWillBeRawPtr<CSSRuleSourceData> sourceData = ruleSourceDataAt(id.ordin al());
1126 if (!sourceData) { 1212 if (!sourceData) {
1127 exceptionState.throwDOMException(NotFoundError, "No style rule could be found for the provided ID."); 1213 exceptionState.throwDOMException(NotFoundError, "No style rule could be found for the provided ID.");
1128 return false; 1214 return false;
1129 } 1215 }
1130 1216
1131 styleSheet->deleteRule(id.ordinal(), exceptionState); 1217 CSSRule* parentRule = rule->parentRule();
1218 if (parentRule) {
1219 if (parentRule->type() != CSSRule::MEDIA_RULE) {
1220 exceptionState.throwDOMException(NotFoundError, "Cannot remove rule from non-media rule.");
1221 return false;
1222 }
1223 CSSMediaRule* parentMediaRule = toCSSMediaRule(parentRule);
1224 size_t index = -1;
1225 for (size_t i = 0; i < parentMediaRule->length(); ++i) {
1226 if (parentMediaRule->item(i) != rule)
1227 continue;
1228 index = i;
1229 break;
1230 }
1231 ASSERT(index != -1);
1232 parentMediaRule->deleteRule(index, exceptionState);
1233 } else {
1234 size_t index = -1;
1235 for (size_t i = 0; i < styleSheet->length(); ++i) {
1236 if (styleSheet->item(i) != rule)
1237 continue;
1238 index = i;
1239 break;
1240 }
1241 ASSERT(index != -1);
1242 styleSheet->deleteRule(index, exceptionState);
1243 }
1132 // |rule| MAY NOT be addressed after this line! 1244 // |rule| MAY NOT be addressed after this line!
1133 1245
1134 if (exceptionState.hadException()) 1246 if (exceptionState.hadException())
1135 return false; 1247 return false;
1136 1248
1137 String sheetText = m_parsedStyleSheet->text(); 1249 m_parsedStyleSheet->setText(oldText);
1138 sheetText.remove(sourceData->ruleHeaderRange.start, sourceData->ruleBodyRang e.end - sourceData->ruleHeaderRange.start + 1);
1139 m_parsedStyleSheet->setText(sheetText);
1140 m_flatRules.clear(); 1250 m_flatRules.clear();
1141 fireStyleSheetChanged(); 1251 fireStyleSheetChanged();
1142 return true; 1252 return true;
1143 } 1253 }
1144 1254
1145 void InspectorStyleSheet::updateText(const String& newText) 1255 void InspectorStyleSheet::updateText(const String& newText)
1146 { 1256 {
1147 Element* element = ownerStyleElement(); 1257 Element* element = ownerStyleElement();
1148 if (!element) 1258 if (!element)
1149 m_pageAgent->addEditedResourceContent(finalURL(), newText); 1259 m_pageAgent->addEditedResourceContent(finalURL(), newText);
(...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after
1715 void InspectorStyleSheetForInlineStyle::trace(Visitor* visitor) 1825 void InspectorStyleSheetForInlineStyle::trace(Visitor* visitor)
1716 { 1826 {
1717 visitor->trace(m_element); 1827 visitor->trace(m_element);
1718 visitor->trace(m_ruleSourceData); 1828 visitor->trace(m_ruleSourceData);
1719 visitor->trace(m_inspectorStyle); 1829 visitor->trace(m_inspectorStyle);
1720 InspectorStyleSheetBase::trace(visitor); 1830 InspectorStyleSheetBase::trace(visitor);
1721 } 1831 }
1722 1832
1723 } // namespace blink 1833 } // namespace blink
1724 1834
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698