Chromium Code Reviews| Index: Source/core/css/CSSStyleDeclaration.cpp |
| diff --git a/Source/core/css/CSSStyleDeclaration.cpp b/Source/core/css/CSSStyleDeclaration.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..55313e0e4c34e17022536c7941c6d6b731571c20 |
| --- /dev/null |
| +++ b/Source/core/css/CSSStyleDeclaration.cpp |
| @@ -0,0 +1,167 @@ |
| +// Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "config.h" |
| +#include "core/css/CSSStyleDeclaration.h" |
| + |
| +#include "core/css/CSSPropertyMetadata.h" |
| +#include "core/css/parser/CSSParser.h" |
| +#include "core/frame/UseCounter.h" |
| +#include "wtf/text/WTFString.h" |
| + |
| +using namespace WTF; |
| + |
| +namespace blink { |
| + |
| +// Check for a CSS prefix. |
| +// Passed prefix is all lowercase. |
| +// First character of the prefix within the property name may be upper or lowercase. |
| +// Other characters in the prefix within the property name must be lowercase. |
| +// The prefix within the property name must be followed by a capital letter. |
| +static bool hasCSSPropertyNamePrefix(const String& propertyName, const char* prefix) |
| +{ |
| +#if ENABLE(ASSERT) |
| + ASSERT(*prefix); |
| + for (const char* p = prefix; *p; ++p) |
| + ASSERT(isASCIILower(*p)); |
| + ASSERT(propertyName.length()); |
| +#endif |
| + |
| + if (toASCIILower(propertyName[0]) != prefix[0]) |
| + return false; |
| + |
| + unsigned length = propertyName.length(); |
| + for (unsigned i = 1; i < length; ++i) { |
| + if (!prefix[i]) |
| + return isASCIIUpper(propertyName[i]); |
| + if (propertyName[i] != prefix[i]) |
| + return false; |
| + } |
| + return false; |
| +} |
| + |
| +static CSSPropertyID parseCSSPropertyID(v8::Isolate* isolate, const String& propertyName) |
| +{ |
| + unsigned length = propertyName.length(); |
| + if (!length) |
| + return CSSPropertyInvalid; |
| + |
| + StringBuilder builder; |
| + builder.reserveCapacity(length); |
| + |
| + unsigned i = 0; |
| + bool hasSeenDash = false; |
| + |
| + if (hasCSSPropertyNamePrefix(propertyName, "css")) { |
| + i += 3; |
| + // getComputedStyle(elem).cssX is a non-standard behaviour |
| + // Measure this behaviour as CSSXGetComputedStyleQueries. |
| + UseCounter::countIfNotPrivateScript(isolate, callingExecutionContext(isolate), UseCounter::CSSXGetComputedStyleQueries); |
| + } else if (hasCSSPropertyNamePrefix(propertyName, "webkit")) { |
| + builder.append('-'); |
| + } else if (isASCIIUpper(propertyName[0])) { |
| + return CSSPropertyInvalid; |
| + } |
| + |
| + bool hasSeenUpper = isASCIIUpper(propertyName[i]); |
| + |
| + builder.append(toASCIILower(propertyName[i++])); |
| + |
| + for (; i < length; ++i) { |
| + UChar c = propertyName[i]; |
| + if (!isASCIIUpper(c)) { |
| + if (c == '-') |
| + hasSeenDash = true; |
| + builder.append(c); |
| + } else { |
| + hasSeenUpper = true; |
| + builder.append('-'); |
| + builder.append(toASCIILower(c)); |
| + } |
| + } |
| + |
| + // Reject names containing both dashes and upper-case characters, such as "border-rightColor". |
| + if (hasSeenDash && hasSeenUpper) |
| + return CSSPropertyInvalid; |
| + |
| + String propName = builder.toString(); |
| + return unresolvedCSSPropertyID(propName); |
| +} |
| + |
| +static CSSPropertyID cssPropertyInfo(const String& propertyName, v8::Isolate* isolate) |
| +{ |
| + typedef HashMap<String, CSSPropertyID> CSSPropertyIDMap; |
| + DEFINE_STATIC_LOCAL(CSSPropertyIDMap, map, ()); |
| + CSSPropertyIDMap::iterator iter = map.find(propertyName); |
| + if (iter != map.end()) |
| + return iter->value; |
| + |
| + CSSPropertyID unresolvedProperty = parseCSSPropertyID(isolate, propertyName); |
| + map.add(propertyName, unresolvedProperty); |
| + ASSERT(!unresolvedProperty || CSSPropertyMetadata::isEnabledProperty(unresolvedProperty)); |
| + return unresolvedProperty; |
| +} |
| + |
| +void CSSStyleDeclaration::anonymousNamedGetter(ScriptState* scriptState, const AtomicString& name, StringOrFloat& result) |
| +{ |
| + // Search the style declaration. |
| + CSSPropertyID unresolvedProperty = cssPropertyInfo(name, scriptState->isolate()); |
| + |
| + // Do not handle non-property names. |
| + if (!unresolvedProperty) |
| + return; |
| + CSSPropertyID resolvedProperty = resolveCSSPropertyID(unresolvedProperty); |
| + |
| + RefPtrWillBeRawPtr<CSSValue> cssValue = getPropertyCSSValueInternal(resolvedProperty); |
| + if (cssValue) { |
| + result.setString(cssValue->cssText()); |
|
haraken
2015/04/29 15:53:46
The previous code was using v8SetReturnValueString
|
| + return; |
| + } |
| + |
| + result.setString(getPropertyValueInternal(resolvedProperty)); |
| +} |
| + |
| +bool CSSStyleDeclaration::anonymousNamedSetter(ScriptState* scriptState, const String& name, const String& propertyValue, ExceptionState& exceptionState) |
| +{ |
| + CSSPropertyID unresolvedProperty = cssPropertyInfo(name, scriptState->isolate()); |
| + if (!unresolvedProperty) |
| + return false; |
| + |
| + setPropertyInternal(unresolvedProperty, propertyValue, false, exceptionState); |
|
haraken
2015/04/29 15:53:45
Don't we need:
if (exceptionState.throwIfNeeded
Jens Widell
2015/04/30 13:14:13
We do not. It's the outermost layer's job to actua
|
| + return true; |
| +} |
| + |
| +bool CSSStyleDeclaration::namedPropertyQuery(ScriptState* scriptState, const AtomicString& name, ExceptionState&) |
| +{ |
| + if (!name.length()) |
|
haraken
2015/04/29 15:53:45
Did we have this check in the previous code?
|
| + return false; |
| + // NOTE: cssPropertyInfo lookups incur several mallocs. |
| + // Successful lookups have the same cost the first time, but are cached. |
| + return cssPropertyInfo(name, scriptState->isolate()); |
|
haraken
2015/04/29 15:53:45
In the previous code, we're doing v8SetReturnValue
|
| +} |
| + |
| +void CSSStyleDeclaration::namedPropertyEnumerator(Vector<String>& names, ExceptionState&) |
| +{ |
| + typedef Vector<String, numCSSProperties - 1> PreAllocatedPropertyVector; |
| + DEFINE_STATIC_LOCAL(PreAllocatedPropertyVector, propertyNames, ()); |
| + static unsigned propertyNamesLength = 0; |
| + |
| + if (propertyNames.isEmpty()) { |
| + for (int id = firstCSSProperty; id <= lastCSSProperty; ++id) { |
| + CSSPropertyID propertyId = static_cast<CSSPropertyID>(id); |
| + if (CSSPropertyMetadata::isEnabledProperty(propertyId)) |
| + propertyNames.append(getJSPropertyName(propertyId)); |
| + } |
| + std::sort(propertyNames.begin(), propertyNames.end(), codePointCompareLessThan); |
| + propertyNamesLength = propertyNames.size(); |
| + } |
| + |
| + for (unsigned i = 0; i < propertyNamesLength; ++i) { |
| + String key = propertyNames.at(i); |
| + ASSERT(!key.isNull()); |
| + names.append(key); |
| + } |
| +} |
| + |
| +} |
|
haraken
2015/04/29 15:53:45
// namespace blink
|