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 #include <wtf/text/StringBuilder.h> 38 #include <wtf/text/StringConcatenate.h> 39 40 using namespace JSC; 41 using namespace WTF; 42 43 namespace WebCore { 44 45 void JSCSSStyleDeclaration::markChildren(MarkStack& markStack) 46 { 47 Base::markChildren(markStack); 48 49 CSSStyleDeclaration* declaration = impl(); 50 JSGlobalData& globalData = *Heap::heap(this)->globalData(); 51 52 if (CSSRule* parentRule = declaration->parentRule()) 53 markDOMObjectWrapper(markStack, globalData, parentRule); 54 55 if (declaration->isMutableStyleDeclaration()) { 56 CSSMutableStyleDeclaration* mutableDeclaration = static_cast<CSSMutableStyleDeclaration*>(declaration); 57 CSSMutableStyleDeclaration::const_iterator end = mutableDeclaration->end(); 58 for (CSSMutableStyleDeclaration::const_iterator it = mutableDeclaration->begin(); it != end; ++it) 59 markDOMObjectWrapper(markStack, globalData, it->value()); 60 } 61 } 62 63 // Check for a CSS prefix. 64 // Passed prefix is all lowercase. 65 // First character of the prefix within the property name may be upper or lowercase. 66 // Other characters in the prefix within the property name must be lowercase. 67 // The prefix within the property name must be followed by a capital letter. 68 static bool hasCSSPropertyNamePrefix(const Identifier& propertyName, const char* prefix) 69 { 70 #ifndef NDEBUG 71 ASSERT(*prefix); 72 for (const char* p = prefix; *p; ++p) 73 ASSERT(isASCIILower(*p)); 74 ASSERT(propertyName.length()); 75 #endif 76 77 if (toASCIILower(propertyName.characters()[0]) != prefix[0]) 78 return false; 79 80 unsigned length = propertyName.length(); 81 for (unsigned i = 1; i < length; ++i) { 82 if (!prefix[i]) 83 return isASCIIUpper(propertyName.characters()[i]); 84 if (propertyName.characters()[i] != prefix[i]) 85 return false; 86 } 87 return false; 88 } 89 90 static String cssPropertyName(const Identifier& propertyName, bool* hadPixelOrPosPrefix = 0) 91 { 92 if (hadPixelOrPosPrefix) 93 *hadPixelOrPosPrefix = false; 94 95 unsigned length = propertyName.length(); 96 if (!length) 97 return String(); 98 99 StringBuilder builder; 100 builder.reserveCapacity(length); 101 102 unsigned i = 0; 103 104 if (hasCSSPropertyNamePrefix(propertyName, "css")) 105 i += 3; 106 else if (hasCSSPropertyNamePrefix(propertyName, "pixel")) { 107 i += 5; 108 if (hadPixelOrPosPrefix) 109 *hadPixelOrPosPrefix = true; 110 } else if (hasCSSPropertyNamePrefix(propertyName, "pos")) { 111 i += 3; 112 if (hadPixelOrPosPrefix) 113 *hadPixelOrPosPrefix = true; 114 } else if (hasCSSPropertyNamePrefix(propertyName, "webkit") 115 || hasCSSPropertyNamePrefix(propertyName, "khtml") 116 || hasCSSPropertyNamePrefix(propertyName, "apple")) 117 builder.append('-'); 118 else { 119 if (isASCIIUpper(propertyName.characters()[0])) 120 return String(); 121 } 122 123 builder.append(toASCIILower(propertyName.characters()[i++])); 124 125 for (; i < length; ++i) { 126 UChar c = propertyName.characters()[i]; 127 if (!isASCIIUpper(c)) 128 builder.append(c); 129 else 130 builder.append(makeString('-', toASCIILower(c))); 131 } 132 133 return builder.toString(); 134 } 135 136 static bool isCSSPropertyName(const Identifier& propertyIdentifier) 137 { 138 // FIXME: This mallocs a string for the property name and then throws it 139 // away. This shows up on peacekeeper's domDynamicCreationCreateElement. 140 return CSSStyleDeclaration::isPropertyName(cssPropertyName(propertyIdentifier)); 141 } 142 143 bool JSCSSStyleDeclaration::canGetItemsForName(ExecState*, CSSStyleDeclaration*, const Identifier& propertyName) 144 { 145 return isCSSPropertyName(propertyName); 146 } 147 148 // FIXME: You can get these properties, and set them (see putDelegate below), 149 // but you should also be able to enumerate them. 150 JSValue JSCSSStyleDeclaration::nameGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) 151 { 152 JSCSSStyleDeclaration* thisObj = static_cast<JSCSSStyleDeclaration*>(asObject(slotBase)); 153 154 // Set up pixelOrPos boolean to handle the fact that 155 // pixelTop returns "CSS Top" as number value in unit pixels 156 // posTop returns "CSS top" as number value in unit pixels _if_ its a 157 // positioned element. if it is not a positioned element, return 0 158 // from MSIE documentation FIXME: IMPLEMENT THAT (Dirk) 159 bool pixelOrPos; 160 String prop = cssPropertyName(propertyName, &pixelOrPos); 161 RefPtr<CSSValue> v = thisObj->impl()->getPropertyCSSValue(prop); 162 if (v) { 163 if (pixelOrPos && v->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) 164 return jsNumber(static_pointer_cast<CSSPrimitiveValue>(v)->getFloatValue(CSSPrimitiveValue::CSS_PX)); 165 return jsStringOrNull(exec, v->cssText()); 166 } 167 168 // If the property is a shorthand property (such as "padding"), 169 // it can only be accessed using getPropertyValue. 170 171 // Make the SVG 'filter' attribute undetectable, to avoid confusion with the IE 'filter' attribute. 172 if (propertyName == "filter") 173 return StringObjectThatMasqueradesAsUndefined::create(exec, stringToUString(thisObj->impl()->getPropertyValue(prop))); 174 175 return jsString(exec, thisObj->impl()->getPropertyValue(prop)); 176 } 177 178 179 bool JSCSSStyleDeclaration::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot&) 180 { 181 bool pixelOrPos; 182 String prop = cssPropertyName(propertyName, &pixelOrPos); 183 if (!CSSStyleDeclaration::isPropertyName(prop)) 184 return false; 185 186 String propValue = valueToStringWithNullCheck(exec, value); 187 if (pixelOrPos) 188 propValue += "px"; 189 ExceptionCode ec = 0; 190 impl()->setProperty(prop, propValue, ec); 191 setDOMException(exec, ec); 192 return true; 193 } 194 195 } // namespace WebCore 196