V8CSSStyleDeclarationCustom.cpp [plain text]
#include "config.h"
#include "V8CSSStyleDeclaration.h"
#include "CSSParser.h"
#include "CSSPropertyNames.h"
#include "CSSStyleDeclaration.h"
#include "CSSValue.h"
#include "CSSPrimitiveValue.h"
#include "EventTarget.h"
#include "V8Binding.h"
#include "V8Proxy.h"
#include <wtf/text/StringBuilder.h>
#include <wtf/text/StringConcatenate.h>
#include <wtf/ASCIICType.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
#include <wtf/StdLibExtras.h>
#include <wtf/Vector.h>
using namespace WTF;
using namespace std;
namespace WebCore {
static bool hasCSSPropertyNamePrefix(const String& propertyName, const char* prefix)
{
#ifndef NDEBUG
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;
}
class CSSPropertyInfo {
public:
CSSPropertyID propID;
bool hadPixelOrPosPrefix;
};
static CSSPropertyInfo* cssPropertyInfo(v8::Handle<v8::String>v8PropertyName)
{
String propertyName = toWebCoreString(v8PropertyName);
typedef HashMap<String, CSSPropertyInfo*> CSSPropertyInfoMap;
DEFINE_STATIC_LOCAL(CSSPropertyInfoMap, map, ());
CSSPropertyInfo* propInfo = map.get(propertyName);
if (!propInfo) {
unsigned length = propertyName.length();
bool hadPixelOrPosPrefix = false;
if (!length)
return 0;
StringBuilder builder;
builder.reserveCapacity(length);
unsigned i = 0;
if (hasCSSPropertyNamePrefix(propertyName, "css"))
i += 3;
else if (hasCSSPropertyNamePrefix(propertyName, "pixel")) {
i += 5;
hadPixelOrPosPrefix = true;
} else if (hasCSSPropertyNamePrefix(propertyName, "pos")) {
i += 3;
hadPixelOrPosPrefix = true;
} else if (hasCSSPropertyNamePrefix(propertyName, "webkit")
#if ENABLE(LEGACY_CSS_VENDOR_PREFIXES)
|| hasCSSPropertyNamePrefix(propertyName, "khtml")
|| hasCSSPropertyNamePrefix(propertyName, "apple")
#endif
)
builder.append('-');
else if (isASCIIUpper(propertyName[0]))
return 0;
builder.append(toASCIILower(propertyName[i++]));
for (; i < length; ++i) {
UChar c = propertyName[i];
if (!isASCIIUpper(c))
builder.append(c);
else
builder.append(makeString('-', toASCIILower(c)));
}
String propName = builder.toString();
CSSPropertyID propertyID = cssPropertyID(propName);
if (propertyID) {
propInfo = new CSSPropertyInfo();
propInfo->hadPixelOrPosPrefix = hadPixelOrPosPrefix;
propInfo->propID = propertyID;
map.add(propertyName, propInfo);
}
}
return propInfo;
}
v8::Handle<v8::Array> V8CSSStyleDeclaration::namedPropertyEnumerator(const v8::AccessorInfo& info)
{
typedef Vector<String, numCSSProperties - 1> PreAllocatedPropertyVector;
DEFINE_STATIC_LOCAL(PreAllocatedPropertyVector, propertyNames, ());
static unsigned propertyNamesLength = 0;
if (propertyNames.isEmpty()) {
for (int id = firstCSSProperty; id < firstCSSProperty + numCSSProperties; ++id)
propertyNames.append(getJSPropertyName(static_cast<CSSPropertyID>(id)));
sort(propertyNames.begin(), propertyNames.end(), codePointCompareLessThan);
propertyNamesLength = propertyNames.size();
}
v8::Handle<v8::Array> properties = v8::Array::New(propertyNamesLength);
for (unsigned i = 0; i < propertyNamesLength; ++i) {
String key = propertyNames.at(i);
ASSERT(!key.isNull());
properties->Set(v8::Integer::New(i), v8String(key));
}
return properties;
}
v8::Handle<v8::Integer> V8CSSStyleDeclaration::namedPropertyQuery(v8::Local<v8::String> v8Name, const v8::AccessorInfo& info)
{
INC_STATS("DOM.CSSStyleDeclaration.NamedPropertyQuery");
if (cssPropertyInfo(v8Name))
return v8::Integer::New(v8::None);
return v8::Handle<v8::Integer>();
}
v8::Handle<v8::Value> V8CSSStyleDeclaration::namedPropertyGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
INC_STATS("DOM.CSSStyleDeclaration.NamedPropertyGetter");
if (info.Holder()->HasRealNamedCallbackProperty(name))
return notHandledByInterceptor();
CSSPropertyInfo* propInfo = cssPropertyInfo(name);
if (!propInfo)
return notHandledByInterceptor();
CSSStyleDeclaration* imp = V8CSSStyleDeclaration::toNative(info.Holder());
RefPtr<CSSValue> cssValue = imp->getPropertyCSSValueInternal(static_cast<CSSPropertyID>(propInfo->propID));
if (cssValue) {
if (propInfo->hadPixelOrPosPrefix &&
cssValue->isPrimitiveValue()) {
return v8::Number::New(static_cast<CSSPrimitiveValue*>(
cssValue.get())->getFloatValue(CSSPrimitiveValue::CSS_PX));
}
return v8StringOrNull(cssValue->cssText());
}
String result = imp->getPropertyValueInternal(static_cast<CSSPropertyID>(propInfo->propID));
if (result.isNull())
result = "";
return v8String(result);
}
v8::Handle<v8::Value> V8CSSStyleDeclaration::namedPropertySetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
INC_STATS("DOM.CSSStyleDeclaration.NamedPropertySetter");
CSSStyleDeclaration* imp = V8CSSStyleDeclaration::toNative(info.Holder());
CSSPropertyInfo* propInfo = cssPropertyInfo(name);
if (!propInfo)
return notHandledByInterceptor();
String propertyValue = toWebCoreStringWithNullCheck(value);
if (propInfo->hadPixelOrPosPrefix)
propertyValue.append("px");
ExceptionCode ec = 0;
imp->setPropertyInternal(static_cast<CSSPropertyID>(propInfo->propID), propertyValue, false, ec);
if (ec)
throwError(ec);
return value;
}
}