<!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>[165598] trunk/Source</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/165598">165598</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2014-03-13 19:49:57 -0700 (Thu, 13 Mar 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Refactor Vibration algorithm to use only one timer.
https://bugs.webkit.org/show_bug.cgi?id=130059

Patch by Jinwoo Jeong &lt;jw00.jeong@samsung.com&gt; on 2014-03-13
Reviewed by Darin Adler.

Source/WebCore:

Currently Vibration is using two timers,
one is to start a vibration and another is to check termination of a vibration.
But they do not work in same time, if one of them is fired, then anothor will start.
Thus this patch removes one of them, and manages vibration states by enumeration.

Also, this patch implement the missing part of the algorithm,
which check the maximum length of the vibration pattern and the maximum duration of the vibration.

Lastly, this patch removes unused methods from Vibration.

* Modules/vibration/Vibration.cpp:
(WebCore::Vibration::Vibration):
(WebCore::Vibration::vibrate):
(WebCore::Vibration::cancelVibration):
Removed stopVibration() and its contents moved to cancelVibration().
(WebCore::Vibration::timerFired): Combined timerStartFired() and timerStopFired().
Removed suspendVibration() and resumeVibration(), which is never called since r.
* Modules/vibration/Vibration.h: Added new enumertaion to specify states of Vibration.
(WebCore::Vibration::isVibrating):

Source/WebKit2:

This patch adds a vibration unit test regression after <a href="http://trac.webkit.org/projects/webkit/changeset/161257">r161257</a>.
It consists of two short term requests to check
that Vibration could work properly by sequential requests.

Indeed this patch tightens condition of existing tests.

* UIProcess/API/efl/tests/test_ewk2_view.cpp:
(TEST_F):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesvibrationVibrationcpp">trunk/Source/WebCore/Modules/vibration/Vibration.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesvibrationVibrationh">trunk/Source/WebCore/Modules/vibration/Vibration.h</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIeflteststest_ewk2_viewcpp">trunk/Source/WebKit2/UIProcess/API/efl/tests/test_ewk2_view.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (165597 => 165598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-03-14 02:49:04 UTC (rev 165597)
+++ trunk/Source/WebCore/ChangeLog        2014-03-14 02:49:57 UTC (rev 165598)
</span><span class="lines">@@ -1,3 +1,30 @@
</span><ins>+2014-03-13  Jinwoo Jeong  &lt;jw00.jeong@samsung.com&gt;
+
+        Refactor Vibration algorithm to use only one timer.
+        https://bugs.webkit.org/show_bug.cgi?id=130059
+
+        Reviewed by Darin Adler.
+
+        Currently Vibration is using two timers,
+        one is to start a vibration and another is to check termination of a vibration.
+        But they do not work in same time, if one of them is fired, then anothor will start.
+        Thus this patch removes one of them, and manages vibration states by enumeration.
+
+        Also, this patch implement the missing part of the algorithm,
+        which check the maximum length of the vibration pattern and the maximum duration of the vibration.
+
+        Lastly, this patch removes unused methods from Vibration.
+
+        * Modules/vibration/Vibration.cpp:
+        (WebCore::Vibration::Vibration):
+        (WebCore::Vibration::vibrate):
+        (WebCore::Vibration::cancelVibration):
+        Removed stopVibration() and its contents moved to cancelVibration().
+        (WebCore::Vibration::timerFired): Combined timerStartFired() and timerStopFired().
+        Removed suspendVibration() and resumeVibration(), which is never called since r.
+        * Modules/vibration/Vibration.h: Added new enumertaion to specify states of Vibration.
+        (WebCore::Vibration::isVibrating):
+
</ins><span class="cx"> 2014-03-13  James Craig  &lt;jcraig@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: AXI: Use loc strings for known aria-invalid types
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesvibrationVibrationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/vibration/Vibration.cpp (165597 => 165598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/vibration/Vibration.cpp        2014-03-14 02:49:04 UTC (rev 165597)
+++ trunk/Source/WebCore/Modules/vibration/Vibration.cpp        2014-03-14 02:49:57 UTC (rev 165598)
</span><span class="lines">@@ -26,11 +26,15 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><ins>+// Maximum number of entries in a vibration pattern.
+const unsigned MaxVibrationPatternLength = 99;
+// Maximum duration of a vibration in 10 seconds.
+const unsigned MaxVibrationDuration = 10000;
+
</ins><span class="cx"> Vibration::Vibration(VibrationClient* client)
</span><span class="cx">     : m_vibrationClient(client)
</span><del>-    , m_timerStart(this, &amp;Vibration::timerStartFired)
-    , m_timerStop(this, &amp;Vibration::timerStopFired)
-    , m_isVibrating(false)
</del><ins>+    , m_timer(this, &amp;Vibration::timerFired)
+    , m_state(State::Idle)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -46,82 +50,76 @@
</span><span class="cx"> 
</span><span class="cx"> bool Vibration::vibrate(const VibrationPattern&amp; pattern)
</span><span class="cx"> {
</span><del>-    size_t length = pattern.size();
</del><ins>+    VibrationPattern&amp; sanitized = const_cast&lt;VibrationPattern&amp;&gt;(pattern);
+    size_t length = sanitized.size();
</ins><span class="cx"> 
</span><del>-    m_pattern = pattern;
-    if (length &amp;&amp; !(length % 2))
-        m_pattern.removeLast();
</del><ins>+    // If the pattern is too long then truncate it.
+    if (length &gt; MaxVibrationPatternLength) {
+        sanitized.shrink(MaxVibrationPatternLength);
+        length = MaxVibrationPatternLength;
+    }
</ins><span class="cx"> 
</span><del>-    // Pre-exsiting instance need to be canceled when vibration is called.
-    // And if time is 0, vibration have to be canceled also.
-    if (m_isVibrating || (m_pattern.size() == 1 &amp;&amp; !m_pattern[0]))
</del><ins>+    // If the length of pattern is even and is not zero, then remove the last entry in pattern.
+    if (length &amp;&amp; !(length % 2)) {
+        sanitized.removeLast();
+        length--;
+    }
+
+    // If any pattern entry is too long then truncate it.
+    for (auto&amp; duration : sanitized)
+        duration = std::min(duration, MaxVibrationDuration);
+
+    // Pre-exisiting instance need to be canceled when vibrate() is called.
+    if (isVibrating())
</ins><span class="cx">         cancelVibration();
</span><span class="cx"> 
</span><del>-    if (!m_pattern.size())
</del><ins>+    // If pattern is an empty list, then return true and terminate these steps.
+    if (!length || (length == 1 &amp;&amp; !sanitized[0])) {
+        cancelVibration();
</ins><span class="cx">         return true;
</span><ins>+    }
</ins><span class="cx"> 
</span><del>-    m_timerStart.startOneShot(0);
-    m_isVibrating = true;
</del><ins>+    m_pattern = sanitized;
+
+    m_timer.startOneShot(0);
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Vibration::cancelVibration()
</span><span class="cx"> {
</span><span class="cx">     m_pattern.clear();
</span><del>-    if (m_isVibrating)
-        stopVibration();
</del><ins>+    if (isVibrating()) {
+        m_timer.stop();
+        m_state = State::Idle;
+        m_vibrationClient-&gt;cancelVibration();
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Vibration::suspendVibration()
</del><ins>+void Vibration::timerFired(Timer&lt;Vibration&gt;* timer)
</ins><span class="cx"> {
</span><del>-    if (!m_isVibrating)
-        return;
</del><ins>+    ASSERT_UNUSED(timer, timer == &amp;m_timer);
</ins><span class="cx"> 
</span><del>-    m_pattern.insert(0, m_timerStop.nextFireInterval());
-    stopVibration();
-}
</del><ins>+    m_timer.stop();
</ins><span class="cx"> 
</span><del>-void Vibration::resumeVibration()
-{
-    m_timerStart.startOneShot(0);
-    m_isVibrating = true;
-}
</del><ins>+    if (m_pattern.isEmpty()) {
+        m_state = State::Idle;
+        return;
+    }
</ins><span class="cx"> 
</span><del>-void Vibration::stopVibration()
-{
-    m_timerStart.stop();
-    m_timerStop.stop();
-    m_vibrationClient-&gt;cancelVibration();
-    m_isVibrating = false;
-}
-
-void Vibration::timerStartFired(Timer&lt;Vibration&gt;* timer)
-{
-    ASSERT_UNUSED(timer, timer == &amp;m_timerStart);
-
-    m_timerStart.stop();
-
-    if (!m_pattern.isEmpty()) {
</del><ins>+    switch (m_state) {
+    case State::Vibrating:
+        m_state = State::Waiting;
+        break;
+    case State::Waiting:
+    case State::Idle:
+        m_state = State::Vibrating;
</ins><span class="cx">         m_vibrationClient-&gt;vibrate(m_pattern[0]);
</span><del>-        m_timerStop.startOneShot(m_pattern[0] / 1000.0);
-        m_pattern.remove(0);
</del><ins>+        break;
</ins><span class="cx">     }
</span><ins>+    m_timer.startOneShot(m_pattern[0] / 1000.0);
+    m_pattern.remove(0);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Vibration::timerStopFired(Timer&lt;Vibration&gt;* timer)
-{
-    ASSERT_UNUSED(timer, timer == &amp;m_timerStop);
-
-    m_timerStop.stop();
-
-    if (!m_pattern.isEmpty()) {
-        m_timerStart.startOneShot(m_pattern[0] / 1000.0);
-        m_pattern.remove(0);
-        if (m_pattern.isEmpty())
-            m_isVibrating = false;
-    }
-}
-
</del><span class="cx"> const char* Vibration::supplementName()
</span><span class="cx"> {
</span><span class="cx">     return &quot;Vibration&quot;;
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesvibrationVibrationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/vibration/Vibration.h (165597 => 165598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/vibration/Vibration.h        2014-03-14 02:49:04 UTC (rev 165597)
+++ trunk/Source/WebCore/Modules/vibration/Vibration.h        2014-03-14 02:49:57 UTC (rev 165598)
</span><span class="lines">@@ -40,26 +40,22 @@
</span><span class="cx">     static PassOwnPtr&lt;Vibration&gt; create(VibrationClient*);
</span><span class="cx"> 
</span><span class="cx">     bool vibrate(const VibrationPattern&amp;);
</span><ins>+    // FIXME: When a visibilitychange event is dispatched while vibrating, the vibration should be canceled.
</ins><span class="cx">     void cancelVibration();
</span><span class="cx"> 
</span><del>-    // FIXME : Add suspendVibration() and resumeVibration() to the page visibility feature, when the document.hidden attribute is changed.
-    void suspendVibration();
-    void resumeVibration();
-    void timerStartFired(Timer&lt;Vibration&gt;*);
-    void timerStopFired(Timer&lt;Vibration&gt;*);
</del><ins>+    void timerFired(Timer&lt;Vibration&gt;*);
</ins><span class="cx"> 
</span><span class="cx">     static const char* supplementName();
</span><span class="cx">     static Vibration* from(Page* page) { return static_cast&lt;Vibration*&gt;(Supplement&lt;Page&gt;::from(page, supplementName())); }
</span><span class="cx"> 
</span><del>-    bool isVibrating() { return m_isVibrating; }
</del><ins>+    bool isVibrating() { return m_state != State::Idle; }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    void stopVibration();
</del><ins>+    enum class State { Idle, Vibrating, Waiting };
</ins><span class="cx"> 
</span><span class="cx">     VibrationClient* m_vibrationClient;
</span><del>-    Timer&lt;Vibration&gt; m_timerStart;
-    Timer&lt;Vibration&gt; m_timerStop;
-    bool m_isVibrating;
</del><ins>+    Timer&lt;Vibration&gt; m_timer;
+    State m_state;
</ins><span class="cx">     VibrationPattern m_pattern;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (165597 => 165598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2014-03-14 02:49:04 UTC (rev 165597)
+++ trunk/Source/WebKit2/ChangeLog        2014-03-14 02:49:57 UTC (rev 165598)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2014-03-13  Jinwoo Jeong  &lt;jw00.jeong@samsung.com&gt;
+
+        Refactor Vibration algorithm to use only one timer.
+        https://bugs.webkit.org/show_bug.cgi?id=130059
+
+        Reviewed by Darin Adler.
+
+        This patch adds a vibration unit test regression after r161257.
+        It consists of two short term requests to check
+        that Vibration could work properly by sequential requests.
+
+        Indeed this patch tightens condition of existing tests.
+
+        * UIProcess/API/efl/tests/test_ewk2_view.cpp:
+        (TEST_F):
+
</ins><span class="cx"> 2014-03-13  Paul Hankes Drielsma  &lt;phd@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Add SPI to set a custom user agent on WKWebView
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIeflteststest_ewk2_viewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/efl/tests/test_ewk2_view.cpp (165597 => 165598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/efl/tests/test_ewk2_view.cpp        2014-03-14 02:49:04 UTC (rev 165597)
+++ trunk/Source/WebKit2/UIProcess/API/efl/tests/test_ewk2_view.cpp        2014-03-14 02:49:57 UTC (rev 165598)
</span><span class="lines">@@ -928,24 +928,35 @@
</span><span class="cx">     // Vibrate for 5 seconds.
</span><span class="cx">     loadVibrationHTMLString(webView(), &quot;5000&quot;, &amp;data);
</span><span class="cx">     waitUntilTrue(data.testFinished);
</span><del>-    ASSERT_TRUE(data.didReceiveVibrate);
</del><ins>+    ASSERT_TRUE(data.didReceiveVibrate &amp;&amp; !data.didReceiveCancelVibration);
</ins><span class="cx"> 
</span><span class="cx">     // Cancel any existing vibrations.
</span><span class="cx">     loadVibrationHTMLString(webView(), &quot;0&quot;, &amp;data);
</span><span class="cx">     waitUntilTrue(data.testFinished);
</span><del>-    ASSERT_TRUE(data.didReceiveCancelVibration);
</del><ins>+    ASSERT_TRUE(!data.didReceiveVibrate &amp;&amp; data.didReceiveCancelVibration);
</ins><span class="cx"> 
</span><span class="cx">     // This case the pattern will cause the device to vibrate for 200 ms, be still for 100 ms, and then vibrate for 5000 ms.
</span><span class="cx">     loadVibrationHTMLString(webView(), &quot;[200, 100, 5000]&quot;, &amp;data);
</span><span class="cx">     waitUntilTrue(data.testFinished);
</span><span class="cx">     ASSERT_EQ(2, data.vibrateCalledCount);
</span><del>-    ASSERT_TRUE(data.didReceiveVibrate);
</del><ins>+    ASSERT_TRUE(data.didReceiveVibrate &amp;&amp; !data.didReceiveCancelVibration);
</ins><span class="cx"> 
</span><span class="cx">     // Cancel outstanding vibration pattern.
</span><span class="cx">     loadVibrationHTMLString(webView(), &quot;[0]&quot;, &amp;data);
</span><span class="cx">     waitUntilTrue(data.testFinished);
</span><del>-    ASSERT_TRUE(data.didReceiveCancelVibration);
</del><ins>+    ASSERT_TRUE(!data.didReceiveVibrate &amp;&amp; data.didReceiveCancelVibration);
</ins><span class="cx"> 
</span><ins>+    // Check that vibration works properly by continuous request.
+    data.expectedVibrationTime = 5;
+    loadVibrationHTMLString(webView(), &quot;5&quot;, &amp;data);
+    waitUntilTrue(data.testFinished);
+    ASSERT_TRUE(data.didReceiveVibrate &amp;&amp; !data.didReceiveCancelVibration);
+
+    loadVibrationHTMLString(webView(), &quot;5&quot;, &amp;data);
+    waitUntilTrue(data.testFinished);
+    ASSERT_EQ(1, data.vibrateCalledCount);
+    ASSERT_TRUE(data.didReceiveVibrate &amp;&amp; !data.didReceiveCancelVibration);
+
</ins><span class="cx">     // Stop listening for vibration events, by calling the function with null for the callbacks.
</span><span class="cx">     evas_object_smart_callback_del(webView(), &quot;vibrate&quot;, onVibrate);
</span><span class="cx">     evas_object_smart_callback_del(webView(), &quot;cancel,vibration&quot;, onCancelVibration);
</span></span></pre>
</div>
</div>

</body>
</html>