Changeset 187031 in webkit


Ignore:
Timestamp:
Jul 20, 2015 1:16:18 PM (9 years ago)
Author:
akling@apple.com
Message:

Improve behavior of media elements in page cache.
<https://webkit.org/b/147020>
<rdar://problem/21712311>

Reviewed by Chris Dumez.

Source/WebCore:

Make improvements for media elements when transitioning in/out of page cache:

  • Events that were scheduled when going into cache will now be delivered when the page is restored from cache.
  • Data buffering is turned off while in the cache. This reduces the memory cost of cached pages with media elements on iOS (where mediaserverd would keep upcoming video frames in memory for cached pages.)

Test: media/restore-from-page-cache.html (amended)

  • dom/GenericEventQueue.h:
  • dom/GenericEventQueue.cpp:

(WebCore::GenericEventQueue::enqueueEvent):
(WebCore::GenericEventQueue::suspend):
(WebCore::GenericEventQueue::resume):

Add a simple suspend/resume mechanism to GenericEventQueue that can
be used to support page caching.

  • html/HTMLMediaElement.cpp:

(WebCore::HTMLMediaElement::stop):
(WebCore::HTMLMediaElement::suspend):
(WebCore::HTMLMediaElement::resume):
(WebCore::HTMLMediaElement::stopWithoutDestroyingMediaPlayer):

Adapt to event queueing changes and add calls to setShouldBufferData().

  • html/HTMLSourceElement.h:
  • html/HTMLSourceElement.cpp:

(WebCore::HTMLSourceElement::HTMLSourceElement):
(WebCore::HTMLSourceElement::create):
(WebCore::HTMLSourceElement::activeDOMObjectName):
(WebCore::HTMLSourceElement::canSuspendForPageCache):
(WebCore::HTMLSourceElement::suspend):
(WebCore::HTMLSourceElement::resume):
(WebCore::HTMLSourceElement::stop):

Turn HTMLSourceElement into an ActiveDOMObject so it gets all the
appropriate page cache notifications directly. Suspend the delayed
error event delivery timer when cached.

LayoutTests:

Add some coverage for suspend/resume of queued events on cached media elements.

  • media/restore-from-page-cache-expected.txt:
  • media/restore-from-page-cache.html:
Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r187018 r187031  
     12015-07-20  Andreas Kling  <akling@apple.com>
     2
     3        Improve behavior of media elements in page cache.
     4        <https://webkit.org/b/147020>
     5        <rdar://problem/21712311>
     6
     7        Reviewed by Chris Dumez.
     8
     9        Add some coverage for suspend/resume of queued events on cached media elements.
     10
     11        * media/restore-from-page-cache-expected.txt:
     12        * media/restore-from-page-cache.html:
     13
    1142015-07-19  Tim Horton  <timothy_horton@apple.com>
    215
  • trunk/LayoutTests/media/restore-from-page-cache-expected.txt

    r186569 r187031  
    66EXPECTED (loadCount == '0') OK
    77*** Page going into cache
     8*** Changing playbackRate just before going into cache, to schedule a ratechange event.
     9*** Changing volume just before going into cache, to schedule a volumechange event.
    810*** Page returned from cache
    911EXPECTED (loadCount == '1') OK
    1012EXPECTED (videoComputedStyle.width == '320px') OK
    1113EXPECTED (videoComputedStyle.height == '240px') OK
     14*** ratechange event fired. This should happen AFTER returning from cache.
     15*** volumechange event fired. This should happen AFTER returning from cache.
    1216
  • trunk/LayoutTests/media/restore-from-page-cache.html

    r186569 r187031  
    3434                }
    3535            }
    36                
     36
     37            function pagehide()
     38            {
     39                // Have the video element generate some events that need to be suspended.
     40                // We use multiple events to verify that they fire in the correct order.
     41                consoleWrite("*** Changing playbackRate just before going into cache, to schedule a ratechange event.");
     42                document.getElementsByTagName("video")[0].playbackRate = 2;
     43                consoleWrite("*** Changing volume just before going into cache, to schedule a volumechange event.");
     44                document.getElementsByTagName("video")[0].volume = 0.5;
     45            }
     46
    3747            function canplaythrough()
    3848            {
    3949                testExpected("loadCount", 0);
    4050                if (!loadCount) {
     51                    video = document.getElementsByTagName('video')[0];
    4152                    consoleWrite("*** Page going into cache");
    4253                    setTimeout('window.location = "data:text/html,<script>history.back()<" + "/script>"', 0);
    4354                }
    4455                ++loadCount;
     56            }
     57
     58            function propertyChangeCallback(evt)
     59            {
     60                consoleWrite("*** " + evt.type +  " event fired. This should happen AFTER returning from cache.");
    4561            }
    4662
     
    5369               
    5470                video.src = mediaFile;
     71
     72                video.onratechange = propertyChangeCallback;
     73                video.onvolumechange = propertyChangeCallback;
    5574            }
    5675
    5776            window.onpageshow = pageshow;
     77            window.onpagehide = pagehide;
    5878        </script>
    5979    </head>
  • trunk/Source/WebCore/ChangeLog

    r187026 r187031  
     12015-07-20  Andreas Kling  <akling@apple.com>
     2
     3        Improve behavior of media elements in page cache.
     4        <https://webkit.org/b/147020>
     5        <rdar://problem/21712311>
     6
     7        Reviewed by Chris Dumez.
     8
     9        Make improvements for media elements when transitioning in/out of page cache:
     10
     11        - Events that were scheduled when going into cache will now be delivered
     12          when the page is restored from cache.
     13
     14        - Data buffering is turned off while in the cache. This reduces the memory
     15          cost of cached pages with media elements on iOS (where mediaserverd would
     16          keep upcoming video frames in memory for cached pages.)
     17
     18        Test: media/restore-from-page-cache.html (amended)
     19
     20        * dom/GenericEventQueue.h:
     21        * dom/GenericEventQueue.cpp:
     22        (WebCore::GenericEventQueue::enqueueEvent):
     23        (WebCore::GenericEventQueue::suspend):
     24        (WebCore::GenericEventQueue::resume):
     25
     26            Add a simple suspend/resume mechanism to GenericEventQueue that can
     27            be used to support page caching.
     28
     29        * html/HTMLMediaElement.cpp:
     30        (WebCore::HTMLMediaElement::stop):
     31        (WebCore::HTMLMediaElement::suspend):
     32        (WebCore::HTMLMediaElement::resume):
     33        (WebCore::HTMLMediaElement::stopWithoutDestroyingMediaPlayer):
     34
     35            Adapt to event queueing changes and add calls to setShouldBufferData().
     36
     37        * html/HTMLSourceElement.h:
     38        * html/HTMLSourceElement.cpp:
     39        (WebCore::HTMLSourceElement::HTMLSourceElement):
     40        (WebCore::HTMLSourceElement::create):
     41        (WebCore::HTMLSourceElement::activeDOMObjectName):
     42        (WebCore::HTMLSourceElement::canSuspendForPageCache):
     43        (WebCore::HTMLSourceElement::suspend):
     44        (WebCore::HTMLSourceElement::resume):
     45        (WebCore::HTMLSourceElement::stop):
     46
     47            Turn HTMLSourceElement into an ActiveDOMObject so it gets all the
     48            appropriate page cache notifications directly. Suspend the delayed
     49            error event delivery timer when cached.
     50
    1512015-07-20  Mark Lam  <mark.lam@apple.com>
    252
  • trunk/Source/WebCore/dom/GenericEventQueue.cpp

    r176024 r187031  
    4646}
    4747
    48 bool GenericEventQueue::enqueueEvent(PassRefPtr<Event> event)
     48void GenericEventQueue::enqueueEvent(PassRefPtr<Event> event)
    4949{
    5050    if (m_isClosed)
    51         return false;
     51        return;
    5252
    5353    if (event->target() == &m_owner)
     
    5555
    5656    m_pendingEvents.append(event);
     57
     58    if (m_isSuspended)
     59        return;
     60
    5761    pendingQueues().append(m_weakPtrFactory.createWeakPtr());
    5862    if (!sharedTimer().isActive())
    5963        sharedTimer().startOneShot(0);
    60 
    61     return true;
    6264}
    6365
     
    121123}
    122124
     125void GenericEventQueue::suspend()
     126{
     127    ASSERT(!m_isSuspended);
     128    m_isSuspended = true;
     129    m_weakPtrFactory.revokeAll();
    123130}
     131
     132void GenericEventQueue::resume()
     133{
     134    ASSERT(m_isSuspended);
     135    m_isSuspended = false;
     136
     137    if (m_pendingEvents.isEmpty())
     138        return;
     139
     140    for (unsigned i = 0; i < m_pendingEvents.size(); ++i)
     141        pendingQueues().append(m_weakPtrFactory.createWeakPtr());
     142
     143    if (!sharedTimer().isActive())
     144        sharedTimer().startOneShot(0);
     145}
     146
     147}
  • trunk/Source/WebCore/dom/GenericEventQueue.h

    r176024 r187031  
    4343    ~GenericEventQueue();
    4444
    45     bool enqueueEvent(PassRefPtr<Event>);
     45    void enqueueEvent(PassRefPtr<Event>);
    4646    void close();
    4747
    4848    void cancelAllEvents();
    4949    bool hasPendingEvents() const;
     50
     51    void suspend();
     52    void resume();
    5053
    5154private:
     
    6063    WeakPtrFactory<GenericEventQueue> m_weakPtrFactory;
    6164    bool m_isClosed;
     65    bool m_isSuspended { false };
    6266};
    6367
  • trunk/Source/WebCore/html/HTMLMediaElement.cpp

    r186980 r187031  
    48914891   
    48924892    stopPeriodicTimers();
    4893     cancelPendingEventsAndCallbacks();
     4893
     4894    updateSleepDisabling();
     4895}
     4896
     4897void HTMLMediaElement::stop()
     4898{
     4899    LOG(Media, "HTMLMediaElement::stop(%p)", this);
     4900
     4901    stopWithoutDestroyingMediaPlayer();
    48944902
    48954903    m_asyncEventQueue.close();
    4896 
    4897     updateSleepDisabling();
    4898 }
    4899 
    4900 void HTMLMediaElement::stop()
    4901 {
    4902     LOG(Media, "HTMLMediaElement::stop(%p)", this);
    4903 
    4904     stopWithoutDestroyingMediaPlayer();
    49054904
    49064905    // Once an active DOM object has been stopped it can not be restarted, so we can deallocate
     
    49194918        case PageCache:
    49204919            stopWithoutDestroyingMediaPlayer();
     4920            m_asyncEventQueue.suspend();
     4921            setShouldBufferData(false);
    49214922            m_mediaSession->addBehaviorRestriction(MediaElementSession::RequirePageConsentToResumeMedia);
    49224923            break;
     
    49354936
    49364937    m_inActiveDocument = true;
     4938
     4939    m_asyncEventQueue.resume();
     4940
     4941    setShouldBufferData(true);
    49374942
    49384943    if (!m_mediaSession->pageAllowsPlaybackAfterResuming(*this))
  • trunk/Source/WebCore/html/HTMLSourceElement.cpp

    r177996 r187031  
    4141inline HTMLSourceElement::HTMLSourceElement(const QualifiedName& tagName, Document& document)
    4242    : HTMLElement(tagName, document)
     43    , ActiveDOMObject(&document)
    4344    , m_errorEventTimer(*this, &HTMLSourceElement::errorEventTimerFired)
    4445{
     
    4950Ref<HTMLSourceElement> HTMLSourceElement::create(const QualifiedName& tagName, Document& document)
    5051{
    51     return adoptRef(*new HTMLSourceElement(tagName, document));
     52    Ref<HTMLSourceElement> sourceElement = adoptRef(*new HTMLSourceElement(tagName, document));
     53    sourceElement->suspendIfNeeded();
     54    return sourceElement;
    5255}
    5356
     
    122125}
    123126
     127const char* HTMLSourceElement::activeDOMObjectName() const
     128{
     129    return "HTMLSourceElement";
     130}
     131
     132bool HTMLSourceElement::canSuspendForPageCache() const
     133{
     134    return true;
     135}
     136
     137void HTMLSourceElement::suspend(ReasonForSuspension why)
     138{
     139    if (why == PageCache) {
     140        m_shouldRescheduleErrorEventOnResume = m_errorEventTimer.isActive();
     141        m_errorEventTimer.stop();
     142    }
     143}
     144
     145void HTMLSourceElement::resume()
     146{
     147    if (m_shouldRescheduleErrorEventOnResume) {
     148        m_errorEventTimer.startOneShot(0);
     149        m_shouldRescheduleErrorEventOnResume = false;
     150    }
     151}
     152
     153void HTMLSourceElement::stop()
     154{
     155    cancelPendingErrorEvent();
     156}
     157
    124158}
    125159
  • trunk/Source/WebCore/html/HTMLSourceElement.h

    r177996 r187031  
    3333namespace WebCore {
    3434
    35 class HTMLSourceElement final : public HTMLElement {
     35class HTMLSourceElement final : public HTMLElement, public ActiveDOMObject {
    3636public:
    3737    static Ref<HTMLSourceElement> create(const QualifiedName&, Document&);
     
    5353    virtual bool isURLAttribute(const Attribute&) const override;
    5454
     55    // ActiveDOMObject.
     56    const char* activeDOMObjectName() const override;
     57    bool canSuspendForPageCache() const override;
     58    void suspend(ReasonForSuspension) override;
     59    void resume() override;
     60    void stop() override;
     61
    5562    void errorEventTimerFired();
    5663
    5764    Timer m_errorEventTimer;
     65    bool m_shouldRescheduleErrorEventOnResume { false };
    5866};
    5967
Note: See TracChangeset for help on using the changeset viewer.