Changeset 176212 in webkit


Ignore:
Timestamp:
Nov 17, 2014 11:23:43 AM (10 years ago)
Author:
Chris Dumez
Message:

Throttle timers that change the style of elements outside the viewport
https://bugs.webkit.org/show_bug.cgi?id=138292

Reviewed by Antti Koivisto.

Throttle timers that change the style of elements outside the viewport
to 1 second, similarly to what was already done for timers interacting
with non user observable plugins. To be conservative, we don't throttle
timers that also cause DOM Tree modifications (e.g. adding/removing
nodes, modify element attributes).

On huffingtonpost.com, the CPU usage is at ~17% when the top scrolling
banner is inside the viewport on my machine. Without this patch, CPU
usage would stay ~17% when the banner is outside the viewport. Thanks
to timer throttling, CPU usage now goes down to ~1.5%, without user
observable side effects. The timers get unthrottled when they are
inside the viewport again (i.e. due to scrolling or layout).

On espn.com, the CPU usage goes down from ~7% at the top of the page
to ~1% when scrolling to the bottom of the page. On ebay.com, CPU
usage goes down from ~25% at the top of the page to less than 1% when
scrolling to the bottom of the page.

Location:
trunk/Source/WebCore
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r176210 r176212  
     12014-11-17  Chris Dumez  <cdumez@apple.com>
     2
     3        Throttle timers that change the style of elements outside the viewport
     4        https://bugs.webkit.org/show_bug.cgi?id=138292
     5
     6        Reviewed by Antti Koivisto.
     7
     8        Throttle timers that change the style of elements outside the viewport
     9        to 1 second, similarly to what was already done for timers interacting
     10        with non user observable plugins. To be conservative, we don't throttle
     11        timers that also cause DOM Tree modifications (e.g. adding/removing
     12        nodes, modify element attributes).
     13
     14        On huffingtonpost.com, the CPU usage is at ~17% when the top scrolling
     15        banner is inside the viewport on my machine. Without this patch, CPU
     16        usage would stay ~17% when the banner is outside the viewport. Thanks
     17        to timer throttling, CPU usage now goes down to ~1.5%, without user
     18        observable side effects. The timers get unthrottled when they are
     19        inside the viewport again (i.e. due to scrolling or layout).
     20
     21        On espn.com, the CPU usage goes down from ~7% at the top of the page
     22        to ~1% when scrolling to the bottom of the page. On ebay.com, CPU
     23        usage goes down from ~25% at the top of the page to less than 1% when
     24        scrolling to the bottom of the page.
     25
    1262014-11-17  peavo@outlook.com  <peavo@outlook.com>
    227
  • trunk/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp

    r173410 r176212  
    340340
    341341    ExceptionCode ec = 0;
    342     impl().setPropertyInternal(static_cast<CSSPropertyID>(propertyInfo.propertyID), propValue, important, ec);
     342    bool changed = impl().setPropertyInternal(static_cast<CSSPropertyID>(propertyInfo.propertyID), propValue, important, ec);
    343343    setDOMException(exec, ec);
     344
     345    // Choke point for interaction with style of element; notify DOMTimer of the event.
     346    if (auto* element = impl().parentElement())
     347        DOMTimer::scriptDidUpdateStyleOfElement(*element, changed);
     348
    344349    return true;
    345350}
  • trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp

    r176050 r176212  
    33323332}
    33333333
    3334 void CSSComputedStyleDeclaration::setPropertyInternal(CSSPropertyID, const String&, bool, ExceptionCode& ec)
     3334bool CSSComputedStyleDeclaration::setPropertyInternal(CSSPropertyID, const String&, bool, ExceptionCode& ec)
    33353335{
    33363336    ec = NO_MODIFICATION_ALLOWED_ERR;
     3337    return false;
    33373338}
    33383339
  • trunk/Source/WebCore/css/CSSComputedStyleDeclaration.h

    r175391 r176212  
    115115    virtual PassRefPtr<CSSValue> getPropertyCSSValueInternal(CSSPropertyID) override;
    116116    virtual String getPropertyValueInternal(CSSPropertyID) override;
    117     virtual void setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) override;
     117    virtual bool setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) override;
    118118    virtual PassRef<MutableStyleProperties> copyProperties() const override;
    119119
  • trunk/Source/WebCore/css/CSSStyleDeclaration.h

    r159856 r176212  
    4646    virtual void deref() = 0;
    4747
     48    virtual StyledElement* parentElement() const { return nullptr; }
    4849    virtual CSSRule* parentRule() const = 0;
    4950    virtual String cssText() const = 0;
     
    6465    virtual PassRefPtr<CSSValue> getPropertyCSSValueInternal(CSSPropertyID) = 0;
    6566    virtual String getPropertyValueInternal(CSSPropertyID) = 0;
    66     virtual void setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) = 0;
     67    virtual bool setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) = 0;
    6768
    6869    virtual PassRef<MutableStyleProperties> copyProperties() const = 0;
  • trunk/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp

    r173659 r176212  
    256256}
    257257
    258 void PropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID propertyID, const String& value, bool important, ExceptionCode& ec)
     258bool PropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID propertyID, const String& value, bool important, ExceptionCode& ec)
    259259{
    260260    StyleAttributeMutationScope mutationScope(this);
    261261    if (!willMutate())
    262         return;
     262        return false;
    263263
    264264    ec = 0;
     
    269269    if (changed)
    270270        mutationScope.enqueueMutationRecord();
     271    return changed;
    271272}
    272273
  • trunk/Source/WebCore/css/PropertySetCSSStyleDeclaration.h

    r175391 r176212  
    4545    PropertySetCSSStyleDeclaration(MutableStyleProperties* propertySet) : m_propertySet(propertySet) { }
    4646   
    47     virtual StyledElement* parentElement() const { return nullptr; }
    4847    virtual void clearParentElement() { ASSERT_NOT_REACHED(); }
    4948    StyleSheetContents* contextStyleSheet() const;
     
    6766    virtual PassRefPtr<CSSValue> getPropertyCSSValueInternal(CSSPropertyID) override final;
    6867    virtual String getPropertyValueInternal(CSSPropertyID) override final;
    69     virtual void setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) override final;
     68    virtual bool setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) override final;
    7069   
    7170    virtual PassRef<MutableStyleProperties> copyProperties() const override final;
  • trunk/Source/WebCore/dom/Element.cpp

    r176084 r176212  
    23482348}
    23492349
     2350bool Element::isInsideViewport(const IntRect* visibleRect) const
     2351{
     2352    return renderer() && renderer()->isInsideViewport(visibleRect);
     2353}
     2354
    23502355DOMTokenList& Element::classList()
    23512356{
  • trunk/Source/WebCore/dom/Element.h

    r176174 r176212  
    201201    double offsetHeight();
    202202
     203    bool isInsideViewport(const IntRect* visibleRect = nullptr) const;
     204
    203205    // FIXME: Replace uses of offsetParent in the platform with calls
    204206    // to the render layer and merge bindingsOffsetParent and offsetParent.
  • trunk/Source/WebCore/page/DOMTimer.cpp

    r176065 r176212  
    11/*
    2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
     2 * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2828#include "DOMTimer.h"
    2929
     30#include "FrameView.h"
    3031#include "HTMLPlugInElement.h"
    3132#include "InspectorInstrumentation.h"
     33#include "Logging.h"
    3234#include "PluginViewBase.h"
    3335#include "ScheduledAction.h"
     
    5153
    5254static const int maxIntervalForUserGestureForwarding = 1000; // One second matches Gecko.
    53 static const int minIntervalForNonUserObservablePluginScriptTimers = 1000; // Empirically determined to maximize battery life.
     55static const int minIntervalForNonUserObservableChangeTimers = 1000; // Empirically determined to maximize battery life.
    5456static const int maxTimerNestingLevel = 5;
    5557static const double oneMillisecond = 0.001;
    5658
    57 struct DOMTimerFireState {
     59class DOMTimerFireState {
     60public:
    5861    explicit DOMTimerFireState(ScriptExecutionContext& context)
    59         : scriptDidInteractWithNonUserObservablePlugin(false)
    60         , scriptDidInteractWithUserObservablePlugin(false)
    61         , shouldSetCurrent(is<Document>(context))
     62        : m_context(context)
     63        , m_contextIsDocument(is<Document>(m_context))
    6264    {
    6365        // For worker threads, don't update the current DOMTimerFireState.
    6466        // Setting this from workers would not be thread-safe, and its not relevant to current uses.
    65         if (shouldSetCurrent) {
    66             previous = current;
     67        if (m_contextIsDocument) {
     68            m_initialDOMTreeVersion = downcast<Document>(context).domTreeVersion();
     69            m_previous = current;
    6770            current = this;
    6871        }
     
    7174    ~DOMTimerFireState()
    7275    {
    73         if (shouldSetCurrent)
    74             current = previous;
     76        if (m_contextIsDocument)
     77            current = m_previous;
     78    }
     79
     80    void setScriptMadeUserObservableChanges() { m_scriptMadeUserObservableChanges = true; }
     81    void setScriptMadeNonUserObservableChanges() { m_scriptMadeNonUserObservableChanges = true; }
     82    void setScriptMadeNonUserObservableChangesToElementStyle(StyledElement& element)
     83    {
     84        m_scriptMadeNonUserObservableChanges = true;
     85        m_elementsChangedOutsideViewport.add(&element);
     86    }
     87
     88    bool scriptMadeNonUserObservableChanges() const { return m_scriptMadeNonUserObservableChanges; }
     89    bool scriptMadeUserObservableChanges() const
     90    {
     91        if (m_scriptMadeUserObservableChanges)
     92            return true;
     93
     94        // To be conservative, we also consider any DOM Tree change to be user observable.
     95        return m_contextIsDocument && downcast<Document>(m_context).domTreeVersion() != m_initialDOMTreeVersion;
     96    }
     97
     98    void setChangedStyleOfElementOutsideViewport(StyledElement& element)
     99    {
     100        m_elementsChangedOutsideViewport.add(&element);
     101    }
     102
     103    void elementsChangedOutsideViewport(Vector<RefPtr<StyledElement>>& elements) const
     104    {
     105        copyToVector(m_elementsChangedOutsideViewport, elements);
    75106    }
    76107
    77108    static DOMTimerFireState* current;
    78109
    79     bool scriptDidInteractWithNonUserObservablePlugin;
    80     bool scriptDidInteractWithUserObservablePlugin;
    81 
    82110private:
    83     bool shouldSetCurrent;
    84     DOMTimerFireState* previous;
     111    ScriptExecutionContext& m_context;
     112    uint64_t m_initialDOMTreeVersion;
     113    DOMTimerFireState* m_previous;
     114    HashSet<RefPtr<StyledElement>> m_elementsChangedOutsideViewport;
     115    bool m_contextIsDocument;
     116    bool m_scriptMadeNonUserObservableChanges { false };
     117    bool m_scriptMadeUserObservableChanges { false };
    85118};
    86119
     
    169202    else
    170203        startRepeating(m_currentTimerInterval);
     204}
     205
     206DOMTimer::~DOMTimer()
     207{
     208    if (isIntervalDependentOnViewport())
     209        unregisterForViewportChanges();
    171210}
    172211
     
    215254void DOMTimer::updateThrottlingStateIfNecessary(const DOMTimerFireState& fireState)
    216255{
    217     if (fireState.scriptDidInteractWithUserObservablePlugin) {
     256    if (fireState.scriptMadeUserObservableChanges()) {
    218257        if (m_throttleState != ShouldNotThrottle) {
    219258            m_throttleState = ShouldNotThrottle;
     259            ASSERT(m_elementsCausingThrottling.isEmpty());
    220260            updateTimerIntervalIfNecessary();
    221261        }
    222     } else if (fireState.scriptDidInteractWithNonUserObservablePlugin) {
     262    } else if (fireState.scriptMadeNonUserObservableChanges()) {
    223263        if (m_throttleState != ShouldThrottle) {
    224264            m_throttleState = ShouldThrottle;
     265            fireState.elementsChangedOutsideViewport(m_elementsCausingThrottling);
    225266            updateTimerIntervalIfNecessary();
    226267        }
     
    234275
    235276    if (pluginElement.isUserObservable())
    236         DOMTimerFireState::current->scriptDidInteractWithUserObservablePlugin = true;
     277        DOMTimerFireState::current->setScriptMadeUserObservableChanges();
    237278    else
    238         DOMTimerFireState::current->scriptDidInteractWithNonUserObservablePlugin = true;
     279        DOMTimerFireState::current->setScriptMadeNonUserObservableChanges();
     280}
     281
     282void DOMTimer::scriptDidUpdateStyleOfElement(StyledElement& styledElement, bool changed)
     283{
     284    if (!DOMTimerFireState::current)
     285        return;
     286
     287    if (!changed) {
     288        // The script set a CSS property on the Element but it did not cause any change.
     289        DOMTimerFireState::current->setScriptMadeNonUserObservableChanges();
     290        return;
     291    }
     292
     293    if (styledElement.isInsideViewport())
     294        DOMTimerFireState::current->setScriptMadeUserObservableChanges();
     295    else
     296        DOMTimerFireState::current->setScriptMadeNonUserObservableChangesToElementStyle(styledElement);
    239297}
    240298
     
    250308
    251309    DOMTimerFireState fireState(context);
     310    if (isIntervalDependentOnViewport()) {
     311        // We re-evaluate if the timer interval is dependent on the viewport every time it fires.
     312        unregisterForViewportChanges();
     313    }
    252314
    253315#if PLATFORM(IOS)
     
    342404}
    343405
     406void DOMTimer::registerForViewportChanges()
     407{
     408    ASSERT(isIntervalDependentOnViewport());
     409    if (auto* frameView = downcast<Document>(*scriptExecutionContext()).view())
     410        frameView->registerThrottledDOMTimer(this);
     411}
     412
     413void DOMTimer::unregisterForViewportChanges()
     414{
     415    if (auto* frameView = downcast<Document>(*scriptExecutionContext()).view())
     416        frameView->unregisterThrottledDOMTimer(this);
     417
     418    m_elementsCausingThrottling.clear();
     419}
     420
    344421void DOMTimer::updateTimerIntervalIfNecessary()
    345422{
     
    349426    m_currentTimerInterval = intervalClampedToMinimum();
    350427
    351     if (WTF::areEssentiallyEqual(previousInterval, m_currentTimerInterval))
    352         return;
     428    if (WTF::areEssentiallyEqual(previousInterval, m_currentTimerInterval, oneMillisecond))
     429        return;
     430
     431    // Timer was throttled / unthrottled, make sure we register / unregister
     432    // from the FrameView if the timer's interval is dependent on viewport.
     433    if (isIntervalDependentOnViewport())
     434        registerForViewportChanges();
     435    else if (m_throttleState == ShouldNotThrottle)
     436        unregisterForViewportChanges();
    353437
    354438    if (repeatInterval()) {
    355         ASSERT(WTF::areEssentiallyEqual(repeatInterval(), previousInterval));
     439        ASSERT(WTF::areEssentiallyEqual(repeatInterval(), previousInterval, oneMillisecond));
     440        LOG(DOMTimers, "%p - Updating DOMTimer's repeat interval from %g ms to %g ms due to throttling.", this, previousInterval * 1000., m_currentTimerInterval * 1000.);
    356441        augmentRepeatInterval(m_currentTimerInterval - previousInterval);
    357     } else
     442    } else {
     443        LOG(DOMTimers, "%p - Updating DOMTimer's fire interval from %g ms to %g ms due to throttling.", this, previousInterval * 1000., m_currentTimerInterval * 1000.);
    358444        augmentFireInterval(m_currentTimerInterval - previousInterval);
     445    }
     446}
     447
     448void DOMTimer::updateThrottlingStateAfterViewportChange(const IntRect& visibleRect)
     449{
     450    ASSERT(isIntervalDependentOnViewport());
     451    // Check if the elements that caused this timer to be throttled are still outside the viewport.
     452    for (auto& element : m_elementsCausingThrottling) {
     453        // Skip elements that were removed from the document.
     454        if (!element->inDocument())
     455            continue;
     456
     457        if (element->isInsideViewport(&visibleRect)) {
     458            LOG(DOMTimers, "%p - Script is changing style of an element that is now inside the viewport, unthrottling the timer.", this);
     459            m_throttleState = ShouldNotThrottle;
     460            updateTimerIntervalIfNecessary();
     461            break;
     462        }
     463    }
    359464}
    360465
     
    373478    intervalInSeconds = std::max(intervalInSeconds, scriptExecutionContext()->minimumTimerInterval());
    374479    if (m_throttleState == ShouldThrottle)
    375         intervalInSeconds = std::max(intervalInSeconds, minIntervalForNonUserObservablePluginScriptTimers * oneMillisecond);
     480        intervalInSeconds = std::max(intervalInSeconds, minIntervalForNonUserObservableChangeTimers * oneMillisecond);
    376481    return intervalInSeconds;
    377482}
  • trunk/Source/WebCore/page/DOMTimer.h

    r176065 r176212  
    11/*
    2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
     2 * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3030#include "SuspendableTimer.h"
    3131#include <memory>
     32#include <wtf/HashSet.h>
    3233#include <wtf/RefCounted.h>
    3334
    3435namespace WebCore {
    3536
    36     struct DOMTimerFireState;
     37    class DOMTimerFireState;
    3738    class HTMLPlugInElement;
     39    class IntRect;
    3840    class ScheduledAction;
     41    class StyledElement;
    3942
    4043    class DOMTimer final : public RefCounted<DOMTimer>, public SuspendableTimer {
     
    4245        WTF_MAKE_FAST_ALLOCATED;
    4346    public:
     47        virtual ~DOMTimer();
     48
    4449        // Creates a new timer owned by specified ScriptExecutionContext, starts it
    4550        // and returns its Id.
     
    5055        // setting for the context has changed).
    5156        void updateTimerIntervalIfNecessary();
     57        void updateThrottlingStateAfterViewportChange(const IntRect& visibleRect);
    5258
    5359        static void scriptDidInteractWithPlugin(HTMLPlugInElement&);
     60        static void scriptDidUpdateStyleOfElement(StyledElement&, bool changed);
    5461
    5562    private:
    5663        DOMTimer(ScriptExecutionContext&, std::unique_ptr<ScheduledAction>, int interval, bool singleShot);
    5764        double intervalClampedToMinimum() const;
     65
     66        bool isIntervalDependentOnViewport() const { return m_throttleState == ShouldThrottle && !m_elementsCausingThrottling.isEmpty(); }
     67        void registerForViewportChanges();
     68        void unregisterForViewportChanges();
     69
    5870        void updateThrottlingStateIfNecessary(const DOMTimerFireState&);
    5971
     
    7688        double m_currentTimerInterval;
    7789        bool m_shouldForwardUserGesture;
     90        // Hold a reference to the elements in case they get removed from the
     91        // Document after the timer is throttled.
     92        Vector<RefPtr<StyledElement>> m_elementsCausingThrottling;
    7893    };
    7994
  • trunk/Source/WebCore/page/FrameView.cpp

    r175719 r176212  
    44 *                     1999 Antti Koivisto <koivisto@kde.org>
    55 *                     2000 Dirk Mueller <mueller@kde.org>
    6  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved.
     6 * Copyright (C) 2004-2008, 2013, 2014 Apple Inc. All rights reserved.
    77 *           (C) 2006 Graham Dennis (graham.dennis@gmail.com)
    88 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
     
    287287    m_firstVisuallyNonEmptyLayoutCallbackPending = true;
    288288    m_maintainScrollPositionAnchor = 0;
     289    m_throttledTimers.clear();
    289290}
    290291
     
    21022103
    21032104    resumeVisibleImageAnimationsIncludingSubframes();
     2105    updateThrottledDOMTimersState();
    21042106}
    21052107
     
    29182920
    29192921    sendResizeEventIfNeeded();
     2922
     2923    // Check if we should unthrottle DOMTimers after layout as the position
     2924    // of Elements may have changed.
     2925    updateThrottledDOMTimersState();
    29202926}
    29212927
     
    30033009{
    30043010    performPostLayoutTasks();
     3011}
     3012
     3013void FrameView::registerThrottledDOMTimer(DOMTimer* timer)
     3014{
     3015    m_throttledTimers.add(timer);
     3016}
     3017
     3018void FrameView::unregisterThrottledDOMTimer(DOMTimer* timer)
     3019{
     3020    m_throttledTimers.remove(timer);
     3021}
     3022
     3023void FrameView::updateThrottledDOMTimersState()
     3024{
     3025    if (m_throttledTimers.isEmpty())
     3026        return;
     3027
     3028    IntRect visibleRect = windowToContents(windowClipRect());
     3029
     3030    // Do not iterate over the HashSet because calling DOMTimer::updateThrottlingStateAfterViewportChange()
     3031    // may cause timers to remove themselves from it while we are iterating.
     3032    Vector<DOMTimer*> timers;
     3033    copyToVector(m_throttledTimers, timers);
     3034    for (auto* timer : timers)
     3035        timer->updateThrottlingStateAfterViewportChange(visibleRect);
    30053036}
    30063037
  • trunk/Source/WebCore/page/FrameView.h

    r175719 r176212  
    55             (C) 1999 Lars Knoll (knoll@kde.org)
    66             (C) 1999 Antti Koivisto (koivisto@kde.org)
    7    Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
     7   Copyright (C) 2004-2009, 2014 Apple Inc. All rights reserved.
    88
    99   This library is free software; you can redistribute it and/or
     
    3636#include <memory>
    3737#include <wtf/Forward.h>
     38#include <wtf/HashSet.h>
    3839#include <wtf/ListHashSet.h>
    3940#include <wtf/text/WTFString.h>
     
    4243
    4344class AXObjectCache;
     45class DOMTimer;
    4446class Element;
    4547class FloatSize;
     
    303305
    304306    void postLayoutTimerFired(Timer&);
     307
     308    void registerThrottledDOMTimer(DOMTimer*);
     309    void unregisterThrottledDOMTimer(DOMTimer*);
    305310
    306311    WEBCORE_EXPORT bool wasScrolledByUser() const;
     
    562567    void performPostLayoutTasks();
    563568    void autoSizeIfEnabled();
     569    void updateThrottledDOMTimersState();
    564570
    565571    void updateLayerFlushThrottling();
     
    750756    std::unique_ptr<ViewportConstrainedObjectSet> m_viewportConstrainedObjects;
    751757
     758    HashSet<DOMTimer*> m_throttledTimers;
     759
    752760    int m_headerHeight;
    753761    int m_footerHeight;
  • trunk/Source/WebCore/platform/Logging.h

    r174524 r176212  
    4343    M(BackForward) \
    4444    M(Compositing) \
     45    M(DOMTimers) \
    4546    M(Editing) \
    4647    M(Events) \
  • trunk/Source/WebCore/rendering/RenderElement.cpp

    r175583 r176212  
    13341334}
    13351335
     1336bool RenderElement::isInsideViewport(const IntRect* visibleRect) const
     1337{
     1338    auto& frameView = view().frameView();
     1339    if (frameView.isOffscreen())
     1340        return false;
     1341
     1342    // Compute viewport rect if it was not provided.
     1343    const IntRect& viewportRect = visibleRect ? *visibleRect : frameView.windowToContents(frameView.windowClipRect());
     1344    return viewportRect.intersects(enclosingIntRect(absoluteClippedOverflowRect()));
     1345}
     1346
    13361347static bool shouldRepaintForImageAnimation(const RenderElement& renderer, const IntRect& visibleRect)
    13371348{
    13381349    const Document& document = renderer.document();
    13391350    if (document.inPageCache())
    1340         return false;
    1341     auto& frameView = renderer.view().frameView();
    1342     if (frameView.isOffscreen())
    13431351        return false;
    13441352#if PLATFORM(IOS)
     
    13501358    if (renderer.style().visibility() != VISIBLE)
    13511359        return false;
    1352     if (!visibleRect.intersects(renderer.absoluteBoundingBoxRect()))
     1360    if (!renderer.isInsideViewport(&visibleRect))
    13531361        return false;
    13541362
  • trunk/Source/WebCore/rendering/RenderElement.h

    r175716 r176212  
    121121
    122122    bool borderImageIsLoadedAndCanBeRendered() const;
     123    bool isInsideViewport(const IntRect* visibleRect = nullptr) const;
    123124
    124125    // Returns true if this renderer requires a new stacking context.
Note: See TracChangeset for help on using the changeset viewer.