+2015-04-20 Simon Fraser <simon.fraser@apple.com>
+
+ Setting inline style to the same value it already has triggers a style recalc
+ https://bugs.webkit.org/show_bug.cgi?id=143922
+
+ Reviewed by Antti Koivisto.
+
+ Test that changes inline-style (to test this bug fix), and classes (for
+ proactive testing) and counts style recalcs.
+
+ * fast/css/set-inline-style-recalc-expected.txt: Added.
+ * fast/css/set-inline-style-recalc.html: Added.
+
2015-04-20 Brady Eidson <beidson@apple.com>
Crash in StyleResolver::invalidateMatchedPropertiesCache() when using content extensions.
--- /dev/null
+Test to count the number of recalcStyle calls on inline style and class changes.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS numStyleRecalcs is 1
+PASS numStyleRecalcs is 1
+PASS numStyleRecalcs is 0
+PASS numStyleRecalcs is 1
+PASS numStyleRecalcs is 0
+PASS numStyleRecalcs is 1
+PASS numStyleRecalcs is 0
+PASS numStyleRecalcs is 1
+PASS numStyleRecalcs is 0
+PASS numStyleRecalcs is 1
+PASS numStyleRecalcs is 0
+PASS numStyleRecalcs is 1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+<style>
+ .test {
+ position: relative;
+ }
+
+ .foo {
+ font-size: 10px;
+ }
+
+ .bar {
+ }
+</style>
+</head>
+<body>
+<script>
+function setStyleAndForceLayout(changeFunc)
+{
+ if (window.internals) {
+ internals.updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks();
+ internals.startTrackingStyleRecalcs();
+ }
+
+ changeFunc();
+
+ var numStyleRecalcs = 0;
+ if (window.internals) {
+ internals.updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks();
+ numStyleRecalcs = internals.styleRecalcCount();
+ }
+ return numStyleRecalcs;
+}
+
+description("Test to count the number of recalcStyle calls on inline style and class changes.")
+
+var testContainer = document.createElement("div");
+testContainer.className = 'test';
+document.body.appendChild(testContainer);
+
+var style = testContainer.style;
+
+var numStyleRecalcs = setStyleAndForceLayout(function() { style.height = "10px"; });
+shouldBe("numStyleRecalcs", "1");
+numStyleRecalcs = setStyleAndForceLayout(function() { style.height = "20px"; });
+shouldBe("numStyleRecalcs", "1");
+numStyleRecalcs = setStyleAndForceLayout(function() { style.height = "20px"; });
+shouldBe("numStyleRecalcs", "0");
+
+numStyleRecalcs = setStyleAndForceLayout(function() { style.backgroundPosition = "10px 10%"; });
+shouldBe("numStyleRecalcs", "1");
+numStyleRecalcs = setStyleAndForceLayout(function() { style.backgroundPosition = "10px 10%"; });
+shouldBe("numStyleRecalcs", "0");
+
+numStyleRecalcs = setStyleAndForceLayout(function() { style.backgroundColor = "red"; });
+shouldBe("numStyleRecalcs", "1");
+numStyleRecalcs = setStyleAndForceLayout(function() { style.backgroundColor = "red"; });
+shouldBe("numStyleRecalcs", "0");
+
+numStyleRecalcs = setStyleAndForceLayout(function() { style.transform = "translate(10px, 10px) rotate(10deg)"; });
+shouldBe("numStyleRecalcs", "1");
+numStyleRecalcs = setStyleAndForceLayout(function() { style.transform = "translate(10px, 10px) rotate(10deg)"; });
+shouldBe("numStyleRecalcs", "0");
+
+numStyleRecalcs = setStyleAndForceLayout(function() { testContainer.classList.add('foo'); });
+shouldBe("numStyleRecalcs", "1");
+numStyleRecalcs = setStyleAndForceLayout(function() { testContainer.classList.add('foo'); });
+shouldBe("numStyleRecalcs", "0");
+numStyleRecalcs = setStyleAndForceLayout(function() { testContainer.classList.add('bar'); });
+shouldBe("numStyleRecalcs", "1");
+
+document.body.removeChild(testContainer);
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
+2015-04-20 Simon Fraser <simon.fraser@apple.com>
+
+ Setting inline style to the same value it already has triggers a style recalc
+ https://bugs.webkit.org/show_bug.cgi?id=143922
+
+ Reviewed by Antti Koivisto.
+
+ MutableStyleProperties::setProperty() was taking the result of CSSParser::parseValue()
+ to mean "parsing changed the style", but it actually just means "parsing succeeded".
+ Add a new out param, piped through various parser functions, to indicate whether
+ parsing actually changed style, and instead return that from setProperty().
+
+ Add internals.startTrackingStyleRecalcs() and internals.styleRecalcCount() so
+ we can write tests for style recalc.
+
+ Test: fast/css/set-inline-style-recalc.html
+
+ * WebCore.xcodeproj/project.pbxproj: Let Xcode have it's way.
+ * css/CSSParser.cpp:
+ (WebCore::parseColorValue):
+ (WebCore::parseSimpleLengthValue):
+ (WebCore::parseKeywordValue):
+ (WebCore::parseTranslateTransformValue):
+ (WebCore::CSSParser::parseFontFaceValue):
+ (WebCore::CSSParser::parseValue):
+ * css/CSSParser.h:
+ * css/CSSProperty.h:
+ (WebCore::StylePropertyMetadata::operator==):
+ (WebCore::CSSProperty::operator==):
+ * css/DOMWindowCSS.cpp:
+ (WebCore::DOMWindowCSS::supports):
+ * css/StyleProperties.cpp:
+ (WebCore::MutableStyleProperties::setProperty):
+ (WebCore::MutableStyleProperties::appendPrefixingVariantProperty):
+ (WebCore::MutableStyleProperties::addParsedProperties):
+ (WebCore::MutableStyleProperties::addParsedProperty):
+ * css/StyleProperties.h:
+ * css/WebKitCSSMatrix.cpp:
+ (WebCore::WebKitCSSMatrix::setMatrixValue):
+ * dom/Document.cpp:
+ (WebCore::Document::recalcStyle):
+ (WebCore::Document::startTrackingStyleRecalcs):
+ (WebCore::Document::styleRecalcCount):
+ * dom/Document.h:
+ * html/canvas/CanvasRenderingContext2D.cpp:
+ (WebCore::CanvasRenderingContext2D::setFont):
+ * testing/Internals.cpp:
+ (WebCore::Internals::startTrackingStyleRecalcs):
+ (WebCore::Internals::styleRecalcCount):
+ * testing/Internals.h:
+ * testing/Internals.idl:
+
2015-04-20 Brady Eidson <beidson@apple.com>
Crash in StyleResolver::invalidateMatchedPropertiesCache() when using content extensions.
BC74DA471013F468007987AD /* JSRGBColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSRGBColor.h; sourceTree = "<group>"; };
BC76AC110DD7AD5C00415F34 /* ParserUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParserUtilities.h; sourceTree = "<group>"; };
BC772B360C4EA91E0083285F /* CSSHelper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CSSHelper.h; sourceTree = "<group>"; };
- BC772B370C4EA91E0083285F /* CSSParser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = CSSParser.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+ BC772B370C4EA91E0083285F /* CSSParser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = CSSParser.cpp; sourceTree = "<group>"; };
BC772B380C4EA91E0083285F /* CSSParser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CSSParser.h; sourceTree = "<group>"; };
BC772C440C4EB2C60083285F /* XMLHttpRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = XMLHttpRequest.cpp; sourceTree = "<group>"; };
BC772C450C4EB2C60083285F /* XMLHttpRequest.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = XMLHttpRequest.h; sourceTree = "<group>"; };
|| (valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText && !strict));
}
-static bool parseColorValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
+static CSSParser::ParseResult parseColorValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
{
ASSERT(!string.isEmpty());
bool strict = isStrictParserMode(cssParserMode);
if (!isColorPropertyID(propertyId))
- return false;
+ return CSSParser::ParseResult::Error;
+
CSSParserString cssString;
cssString.init(string);
CSSValueID valueID = cssValueKeywordID(cssString);
if (validPrimitiveValueColor(valueID, strict)) {
RefPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID);
- declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
- return true;
+ return declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged;
}
RGBA32 color;
if (!CSSParser::fastParseColor(color, string, strict && string[0] != '#'))
- return false;
+ return CSSParser::ParseResult::Error;
+
RefPtr<CSSValue> value = cssValuePool().createColorValue(color);
- declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
- return true;
+ return declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged;
}
static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
return ok;
}
-static bool parseSimpleLengthValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
+static CSSParser::ParseResult parseSimpleLengthValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
{
ASSERT(!string.isEmpty());
bool acceptsNegativeNumbers;
if (!isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
- return false;
+ return CSSParser::ParseResult::Error;
unsigned length = string.length();
double number;
if (string.is8Bit()) {
if (!parseSimpleLength(string.characters8(), length, unit, number))
- return false;
+ return CSSParser::ParseResult::Error;
} else {
if (!parseSimpleLength(string.characters16(), length, unit, number))
- return false;
+ return CSSParser::ParseResult::Error;
}
if (unit == CSSPrimitiveValue::CSS_NUMBER) {
if (number && isStrictParserMode(cssParserMode))
- return false;
+ return CSSParser::ParseResult::Error;
unit = CSSPrimitiveValue::CSS_PX;
}
if (number < 0 && !acceptsNegativeNumbers)
- return false;
+ return CSSParser::ParseResult::Error;
if (std::isinf(number))
- return false;
+ return CSSParser::ParseResult::Error;
RefPtr<CSSValue> value = cssValuePool().createValue(number, unit);
- declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
- return true;
+ return declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged;
}
static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext, StyleSheetContents* styleSheetContents)
}
}
-static bool parseKeywordValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext, StyleSheetContents* styleSheetContents)
+static CSSParser::ParseResult parseKeywordValue(MutableStyleProperties* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext, StyleSheetContents* styleSheetContents)
{
ASSERT(!string.isEmpty());
// All properties accept the values of "initial" and "inherit".
String lowerCaseString = string.lower();
if (lowerCaseString != "initial" && lowerCaseString != "inherit")
- return false;
+ return CSSParser::ParseResult::Error;
// Parse initial/inherit shorthands using the CSSParser.
if (shorthandForProperty(propertyId).length())
- return false;
+ return CSSParser::ParseResult::Error;
}
CSSParserString cssString;
CSSValueID valueID = cssValueKeywordID(cssString);
if (!valueID)
- return false;
+ return CSSParser::ParseResult::Error;
RefPtr<CSSValue> value;
if (valueID == CSSValueInherit)
else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext, styleSheetContents))
value = cssValuePool().createIdentifierValue(valueID);
else
- return false;
+ return CSSParser::ParseResult::Error;
- declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
- return true;
+ return declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important)) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged;
}
template <typename CharacterType>
return true;
}
-static bool parseTranslateTransformValue(MutableStyleProperties* properties, CSSPropertyID propertyID, const String& string, bool important)
+static CSSParser::ParseResult parseTranslateTransformValue(MutableStyleProperties* properties, CSSPropertyID propertyID, const String& string, bool important)
{
if (propertyID != CSSPropertyTransform)
- return false;
+ return CSSParser::ParseResult::Error;
+
static const unsigned shortestValidTransformStringLength = 12;
static const unsigned likelyMultipartTransformStringLengthCutoff = 32;
if (string.length() < shortestValidTransformStringLength || string.length() > likelyMultipartTransformStringLengthCutoff)
- return false;
+ return CSSParser::ParseResult::Error;
+
if (!string.startsWith("translate", false))
- return false;
+ return CSSParser::ParseResult::Error;
+
UChar c9 = toASCIILower(string[9]);
UChar c10 = toASCIILower(string[10]);
expectedArgumentCount = 3;
argumentStart = 12;
} else
- return false;
+ return CSSParser::ParseResult::Error;
RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(transformType);
bool success;
else
success = parseTransformTranslateArguments(*transformValue, string.characters16(), string.length(), argumentStart, expectedArgumentCount);
if (!success)
- return false;
+ return CSSParser::ParseResult::Error;
+
RefPtr<CSSValueList> result = CSSValueList::createSpaceSeparated();
result->append(transformValue.releaseNonNull());
- properties->addParsedProperty(CSSProperty(CSSPropertyTransform, result.release(), important));
- return true;
+ return properties->addParsedProperty(CSSProperty(CSSPropertyTransform, result.release(), important)) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged;
}
PassRefPtr<CSSValueList> CSSParser::parseFontFaceValue(const AtomicString& string)
if (string.isEmpty())
return nullptr;
RefPtr<MutableStyleProperties> dummyStyle = MutableStyleProperties::create();
- if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, CSSQuirksMode, nullptr))
+
+ if (parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, CSSQuirksMode, nullptr) == ParseResult::Error)
return nullptr;
RefPtr<CSSValue> fontFamily = dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily);
return static_pointer_cast<CSSValueList>(fontFamily.release());
}
-bool CSSParser::parseValue(MutableStyleProperties* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
+CSSParser::ParseResult CSSParser::parseValue(MutableStyleProperties* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
{
ASSERT(!string.isEmpty());
- if (parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode))
- return true;
- if (parseColorValue(declaration, propertyID, string, important, cssParserMode))
- return true;
+ CSSParser::ParseResult result = parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode);
+ if (result != ParseResult::Error)
+ return result;
+
+ result = parseColorValue(declaration, propertyID, string, important, cssParserMode);
+ if (result != ParseResult::Error)
+ return result;
CSSParserContext context(cssParserMode);
if (contextStyleSheet) {
context.mode = cssParserMode;
}
- if (parseKeywordValue(declaration, propertyID, string, important, context, contextStyleSheet))
- return true;
- if (parseTranslateTransformValue(declaration, propertyID, string, important))
- return true;
+ result = parseKeywordValue(declaration, propertyID, string, important, context, contextStyleSheet);
+ if (result != ParseResult::Error)
+ return result;
+
+ result = parseTranslateTransformValue(declaration, propertyID, string, important);
+ if (result != ParseResult::Error)
+ return result;
CSSParser parser(context);
return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet);
}
-bool CSSParser::parseValue(MutableStyleProperties* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet)
+CSSParser::ParseResult CSSParser::parseValue(MutableStyleProperties* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet)
{
setStyleSheet(contextStyleSheet);
m_rule = nullptr;
- bool ok = false;
+ ParseResult result = ParseResult::Error;
if (m_hasFontFaceOnlyValues)
deleteFontFaceOnlyValues();
+
if (!m_parsedProperties.isEmpty()) {
- ok = true;
- declaration->addParsedProperties(m_parsedProperties);
+ result = declaration->addParsedProperties(m_parsedProperties) ? ParseResult::Changed : ParseResult::Unchanged;
clearProperties();
}
- return ok;
+ return result;
}
// The color will only be changed when string contains a valid CSS color, so callers
GeneralSyntaxError
};
+ enum class ParseResult {
+ Changed,
+ Unchanged,
+ Error
+ };
+
class ValueWithCalculation {
public:
explicit ValueWithCalculation(CSSParserValue& value)
};
WEBCORE_EXPORT CSSParser(const CSSParserContext&);
-
WEBCORE_EXPORT ~CSSParser();
void parseSheet(StyleSheetContents*, const String&, const TextPosition&, RuleSourceDataList*, bool logErrors);
PassRefPtr<StyleRuleBase> parseRule(StyleSheetContents*, const String&);
PassRefPtr<StyleKeyframe> parseKeyframeRule(StyleSheetContents*, const String&);
bool parseSupportsCondition(const String&);
- static bool parseValue(MutableStyleProperties*, CSSPropertyID, const String&, bool important, CSSParserMode, StyleSheetContents*);
+
+ static ParseResult parseValue(MutableStyleProperties*, CSSPropertyID, const String&, bool important, CSSParserMode, StyleSheetContents*);
+
static bool parseColor(RGBA32& color, const String&, bool strict = false);
static bool parseSystemColor(RGBA32& color, const String&, Document*);
static PassRefPtr<CSSValueList> parseFontFaceValue(const AtomicString&);
PassRefPtr<CSSPrimitiveValue> parseValidPrimitive(CSSValueID ident, ValueWithCalculation&);
+
WEBCORE_EXPORT bool parseDeclaration(MutableStyleProperties*, const String&, PassRefPtr<CSSRuleSourceData>, StyleSheetContents* contextStyleSheet);
static Ref<ImmutableStyleProperties> parseInlineStyleDeclaration(const String&, Element*);
std::unique_ptr<MediaQuery> parseMediaQuery(const String&);
bool isGeneratedImageValue(CSSParserValue&) const;
bool parseGeneratedImage(CSSParserValueList&, RefPtr<CSSValue>&);
- bool parseValue(MutableStyleProperties*, CSSPropertyID, const String&, bool important, StyleSheetContents* contextStyleSheet);
+ ParseResult parseValue(MutableStyleProperties*, CSSPropertyID, const String&, bool important, StyleSheetContents* contextStyleSheet);
Ref<ImmutableStyleProperties> parseDeclaration(const String&, StyleSheetContents* contextStyleSheet);
PassRefPtr<CSSBasicShape> parseInsetRoundedCorners(PassRefPtr<CSSBasicShapeInset>, CSSParserValueList&);
}
CSSPropertyID shorthandID() const;
+
+ bool operator==(const StylePropertyMetadata& other) const
+ {
+ return m_propertyID == other.m_propertyID
+ && m_isSetFromShorthand == other.m_isSetFromShorthand
+ && m_indexInShorthandsVector == other.m_indexInShorthandsVector
+ && m_important == other.m_important
+ && m_implicit == other.m_implicit
+ && m_inherited == other.m_inherited;
+ }
uint16_t m_propertyID : 10;
uint16_t m_isSetFromShorthand : 1;
const StylePropertyMetadata& metadata() const { return m_metadata; }
+ bool operator==(const CSSProperty& other) const
+ {
+ if (!(m_metadata == other.m_metadata))
+ return false;
+
+ if (!m_value && !other.m_value)
+ return true;
+
+ if (!m_value || !other.m_value)
+ return false;
+
+ return m_value->equals(*other.m_value);
+ }
+
private:
StylePropertyMetadata m_metadata;
RefPtr<CSSValue> m_value;
return false;
RefPtr<MutableStyleProperties> dummyStyle = MutableStyleProperties::create();
- return CSSParser::parseValue(dummyStyle.get(), propertyID, normalizedValue, false, CSSStrictMode, 0);
+ return CSSParser::parseValue(dummyStyle.get(), propertyID, normalizedValue, false, CSSStrictMode, nullptr) != CSSParser::ParseResult::Error;
}
bool DOMWindowCSS::supports(const String& conditionText) const
{
// Interpret fontString in the same way as the 'font' attribute of CanvasRenderingContext2D.
RefPtr<MutableStyleProperties> parsedStyle = MutableStyleProperties::create();
- CSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, fontString, true, CSSStrictMode, 0);
+ CSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, fontString, true, CSSStrictMode, nullptr);
if (parsedStyle->isEmpty())
return false;
// When replacing an existing property value, this moves the property to the end of the list.
// Firefox preserves the position, and MSIE moves the property to the beginning.
- return CSSParser::parseValue(this, propertyID, value, important, cssParserMode(), contextStyleSheet);
+ return CSSParser::parseValue(this, propertyID, value, important, cssParserMode(), contextStyleSheet) == CSSParser::ParseResult::Changed;
}
void MutableStyleProperties::setProperty(CSSPropertyID propertyID, PassRefPtr<CSSValue> prpValue, bool important)
m_propertyVector.append(CSSProperty(shorthand.properties()[i], value, important));
}
-void MutableStyleProperties::setProperty(const CSSProperty& property, CSSProperty* slot)
+bool MutableStyleProperties::setProperty(const CSSProperty& property, CSSProperty* slot)
{
if (!removeShorthandProperty(property.id())) {
CSSProperty* toReplace = slot ? slot : findCSSPropertyWithID(property.id());
if (toReplace) {
+ if (*toReplace == property)
+ return false;
+
*toReplace = property;
setPrefixingVariantProperty(property);
- return;
+ return true;
}
}
- appendPrefixingVariantProperty(property);
+
+ return appendPrefixingVariantProperty(property);
}
static unsigned getIndexInShorthandVectorForPrefixingVariant(const CSSProperty& property, CSSPropertyID prefixingVariant)
return indexOfShorthandForLonghand(prefixedShorthand, matchingShorthandsForLonghand(prefixingVariant));
}
-void MutableStyleProperties::appendPrefixingVariantProperty(const CSSProperty& property)
+bool MutableStyleProperties::appendPrefixingVariantProperty(const CSSProperty& property)
{
m_propertyVector.append(property);
CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id());
if (prefixingVariant == property.id())
- return;
+ return true;
m_propertyVector.append(CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.isSetFromShorthand(), getIndexInShorthandVectorForPrefixingVariant(property, prefixingVariant), property.metadata().m_implicit));
+ return true;
}
void MutableStyleProperties::setPrefixingVariantProperty(const CSSProperty& property)
bool MutableStyleProperties::setProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
{
- setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
- return true;
+ return setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
}
bool MutableStyleProperties::setProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
{
- setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
- return true;
+ return setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
}
void MutableStyleProperties::parseDeclaration(const String& styleDeclaration, StyleSheetContents* contextStyleSheet)
parser.parseDeclaration(this, styleDeclaration, 0, contextStyleSheet);
}
-void MutableStyleProperties::addParsedProperties(const Vector<CSSProperty>& properties)
+bool MutableStyleProperties::addParsedProperties(const Vector<CSSProperty>& properties)
{
+ bool anyChanged = false;
m_propertyVector.reserveCapacity(m_propertyVector.size() + properties.size());
- for (unsigned i = 0; i < properties.size(); ++i)
- addParsedProperty(properties[i]);
+ for (unsigned i = 0; i < properties.size(); ++i) {
+ if (addParsedProperty(properties[i]))
+ anyChanged = true;
+ }
+
+ return anyChanged;
}
-void MutableStyleProperties::addParsedProperty(const CSSProperty& property)
+bool MutableStyleProperties::addParsedProperty(const CSSProperty& property)
{
// Only add properties that have no !important counterpart present
if (!propertyIsImportant(property.id()) || property.isImportant())
- setProperty(property);
+ return setProperty(property);
+
+ return false;
}
String StyleProperties::asText() const
PropertySetCSSStyleDeclaration* cssStyleDeclaration();
- void addParsedProperties(const Vector<CSSProperty>&);
- void addParsedProperty(const CSSProperty&);
+ bool addParsedProperties(const Vector<CSSProperty>&);
+ bool addParsedProperty(const CSSProperty&);
// These expand shorthand properties into multiple properties.
bool setProperty(CSSPropertyID, const String& value, bool important = false, StyleSheetContents* contextStyleSheet = 0);
// These do not. FIXME: This is too messy, we can do better.
bool setProperty(CSSPropertyID, CSSValueID identifier, bool important = false);
bool setProperty(CSSPropertyID, CSSPropertyID identifier, bool important = false);
- void appendPrefixingVariantProperty(const CSSProperty&);
+ bool appendPrefixingVariantProperty(const CSSProperty&);
void setPrefixingVariantProperty(const CSSProperty&);
- void setProperty(const CSSProperty&, CSSProperty* slot = 0);
+ bool setProperty(const CSSProperty&, CSSProperty* slot = nullptr);
- bool removeProperty(CSSPropertyID, String* returnText = 0);
+ bool removeProperty(CSSPropertyID, String* returnText = nullptr);
void removePrefixedOrUnprefixedProperty(CSSPropertyID);
void removeBlockProperties();
bool removePropertiesInSet(const CSSPropertyID* set, unsigned length);
return;
RefPtr<MutableStyleProperties> styleDeclaration = MutableStyleProperties::create();
- if (CSSParser::parseValue(styleDeclaration.get(), CSSPropertyTransform, string, true, CSSStrictMode, 0)) {
+ if (CSSParser::parseValue(styleDeclaration.get(), CSSPropertyTransform, string, true, CSSStrictMode, nullptr) != CSSParser::ParseResult::Error) {
// Convert to TransformOperations. This can fail if a property
// requires style (i.e., param uses 'ems' or 'exs')
RefPtr<CSSValue> value = styleDeclaration->getPropertyCSSValue(CSSPropertyTransform);
m_closeAfterStyleRecalc = false;
implicitClose();
}
+
+ ++m_styleRecalcCount;
InspectorInstrumentation::didRecalculateStyle(cookie);
m_lastHandledUserGestureTimestamp = monotonicallyIncreasingTime();
}
+void Document::startTrackingStyleRecalcs()
+{
+ m_styleRecalcCount = 0;
+}
+
+unsigned Document::styleRecalcCount() const
+{
+ return m_styleRecalcCount;
+}
+
DocumentLoader* Document::loader() const
{
if (!m_frame)
WEBCORE_EXPORT unsigned wheelEventHandlerCount() const;
WEBCORE_EXPORT unsigned touchEventHandlerCount() const;
+ WEBCORE_EXPORT void startTrackingStyleRecalcs();
+ WEBCORE_EXPORT unsigned styleRecalcCount() const;
+
void didAddTouchEventHandler(Node&);
void didRemoveTouchEventHandler(Node&, EventHandlerRemoval = EventHandlerRemoval::One);
// http://www.whatwg.org/specs/web-apps/current-work/#ignore-destructive-writes-counter
unsigned m_ignoreDestructiveWriteCount;
+ unsigned m_styleRecalcCount { 0 };
+
StringWithDirection m_title;
StringWithDirection m_rawTitle;
bool m_titleSetExplicitly;
return;
RefPtr<MutableStyleProperties> parsedStyle = MutableStyleProperties::create();
- CSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, newFont, true, strictToCSSParserMode(!m_usesCSSCompatibilityParseMode), 0);
+ CSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, newFont, true, strictToCSSParserMode(!m_usesCSSCompatibilityParseMode), nullptr);
if (parsedStyle->isEmpty())
return;
return document->renderView()->compositor().layerFlushCount();
}
+void Internals::startTrackingStyleRecalcs(ExceptionCode& ec)
+{
+ Document* document = contextDocument();
+ if (!document) {
+ ec = INVALID_ACCESS_ERR;
+ return;
+ }
+ document->startTrackingStyleRecalcs();
+}
+
+unsigned long Internals::styleRecalcCount(ExceptionCode& ec)
+{
+ Document* document = contextDocument();
+ if (!document) {
+ ec = INVALID_ACCESS_ERR;
+ return 0;
+ }
+
+ return document->styleRecalcCount();
+}
+
void Internals::updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(ExceptionCode& ec)
{
updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(nullptr, ec);
void startTrackingLayerFlushes(ExceptionCode&);
unsigned long layerFlushCount(ExceptionCode&);
+ void startTrackingStyleRecalcs(ExceptionCode&);
+ unsigned long styleRecalcCount(ExceptionCode&);
+
void updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(ExceptionCode&);
void updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node*, ExceptionCode&);
// Query if a timer is currently throttled, to debug timer throttling.
[RaisesException] boolean isTimerThrottled(long timerHandle);
+ [RaisesException] void startTrackingStyleRecalcs();
+ [RaisesException] unsigned long styleRecalcCount();
+
// |node| should be Document, HTMLIFrameElement, or unspecified.
// If |node| is an HTMLIFrameElement, it assumes node.contentDocument is
// specified without security checks. Unspecified means this document.