Home | History | Annotate | Download | only in resolver
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde (at) carewolf.com)
      4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit (at) nickshanks.com)
      5  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
      6  * Copyright (C) 2007 Alexey Proskuryakov <ap (at) webkit.org>
      7  * Copyright (C) 2007, 2008 Eric Seidel <eric (at) webkit.org>
      8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
      9  * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
     10  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
     11  * Copyright (C) 2013 Google Inc. All rights reserved.
     12  *
     13  * This library is free software; you can redistribute it and/or
     14  * modify it under the terms of the GNU Library General Public
     15  * License as published by the Free Software Foundation; either
     16  * version 2 of the License, or (at your option) any later version.
     17  *
     18  * This library is distributed in the hope that it will be useful,
     19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     21  * Library General Public License for more details.
     22  *
     23  * You should have received a copy of the GNU Library General Public License
     24  * along with this library; see the file COPYING.LIB.  If not, write to
     25  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     26  * Boston, MA 02110-1301, USA.
     27  */
     28 
     29 #include "config.h"
     30 #include "core/css/resolver/MatchedPropertiesCache.h"
     31 
     32 #include "core/css/StylePropertySet.h"
     33 #include "core/css/resolver/StyleResolverState.h"
     34 #include "core/rendering/style/RenderStyle.h"
     35 
     36 namespace WebCore {
     37 
     38 void CachedMatchedProperties::set(const RenderStyle* style, const RenderStyle* parentStyle, const MatchResult& matchResult)
     39 {
     40     matchedProperties.appendVector(matchResult.matchedProperties);
     41     ranges = matchResult.ranges;
     42 
     43     // Note that we don't cache the original RenderStyle instance. It may be further modified.
     44     // The RenderStyle in the cache is really just a holder for the substructures and never used as-is.
     45     this->renderStyle = RenderStyle::clone(style);
     46     this->parentRenderStyle = RenderStyle::clone(parentStyle);
     47 }
     48 
     49 void CachedMatchedProperties::clear()
     50 {
     51     matchedProperties.clear();
     52     renderStyle = nullptr;
     53     parentRenderStyle = nullptr;
     54 }
     55 
     56 MatchedPropertiesCache::MatchedPropertiesCache()
     57     : m_additionsSinceLastSweep(0)
     58     , m_sweepTimer(this, &MatchedPropertiesCache::sweep)
     59 {
     60 }
     61 
     62 const CachedMatchedProperties* MatchedPropertiesCache::find(unsigned hash, const StyleResolverState& styleResolverState, const MatchResult& matchResult)
     63 {
     64     ASSERT(hash);
     65 
     66     Cache::iterator it = m_cache.find(hash);
     67     if (it == m_cache.end())
     68         return 0;
     69     CachedMatchedProperties* cacheItem = it->value.get();
     70     ASSERT(cacheItem);
     71 
     72     size_t size = matchResult.matchedProperties.size();
     73     if (size != cacheItem->matchedProperties.size())
     74         return 0;
     75     if (cacheItem->renderStyle->insideLink() != styleResolverState.style()->insideLink())
     76         return 0;
     77     for (size_t i = 0; i < size; ++i) {
     78         if (matchResult.matchedProperties[i] != cacheItem->matchedProperties[i])
     79             return 0;
     80     }
     81     if (cacheItem->ranges != matchResult.ranges)
     82         return 0;
     83     return cacheItem;
     84 }
     85 
     86 void MatchedPropertiesCache::add(const RenderStyle* style, const RenderStyle* parentStyle, unsigned hash, const MatchResult& matchResult)
     87 {
     88     static const unsigned maxAdditionsBetweenSweeps = 100;
     89     if (++m_additionsSinceLastSweep >= maxAdditionsBetweenSweeps
     90         && !m_sweepTimer.isActive()) {
     91         static const unsigned sweepTimeInSeconds = 60;
     92         m_sweepTimer.startOneShot(sweepTimeInSeconds, FROM_HERE);
     93     }
     94 
     95     ASSERT(hash);
     96     Cache::AddResult addResult = m_cache.add(hash, nullptr);
     97     if (addResult.isNewEntry)
     98         addResult.storedValue->value = adoptPtr(new CachedMatchedProperties);
     99 
    100     CachedMatchedProperties* cacheItem = addResult.storedValue->value.get();
    101     if (!addResult.isNewEntry)
    102         cacheItem->clear();
    103 
    104     cacheItem->set(style, parentStyle, matchResult);
    105 }
    106 
    107 void MatchedPropertiesCache::clear()
    108 {
    109     m_cache.clear();
    110 }
    111 
    112 void MatchedPropertiesCache::clearViewportDependent()
    113 {
    114     Vector<unsigned, 16> toRemove;
    115     for (Cache::iterator it = m_cache.begin(); it != m_cache.end(); ++it) {
    116         CachedMatchedProperties* cacheItem = it->value.get();
    117         if (cacheItem->renderStyle->hasViewportUnits())
    118             toRemove.append(it->key);
    119     }
    120     m_cache.removeAll(toRemove);
    121 }
    122 
    123 void MatchedPropertiesCache::sweep(Timer<MatchedPropertiesCache>*)
    124 {
    125     // Look for cache entries containing a style declaration with a single ref and remove them.
    126     // This may happen when an element attribute mutation causes it to generate a new inlineStyle()
    127     // or presentationAttributeStyle(), potentially leaving this cache with the last ref on the old one.
    128     Vector<unsigned, 16> toRemove;
    129     Cache::iterator it = m_cache.begin();
    130     Cache::iterator end = m_cache.end();
    131     for (; it != end; ++it) {
    132         CachedMatchedProperties* cacheItem = it->value.get();
    133         Vector<MatchedProperties>& matchedProperties = cacheItem->matchedProperties;
    134         for (size_t i = 0; i < matchedProperties.size(); ++i) {
    135             if (matchedProperties[i].properties->hasOneRef()) {
    136                 toRemove.append(it->key);
    137                 break;
    138             }
    139         }
    140     }
    141     m_cache.removeAll(toRemove);
    142     m_additionsSinceLastSweep = 0;
    143 }
    144 
    145 bool MatchedPropertiesCache::isCacheable(const Element* element, const RenderStyle* style, const RenderStyle* parentStyle)
    146 {
    147     // FIXME: CSSPropertyWebkitWritingMode modifies state when applying to document element. We can't skip the applying by caching.
    148     if (element == element->document().documentElement() && element->document().writingModeSetOnDocumentElement())
    149         return false;
    150     if (style->unique() || (style->styleType() != NOPSEUDO && parentStyle->unique()))
    151         return false;
    152     if (style->hasAppearance())
    153         return false;
    154     if (style->zoom() != RenderStyle::initialZoom())
    155         return false;
    156     if (style->writingMode() != RenderStyle::initialWritingMode())
    157         return false;
    158     if (style->hasCurrentColor())
    159         return false;
    160     // CSSPropertyInternalCallback sets the rule's selector name into the RenderStyle, and that's not recalculated if the RenderStyle is loaded from the cache, so don't cache it.
    161     if (!style->callbackSelectors().isEmpty())
    162         return false;
    163     // The cache assumes static knowledge about which properties are inherited.
    164     if (parentStyle->hasExplicitlyInheritedProperties())
    165         return false;
    166     return true;
    167 }
    168 
    169 }
    170