WebCore/loader/MediaDocument.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  * 1. Redistributions of source code must retain the above copyright
       
     8  *    notice, this list of conditions and the following disclaimer.
       
     9  * 2. Redistributions in binary form must reproduce the above copyright
       
    10  *    notice, this list of conditions and the following disclaimer in the
       
    11  *    documentation and/or other materials provided with the distribution.
       
    12  *
       
    13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
       
    14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
       
    17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
       
    21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
       
    24  */
       
    25 
       
    26 #include "config.h"
       
    27 
       
    28 #if ENABLE(VIDEO)
       
    29 #include "MediaDocument.h"
       
    30 
       
    31 #include "DocumentLoader.h"
       
    32 #include "EventNames.h"
       
    33 #include "Frame.h"
       
    34 #include "FrameLoaderClient.h"
       
    35 #include "HTMLEmbedElement.h"
       
    36 #include "HTMLNames.h"
       
    37 #include "HTMLVideoElement.h"
       
    38 #include "KeyboardEvent.h"
       
    39 #include "MainResourceLoader.h"
       
    40 #include "NodeList.h"
       
    41 #include "RawDataDocumentParser.h"
       
    42 
       
    43 namespace WebCore {
       
    44 
       
    45 using namespace HTMLNames;
       
    46 
       
    47 // FIXME: Share more code with PluginDocumentParser.
       
    48 class MediaDocumentParser : public RawDataDocumentParser {
       
    49 public:
       
    50     MediaDocumentParser(Document* document)
       
    51         : RawDataDocumentParser(document)
       
    52         , m_mediaElement(0)
       
    53     {
       
    54     }
       
    55 
       
    56 private:
       
    57     virtual void appendBytes(DocumentWriter*, const char*, int, bool);
       
    58 
       
    59     void createDocumentStructure();
       
    60 
       
    61     HTMLMediaElement* m_mediaElement;
       
    62 };
       
    63     
       
    64 void MediaDocumentParser::createDocumentStructure()
       
    65 {
       
    66     ExceptionCode ec;
       
    67     RefPtr<Element> rootElement = document()->createElement(htmlTag, false);
       
    68     document()->appendChild(rootElement, ec);
       
    69         
       
    70     RefPtr<Element> body = document()->createElement(bodyTag, false);
       
    71     body->setAttribute(styleAttr, "background-color: rgb(38,38,38);");
       
    72 
       
    73     rootElement->appendChild(body, ec);
       
    74         
       
    75     RefPtr<Element> mediaElement = document()->createElement(videoTag, false);
       
    76         
       
    77     m_mediaElement = static_cast<HTMLVideoElement*>(mediaElement.get());
       
    78     m_mediaElement->setAttribute(controlsAttr, "");
       
    79     m_mediaElement->setAttribute(autoplayAttr, "");
       
    80     m_mediaElement->setAttribute(styleAttr, "margin: auto; position: absolute; top: 0; right: 0; bottom: 0; left: 0;");
       
    81 
       
    82     m_mediaElement->setAttribute(nameAttr, "media");
       
    83     m_mediaElement->setSrc(document()->url());
       
    84     
       
    85     body->appendChild(mediaElement, ec);
       
    86 
       
    87     Frame* frame = document()->frame();
       
    88     if (!frame)
       
    89         return;
       
    90 
       
    91     frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false);
       
    92 }
       
    93 
       
    94 void MediaDocumentParser::appendBytes(DocumentWriter*, const char*, int, bool)
       
    95 {
       
    96     ASSERT(!m_mediaElement);
       
    97     if (m_mediaElement)
       
    98         return;
       
    99 
       
   100     createDocumentStructure();
       
   101     finish();
       
   102 }
       
   103     
       
   104 MediaDocument::MediaDocument(Frame* frame, const KURL& url)
       
   105     : HTMLDocument(frame, url)
       
   106     , m_replaceMediaElementTimer(this, &MediaDocument::replaceMediaElementTimerFired)
       
   107 {
       
   108     setParseMode(Compat);
       
   109 }
       
   110 
       
   111 MediaDocument::~MediaDocument()
       
   112 {
       
   113     ASSERT(!m_replaceMediaElementTimer.isActive());
       
   114 }
       
   115 
       
   116 DocumentParser* MediaDocument::createParser()
       
   117 {
       
   118     return new MediaDocumentParser(this);
       
   119 }
       
   120 
       
   121 void MediaDocument::defaultEventHandler(Event* event)
       
   122 {
       
   123     // Match the default Quicktime plugin behavior to allow 
       
   124     // clicking and double-clicking to pause and play the media.
       
   125     Node* targetNode = event->target()->toNode();
       
   126     if (targetNode && targetNode->hasTagName(videoTag)) {
       
   127         HTMLVideoElement* video = static_cast<HTMLVideoElement*>(targetNode);
       
   128         if (event->type() == eventNames().clickEvent) {
       
   129             if (!video->canPlay()) {
       
   130                 video->pause(event->fromUserGesture());
       
   131                 event->setDefaultHandled();
       
   132             }
       
   133         } else if (event->type() == eventNames().dblclickEvent) {
       
   134             if (video->canPlay()) {
       
   135                 video->play(event->fromUserGesture());
       
   136                 event->setDefaultHandled();
       
   137             }
       
   138         }
       
   139     }
       
   140 
       
   141     if (event->type() == eventNames().keydownEvent && event->isKeyboardEvent()) {
       
   142         HTMLVideoElement* video = 0;
       
   143         if (targetNode) {
       
   144             if (targetNode->hasTagName(videoTag))
       
   145                 video = static_cast<HTMLVideoElement*>(targetNode);
       
   146             else {
       
   147                 RefPtr<NodeList> nodeList = targetNode->getElementsByTagName("video");
       
   148                 if (nodeList.get()->length() > 0)
       
   149                     video = static_cast<HTMLVideoElement*>(nodeList.get()->item(0));
       
   150             }
       
   151         }
       
   152         if (video) {
       
   153             KeyboardEvent* keyboardEvent = static_cast<KeyboardEvent*>(event);
       
   154             if (keyboardEvent->keyIdentifier() == "U+0020") { // space
       
   155                 if (video->paused()) {
       
   156                     if (video->canPlay())
       
   157                         video->play(event->fromUserGesture());
       
   158                 } else
       
   159                     video->pause(event->fromUserGesture());
       
   160                 event->setDefaultHandled();
       
   161             }
       
   162         }
       
   163     }
       
   164 }
       
   165 
       
   166 void MediaDocument::mediaElementSawUnsupportedTracks()
       
   167 {
       
   168     // The HTMLMediaElement was told it has something that the underlying 
       
   169     // MediaPlayer cannot handle so we should switch from <video> to <embed> 
       
   170     // and let the plugin handle this. Don't do it immediately as this 
       
   171     // function may be called directly from a media engine callback, and 
       
   172     // replaceChild will destroy the element, media player, and media engine.
       
   173     m_replaceMediaElementTimer.startOneShot(0);
       
   174 }
       
   175 
       
   176 void MediaDocument::replaceMediaElementTimerFired(Timer<MediaDocument>*)
       
   177 {
       
   178     HTMLElement* htmlBody = body();
       
   179     if (!htmlBody)
       
   180         return;
       
   181 
       
   182     // Set body margin width and height to 0 as that is what a PluginDocument uses.
       
   183     htmlBody->setAttribute(marginwidthAttr, "0");
       
   184     htmlBody->setAttribute(marginheightAttr, "0");
       
   185 
       
   186     RefPtr<NodeList> nodeList = htmlBody->getElementsByTagName("video");
       
   187 
       
   188     if (nodeList.get()->length() > 0) {
       
   189         HTMLVideoElement* videoElement = static_cast<HTMLVideoElement*>(nodeList.get()->item(0));
       
   190 
       
   191         RefPtr<Element> element = Document::createElement(embedTag, false);
       
   192         HTMLEmbedElement* embedElement = static_cast<HTMLEmbedElement*>(element.get());
       
   193 
       
   194         embedElement->setAttribute(widthAttr, "100%");
       
   195         embedElement->setAttribute(heightAttr, "100%");
       
   196         embedElement->setAttribute(nameAttr, "plugin");
       
   197         embedElement->setAttribute(srcAttr, url().string());
       
   198         embedElement->setAttribute(typeAttr, frame()->loader()->writer()->mimeType());
       
   199 
       
   200         ExceptionCode ec;
       
   201         videoElement->parent()->replaceChild(embedElement, videoElement, ec);
       
   202     }
       
   203 }
       
   204 
       
   205 }
       
   206 #endif