JSCSSStyleDeclarationCustom.cpp revision cad810f21b803229eb11403f9209855525a25d57
1/*
2 * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "JSCSSStyleDeclarationCustom.h"
28
29#include "CSSMutableStyleDeclaration.h"
30#include "CSSPrimitiveValue.h"
31#include "CSSValue.h"
32#include "PlatformString.h"
33#include <runtime/StringObjectThatMasqueradesAsUndefined.h>
34#include <runtime/StringPrototype.h>
35#include <wtf/ASCIICType.h>
36#include <wtf/text/AtomicString.h>
37
38using namespace JSC;
39using namespace WTF;
40
41namespace WebCore {
42
43void JSCSSStyleDeclaration::markChildren(MarkStack& markStack)
44{
45    Base::markChildren(markStack);
46
47    CSSStyleDeclaration* declaration = impl();
48    JSGlobalData& globalData = *Heap::heap(this)->globalData();
49
50    if (CSSRule* parentRule = declaration->parentRule())
51        markDOMObjectWrapper(markStack, globalData, parentRule);
52
53    if (declaration->isMutableStyleDeclaration()) {
54        CSSMutableStyleDeclaration* mutableDeclaration = static_cast<CSSMutableStyleDeclaration*>(declaration);
55        CSSMutableStyleDeclaration::const_iterator end = mutableDeclaration->end();
56        for (CSSMutableStyleDeclaration::const_iterator it = mutableDeclaration->begin(); it != end; ++it)
57            markDOMObjectWrapper(markStack, globalData, it->value());
58    }
59}
60
61// Check for a CSS prefix.
62// Passed prefix is all lowercase.
63// First character of the prefix within the property name may be upper or lowercase.
64// Other characters in the prefix within the property name must be lowercase.
65// The prefix within the property name must be followed by a capital letter.
66static bool hasCSSPropertyNamePrefix(const Identifier& propertyName, const char* prefix)
67{
68#ifndef NDEBUG
69    ASSERT(*prefix);
70    for (const char* p = prefix; *p; ++p)
71        ASSERT(isASCIILower(*p));
72    ASSERT(propertyName.length());
73#endif
74
75    if (toASCIILower(propertyName.characters()[0]) != prefix[0])
76        return false;
77
78    unsigned length = propertyName.length();
79    for (unsigned i = 1; i < length; ++i) {
80        if (!prefix[i])
81            return isASCIIUpper(propertyName.characters()[i]);
82        if (propertyName.characters()[i] != prefix[i])
83            return false;
84    }
85    return false;
86}
87
88static String cssPropertyName(const Identifier& propertyName, bool* hadPixelOrPosPrefix = 0)
89{
90    if (hadPixelOrPosPrefix)
91        *hadPixelOrPosPrefix = false;
92
93    unsigned length = propertyName.length();
94    if (!length)
95        return String();
96
97    Vector<UChar> name;
98    name.reserveInitialCapacity(length);
99
100    unsigned i = 0;
101
102    if (hasCSSPropertyNamePrefix(propertyName, "css"))
103        i += 3;
104    else if (hasCSSPropertyNamePrefix(propertyName, "pixel")) {
105        i += 5;
106        if (hadPixelOrPosPrefix)
107            *hadPixelOrPosPrefix = true;
108    } else if (hasCSSPropertyNamePrefix(propertyName, "pos")) {
109        i += 3;
110        if (hadPixelOrPosPrefix)
111            *hadPixelOrPosPrefix = true;
112    } else if (hasCSSPropertyNamePrefix(propertyName, "webkit")
113            || hasCSSPropertyNamePrefix(propertyName, "khtml")
114            || hasCSSPropertyNamePrefix(propertyName, "apple"))
115        name.append('-');
116    else {
117        if (isASCIIUpper(propertyName.characters()[0]))
118            return String();
119    }
120
121    name.append(toASCIILower(propertyName.characters()[i++]));
122
123    for (; i < length; ++i) {
124        UChar c = propertyName.characters()[i];
125        if (!isASCIIUpper(c))
126            name.append(c);
127        else {
128            name.append('-');
129            name.append(toASCIILower(c));
130        }
131    }
132
133    return String::adopt(name);
134}
135
136static bool isCSSPropertyName(const Identifier& propertyName)
137{
138    return CSSStyleDeclaration::isPropertyName(cssPropertyName(propertyName));
139}
140
141bool JSCSSStyleDeclaration::canGetItemsForName(ExecState*, CSSStyleDeclaration*, const Identifier& propertyName)
142{
143    return isCSSPropertyName(propertyName);
144}
145
146// FIXME: You can get these properties, and set them (see putDelegate below),
147// but you should also be able to enumerate them.
148JSValue JSCSSStyleDeclaration::nameGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
149{
150    JSCSSStyleDeclaration* thisObj = static_cast<JSCSSStyleDeclaration*>(asObject(slotBase));
151
152    // Set up pixelOrPos boolean to handle the fact that
153    // pixelTop returns "CSS Top" as number value in unit pixels
154    // posTop returns "CSS top" as number value in unit pixels _if_ its a
155    // positioned element. if it is not a positioned element, return 0
156    // from MSIE documentation FIXME: IMPLEMENT THAT (Dirk)
157    bool pixelOrPos;
158    String prop = cssPropertyName(propertyName, &pixelOrPos);
159    RefPtr<CSSValue> v = thisObj->impl()->getPropertyCSSValue(prop);
160    if (v) {
161        if (pixelOrPos && v->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE)
162            return jsNumber(static_pointer_cast<CSSPrimitiveValue>(v)->getFloatValue(CSSPrimitiveValue::CSS_PX));
163        return jsStringOrNull(exec, v->cssText());
164    }
165
166    // If the property is a shorthand property (such as "padding"),
167    // it can only be accessed using getPropertyValue.
168
169    // Make the SVG 'filter' attribute undetectable, to avoid confusion with the IE 'filter' attribute.
170    if (propertyName == "filter")
171        return StringObjectThatMasqueradesAsUndefined::create(exec, stringToUString(thisObj->impl()->getPropertyValue(prop)));
172
173    return jsString(exec, thisObj->impl()->getPropertyValue(prop));
174}
175
176
177bool JSCSSStyleDeclaration::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot&)
178{
179    if (!isCSSPropertyName(propertyName))
180        return false;
181
182    bool pixelOrPos;
183    String prop = cssPropertyName(propertyName, &pixelOrPos);
184    String propValue = valueToStringWithNullCheck(exec, value);
185    if (pixelOrPos)
186        propValue += "px";
187    ExceptionCode ec = 0;
188    impl()->setProperty(prop, propValue, ec);
189    setDOMException(exec, ec);
190    return true;
191}
192
193} // namespace WebCore
194