<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[176212] trunk/Source/WebCore</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/176212">176212</a></dd>
<dt>Author</dt> <dd>cdumez@apple.com</dd>
<dt>Date</dt> <dd>2014-11-17 11:23:43 -0800 (Mon, 17 Nov 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>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.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorebindingsjsJSCSSStyleDeclarationCustomcpp">trunk/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp</a></li>
<li><a href="#trunkSourceWebCorecssCSSComputedStyleDeclarationcpp">trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp</a></li>
<li><a href="#trunkSourceWebCorecssCSSComputedStyleDeclarationh">trunk/Source/WebCore/css/CSSComputedStyleDeclaration.h</a></li>
<li><a href="#trunkSourceWebCorecssCSSStyleDeclarationh">trunk/Source/WebCore/css/CSSStyleDeclaration.h</a></li>
<li><a href="#trunkSourceWebCorecssPropertySetCSSStyleDeclarationcpp">trunk/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp</a></li>
<li><a href="#trunkSourceWebCorecssPropertySetCSSStyleDeclarationh">trunk/Source/WebCore/css/PropertySetCSSStyleDeclaration.h</a></li>
<li><a href="#trunkSourceWebCoredomElementcpp">trunk/Source/WebCore/dom/Element.cpp</a></li>
<li><a href="#trunkSourceWebCoredomElementh">trunk/Source/WebCore/dom/Element.h</a></li>
<li><a href="#trunkSourceWebCorepageDOMTimercpp">trunk/Source/WebCore/page/DOMTimer.cpp</a></li>
<li><a href="#trunkSourceWebCorepageDOMTimerh">trunk/Source/WebCore/page/DOMTimer.h</a></li>
<li><a href="#trunkSourceWebCorepageFrameViewcpp">trunk/Source/WebCore/page/FrameView.cpp</a></li>
<li><a href="#trunkSourceWebCorepageFrameViewh">trunk/Source/WebCore/page/FrameView.h</a></li>
<li><a href="#trunkSourceWebCoreplatformLoggingh">trunk/Source/WebCore/platform/Logging.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderElementcpp">trunk/Source/WebCore/rendering/RenderElement.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderElementh">trunk/Source/WebCore/rendering/RenderElement.h</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/ChangeLog        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -1,3 +1,28 @@
</span><ins>+2014-11-17 Chris Dumez <cdumez@apple.com>
+
+ 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.
+
</ins><span class="cx"> 2014-11-17 peavo@outlook.com <peavo@outlook.com>
</span><span class="cx">
</span><span class="cx"> [WinCairo] Compile error, CoreGraphics header file included.
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsjsJSCSSStyleDeclarationCustomcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -339,8 +339,13 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> ExceptionCode ec = 0;
</span><del>- impl().setPropertyInternal(static_cast<CSSPropertyID>(propertyInfo.propertyID), propValue, important, ec);
</del><ins>+ bool changed = impl().setPropertyInternal(static_cast<CSSPropertyID>(propertyInfo.propertyID), propValue, important, ec);
</ins><span class="cx"> setDOMException(exec, ec);
</span><ins>+
+ // Choke point for interaction with style of element; notify DOMTimer of the event.
+ if (auto* element = impl().parentElement())
+ DOMTimer::scriptDidUpdateStyleOfElement(*element, changed);
+
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSComputedStyleDeclarationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -3331,9 +3331,10 @@
</span><span class="cx"> return getPropertyValue(propertyID);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void CSSComputedStyleDeclaration::setPropertyInternal(CSSPropertyID, const String&, bool, ExceptionCode& ec)
</del><ins>+bool CSSComputedStyleDeclaration::setPropertyInternal(CSSPropertyID, const String&, bool, ExceptionCode& ec)
</ins><span class="cx"> {
</span><span class="cx"> ec = NO_MODIFICATION_ALLOWED_ERR;
</span><ins>+ return false;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> PassRefPtr<CSSValueList> ComputedStyleExtractor::getBackgroundShorthandValue() const
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSComputedStyleDeclarationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSComputedStyleDeclaration.h (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSComputedStyleDeclaration.h        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/css/CSSComputedStyleDeclaration.h        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -114,7 +114,7 @@
</span><span class="cx"> virtual void setCssText(const String&, ExceptionCode&) override;
</span><span class="cx"> virtual PassRefPtr<CSSValue> getPropertyCSSValueInternal(CSSPropertyID) override;
</span><span class="cx"> virtual String getPropertyValueInternal(CSSPropertyID) override;
</span><del>- virtual void setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) override;
</del><ins>+ virtual bool setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) override;
</ins><span class="cx"> virtual PassRef<MutableStyleProperties> copyProperties() const override;
</span><span class="cx">
</span><span class="cx"> PassRefPtr<CSSValue> getPropertyCSSValue(CSSPropertyID, EUpdateLayout = UpdateLayout) const;
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSStyleDeclarationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSStyleDeclaration.h (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSStyleDeclaration.h        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/css/CSSStyleDeclaration.h        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -45,6 +45,7 @@
</span><span class="cx"> virtual void ref() = 0;
</span><span class="cx"> virtual void deref() = 0;
</span><span class="cx">
</span><ins>+ virtual StyledElement* parentElement() const { return nullptr; }
</ins><span class="cx"> virtual CSSRule* parentRule() const = 0;
</span><span class="cx"> virtual String cssText() const = 0;
</span><span class="cx"> virtual void setCssText(const String&, ExceptionCode&) = 0;
</span><span class="lines">@@ -63,7 +64,7 @@
</span><span class="cx"> // The CSSValue returned by this function should not be exposed to the web as it may be used by multiple documents at the same time.
</span><span class="cx"> virtual PassRefPtr<CSSValue> getPropertyCSSValueInternal(CSSPropertyID) = 0;
</span><span class="cx"> virtual String getPropertyValueInternal(CSSPropertyID) = 0;
</span><del>- virtual void setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) = 0;
</del><ins>+ virtual bool setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) = 0;
</ins><span class="cx">
</span><span class="cx"> virtual PassRef<MutableStyleProperties> copyProperties() const = 0;
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCorecssPropertySetCSSStyleDeclarationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -255,11 +255,11 @@
</span><span class="cx"> return m_propertySet->getPropertyValue(propertyID);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void PropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID propertyID, const String& value, bool important, ExceptionCode& ec)
</del><ins>+bool PropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID propertyID, const String& value, bool important, ExceptionCode& ec)
</ins><span class="cx"> {
</span><span class="cx"> StyleAttributeMutationScope mutationScope(this);
</span><span class="cx"> if (!willMutate())
</span><del>- return;
</del><ins>+ return false;
</ins><span class="cx">
</span><span class="cx"> ec = 0;
</span><span class="cx"> bool changed = m_propertySet->setProperty(propertyID, value, important, contextStyleSheet());
</span><span class="lines">@@ -268,6 +268,7 @@
</span><span class="cx">
</span><span class="cx"> if (changed)
</span><span class="cx"> mutationScope.enqueueMutationRecord();
</span><ins>+ return changed;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> CSSValue* PropertySetCSSStyleDeclaration::cloneAndCacheForCSSOM(CSSValue* internalValue)
</span></span></pre></div>
<a id="trunkSourceWebCorecssPropertySetCSSStyleDeclarationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/PropertySetCSSStyleDeclaration.h (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/PropertySetCSSStyleDeclaration.h        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/css/PropertySetCSSStyleDeclaration.h        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -44,7 +44,6 @@
</span><span class="cx"> public:
</span><span class="cx"> PropertySetCSSStyleDeclaration(MutableStyleProperties* propertySet) : m_propertySet(propertySet) { }
</span><span class="cx">
</span><del>- virtual StyledElement* parentElement() const { return nullptr; }
</del><span class="cx"> virtual void clearParentElement() { ASSERT_NOT_REACHED(); }
</span><span class="cx"> StyleSheetContents* contextStyleSheet() const;
</span><span class="cx">
</span><span class="lines">@@ -66,7 +65,7 @@
</span><span class="cx"> virtual void setCssText(const String&, ExceptionCode&) override final;
</span><span class="cx"> virtual PassRefPtr<CSSValue> getPropertyCSSValueInternal(CSSPropertyID) override final;
</span><span class="cx"> virtual String getPropertyValueInternal(CSSPropertyID) override final;
</span><del>- virtual void setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) override final;
</del><ins>+ virtual bool setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) override final;
</ins><span class="cx">
</span><span class="cx"> virtual PassRef<MutableStyleProperties> copyProperties() const override final;
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCoredomElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Element.cpp (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Element.cpp        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/dom/Element.cpp        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -2347,6 +2347,11 @@
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+bool Element::isInsideViewport(const IntRect* visibleRect) const
+{
+ return renderer() && renderer()->isInsideViewport(visibleRect);
+}
+
</ins><span class="cx"> DOMTokenList& Element::classList()
</span><span class="cx"> {
</span><span class="cx"> ElementRareData& data = ensureElementRareData();
</span></span></pre></div>
<a id="trunkSourceWebCoredomElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Element.h (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Element.h        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/dom/Element.h        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -200,6 +200,8 @@
</span><span class="cx"> double offsetWidth();
</span><span class="cx"> double offsetHeight();
</span><span class="cx">
</span><ins>+ bool isInsideViewport(const IntRect* visibleRect = nullptr) const;
+
</ins><span class="cx"> // FIXME: Replace uses of offsetParent in the platform with calls
</span><span class="cx"> // to the render layer and merge bindingsOffsetParent and offsetParent.
</span><span class="cx"> Element* bindingsOffsetParent();
</span></span></pre></div>
<a id="trunkSourceWebCorepageDOMTimercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/DOMTimer.cpp (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/DOMTimer.cpp        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/page/DOMTimer.cpp        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
</del><ins>+ * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -27,8 +27,10 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "DOMTimer.h"
</span><span class="cx">
</span><ins>+#include "FrameView.h"
</ins><span class="cx"> #include "HTMLPlugInElement.h"
</span><span class="cx"> #include "InspectorInstrumentation.h"
</span><ins>+#include "Logging.h"
</ins><span class="cx"> #include "PluginViewBase.h"
</span><span class="cx"> #include "ScheduledAction.h"
</span><span class="cx"> #include "ScriptExecutionContext.h"
</span><span class="lines">@@ -50,38 +52,69 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx">
</span><span class="cx"> static const int maxIntervalForUserGestureForwarding = 1000; // One second matches Gecko.
</span><del>-static const int minIntervalForNonUserObservablePluginScriptTimers = 1000; // Empirically determined to maximize battery life.
</del><ins>+static const int minIntervalForNonUserObservableChangeTimers = 1000; // Empirically determined to maximize battery life.
</ins><span class="cx"> static const int maxTimerNestingLevel = 5;
</span><span class="cx"> static const double oneMillisecond = 0.001;
</span><span class="cx">
</span><del>-struct DOMTimerFireState {
</del><ins>+class DOMTimerFireState {
+public:
</ins><span class="cx"> explicit DOMTimerFireState(ScriptExecutionContext& context)
</span><del>- : scriptDidInteractWithNonUserObservablePlugin(false)
- , scriptDidInteractWithUserObservablePlugin(false)
- , shouldSetCurrent(is<Document>(context))
</del><ins>+ : m_context(context)
+ , m_contextIsDocument(is<Document>(m_context))
</ins><span class="cx"> {
</span><span class="cx"> // For worker threads, don't update the current DOMTimerFireState.
</span><span class="cx"> // Setting this from workers would not be thread-safe, and its not relevant to current uses.
</span><del>- if (shouldSetCurrent) {
- previous = current;
</del><ins>+ if (m_contextIsDocument) {
+ m_initialDOMTreeVersion = downcast<Document>(context).domTreeVersion();
+ m_previous = current;
</ins><span class="cx"> current = this;
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> ~DOMTimerFireState()
</span><span class="cx"> {
</span><del>- if (shouldSetCurrent)
- current = previous;
</del><ins>+ if (m_contextIsDocument)
+ current = m_previous;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ void setScriptMadeUserObservableChanges() { m_scriptMadeUserObservableChanges = true; }
+ void setScriptMadeNonUserObservableChanges() { m_scriptMadeNonUserObservableChanges = true; }
+ void setScriptMadeNonUserObservableChangesToElementStyle(StyledElement& element)
+ {
+ m_scriptMadeNonUserObservableChanges = true;
+ m_elementsChangedOutsideViewport.add(&element);
+ }
+
+ bool scriptMadeNonUserObservableChanges() const { return m_scriptMadeNonUserObservableChanges; }
+ bool scriptMadeUserObservableChanges() const
+ {
+ if (m_scriptMadeUserObservableChanges)
+ return true;
+
+ // To be conservative, we also consider any DOM Tree change to be user observable.
+ return m_contextIsDocument && downcast<Document>(m_context).domTreeVersion() != m_initialDOMTreeVersion;
+ }
+
+ void setChangedStyleOfElementOutsideViewport(StyledElement& element)
+ {
+ m_elementsChangedOutsideViewport.add(&element);
+ }
+
+ void elementsChangedOutsideViewport(Vector<RefPtr<StyledElement>>& elements) const
+ {
+ copyToVector(m_elementsChangedOutsideViewport, elements);
+ }
+
</ins><span class="cx"> static DOMTimerFireState* current;
</span><span class="cx">
</span><del>- bool scriptDidInteractWithNonUserObservablePlugin;
- bool scriptDidInteractWithUserObservablePlugin;
-
</del><span class="cx"> private:
</span><del>- bool shouldSetCurrent;
- DOMTimerFireState* previous;
</del><ins>+ ScriptExecutionContext& m_context;
+ uint64_t m_initialDOMTreeVersion;
+ DOMTimerFireState* m_previous;
+ HashSet<RefPtr<StyledElement>> m_elementsChangedOutsideViewport;
+ bool m_contextIsDocument;
+ bool m_scriptMadeNonUserObservableChanges { false };
+ bool m_scriptMadeUserObservableChanges { false };
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> DOMTimerFireState* DOMTimerFireState::current = nullptr;
</span><span class="lines">@@ -170,6 +203,12 @@
</span><span class="cx"> startRepeating(m_currentTimerInterval);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+DOMTimer::~DOMTimer()
+{
+ if (isIntervalDependentOnViewport())
+ unregisterForViewportChanges();
+}
+
</ins><span class="cx"> int DOMTimer::install(ScriptExecutionContext& context, std::unique_ptr<ScheduledAction> action, int timeout, bool singleShot)
</span><span class="cx"> {
</span><span class="cx"> // DOMTimer constructor passes ownership of the initial ref on the object to the constructor.
</span><span class="lines">@@ -214,14 +253,16 @@
</span><span class="cx">
</span><span class="cx"> void DOMTimer::updateThrottlingStateIfNecessary(const DOMTimerFireState& fireState)
</span><span class="cx"> {
</span><del>- if (fireState.scriptDidInteractWithUserObservablePlugin) {
</del><ins>+ if (fireState.scriptMadeUserObservableChanges()) {
</ins><span class="cx"> if (m_throttleState != ShouldNotThrottle) {
</span><span class="cx"> m_throttleState = ShouldNotThrottle;
</span><ins>+ ASSERT(m_elementsCausingThrottling.isEmpty());
</ins><span class="cx"> updateTimerIntervalIfNecessary();
</span><span class="cx"> }
</span><del>- } else if (fireState.scriptDidInteractWithNonUserObservablePlugin) {
</del><ins>+ } else if (fireState.scriptMadeNonUserObservableChanges()) {
</ins><span class="cx"> if (m_throttleState != ShouldThrottle) {
</span><span class="cx"> m_throttleState = ShouldThrottle;
</span><ins>+ fireState.elementsChangedOutsideViewport(m_elementsCausingThrottling);
</ins><span class="cx"> updateTimerIntervalIfNecessary();
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -233,11 +274,28 @@
</span><span class="cx"> return;
</span><span class="cx">
</span><span class="cx"> if (pluginElement.isUserObservable())
</span><del>- DOMTimerFireState::current->scriptDidInteractWithUserObservablePlugin = true;
</del><ins>+ DOMTimerFireState::current->setScriptMadeUserObservableChanges();
</ins><span class="cx"> else
</span><del>- DOMTimerFireState::current->scriptDidInteractWithNonUserObservablePlugin = true;
</del><ins>+ DOMTimerFireState::current->setScriptMadeNonUserObservableChanges();
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+void DOMTimer::scriptDidUpdateStyleOfElement(StyledElement& styledElement, bool changed)
+{
+ if (!DOMTimerFireState::current)
+ return;
+
+ if (!changed) {
+ // The script set a CSS property on the Element but it did not cause any change.
+ DOMTimerFireState::current->setScriptMadeNonUserObservableChanges();
+ return;
+ }
+
+ if (styledElement.isInsideViewport())
+ DOMTimerFireState::current->setScriptMadeUserObservableChanges();
+ else
+ DOMTimerFireState::current->setScriptMadeNonUserObservableChangesToElementStyle(styledElement);
+}
+
</ins><span class="cx"> void DOMTimer::fired()
</span><span class="cx"> {
</span><span class="cx"> // Retain this - if the timer is cancelled while this function is on the stack (implicitly and always
</span><span class="lines">@@ -249,6 +307,10 @@
</span><span class="cx"> ScriptExecutionContext& context = *scriptExecutionContext();
</span><span class="cx">
</span><span class="cx"> DOMTimerFireState fireState(context);
</span><ins>+ if (isIntervalDependentOnViewport()) {
+ // We re-evaluate if the timer interval is dependent on the viewport every time it fires.
+ unregisterForViewportChanges();
+ }
</ins><span class="cx">
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx"> Document* document = nullptr;
</span><span class="lines">@@ -341,6 +403,21 @@
</span><span class="cx"> m_action = nullptr;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void DOMTimer::registerForViewportChanges()
+{
+ ASSERT(isIntervalDependentOnViewport());
+ if (auto* frameView = downcast<Document>(*scriptExecutionContext()).view())
+ frameView->registerThrottledDOMTimer(this);
+}
+
+void DOMTimer::unregisterForViewportChanges()
+{
+ if (auto* frameView = downcast<Document>(*scriptExecutionContext()).view())
+ frameView->unregisterThrottledDOMTimer(this);
+
+ m_elementsCausingThrottling.clear();
+}
+
</ins><span class="cx"> void DOMTimer::updateTimerIntervalIfNecessary()
</span><span class="cx"> {
</span><span class="cx"> ASSERT(m_nestingLevel <= maxTimerNestingLevel);
</span><span class="lines">@@ -348,16 +425,44 @@
</span><span class="cx"> double previousInterval = m_currentTimerInterval;
</span><span class="cx"> m_currentTimerInterval = intervalClampedToMinimum();
</span><span class="cx">
</span><del>- if (WTF::areEssentiallyEqual(previousInterval, m_currentTimerInterval))
</del><ins>+ if (WTF::areEssentiallyEqual(previousInterval, m_currentTimerInterval, oneMillisecond))
</ins><span class="cx"> return;
</span><span class="cx">
</span><ins>+ // Timer was throttled / unthrottled, make sure we register / unregister
+ // from the FrameView if the timer's interval is dependent on viewport.
+ if (isIntervalDependentOnViewport())
+ registerForViewportChanges();
+ else if (m_throttleState == ShouldNotThrottle)
+ unregisterForViewportChanges();
+
</ins><span class="cx"> if (repeatInterval()) {
</span><del>- ASSERT(WTF::areEssentiallyEqual(repeatInterval(), previousInterval));
</del><ins>+ ASSERT(WTF::areEssentiallyEqual(repeatInterval(), previousInterval, oneMillisecond));
+ LOG(DOMTimers, "%p - Updating DOMTimer's repeat interval from %g ms to %g ms due to throttling.", this, previousInterval * 1000., m_currentTimerInterval * 1000.);
</ins><span class="cx"> augmentRepeatInterval(m_currentTimerInterval - previousInterval);
</span><del>- } else
</del><ins>+ } else {
+ LOG(DOMTimers, "%p - Updating DOMTimer's fire interval from %g ms to %g ms due to throttling.", this, previousInterval * 1000., m_currentTimerInterval * 1000.);
</ins><span class="cx"> augmentFireInterval(m_currentTimerInterval - previousInterval);
</span><ins>+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+void DOMTimer::updateThrottlingStateAfterViewportChange(const IntRect& visibleRect)
+{
+ ASSERT(isIntervalDependentOnViewport());
+ // Check if the elements that caused this timer to be throttled are still outside the viewport.
+ for (auto& element : m_elementsCausingThrottling) {
+ // Skip elements that were removed from the document.
+ if (!element->inDocument())
+ continue;
+
+ if (element->isInsideViewport(&visibleRect)) {
+ LOG(DOMTimers, "%p - Script is changing style of an element that is now inside the viewport, unthrottling the timer.", this);
+ m_throttleState = ShouldNotThrottle;
+ updateTimerIntervalIfNecessary();
+ break;
+ }
+ }
+}
+
</ins><span class="cx"> double DOMTimer::intervalClampedToMinimum() const
</span><span class="cx"> {
</span><span class="cx"> ASSERT(scriptExecutionContext());
</span><span class="lines">@@ -372,7 +477,7 @@
</span><span class="cx"> // Apply two throttles - the global (per Page) minimum, and also a per-timer throttle.
</span><span class="cx"> intervalInSeconds = std::max(intervalInSeconds, scriptExecutionContext()->minimumTimerInterval());
</span><span class="cx"> if (m_throttleState == ShouldThrottle)
</span><del>- intervalInSeconds = std::max(intervalInSeconds, minIntervalForNonUserObservablePluginScriptTimers * oneMillisecond);
</del><ins>+ intervalInSeconds = std::max(intervalInSeconds, minIntervalForNonUserObservableChangeTimers * oneMillisecond);
</ins><span class="cx"> return intervalInSeconds;
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCorepageDOMTimerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/DOMTimer.h (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/DOMTimer.h        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/page/DOMTimer.h        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
</del><ins>+ * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -29,18 +29,23 @@
</span><span class="cx">
</span><span class="cx"> #include "SuspendableTimer.h"
</span><span class="cx"> #include <memory>
</span><ins>+#include <wtf/HashSet.h>
</ins><span class="cx"> #include <wtf/RefCounted.h>
</span><span class="cx">
</span><span class="cx"> namespace WebCore {
</span><span class="cx">
</span><del>- struct DOMTimerFireState;
</del><ins>+ class DOMTimerFireState;
</ins><span class="cx"> class HTMLPlugInElement;
</span><ins>+ class IntRect;
</ins><span class="cx"> class ScheduledAction;
</span><ins>+ class StyledElement;
</ins><span class="cx">
</span><span class="cx"> class DOMTimer final : public RefCounted<DOMTimer>, public SuspendableTimer {
</span><span class="cx"> WTF_MAKE_NONCOPYABLE(DOMTimer);
</span><span class="cx"> WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx"> public:
</span><ins>+ virtual ~DOMTimer();
+
</ins><span class="cx"> // Creates a new timer owned by specified ScriptExecutionContext, starts it
</span><span class="cx"> // and returns its Id.
</span><span class="cx"> static int install(ScriptExecutionContext&, std::unique_ptr<ScheduledAction>, int timeout, bool singleShot);
</span><span class="lines">@@ -49,12 +54,19 @@
</span><span class="cx"> // Notify that the interval may need updating (e.g. because the minimum interval
</span><span class="cx"> // setting for the context has changed).
</span><span class="cx"> void updateTimerIntervalIfNecessary();
</span><ins>+ void updateThrottlingStateAfterViewportChange(const IntRect& visibleRect);
</ins><span class="cx">
</span><span class="cx"> static void scriptDidInteractWithPlugin(HTMLPlugInElement&);
</span><ins>+ static void scriptDidUpdateStyleOfElement(StyledElement&, bool changed);
</ins><span class="cx">
</span><span class="cx"> private:
</span><span class="cx"> DOMTimer(ScriptExecutionContext&, std::unique_ptr<ScheduledAction>, int interval, bool singleShot);
</span><span class="cx"> double intervalClampedToMinimum() const;
</span><ins>+
+ bool isIntervalDependentOnViewport() const { return m_throttleState == ShouldThrottle && !m_elementsCausingThrottling.isEmpty(); }
+ void registerForViewportChanges();
+ void unregisterForViewportChanges();
+
</ins><span class="cx"> void updateThrottlingStateIfNecessary(const DOMTimerFireState&);
</span><span class="cx">
</span><span class="cx"> // SuspendableTimer
</span><span class="lines">@@ -75,6 +87,9 @@
</span><span class="cx"> TimerThrottleState m_throttleState;
</span><span class="cx"> double m_currentTimerInterval;
</span><span class="cx"> bool m_shouldForwardUserGesture;
</span><ins>+ // Hold a reference to the elements in case they get removed from the
+ // Document after the timer is throttled.
+ Vector<RefPtr<StyledElement>> m_elementsCausingThrottling;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCorepageFrameViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/FrameView.cpp (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/FrameView.cpp        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/page/FrameView.cpp        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -3,7 +3,7 @@
</span><span class="cx"> * 1999 Lars Knoll <knoll@kde.org>
</span><span class="cx"> * 1999 Antti Koivisto <koivisto@kde.org>
</span><span class="cx"> * 2000 Dirk Mueller <mueller@kde.org>
</span><del>- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2004-2008, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> * (C) 2006 Graham Dennis (graham.dennis@gmail.com)
</span><span class="cx"> * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
</span><span class="cx"> * Copyright (C) 2009 Google Inc. All rights reserved.
</span><span class="lines">@@ -286,6 +286,7 @@
</span><span class="cx"> m_isVisuallyNonEmpty = false;
</span><span class="cx"> m_firstVisuallyNonEmptyLayoutCallbackPending = true;
</span><span class="cx"> m_maintainScrollPositionAnchor = 0;
</span><ins>+ m_throttledTimers.clear();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void FrameView::removeFromAXObjectCache()
</span><span class="lines">@@ -2101,6 +2102,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> resumeVisibleImageAnimationsIncludingSubframes();
</span><ins>+ updateThrottledDOMTimersState();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void FrameView::resumeVisibleImageAnimationsIncludingSubframes()
</span><span class="lines">@@ -2917,6 +2919,10 @@
</span><span class="cx"> scrollToAnchor();
</span><span class="cx">
</span><span class="cx"> sendResizeEventIfNeeded();
</span><ins>+
+ // Check if we should unthrottle DOMTimers after layout as the position
+ // of Elements may have changed.
+ updateThrottledDOMTimersState();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> IntSize FrameView::sizeForResizeEvent() const
</span><span class="lines">@@ -3004,6 +3010,31 @@
</span><span class="cx"> performPostLayoutTasks();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void FrameView::registerThrottledDOMTimer(DOMTimer* timer)
+{
+ m_throttledTimers.add(timer);
+}
+
+void FrameView::unregisterThrottledDOMTimer(DOMTimer* timer)
+{
+ m_throttledTimers.remove(timer);
+}
+
+void FrameView::updateThrottledDOMTimersState()
+{
+ if (m_throttledTimers.isEmpty())
+ return;
+
+ IntRect visibleRect = windowToContents(windowClipRect());
+
+ // Do not iterate over the HashSet because calling DOMTimer::updateThrottlingStateAfterViewportChange()
+ // may cause timers to remove themselves from it while we are iterating.
+ Vector<DOMTimer*> timers;
+ copyToVector(m_throttledTimers, timers);
+ for (auto* timer : timers)
+ timer->updateThrottlingStateAfterViewportChange(visibleRect);
+}
+
</ins><span class="cx"> void FrameView::autoSizeIfEnabled()
</span><span class="cx"> {
</span><span class="cx"> if (!m_shouldAutoSize)
</span></span></pre></div>
<a id="trunkSourceWebCorepageFrameViewh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/FrameView.h (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/FrameView.h        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/page/FrameView.h        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -4,7 +4,7 @@
</span><span class="cx"> (C) 1998, 1999 Torben Weis (weis@kde.org)
</span><span class="cx"> (C) 1999 Lars Knoll (knoll@kde.org)
</span><span class="cx"> (C) 1999 Antti Koivisto (koivisto@kde.org)
</span><del>- Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
</del><ins>+ Copyright (C) 2004-2009, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">
</span><span class="cx"> This library is free software; you can redistribute it and/or
</span><span class="cx"> modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -35,12 +35,14 @@
</span><span class="cx"> #include "ScrollView.h"
</span><span class="cx"> #include <memory>
</span><span class="cx"> #include <wtf/Forward.h>
</span><ins>+#include <wtf/HashSet.h>
</ins><span class="cx"> #include <wtf/ListHashSet.h>
</span><span class="cx"> #include <wtf/text/WTFString.h>
</span><span class="cx">
</span><span class="cx"> namespace WebCore {
</span><span class="cx">
</span><span class="cx"> class AXObjectCache;
</span><ins>+class DOMTimer;
</ins><span class="cx"> class Element;
</span><span class="cx"> class FloatSize;
</span><span class="cx"> class Frame;
</span><span class="lines">@@ -303,6 +305,9 @@
</span><span class="cx">
</span><span class="cx"> void postLayoutTimerFired(Timer&);
</span><span class="cx">
</span><ins>+ void registerThrottledDOMTimer(DOMTimer*);
+ void unregisterThrottledDOMTimer(DOMTimer*);
+
</ins><span class="cx"> WEBCORE_EXPORT bool wasScrolledByUser() const;
</span><span class="cx"> WEBCORE_EXPORT void setWasScrolledByUser(bool);
</span><span class="cx">
</span><span class="lines">@@ -561,6 +566,7 @@
</span><span class="cx"> void forceLayoutParentViewIfNeeded();
</span><span class="cx"> void performPostLayoutTasks();
</span><span class="cx"> void autoSizeIfEnabled();
</span><ins>+ void updateThrottledDOMTimersState();
</ins><span class="cx">
</span><span class="cx"> void updateLayerFlushThrottling();
</span><span class="cx"> WEBCORE_EXPORT void adjustTiledBackingCoverage();
</span><span class="lines">@@ -749,6 +755,8 @@
</span><span class="cx"> std::unique_ptr<ScrollableAreaSet> m_scrollableAreas;
</span><span class="cx"> std::unique_ptr<ViewportConstrainedObjectSet> m_viewportConstrainedObjects;
</span><span class="cx">
</span><ins>+ HashSet<DOMTimer*> m_throttledTimers;
+
</ins><span class="cx"> int m_headerHeight;
</span><span class="cx"> int m_footerHeight;
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformLoggingh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/Logging.h (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/Logging.h        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/platform/Logging.h        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -42,6 +42,7 @@
</span><span class="cx"> M(Archives) \
</span><span class="cx"> M(BackForward) \
</span><span class="cx"> M(Compositing) \
</span><ins>+ M(DOMTimers) \
</ins><span class="cx"> M(Editing) \
</span><span class="cx"> M(Events) \
</span><span class="cx"> M(FTP) \
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderElement.cpp (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderElement.cpp        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/rendering/RenderElement.cpp        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -1333,14 +1333,22 @@
</span><span class="cx"> return borderImage && borderImage->canRender(this, style().effectiveZoom()) && borderImage->isLoaded();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+bool RenderElement::isInsideViewport(const IntRect* visibleRect) const
+{
+ auto& frameView = view().frameView();
+ if (frameView.isOffscreen())
+ return false;
+
+ // Compute viewport rect if it was not provided.
+ const IntRect& viewportRect = visibleRect ? *visibleRect : frameView.windowToContents(frameView.windowClipRect());
+ return viewportRect.intersects(enclosingIntRect(absoluteClippedOverflowRect()));
+}
+
</ins><span class="cx"> static bool shouldRepaintForImageAnimation(const RenderElement& renderer, const IntRect& visibleRect)
</span><span class="cx"> {
</span><span class="cx"> const Document& document = renderer.document();
</span><span class="cx"> if (document.inPageCache())
</span><span class="cx"> return false;
</span><del>- auto& frameView = renderer.view().frameView();
- if (frameView.isOffscreen())
- return false;
</del><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx"> if (document.frame()->timersPaused())
</span><span class="cx"> return false;
</span><span class="lines">@@ -1349,7 +1357,7 @@
</span><span class="cx"> return false;
</span><span class="cx"> if (renderer.style().visibility() != VISIBLE)
</span><span class="cx"> return false;
</span><del>- if (!visibleRect.intersects(renderer.absoluteBoundingBoxRect()))
</del><ins>+ if (!renderer.isInsideViewport(&visibleRect))
</ins><span class="cx"> return false;
</span><span class="cx">
</span><span class="cx"> return true;
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderElement.h (176211 => 176212)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderElement.h        2014-11-17 19:06:38 UTC (rev 176211)
+++ trunk/Source/WebCore/rendering/RenderElement.h        2014-11-17 19:23:43 UTC (rev 176212)
</span><span class="lines">@@ -120,6 +120,7 @@
</span><span class="cx"> bool repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repaintContainer, const LayoutRect& oldBounds, const LayoutRect& oldOutlineBox, const LayoutRect* newBoundsPtr = nullptr, const LayoutRect* newOutlineBoxPtr = nullptr);
</span><span class="cx">
</span><span class="cx"> bool borderImageIsLoadedAndCanBeRendered() const;
</span><ins>+ bool isInsideViewport(const IntRect* visibleRect = nullptr) const;
</ins><span class="cx">
</span><span class="cx"> // Returns true if this renderer requires a new stacking context.
</span><span class="cx"> bool createsGroup() const { return isTransparent() || hasMask() || hasFilter() || hasBackdropFilter() || hasBlendMode(); }
</span></span></pre>
</div>
</div>
</body>
</html>