Home | History | Annotate | Download | only in js
      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