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#include "core/html/MediaDocument.h"
29
30#include "bindings/core/v8/ExceptionStatePlaceholder.h"
31#include "core/HTMLNames.h"
32#include "core/dom/ElementTraversal.h"
33#include "core/dom/RawDataDocumentParser.h"
34#include "core/events/KeyboardEvent.h"
35#include "core/frame/LocalFrame.h"
36#include "core/html/HTMLBodyElement.h"
37#include "core/html/HTMLHeadElement.h"
38#include "core/html/HTMLHtmlElement.h"
39#include "core/html/HTMLMetaElement.h"
40#include "core/html/HTMLSourceElement.h"
41#include "core/html/HTMLVideoElement.h"
42#include "core/loader/DocumentLoader.h"
43#include "core/loader/FrameLoader.h"
44#include "core/loader/FrameLoaderClient.h"
45#include "platform/KeyboardCodes.h"
46
47namespace blink {
48
49using namespace HTMLNames;
50
51// FIXME: Share more code with PluginDocumentParser.
52class MediaDocumentParser : public RawDataDocumentParser {
53public:
54    static PassRefPtrWillBeRawPtr<MediaDocumentParser> create(MediaDocument* document)
55    {
56        return adoptRefWillBeNoop(new MediaDocumentParser(document));
57    }
58
59private:
60    explicit MediaDocumentParser(Document* document)
61        : RawDataDocumentParser(document)
62        , m_didBuildDocumentStructure(false)
63    {
64    }
65
66    virtual void appendBytes(const char*, size_t) OVERRIDE;
67
68    void createDocumentStructure();
69
70    bool m_didBuildDocumentStructure;
71};
72
73void MediaDocumentParser::createDocumentStructure()
74{
75    ASSERT(document());
76    RefPtrWillBeRawPtr<HTMLHtmlElement> rootElement = HTMLHtmlElement::create(*document());
77    rootElement->insertedByParser();
78    document()->appendChild(rootElement);
79
80    if (document()->frame())
81        document()->frame()->loader().dispatchDocumentElementAvailable();
82
83    RefPtrWillBeRawPtr<HTMLHeadElement> head = HTMLHeadElement::create(*document());
84    RefPtrWillBeRawPtr<HTMLMetaElement> meta = HTMLMetaElement::create(*document());
85    meta->setAttribute(nameAttr, "viewport");
86    meta->setAttribute(contentAttr, "width=device-width");
87    head->appendChild(meta.release());
88
89    RefPtrWillBeRawPtr<HTMLVideoElement> media = HTMLVideoElement::create(*document());
90    media->setAttribute(controlsAttr, "");
91    media->setAttribute(autoplayAttr, "");
92    media->setAttribute(nameAttr, "media");
93
94    RefPtrWillBeRawPtr<HTMLSourceElement> source = HTMLSourceElement::create(*document());
95    source->setSrc(document()->url());
96
97    if (DocumentLoader* loader = document()->loader())
98        source->setType(loader->responseMIMEType());
99
100    media->appendChild(source.release());
101
102    RefPtrWillBeRawPtr<HTMLBodyElement> body = HTMLBodyElement::create(*document());
103    body->appendChild(media.release());
104
105    rootElement->appendChild(head.release());
106    rootElement->appendChild(body.release());
107
108    m_didBuildDocumentStructure = true;
109}
110
111void MediaDocumentParser::appendBytes(const char*, size_t)
112{
113    if (m_didBuildDocumentStructure)
114        return;
115
116    LocalFrame* frame = document()->frame();
117    if (!frame->loader().client()->allowMedia(document()->url()))
118        return;
119
120    createDocumentStructure();
121    finish();
122}
123
124MediaDocument::MediaDocument(const DocumentInit& initializer)
125    : HTMLDocument(initializer, MediaDocumentClass)
126{
127    setCompatibilityMode(QuirksMode);
128    lockCompatibilityMode();
129}
130
131PassRefPtrWillBeRawPtr<DocumentParser> MediaDocument::createParser()
132{
133    return MediaDocumentParser::create(this);
134}
135
136void MediaDocument::defaultEventHandler(Event* event)
137{
138    Node* targetNode = event->target()->toNode();
139    if (!targetNode)
140        return;
141
142    if (event->type() == EventTypeNames::keydown && event->isKeyboardEvent()) {
143        HTMLVideoElement* video = Traversal<HTMLVideoElement>::firstWithin(*targetNode);
144        if (!video)
145            return;
146
147        KeyboardEvent* keyboardEvent = toKeyboardEvent(event);
148        if (keyboardEvent->keyIdentifier() == "U+0020" || keyboardEvent->keyCode() == VKEY_MEDIA_PLAY_PAUSE) {
149            // space or media key (play/pause)
150            video->togglePlayState();
151            event->setDefaultHandled();
152        }
153    }
154}
155
156}
157