Home | History | Annotate | Download | only in css
      1 /*
      2  * (C) 1999-2003 Lars Knoll (knoll (at) kde.org)
      3  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
      4  * Copyright (C) 2011 Research In Motion Limited. All rights reserved.
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Library General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Library General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Library General Public License
     17  * along with this library; see the file COPYING.LIB.  If not, write to
     18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19  * Boston, MA 02110-1301, USA.
     20  */
     21 
     22 #include "config.h"
     23 #include "core/css/PropertySetCSSStyleDeclaration.h"
     24 
     25 #include "bindings/v8/ExceptionState.h"
     26 #include "core/HTMLNames.h"
     27 #include "core/css/parser/BisonCSSParser.h"
     28 #include "core/css/CSSStyleSheet.h"
     29 #include "core/css/StylePropertySet.h"
     30 #include "core/dom/Element.h"
     31 #include "core/dom/MutationObserverInterestGroup.h"
     32 #include "core/dom/MutationRecord.h"
     33 #include "core/inspector/InspectorInstrumentation.h"
     34 #include "platform/RuntimeEnabledFeatures.h"
     35 
     36 namespace WebCore {
     37 
     38 namespace {
     39 
     40 class StyleAttributeMutationScope {
     41     WTF_MAKE_NONCOPYABLE(StyleAttributeMutationScope);
     42     STACK_ALLOCATED();
     43 public:
     44     StyleAttributeMutationScope(AbstractPropertySetCSSStyleDeclaration* decl)
     45     {
     46         InspectorInstrumentation::willMutateStyle(decl);
     47         ++s_scopeCount;
     48 
     49         if (s_scopeCount != 1) {
     50             ASSERT(s_currentDecl == decl);
     51             return;
     52         }
     53 
     54         ASSERT(!s_currentDecl);
     55         s_currentDecl = decl;
     56 
     57         if (!s_currentDecl->parentElement())
     58             return;
     59 
     60         bool shouldReadOldValue = false;
     61 
     62         m_mutationRecipients = MutationObserverInterestGroup::createForAttributesMutation(*s_currentDecl->parentElement(), HTMLNames::styleAttr);
     63         if (m_mutationRecipients && m_mutationRecipients->isOldValueRequested())
     64             shouldReadOldValue = true;
     65 
     66         AtomicString oldValue;
     67         if (shouldReadOldValue)
     68             oldValue = s_currentDecl->parentElement()->getAttribute(HTMLNames::styleAttr);
     69 
     70         if (m_mutationRecipients) {
     71             AtomicString requestedOldValue = m_mutationRecipients->isOldValueRequested() ? oldValue : nullAtom;
     72             m_mutation = MutationRecord::createAttributes(s_currentDecl->parentElement(), HTMLNames::styleAttr, requestedOldValue);
     73         }
     74     }
     75 
     76     ~StyleAttributeMutationScope()
     77     {
     78         --s_scopeCount;
     79         if (s_scopeCount)
     80             return;
     81 
     82         if (m_mutation && s_shouldDeliver)
     83             m_mutationRecipients->enqueueMutationRecord(m_mutation);
     84 
     85         s_shouldDeliver = false;
     86 
     87         // We have to clear internal state before calling Inspector's code.
     88         AbstractPropertySetCSSStyleDeclaration* localCopyStyleDecl = s_currentDecl;
     89         s_currentDecl = 0;
     90         InspectorInstrumentation::didMutateStyle(localCopyStyleDecl, localCopyStyleDecl->parentElement());
     91 
     92         if (!s_shouldNotifyInspector)
     93             return;
     94 
     95         s_shouldNotifyInspector = false;
     96         if (localCopyStyleDecl->parentElement())
     97             InspectorInstrumentation::didInvalidateStyleAttr(localCopyStyleDecl->parentElement());
     98     }
     99 
    100     void enqueueMutationRecord()
    101     {
    102         s_shouldDeliver = true;
    103     }
    104 
    105     void didInvalidateStyleAttr()
    106     {
    107         s_shouldNotifyInspector = true;
    108     }
    109 
    110 private:
    111     static unsigned s_scopeCount;
    112     static AbstractPropertySetCSSStyleDeclaration* s_currentDecl;
    113     static bool s_shouldNotifyInspector;
    114     static bool s_shouldDeliver;
    115 
    116     OwnPtrWillBeMember<MutationObserverInterestGroup> m_mutationRecipients;
    117     RefPtrWillBeMember<MutationRecord> m_mutation;
    118 };
    119 
    120 unsigned StyleAttributeMutationScope::s_scopeCount = 0;
    121 AbstractPropertySetCSSStyleDeclaration* StyleAttributeMutationScope::s_currentDecl = 0;
    122 bool StyleAttributeMutationScope::s_shouldNotifyInspector = false;
    123 bool StyleAttributeMutationScope::s_shouldDeliver = false;
    124 
    125 } // namespace
    126 
    127 #if !ENABLE(OILPAN)
    128 void PropertySetCSSStyleDeclaration::ref()
    129 {
    130     m_propertySet->ref();
    131 }
    132 
    133 void PropertySetCSSStyleDeclaration::deref()
    134 {
    135     m_propertySet->deref();
    136 }
    137 #endif
    138 
    139 void PropertySetCSSStyleDeclaration::trace(Visitor* visitor)
    140 {
    141     visitor->trace(m_propertySet);
    142     AbstractPropertySetCSSStyleDeclaration::trace(visitor);
    143 }
    144 
    145 unsigned AbstractPropertySetCSSStyleDeclaration::length() const
    146 {
    147     return propertySet().propertyCount();
    148 }
    149 
    150 String AbstractPropertySetCSSStyleDeclaration::item(unsigned i) const
    151 {
    152     if (i >= propertySet().propertyCount())
    153         return "";
    154     return propertySet().propertyAt(i).cssName();
    155 }
    156 
    157 String AbstractPropertySetCSSStyleDeclaration::cssText() const
    158 {
    159     return propertySet().asText();
    160 }
    161 
    162 void AbstractPropertySetCSSStyleDeclaration::setCSSText(const String& text, ExceptionState& exceptionState)
    163 {
    164     StyleAttributeMutationScope mutationScope(this);
    165     willMutate();
    166 
    167     // FIXME: Detect syntax errors and set exceptionState.
    168     propertySet().parseDeclaration(text, contextStyleSheet());
    169 
    170     didMutate(PropertyChanged);
    171 
    172     mutationScope.enqueueMutationRecord();
    173 }
    174 
    175 PassRefPtrWillBeRawPtr<CSSValue> AbstractPropertySetCSSStyleDeclaration::getPropertyCSSValue(const String& propertyName)
    176 {
    177     CSSPropertyID propertyID = cssPropertyID(propertyName);
    178     if (!propertyID)
    179         return nullptr;
    180     return cloneAndCacheForCSSOM(propertySet().getPropertyCSSValue(propertyID).get());
    181 }
    182 
    183 String AbstractPropertySetCSSStyleDeclaration::getPropertyValue(const String &propertyName)
    184 {
    185     CSSPropertyID propertyID = cssPropertyID(propertyName);
    186     if (!propertyID)
    187         return String();
    188     return propertySet().getPropertyValue(propertyID);
    189 }
    190 
    191 String AbstractPropertySetCSSStyleDeclaration::getPropertyPriority(const String& propertyName)
    192 {
    193     CSSPropertyID propertyID = cssPropertyID(propertyName);
    194     if (!propertyID)
    195         return String();
    196     return propertySet().propertyIsImportant(propertyID) ? "important" : "";
    197 }
    198 
    199 String AbstractPropertySetCSSStyleDeclaration::getPropertyShorthand(const String& propertyName)
    200 {
    201     CSSPropertyID propertyID = cssPropertyID(propertyName);
    202     if (!propertyID)
    203         return String();
    204     CSSPropertyID shorthandID = propertySet().getPropertyShorthand(propertyID);
    205     if (!shorthandID)
    206         return String();
    207     return getPropertyNameString(shorthandID);
    208 }
    209 
    210 bool AbstractPropertySetCSSStyleDeclaration::isPropertyImplicit(const String& propertyName)
    211 {
    212     CSSPropertyID propertyID = cssPropertyID(propertyName);
    213     if (!propertyID)
    214         return false;
    215     return propertySet().isPropertyImplicit(propertyID);
    216 }
    217 
    218 void AbstractPropertySetCSSStyleDeclaration::setProperty(const String& propertyName, const String& value, const String& priority, ExceptionState& exceptionState)
    219 {
    220     CSSPropertyID propertyID = cssPropertyID(propertyName);
    221     if (!propertyID)
    222         return;
    223 
    224     bool important = equalIgnoringCase(priority, "important");
    225     if (!important && !priority.isEmpty())
    226         return;
    227 
    228     setPropertyInternal(propertyID, value, important, exceptionState);
    229 }
    230 
    231 String AbstractPropertySetCSSStyleDeclaration::removeProperty(const String& propertyName, ExceptionState& exceptionState)
    232 {
    233     StyleAttributeMutationScope mutationScope(this);
    234     CSSPropertyID propertyID = cssPropertyID(propertyName);
    235     if (!propertyID)
    236         return String();
    237 
    238     willMutate();
    239 
    240     String result;
    241     bool changed = propertySet().removeProperty(propertyID, &result);
    242 
    243     didMutate(changed ? PropertyChanged : NoChanges);
    244 
    245     if (changed)
    246         mutationScope.enqueueMutationRecord();
    247     return result;
    248 }
    249 
    250 PassRefPtrWillBeRawPtr<CSSValue> AbstractPropertySetCSSStyleDeclaration::getPropertyCSSValueInternal(CSSPropertyID propertyID)
    251 {
    252     return propertySet().getPropertyCSSValue(propertyID);
    253 }
    254 
    255 String AbstractPropertySetCSSStyleDeclaration::getPropertyValueInternal(CSSPropertyID propertyID)
    256 {
    257     return propertySet().getPropertyValue(propertyID);
    258 }
    259 
    260 void AbstractPropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID propertyID, const String& value, bool important, ExceptionState&)
    261 {
    262     StyleAttributeMutationScope mutationScope(this);
    263     willMutate();
    264 
    265     bool changed = propertySet().setProperty(propertyID, value, important, contextStyleSheet());
    266 
    267     didMutate(changed ? PropertyChanged : NoChanges);
    268 
    269     if (changed)
    270         mutationScope.enqueueMutationRecord();
    271 }
    272 
    273 CSSValue* AbstractPropertySetCSSStyleDeclaration::cloneAndCacheForCSSOM(CSSValue* internalValue)
    274 {
    275     if (!internalValue)
    276         return 0;
    277 
    278     // The map is here to maintain the object identity of the CSSValues over multiple invocations.
    279     // FIXME: It is likely that the identity is not important for web compatibility and this code should be removed.
    280     if (!m_cssomCSSValueClones)
    281         m_cssomCSSValueClones = adoptPtrWillBeNoop(new WillBeHeapHashMap<RawPtrWillBeMember<CSSValue>, RefPtrWillBeMember<CSSValue> >);
    282 
    283     RefPtrWillBeMember<CSSValue>& clonedValue = m_cssomCSSValueClones->add(internalValue, RefPtrWillBeMember<CSSValue>()).storedValue->value;
    284     if (!clonedValue)
    285         clonedValue = internalValue->cloneForCSSOM();
    286     return clonedValue.get();
    287 }
    288 
    289 StyleSheetContents* AbstractPropertySetCSSStyleDeclaration::contextStyleSheet() const
    290 {
    291     CSSStyleSheet* cssStyleSheet = parentStyleSheet();
    292     return cssStyleSheet ? cssStyleSheet->contents() : 0;
    293 }
    294 
    295 PassRefPtrWillBeRawPtr<MutableStylePropertySet> AbstractPropertySetCSSStyleDeclaration::copyProperties() const
    296 {
    297     return propertySet().mutableCopy();
    298 }
    299 
    300 bool AbstractPropertySetCSSStyleDeclaration::cssPropertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
    301 {
    302     return propertySet().propertyMatches(propertyID, propertyValue);
    303 }
    304 
    305 void AbstractPropertySetCSSStyleDeclaration::trace(Visitor* visitor)
    306 {
    307 #if ENABLE(OILPAN)
    308     visitor->trace(m_cssomCSSValueClones);
    309 #endif
    310     CSSStyleDeclaration::trace(visitor);
    311 }
    312 
    313 StyleRuleCSSStyleDeclaration::StyleRuleCSSStyleDeclaration(MutableStylePropertySet& propertySetArg, CSSRule* parentRule)
    314     : PropertySetCSSStyleDeclaration(propertySetArg)
    315 #if !ENABLE(OILPAN)
    316     , m_refCount(1)
    317 #endif
    318     , m_parentRule(parentRule)
    319 {
    320 #if !ENABLE(OILPAN)
    321     m_propertySet->ref();
    322 #endif
    323 }
    324 
    325 StyleRuleCSSStyleDeclaration::~StyleRuleCSSStyleDeclaration()
    326 {
    327 #if !ENABLE(OILPAN)
    328     m_propertySet->deref();
    329 #endif
    330 }
    331 
    332 #if !ENABLE(OILPAN)
    333 void StyleRuleCSSStyleDeclaration::ref()
    334 {
    335     ++m_refCount;
    336 }
    337 
    338 void StyleRuleCSSStyleDeclaration::deref()
    339 {
    340     ASSERT(m_refCount);
    341     if (!--m_refCount)
    342         delete this;
    343 }
    344 #endif
    345 
    346 void StyleRuleCSSStyleDeclaration::willMutate()
    347 {
    348     if (m_parentRule && m_parentRule->parentStyleSheet())
    349         m_parentRule->parentStyleSheet()->willMutateRules();
    350 }
    351 
    352 void StyleRuleCSSStyleDeclaration::didMutate(MutationType type)
    353 {
    354     if (type == PropertyChanged)
    355         m_cssomCSSValueClones.clear();
    356 
    357     // Style sheet mutation needs to be signaled even if the change failed. willMutateRules/didMutateRules must pair.
    358     if (m_parentRule && m_parentRule->parentStyleSheet())
    359         m_parentRule->parentStyleSheet()->didMutateRules();
    360 }
    361 
    362 CSSStyleSheet* StyleRuleCSSStyleDeclaration::parentStyleSheet() const
    363 {
    364     return m_parentRule ? m_parentRule->parentStyleSheet() : 0;
    365 }
    366 
    367 void StyleRuleCSSStyleDeclaration::reattach(MutableStylePropertySet& propertySet)
    368 {
    369 #if !ENABLE(OILPAN)
    370     m_propertySet->deref();
    371 #endif
    372     m_propertySet = &propertySet;
    373 #if !ENABLE(OILPAN)
    374     m_propertySet->ref();
    375 #endif
    376 }
    377 
    378 void StyleRuleCSSStyleDeclaration::trace(Visitor* visitor)
    379 {
    380     visitor->trace(m_parentRule);
    381     PropertySetCSSStyleDeclaration::trace(visitor);
    382 }
    383 
    384 MutableStylePropertySet& InlineCSSStyleDeclaration::propertySet() const
    385 {
    386     return m_parentElement->ensureMutableInlineStyle();
    387 }
    388 
    389 void InlineCSSStyleDeclaration::didMutate(MutationType type)
    390 {
    391     if (type == NoChanges)
    392         return;
    393 
    394     m_cssomCSSValueClones.clear();
    395 
    396     if (!m_parentElement)
    397         return;
    398 
    399     m_parentElement->clearMutableInlineStyleIfEmpty();
    400     m_parentElement->setNeedsStyleRecalc(LocalStyleChange);
    401     m_parentElement->invalidateStyleAttribute();
    402     StyleAttributeMutationScope(this).didInvalidateStyleAttr();
    403 }
    404 
    405 CSSStyleSheet* InlineCSSStyleDeclaration::parentStyleSheet() const
    406 {
    407     return m_parentElement ? &m_parentElement->document().elementSheet() : 0;
    408 }
    409 
    410 #if !ENABLE(OILPAN)
    411 void InlineCSSStyleDeclaration::ref()
    412 {
    413     m_parentElement->ref();
    414 }
    415 
    416 void InlineCSSStyleDeclaration::deref()
    417 {
    418     m_parentElement->deref();
    419 }
    420 #endif
    421 
    422 void InlineCSSStyleDeclaration::trace(Visitor* visitor)
    423 {
    424     visitor->trace(m_parentElement);
    425     AbstractPropertySetCSSStyleDeclaration::trace(visitor);
    426 }
    427 
    428 } // namespace WebCore
    429