OLD | NEW |
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 Loading... |
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 Loading... |
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 = 0; |
| 1225 while (index < parentMediaRule->length() && parentMediaRule->item(index)
!= rule) |
| 1226 ++index; |
| 1227 ASSERT(index < parentMediaRule->length()); |
| 1228 parentMediaRule->deleteRule(index, exceptionState); |
| 1229 } else { |
| 1230 size_t index = 0; |
| 1231 while (index < styleSheet->length() && styleSheet->item(index) != rule) |
| 1232 ++index; |
| 1233 ASSERT(index < styleSheet->length()); |
| 1234 styleSheet->deleteRule(index, exceptionState); |
| 1235 } |
1132 // |rule| MAY NOT be addressed after this line! | 1236 // |rule| MAY NOT be addressed after this line! |
1133 | 1237 |
1134 if (exceptionState.hadException()) | 1238 if (exceptionState.hadException()) |
1135 return false; | 1239 return false; |
1136 | 1240 |
1137 String sheetText = m_parsedStyleSheet->text(); | 1241 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(); | 1242 m_flatRules.clear(); |
1141 fireStyleSheetChanged(); | 1243 fireStyleSheetChanged(); |
1142 return true; | 1244 return true; |
1143 } | 1245 } |
1144 | 1246 |
1145 void InspectorStyleSheet::updateText(const String& newText) | 1247 void InspectorStyleSheet::updateText(const String& newText) |
1146 { | 1248 { |
1147 Element* element = ownerStyleElement(); | 1249 Element* element = ownerStyleElement(); |
1148 if (!element) | 1250 if (!element) |
1149 m_pageAgent->addEditedResourceContent(finalURL(), newText); | 1251 m_pageAgent->addEditedResourceContent(finalURL(), newText); |
(...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1715 void InspectorStyleSheetForInlineStyle::trace(Visitor* visitor) | 1817 void InspectorStyleSheetForInlineStyle::trace(Visitor* visitor) |
1716 { | 1818 { |
1717 visitor->trace(m_element); | 1819 visitor->trace(m_element); |
1718 visitor->trace(m_ruleSourceData); | 1820 visitor->trace(m_ruleSourceData); |
1719 visitor->trace(m_inspectorStyle); | 1821 visitor->trace(m_inspectorStyle); |
1720 InspectorStyleSheetBase::trace(visitor); | 1822 InspectorStyleSheetBase::trace(visitor); |
1721 } | 1823 } |
1722 | 1824 |
1723 } // namespace blink | 1825 } // namespace blink |
1724 | 1826 |
OLD | NEW |