Move WebCore into Source
[WebKit-https.git] / Source / WebCore / bindings / js / JSCSSStyleDeclarationCustom.cpp
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
38 using namespace JSC;
39 using namespace WTF;
40
41 namespace WebCore {
42
43 void 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.
66 static 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
88 static 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
136 static bool isCSSPropertyName(const Identifier& propertyName)
137 {
138     return CSSStyleDeclaration::isPropertyName(cssPropertyName(propertyName));
139 }
140
141 bool 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.
148 JSValue 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
177 bool 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