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

Unified Diff: Source/core/inspector/InspectorStyleSheet.cpp

Issue 1211813002: DevTools: allow injecting CSS rules without breaking styles sidebar. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 6 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/inspector/InspectorStyleSheet.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/inspector/InspectorStyleSheet.cpp
diff --git a/Source/core/inspector/InspectorStyleSheet.cpp b/Source/core/inspector/InspectorStyleSheet.cpp
index d1d6846bc12574d514f7f93b3ea205586584a20b..d88cac1afd07741ace2ee779ab1431be759dfaa6 100644
--- a/Source/core/inspector/InspectorStyleSheet.cpp
+++ b/Source/core/inspector/InspectorStyleSheet.cpp
@@ -29,6 +29,7 @@
#include "bindings/core/v8/ExceptionStatePlaceholder.h"
#include "bindings/core/v8/ScriptRegexp.h"
#include "core/CSSPropertyNames.h"
+#include "core/css/CSSImportRule.h"
#include "core/css/CSSKeyframesRule.h"
#include "core/css/CSSMediaRule.h"
#include "core/css/CSSRuleList.h"
@@ -335,10 +336,11 @@ void StyleSheetHandler::endMediaQuery()
bool verifyRuleText(Document* document, const String& ruleText)
{
DEFINE_STATIC_LOCAL(String, bogusPropertyName, ("-webkit-boguz-propertee"));
+ RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(strictCSSParserContext());
RuleSourceDataList sourceData;
String text = ruleText + " div { " + bogusPropertyName + ": none; }";
StyleSheetHandler handler(text, document, &sourceData);
- CSSParser::parseSheetForInspector(parserContextForDocument(document), text, handler);
+ CSSParser::parseSheetForInspector(parserContextForDocument(document), styleSheet.get(), text, handler);
unsigned ruleCount = sourceData.size();
// Exactly two rules should be parsed.
@@ -371,10 +373,11 @@ bool verifyStyleText(Document* document, const String& text)
bool verifySelectorText(Document* document, const String& selectorText)
{
DEFINE_STATIC_LOCAL(String, bogusPropertyName, ("-webkit-boguz-propertee"));
+ RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(strictCSSParserContext());
RuleSourceDataList sourceData;
String text = selectorText + " { " + bogusPropertyName + ": none; }";
StyleSheetHandler handler(text, document, &sourceData);
- CSSParser::parseSheetForInspector(parserContextForDocument(document), text, handler);
+ CSSParser::parseSheetForInspector(parserContextForDocument(document), styleSheet.get(), text, handler);
// Exactly one rule should be parsed.
unsigned ruleCount = sourceData.size();
@@ -397,10 +400,11 @@ bool verifySelectorText(Document* document, const String& selectorText)
bool verifyMediaText(Document* document, const String& mediaText)
{
DEFINE_STATIC_LOCAL(String, bogusPropertyName, ("-webkit-boguz-propertee"));
+ RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(strictCSSParserContext());
RuleSourceDataList sourceData;
String text = "@media " + mediaText + " { div { " + bogusPropertyName + ": none; } }";
StyleSheetHandler handler(text, document, &sourceData);
- CSSParser::parseSheetForInspector(parserContextForDocument(document), text, handler);
+ CSSParser::parseSheetForInspector(parserContextForDocument(document), styleSheet.get(), text, handler);
// Exactly one media rule should be parsed.
unsigned ruleCount = sourceData.size();
@@ -497,6 +501,104 @@ void collectFlatRules(RuleList ruleList, CSSRuleVector* result)
}
}
+typedef HashMap<unsigned, unsigned, WTF::IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> IndexMap;
+
+void diff(const Vector<String>& listA, const Vector<String>& listB, IndexMap* aToB, IndexMap* bToA)
+{
+ // Cut of common prefix.
+ size_t startOffset = 0;
+ while (startOffset < listA.size() && startOffset < listB.size()) {
+ if (listA.at(startOffset) != listB.at(startOffset))
+ break;
+ aToB->set(startOffset, startOffset);
+ bToA->set(startOffset, startOffset);
+ ++startOffset;
+ }
+
+ // Cut of common suffix.
+ size_t endOffset = 0;
+ while (endOffset < listA.size() - startOffset && endOffset < listB.size() - startOffset) {
+ size_t indexA = listA.size() - endOffset - 1;
+ size_t indexB = listB.size() - endOffset - 1;
+ if (listA.at(indexA) != listB.at(indexB))
+ break;
+ aToB->set(indexA, indexB);
+ bToA->set(indexB, indexA);
+ ++endOffset;
+ }
+
+ int n = listA.size() - startOffset - endOffset;
+ int m = listB.size() - startOffset - endOffset;
+
+ // If we mapped either of arrays, we have no more work to do.
+ if (n == 0 || m == 0)
+ return;
+
+ int** diff = new int*[n];
+ int** backtrack = new int*[n];
+ for (int i = 0; i < n; ++i) {
+ diff[i] = new int[m];
+ backtrack[i] = new int[m];
+ }
+
+ // Compute longest common subsequence of two cssom models.
+ for (int i = 0; i < n; ++i) {
+ for (int j = 0; j < m; ++j) {
+ int max = 0;
+ int track = 0;
+
+ if (i > 0 && diff[i - 1][j] > max) {
+ max = diff[i - 1][j];
+ track = 1;
+ }
+
+ if (j > 0 && diff[i][j - 1] > max) {
+ max = diff[i][j - 1];
+ track = 2;
+ }
+
+ if (listA.at(i + startOffset) == listB.at(j + startOffset)) {
+ int value = i > 0 && j > 0 ? diff[i - 1][j - 1] + 1 : 1;
+ if (value > max) {
+ max = value;
+ track = 3;
+ }
+ }
+
+ diff[i][j] = max;
+ backtrack[i][j] = track;
+ }
+ }
+
+ // Backtrack and add missing mapping.
+ int i = n - 1, j = m - 1;
+ while (i >= 0 && j >= 0 && backtrack[i][j]) {
+ switch (backtrack[i][j]) {
+ case 1:
+ i -= 1;
+ break;
+ case 2:
+ j -= 1;
+ break;
+ case 3:
+ aToB->set(i + startOffset, j + startOffset);
+ bToA->set(j + startOffset, i + startOffset);
+ i -= 1;
+ j -= 1;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ for (int i = 0; i < n; ++i) {
+ delete [] diff[i];
+ delete [] backtrack[i];
+ }
+ delete [] diff;
+ delete [] backtrack;
+}
+
} // namespace
namespace blink {
@@ -766,7 +868,7 @@ InspectorStyleSheet::InspectorStyleSheet(InspectorResourceAgent* resourceAgent,
success = resourceStyleSheetText(&text);
if (success)
innerSetText(text, false);
- collectFlatRules();
+ mapSourceDataToCSSOM();
}
InspectorStyleSheet::~InspectorStyleSheet()
@@ -819,7 +921,7 @@ bool InspectorStyleSheet::setText(const String& text, ExceptionState& exceptionS
onStyleSheetTextChanged();
m_pageStyleSheet->ownerDocument()->styleResolverChanged(FullStyleUpdate);
- collectFlatRules();
+ mapSourceDataToCSSOM();
return true;
}
@@ -836,7 +938,7 @@ RefPtrWillBeRawPtr<CSSStyleRule> InspectorStyleSheet::setRuleSelector(const Sour
return nullptr;
}
- RefPtrWillBeRawPtr<CSSRule> rule = ruleForSourceData(sourceData.get());
+ RefPtrWillBeRawPtr<CSSRule> rule = ruleForSourceData(sourceData);
if (!rule || !rule->parentStyleSheet() || rule->type() != CSSRule::STYLE_RULE) {
exceptionState.throwDOMException(NotFoundError, "Source range didn't match existing style source range");
return nullptr;
@@ -845,7 +947,8 @@ RefPtrWillBeRawPtr<CSSStyleRule> InspectorStyleSheet::setRuleSelector(const Sour
RefPtrWillBeRawPtr<CSSStyleRule> styleRule = InspectorCSSAgent::asCSSStyleRule(rule.get());
styleRule->setSelectorText(text);
- replaceText(sourceData->ruleHeaderRange, text, newRange, oldText);
+ if (!replaceText(sourceData->ruleHeaderRange, text, newRange, oldText))
+ mapSourceDataToCSSOM();
onStyleSheetTextChanged();
return styleRule;
@@ -864,7 +967,7 @@ RefPtrWillBeRawPtr<CSSStyleRule> InspectorStyleSheet::setStyleText(const SourceR
return nullptr;
}
- RefPtrWillBeRawPtr<CSSRule> rule = ruleForSourceData(sourceData.get());
+ RefPtrWillBeRawPtr<CSSRule> rule = ruleForSourceData(sourceData);
if (!rule || !rule->parentStyleSheet() || rule->type() != CSSRule::STYLE_RULE) {
exceptionState.throwDOMException(NotFoundError, "Source range didn't match existing style source range");
return nullptr;
@@ -873,7 +976,8 @@ RefPtrWillBeRawPtr<CSSStyleRule> InspectorStyleSheet::setStyleText(const SourceR
RefPtrWillBeRawPtr<CSSStyleRule> styleRule = InspectorCSSAgent::asCSSStyleRule(rule.get());
styleRule->style()->setCSSText(text, exceptionState);
- replaceText(sourceData->ruleBodyRange, text, newRange, oldText);
+ if (!replaceText(sourceData->ruleBodyRange, text, newRange, oldText))
+ mapSourceDataToCSSOM();
onStyleSheetTextChanged();
return styleRule;
@@ -892,7 +996,7 @@ RefPtrWillBeRawPtr<CSSMediaRule> InspectorStyleSheet::setMediaRuleText(const Sou
return nullptr;
}
- RefPtrWillBeRawPtr<CSSRule> rule = ruleForSourceData(sourceData.get());
+ RefPtrWillBeRawPtr<CSSRule> rule = ruleForSourceData(sourceData);
if (!rule || !rule->parentStyleSheet() || rule->type() != CSSRule::MEDIA_RULE) {
exceptionState.throwDOMException(NotFoundError, "Source range didn't match existing style source range");
return nullptr;
@@ -901,7 +1005,9 @@ RefPtrWillBeRawPtr<CSSMediaRule> InspectorStyleSheet::setMediaRuleText(const Sou
RefPtrWillBeRawPtr<CSSMediaRule> mediaRule = InspectorCSSAgent::asCSSMediaRule(rule.get());
mediaRule->media()->setMediaText(text);
- replaceText(sourceData->ruleHeaderRange, text, newRange, oldText);
+ if (!replaceText(sourceData->ruleHeaderRange, text, newRange, oldText))
+ mapSourceDataToCSSOM();
+
onStyleSheetTextChanged();
return mediaRule;
@@ -977,12 +1083,12 @@ CSSStyleRule* InspectorStyleSheet::insertCSSOMRuleBySourceRange(const SourceRang
}
RefPtrWillBeRawPtr<CSSRuleSourceData> insertBefore = ruleAfterSourceRange(sourceRange);
- RefPtrWillBeRawPtr<CSSRule> insertBeforeRule = ruleForSourceData(insertBefore.get());
+ RefPtrWillBeRawPtr<CSSRule> insertBeforeRule = ruleForSourceData(insertBefore);
if (!containingRuleSourceData)
return insertCSSOMRuleInStyleSheet(insertBeforeRule.get(), ruleText, exceptionState);
- RefPtrWillBeRawPtr<CSSRule> rule = ruleForSourceData(containingRuleSourceData.get());
+ RefPtrWillBeRawPtr<CSSRule> rule = ruleForSourceData(containingRuleSourceData);
if (!rule || rule->type() != CSSRule::MEDIA_RULE) {
exceptionState.throwDOMException(NotFoundError, "Cannot insert rule in non-media rule.");
return nullptr;
@@ -1013,7 +1119,7 @@ RefPtrWillBeRawPtr<CSSStyleRule> InspectorStyleSheet::addRule(const String& rule
return nullptr;
replaceText(location, ruleText, addedRange, nullptr);
- collectFlatRules();
+ mapSourceDataToCSSOM();
onStyleSheetTextChanged();
return styleRule;
@@ -1043,7 +1149,7 @@ bool InspectorStyleSheet::deleteRule(const SourceRange& range, ExceptionState& e
if (!foundData || foundData->ruleBodyRange.length() > ruleSourceData->ruleBodyRange.length())
foundData = ruleSourceData;
}
- RefPtrWillBeRawPtr<CSSRule> rule = ruleForSourceData(foundData.get());
+ RefPtrWillBeRawPtr<CSSRule> rule = ruleForSourceData(foundData);
if (!rule) {
exceptionState.throwDOMException(NotFoundError, "No style rule could be found in given range.");
return false;
@@ -1078,13 +1184,13 @@ bool InspectorStyleSheet::deleteRule(const SourceRange& range, ExceptionState& e
return false;
replaceText(range, "", nullptr, nullptr);
- collectFlatRules();
+ mapSourceDataToCSSOM();
onStyleSheetTextChanged();
return true;
}
-void InspectorStyleSheet::replaceText(const SourceRange& range, const String& text, SourceRange* newRange, String* oldText)
+bool InspectorStyleSheet::replaceText(const SourceRange& range, const String& text, SourceRange* newRange, String* oldText)
{
String sheetText = m_text;
if (oldText)
@@ -1092,14 +1198,21 @@ void InspectorStyleSheet::replaceText(const SourceRange& range, const String& te
sheetText.replace(range.start, range.length(), text);
if (newRange)
*newRange = SourceRange(range.start, range.start + text.length());
- innerSetText(sheetText, true);
+ return innerSetText(sheetText, true);
}
-void InspectorStyleSheet::innerSetText(const String& text, bool markAsLocallyModified)
+bool InspectorStyleSheet::innerSetText(const String& text, bool markAsLocallyModified)
{
+ unsigned sizeBefore = m_sourceData ? m_sourceData->size() : 0;
+
OwnPtrWillBeRawPtr<RuleSourceDataList> ruleTree = adoptPtrWillBeNoop(new RuleSourceDataList());
+ RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(m_pageStyleSheet->contents()->parserContext());
StyleSheetHandler handler(text, m_pageStyleSheet->ownerDocument(), ruleTree.get());
- CSSParser::parseSheetForInspector(parserContextForDocument(m_pageStyleSheet->ownerDocument()), text, handler);
+ CSSParser::parseSheetForInspector(m_pageStyleSheet->contents()->parserContext(), styleSheet.get(), text, handler);
+ if (toCSSImportRule(m_pageStyleSheet->ownerRule()))
+ m_sourceDataSheet = CSSStyleSheet::create(styleSheet, toCSSImportRule(m_pageStyleSheet->ownerRule()));
+ else
+ m_sourceDataSheet = CSSStyleSheet::create(styleSheet, m_pageStyleSheet->ownerNode());
m_sourceData = adoptPtrWillBeNoop(new RuleSourceDataList());
flattenSourceData(ruleTree.get(), m_sourceData.get());
m_text = text;
@@ -1111,6 +1224,7 @@ void InspectorStyleSheet::innerSetText(const String& text, bool markAsLocallyMod
else
m_cssAgent->addEditedStyleSheet(finalURL(), text);
}
+ return sizeBefore == m_sourceData->size();
}
PassRefPtr<TypeBuilder::CSS::CSSStyleSheetHeader> InspectorStyleSheet::buildObjectForStyleSheetInfo()
@@ -1358,30 +1472,57 @@ RefPtrWillBeRawPtr<CSSRuleSourceData> InspectorStyleSheet::findRuleByBodyRange(c
return nullptr;
}
-RefPtrWillBeRawPtr<CSSRule> InspectorStyleSheet::ruleForSourceData(CSSRuleSourceData* sourceData)
+RefPtrWillBeRawPtr<CSSRule> InspectorStyleSheet::ruleForSourceData(RefPtrWillBeRawPtr<CSSRuleSourceData> sourceData)
{
if (!m_sourceData || !sourceData)
return nullptr;
- for (size_t i = 0; i < m_sourceData->size(); ++i) {
- if (m_sourceData->at(i).get() == sourceData)
- return i < m_flatRules.size() ? m_flatRules.at(i) : nullptr;
- }
- return nullptr;
+ size_t index = m_sourceData->find(sourceData.get());
+ if (index == kNotFound)
+ return nullptr;
+ IndexMap::iterator it = m_sourceDataToRule.find(index);
+ if (it == m_sourceDataToRule.end())
+ return nullptr;
+ ASSERT(it->value < m_flatRules.size());
+ return m_flatRules.at(it->value);
lushnikov 2015/06/25 15:44:12 i think you want to re-calc the mapping if you don
}
-RefPtrWillBeRawPtr<CSSRuleSourceData> InspectorStyleSheet::sourceDataForRule(CSSRule* rule)
+RefPtrWillBeRawPtr<CSSRuleSourceData> InspectorStyleSheet::sourceDataForRule(RefPtrWillBeRawPtr<CSSRule> rule)
{
if (!m_sourceData || !rule)
return nullptr;
-
- size_t index = m_flatRules.find(rule);
- return index < m_sourceData->size() ? m_sourceData->at(index) : nullptr;
+ size_t index = m_flatRules.find(rule.get());
+ if (index == kNotFound)
+ return nullptr;
+ IndexMap::iterator it = m_ruleToSourceData.find(index);
+ if (it == m_ruleToSourceData.end())
+ return nullptr;
+ ASSERT(it->value < m_sourceData->size());
+ return m_sourceData->at(it->value);
lushnikov 2015/06/25 15:44:12 ditto
}
-void InspectorStyleSheet::collectFlatRules()
+void InspectorStyleSheet::mapSourceDataToCSSOM()
{
+ m_ruleToSourceData.clear();
+ m_sourceDataToRule.clear();
+
m_flatRules.clear();
- ::collectFlatRules(m_pageStyleSheet.get(), &m_flatRules);
+ CSSRuleVector& cssomRules = m_flatRules;
+ collectFlatRules(m_pageStyleSheet.get(), &cssomRules);
+
+ if (!m_sourceData)
+ return;
+
+ CSSRuleVector parsedRules;
+ collectFlatRules(m_sourceDataSheet.get(), &parsedRules);
+
+ Vector<String> cssomRulesText = Vector<String>();
+ Vector<String> parsedRulesText = Vector<String>();
+ for (size_t i = 0; i < cssomRules.size(); ++i)
+ cssomRulesText.append(cssomRules.at(i)->cssText());
+ for (size_t j = 0; j < parsedRules.size(); ++j)
+ parsedRulesText.append(parsedRules.at(j)->cssText());
+
+ diff(cssomRulesText, parsedRulesText, &m_ruleToSourceData, &m_sourceDataToRule);
}
const CSSRuleVector& InspectorStyleSheet::flatRules()
« no previous file with comments | « Source/core/inspector/InspectorStyleSheet.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698