Changeset 195970 in webkit


Ignore:
Timestamp:
Feb 1, 2016, 11:45:18 AM (10 years ago)
Author:
commit-queue@webkit.org
Message:

Cache the Path instead of creating it every time it is required
https://bugs.webkit.org/show_bug.cgi?id=152939

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2016-02-01
Reviewed by Darin Adler.

Source/WebCore:

Instead of creating the Path object every time it is required, we should
cache it in an LRU cache. TinyLRUCache returns a reference to the cached
entry so we do not have to pay the cost of copying it either.

  • platform/graphics/FloatRoundedRect.h:

(WebCore::operator!=):
Implement the inequality operator for FloatRoundedRect since it is
called by TinyLRUCache.

  • rendering/ClipPathOperation.h:

Return a reference to the path in the cache since instead of creating a
new copy.

  • rendering/style/BasicShapes.cpp:

(WebCore::SVGPathTranslatedByteStream::SVGPathTranslatedByteStream):
(WebCore::SVGPathTranslatedByteStream::operator==):
(WebCore::SVGPathTranslatedByteStream::operator!=):
(WebCore::SVGPathTranslatedByteStream::isEmpty):
(WebCore::SVGPathTranslatedByteStream::path):
This struct holds an offset and an SVGPathByteStream. It is the key of
the LRU cache for the the translated SVGPathByteStream.

(WebCore::EllipsePathPolicy::isKeyNull):
(WebCore::EllipsePathPolicy::createValueForKey):
(WebCore::RoundedRectPathPolicy::isKeyNull):
(WebCore::RoundedRectPathPolicy::createValueForKey):
(WebCore::PolygonPathPolicy::isKeyNull):
(WebCore::PolygonPathPolicy::createValueForKey):
(WebCore::TranslatedByteStreamPathPolicy::isKeyNull):
(WebCore::TranslatedByteStreamPathPolicy::createValueForKey):
Inherit from the LRU cache policy template, so have a specific name for
the desired path contents and pass this class explicitly to the LRU cache
template.

(WebCore::cachedEllipsePath):
(WebCore::cachedRoundedRectPath):
(WebCore::cachedPolygonPath):
(WebCore::cachedTranslatedByteStreamPath):
Return a cached path object for specific path contents.

(WebCore::BasicShapeCircle::path):
(WebCore::BasicShapeEllipse::path):
(WebCore::BasicShapePolygon::path):
(WebCore::BasicShapePath::path):
(WebCore::BasicShapeInset::path):
Get the Path object from the cache; create a new one if it does not exist.

  • rendering/style/BasicShapes.h:

Change the prototype of the path() function to return a reference to the
path in the cache instead of a having to copying it.

  • svg/SVGPathByteStream.h:

(WebCore::SVGPathByteStream::operator!=):
Implement the inequality operator for SVGPathByteStream because it is
called by TinyLRUCache.

Source/WTF:

If the key type of an LRU cache can't to be strongly tided to a specific
data type; e.g. FloatRect -> Path, we need to be able to pass the policy
type to the TinyLRUCache template instead of just specializing it. This
will make the code more readable and will allow different caches for the
same key type.

  • wtf/TinyLRUCache.h:

(WebCore::TinyLRUCache::get):

Location:
trunk/Source
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r195968 r195970  
     12016-02-01  Said Abou-Hallawa  <sabouhallawa@apple.com>
     2
     3        Cache the Path instead of creating it every time it is required
     4        https://bugs.webkit.org/show_bug.cgi?id=152939
     5
     6        Reviewed by Darin Adler.
     7
     8        If the key type of an LRU cache can't to be strongly tided to a specific
     9        data type; e.g. FloatRect -> Path, we need to be able to pass the policy
     10        type to the TinyLRUCache template instead of just specializing it. This
     11        will make the code more readable and will allow different caches for the
     12        same key type.
     13
     14        * wtf/TinyLRUCache.h:
     15        (WebCore::TinyLRUCache::get):
     16
    1172016-02-01  Alex Christensen  <achristensen@webkit.org>
    218
  • trunk/Source/WTF/wtf/TinyLRUCache.h

    r195356 r195970  
    3939};
    4040
    41 template<typename KeyType, typename ValueType, size_t capacity = 4>
     41template<typename KeyType, typename ValueType, size_t capacity = 4, typename Policy = TinyLRUCachePolicy<KeyType, ValueType>>
    4242class TinyLRUCache {
    4343public:
    4444    const ValueType& get(const KeyType& key)
    4545    {
    46         if (TinyLRUCachePolicy<KeyType, ValueType>::isKeyNull(key)) {
    47             static NeverDestroyed<ValueType> valueForNull = TinyLRUCachePolicy<KeyType, ValueType>::createValueForNullKey();
     46        if (Policy::isKeyNull(key)) {
     47            static NeverDestroyed<ValueType> valueForNull = Policy::createValueForNullKey();
    4848            return valueForNull;
    4949        }
     
    6767            m_cache.remove(0);
    6868
    69         m_cache.append(std::make_pair(key, TinyLRUCachePolicy<KeyType, ValueType>::createValueForKey(key)));
     69        m_cache.append(std::make_pair(key, Policy::createValueForKey(key)));
    7070        return m_cache.last().second;
    7171    }
  • trunk/Source/WebCore/ChangeLog

    r195969 r195970  
     12016-02-01  Said Abou-Hallawa  <sabouhallawa@apple.com>
     2
     3        Cache the Path instead of creating it every time it is required
     4        https://bugs.webkit.org/show_bug.cgi?id=152939
     5
     6        Reviewed by Darin Adler.
     7
     8        Instead of creating the Path object every time it is required, we should
     9        cache it in an LRU cache. TinyLRUCache returns a reference to the cached
     10        entry so we do not have to pay the cost of copying it either.
     11
     12        * platform/graphics/FloatRoundedRect.h:
     13        (WebCore::operator!=):
     14        Implement the inequality operator for FloatRoundedRect since it is
     15        called by TinyLRUCache.
     16       
     17        * rendering/ClipPathOperation.h:
     18        Return a reference to the path in the cache since instead of creating a
     19        new copy.
     20       
     21        * rendering/style/BasicShapes.cpp:
     22        (WebCore::SVGPathTranslatedByteStream::SVGPathTranslatedByteStream):
     23        (WebCore::SVGPathTranslatedByteStream::operator==):
     24        (WebCore::SVGPathTranslatedByteStream::operator!=):
     25        (WebCore::SVGPathTranslatedByteStream::isEmpty):
     26        (WebCore::SVGPathTranslatedByteStream::path):
     27        This struct holds an offset and an SVGPathByteStream. It is the key of
     28        the LRU cache for the the translated SVGPathByteStream.
     29       
     30        (WebCore::EllipsePathPolicy::isKeyNull):
     31        (WebCore::EllipsePathPolicy::createValueForKey):
     32        (WebCore::RoundedRectPathPolicy::isKeyNull):
     33        (WebCore::RoundedRectPathPolicy::createValueForKey):
     34        (WebCore::PolygonPathPolicy::isKeyNull):
     35        (WebCore::PolygonPathPolicy::createValueForKey):
     36        (WebCore::TranslatedByteStreamPathPolicy::isKeyNull):
     37        (WebCore::TranslatedByteStreamPathPolicy::createValueForKey):
     38        Inherit from the LRU cache policy template, so have a specific name for
     39        the desired path contents and pass this class explicitly to the LRU cache
     40        template.
     41       
     42        (WebCore::cachedEllipsePath):
     43        (WebCore::cachedRoundedRectPath):
     44        (WebCore::cachedPolygonPath):
     45        (WebCore::cachedTranslatedByteStreamPath):
     46        Return a cached path object for specific path contents.
     47       
     48        (WebCore::BasicShapeCircle::path):
     49        (WebCore::BasicShapeEllipse::path):
     50        (WebCore::BasicShapePolygon::path):
     51        (WebCore::BasicShapePath::path):
     52        (WebCore::BasicShapeInset::path):
     53        Get the Path object from the cache; create a new one if it does not exist.
     54       
     55        * rendering/style/BasicShapes.h:
     56        Change the prototype of the path() function to return a reference to the
     57        path in the cache instead of a having to copying it.
     58       
     59        * svg/SVGPathByteStream.h:
     60        (WebCore::SVGPathByteStream::operator!=):
     61        Implement the inequality operator for SVGPathByteStream because it is
     62        called by TinyLRUCache.
     63
    1642016-02-01  Chris Dumez  <cdumez@apple.com>
    265
  • trunk/Source/WebCore/platform/graphics/FloatRoundedRect.h

    r191243 r195970  
    142142}
    143143
     144inline bool operator!=(const FloatRoundedRect::Radii& a, const FloatRoundedRect::Radii& b)
     145{
     146    return !(a == b);
     147}
     148
    144149inline bool operator==(const FloatRoundedRect& a, const FloatRoundedRect& b)
    145150{
    146151    return a.rect() == b.rect() && a.radii() == b.radii();
     152}
     153
     154inline bool operator!=(const FloatRoundedRect& a, const FloatRoundedRect& b)
     155{
     156    return !(a == b);
    147157}
    148158
  • trunk/Source/WebCore/rendering/ClipPathOperation.h

    r194496 r195970  
    104104    const BasicShape& basicShape() const { return m_shape; }
    105105    WindRule windRule() const { return m_shape.get().windRule(); }
    106     const Path pathForReferenceRect(const FloatRect& boundingRect)
    107     {
    108         Path path;
    109         m_shape.get().path(path, boundingRect);
    110         return path;
    111     }
     106    const Path& pathForReferenceRect(const FloatRect& boundingRect) { return m_shape.get().path(boundingRect); }
    112107
    113108    void setReferenceBox(CSSBoxType referenceBox) { m_referenceBox = referenceBox; }
  • trunk/Source/WebCore/rendering/style/BasicShapes.cpp

    r194496 r195970  
    4242#include "SVGPathUtilities.h"
    4343
     44#include <wtf/NeverDestroyed.h>
     45#include <wtf/TinyLRUCache.h>
     46
    4447namespace WebCore {
    4548
     
    6164}
    6265
     66struct SVGPathTranslatedByteStream {
     67    SVGPathTranslatedByteStream(const FloatPoint& offset, const SVGPathByteStream& rawStream)
     68        : m_offset(offset)
     69        , m_rawStream(rawStream)
     70    { }
     71
     72    bool operator==(const SVGPathTranslatedByteStream& other) const { return other.m_offset == m_offset && other.m_rawStream == m_rawStream; }
     73    bool operator!=(const SVGPathTranslatedByteStream& other) const { return !(*this == other); }
     74    bool isEmpty() const { return m_rawStream.isEmpty(); }
     75
     76    Path path() const
     77    {
     78        Path path;
     79        buildPathFromByteStream(m_rawStream, path);
     80        path.translate(toFloatSize(m_offset));
     81        return path;
     82    }
     83   
     84    FloatPoint m_offset;
     85    SVGPathByteStream m_rawStream;
     86};
     87
     88struct EllipsePathPolicy : public TinyLRUCachePolicy<FloatRect, Path> {
     89public:
     90    static bool isKeyNull(const FloatRect& rect) { return rect.isEmpty(); }
     91
     92    static Path createValueForKey(const FloatRect& rect)
     93    {
     94        Path path;
     95        path.addEllipse(rect);
     96        return path;
     97    }
     98};
     99
     100struct RoundedRectPathPolicy : public TinyLRUCachePolicy<FloatRoundedRect, Path> {
     101public:
     102    static bool isKeyNull(const FloatRoundedRect& rect) { return rect.isEmpty(); }
     103
     104    static Path createValueForKey(const FloatRoundedRect& rect)
     105    {
     106        Path path;
     107        path.addRoundedRect(rect);
     108        return path;
     109    }
     110};
     111
     112struct PolygonPathPolicy : public TinyLRUCachePolicy<Vector<FloatPoint>, Path> {
     113public:
     114    static bool isKeyNull(const Vector<FloatPoint>& points) { return !points.size(); }
     115
     116    static Path createValueForKey(const Vector<FloatPoint>& points) { return Path::polygonPathFromPoints(points); }
     117};
     118
     119struct TranslatedByteStreamPathPolicy : public TinyLRUCachePolicy<SVGPathTranslatedByteStream, Path> {
     120public:
     121    static bool isKeyNull(const SVGPathTranslatedByteStream& stream) { return stream.isEmpty(); }
     122
     123    static Path createValueForKey(const SVGPathTranslatedByteStream& stream) { return stream.path(); }
     124};
     125
     126static const Path& cachedEllipsePath(const FloatRect& rect)
     127{
     128    static NeverDestroyed<TinyLRUCache<FloatRect, Path, 4, EllipsePathPolicy>> cache;
     129    return cache.get().get(rect);
     130}
     131
     132static const Path& cachedRoundedRectPath(const FloatRoundedRect& rect)
     133{
     134    static NeverDestroyed<TinyLRUCache<FloatRoundedRect, Path, 4, RoundedRectPathPolicy>> cache;
     135    return cache.get().get(rect);
     136}
     137
     138static const Path& cachedPolygonPath(const Vector<FloatPoint>& points)
     139{
     140    static NeverDestroyed<TinyLRUCache<Vector<FloatPoint>, Path, 4, PolygonPathPolicy>> cache;
     141    return cache.get().get(points);
     142}
     143
     144static const Path& cachedTranslatedByteStreamPath(const SVGPathByteStream& stream, const FloatPoint& offset)
     145{
     146    static NeverDestroyed<TinyLRUCache<SVGPathTranslatedByteStream, Path, 4, TranslatedByteStreamPathPolicy>> cache;
     147    return cache.get().get(SVGPathTranslatedByteStream(offset, stream));
     148}
     149
    63150bool BasicShapeCircle::operator==(const BasicShape& other) const
    64151{
     
    89176}
    90177
    91 void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox)
    92 {
    93     ASSERT(path.isEmpty());
    94 
     178const Path& BasicShapeCircle::path(const FloatRect& boundingBox)
     179{
    95180    float centerX = floatValueForCenterCoordinate(m_centerX, boundingBox.width());
    96181    float centerY = floatValueForCenterCoordinate(m_centerY, boundingBox.height());
    97182    float radius = floatValueForRadiusInBox(boundingBox.width(), boundingBox.height());
    98     path.addEllipse(FloatRect(
    99         centerX - radius + boundingBox.x(),
    100         centerY - radius + boundingBox.y(),
    101         radius * 2,
    102         radius * 2
    103     ));
     183
     184    return cachedEllipsePath(FloatRect(centerX - radius + boundingBox.x(), centerY - radius + boundingBox.y(), radius * 2, radius * 2));
    104185}
    105186
     
    149230}
    150231
    151 void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox)
    152 {
    153     ASSERT(path.isEmpty());
    154 
     232const Path& BasicShapeEllipse::path(const FloatRect& boundingBox)
     233{
    155234    float centerX = floatValueForCenterCoordinate(m_centerX, boundingBox.width());
    156235    float centerY = floatValueForCenterCoordinate(m_centerY, boundingBox.height());
    157236    float radiusX = floatValueForRadiusInBox(m_radiusX, centerX, boundingBox.width());
    158237    float radiusY = floatValueForRadiusInBox(m_radiusY, centerY, boundingBox.height());
    159     path.addEllipse(FloatRect(
    160         centerX - radiusX + boundingBox.x(),
    161         centerY - radiusY + boundingBox.y(),
    162         radiusX * 2,
    163         radiusY * 2));
     238
     239    return cachedEllipsePath(FloatRect(centerX - radiusX + boundingBox.x(), centerY - radiusY + boundingBox.y(), radiusX * 2, radiusY * 2));
    164240}
    165241
     
    205281}
    206282
    207 void BasicShapePolygon::path(Path& path, const FloatRect& boundingBox)
    208 {
    209     ASSERT(path.isEmpty());
     283const Path& BasicShapePolygon::path(const FloatRect& boundingBox)
     284{
    210285    ASSERT(!(m_values.size() % 2));
    211286    size_t length = m_values.size();
    212    
    213     if (!length)
    214         return;
    215 
    216     path.moveTo(FloatPoint(floatValueForLength(m_values.at(0), boundingBox.width()) + boundingBox.x(),
    217         floatValueForLength(m_values.at(1), boundingBox.height()) + boundingBox.y()));
    218     for (size_t i = 2; i < length; i = i + 2) {
    219         path.addLineTo(FloatPoint(floatValueForLength(m_values.at(i), boundingBox.width()) + boundingBox.x(),
    220             floatValueForLength(m_values.at(i + 1), boundingBox.height()) + boundingBox.y()));
    221     }
    222     path.closeSubpath();
     287
     288    Vector<FloatPoint> points(length / 2);
     289    for (size_t i = 0; i < points.size(); ++i) {
     290        points[i].setX(floatValueForLength(m_values.at(i * 2), boundingBox.width()) + boundingBox.x());
     291        points[i].setY(floatValueForLength(m_values.at(i * 2 + 1), boundingBox.height()) + boundingBox.y());
     292    }
     293
     294    return cachedPolygonPath(points);
    223295}
    224296
     
    260332}
    261333
    262 void BasicShapePath::path(Path& path, const FloatRect& boundingBox)
    263 {
    264     ASSERT(path.isEmpty());
    265     buildPathFromByteStream(*m_byteStream, path);
    266     path.translate(toFloatSize(boundingBox.location()));
     334const Path& BasicShapePath::path(const FloatRect& boundingBox)
     335{
     336    return cachedTranslatedByteStreamPath(*m_byteStream, boundingBox.location());
    267337}
    268338
     
    321391}
    322392
    323 void BasicShapeInset::path(Path& path, const FloatRect& boundingBox)
    324 {
    325     ASSERT(path.isEmpty());
     393const Path& BasicShapeInset::path(const FloatRect& boundingBox)
     394{
    326395    float left = floatValueForLength(m_left, boundingBox.width());
    327396    float top = floatValueForLength(m_top, boundingBox.height());
     
    334403        floatSizeForLengthSize(m_bottomRightRadius, boundingBox));
    335404    radii.scale(calcBorderRadiiConstraintScaleFor(rect, radii));
    336     path.addRoundedRect(FloatRoundedRect(rect, radii));
     405
     406    return cachedRoundedRectPath(FloatRoundedRect(rect, radii));
    337407}
    338408
  • trunk/Source/WebCore/rendering/style/BasicShapes.h

    r194496 r195970  
    6161    virtual Type type() const = 0;
    6262
    63     virtual void path(Path&, const FloatRect&) = 0;
     63    virtual const Path& path(const FloatRect&) = 0;
    6464    virtual WindRule windRule() const { return RULE_NONZERO; }
    6565
     
    193193    virtual Type type() const override { return BasicShapeCircleType; }
    194194
    195     virtual void path(Path&, const FloatRect&) override;
     195    virtual const Path& path(const FloatRect&) override;
    196196
    197197    virtual bool canBlend(const BasicShape&) const override;
     
    225225    virtual Type type() const override { return BasicShapeEllipseType; }
    226226
    227     virtual void path(Path&, const FloatRect&) override;
     227    virtual const Path& path(const FloatRect&) override;
    228228
    229229    virtual bool canBlend(const BasicShape&) const override;
     
    256256    virtual Type type() const override { return BasicShapePolygonType; }
    257257
    258     virtual void path(Path&, const FloatRect&) override;
     258    virtual const Path& path(const FloatRect&) override;
    259259
    260260    virtual bool canBlend(const BasicShape&) const override;
     
    284284    virtual Type type() const override { return BasicShapePathType; }
    285285
    286     virtual void path(Path&, const FloatRect&) override;
     286    virtual const Path& path(const FloatRect&) override;
    287287
    288288    virtual bool canBlend(const BasicShape&) const override;
     
    324324    virtual Type type() const override { return BasicShapeInsetType; }
    325325
    326     virtual void path(Path&, const FloatRect&) override;
     326    virtual const Path& path(const FloatRect&) override;
    327327
    328328    virtual bool canBlend(const BasicShape&) const override;
  • trunk/Source/WebCore/svg/SVGPathByteStream.h

    r191551 r195970  
    5656    }
    5757
     58    bool operator!=(const SVGPathByteStream& other) const
     59    {
     60        return !(*this == other);
     61    }
     62
    5863    std::unique_ptr<SVGPathByteStream> copy() const
    5964    {
Note: See TracChangeset for help on using the changeset viewer.