Unreviewed build fix
[WebKit-https.git] / Source / WebCore / html / MediaDocument.cpp
index f8a302c..03562e7 100644 (file)
  */
 
 #include "config.h"
+#include "MediaDocument.h"
 
 #if ENABLE(VIDEO)
-#include "MediaDocument.h"
 
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "CustomHeaderFields.h"
 #include "DocumentLoader.h"
 #include "EventNames.h"
-#include "ExceptionCodePlaceholder.h"
 #include "Frame.h"
+#include "FrameLoader.h"
 #include "FrameLoaderClient.h"
+#include "HTMLBodyElement.h"
 #include "HTMLEmbedElement.h"
+#include "HTMLHeadElement.h"
 #include "HTMLHtmlElement.h"
+#include "HTMLMetaElement.h"
 #include "HTMLNames.h"
 #include "HTMLSourceElement.h"
 #include "HTMLVideoElement.h"
 #include "KeyboardEvent.h"
-#include "MainResourceLoader.h"
 #include "NodeList.h"
+#include "Page.h"
 #include "RawDataDocumentParser.h"
+#include "RuntimeEnabledFeatures.h"
 #include "ScriptController.h"
+#include "ShadowRoot.h"
+#include "TypedElementDescendantIterator.h"
+#include <wtf/IsoMallocInlines.h>
+#include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
 
+WTF_MAKE_ISO_ALLOCATED_IMPL(MediaDocument);
+
 using namespace HTMLNames;
 
 // FIXME: Share more code with PluginDocumentParser.
-class MediaDocumentParser : public RawDataDocumentParser {
+class MediaDocumentParser final : public RawDataDocumentParser {
 public:
-    static PassRefPtr<MediaDocumentParser> create(MediaDocument* document)
+    static Ref<MediaDocumentParser> create(MediaDocument& document)
     {
-        return adoptRef(new MediaDocumentParser(document));
+        return adoptRef(*new MediaDocumentParser(document));
     }
     
 private:
-    MediaDocumentParser(Document* document)
-        : RawDataDocumentParser(document)
-        , m_mediaElement(0)
+    MediaDocumentParser(MediaDocument& document)
+        : RawDataDocumentParser { document }
+        , m_outgoingReferrer { document.outgoingReferrer() }
     {
     }
 
-    virtual void appendBytes(DocumentWriter*, const char*, size_t);
-
+    void appendBytes(DocumentWriter&, const char*, size_t) final;
     void createDocumentStructure();
 
-    HTMLMediaElement* m_mediaElement;
+    HTMLMediaElement* m_mediaElement { nullptr };
+    String m_outgoingReferrer;
 };
     
 void MediaDocumentParser::createDocumentStructure()
 {
-    RefPtr<Element> rootElement = document()->createElement(htmlTag, false);
-    document()->appendChild(rootElement, IGNORE_EXCEPTION);
-    document()->setCSSTarget(rootElement.get());
-    static_cast<HTMLHtmlElement*>(rootElement.get())->insertedByParser();
-
-    if (document()->frame())
-        document()->frame()->loader()->dispatchDocumentElementAvailable();
-        
-    RefPtr<Element> body = document()->createElement(bodyTag, false);
-    rootElement->appendChild(body, IGNORE_EXCEPTION);
+    auto& document = *this->document();
 
-    RefPtr<Element> mediaElement = document()->createElement(videoTag, false);
+    auto rootElement = HTMLHtmlElement::create(document);
+    document.appendChild(rootElement);
+    document.setCSSTarget(rootElement.ptr());
+    rootElement->insertedByParser();
 
-    m_mediaElement = static_cast<HTMLVideoElement*>(mediaElement.get());
-    m_mediaElement->setAttribute(controlsAttr, "");
-    m_mediaElement->setAttribute(autoplayAttr, "");
+    if (document.frame())
+        document.frame()->injectUserScripts(InjectAtDocumentStart);
 
-    m_mediaElement->setAttribute(nameAttr, "media");
+#if PLATFORM(IOS_FAMILY)
+    auto headElement = HTMLHeadElement::create(document);
+    rootElement->appendChild(headElement);
 
-    RefPtr<Element> sourceElement = document()->createElement(sourceTag, false);
-    HTMLSourceElement* source = static_cast<HTMLSourceElement*>(sourceElement.get());
-    source->setSrc(document()->url());
+    auto metaElement = HTMLMetaElement::create(document);
+    metaElement->setAttributeWithoutSynchronization(nameAttr, AtomicString("viewport", AtomicString::ConstructFromLiteral));
+    metaElement->setAttributeWithoutSynchronization(contentAttr, AtomicString("width=device-width,initial-scale=1", AtomicString::ConstructFromLiteral));
+    headElement->appendChild(metaElement);
+#endif
 
-    if (DocumentLoader* loader = document()->loader())
-        source->setType(loader->responseMIMEType());
+    auto body = HTMLBodyElement::create(document);
+    rootElement->appendChild(body);
+
+    auto videoElement = HTMLVideoElement::create(document);
+    m_mediaElement = videoElement.ptr();
+    videoElement->setAttributeWithoutSynchronization(controlsAttr, emptyAtom());
+    videoElement->setAttributeWithoutSynchronization(autoplayAttr, emptyAtom());
+    videoElement->setAttributeWithoutSynchronization(srcAttr, document.url().string());
+    if (auto loader = makeRefPtr(document.loader()))
+        videoElement->setAttributeWithoutSynchronization(typeAttr, loader->responseMIMEType());
+
+    if (!RuntimeEnabledFeatures::sharedFeatures().modernMediaControlsEnabled()) {
+        StringBuilder elementStyle;
+        elementStyle.appendLiteral("max-width: 100%; max-height: 100%;");
+#if PLATFORM(IOS_FAMILY)
+        elementStyle.appendLiteral("width: 100%; height: auto;");
+#endif
+        videoElement->setAttribute(styleAttr, elementStyle.toString());
+    }
 
-    m_mediaElement->appendChild(sourceElement, IGNORE_EXCEPTION);
-    body->appendChild(mediaElement, IGNORE_EXCEPTION);
+    body->appendChild(videoElement);
 
-    Frame* frame = document()->frame();
+    RefPtr<Frame> frame = document.frame();
     if (!frame)
         return;
 
-    frame->loader()->activeDocumentLoader()->mainResourceLoader()->setDataBufferingPolicy(DoNotBufferData);
+    frame->loader().activeDocumentLoader()->setMainResourceDataBufferingPolicy(DataBufferingPolicy::DoNotBufferData);
+    frame->loader().setOutgoingReferrer(document.completeURL(m_outgoingReferrer));
 }
 
-void MediaDocumentParser::appendBytes(DocumentWriter*, const char*, size_t)
+void MediaDocumentParser::appendBytes(DocumentWriter&, const char*, size_t)
 {
     if (m_mediaElement)
         return;
@@ -117,12 +144,14 @@ void MediaDocumentParser::appendBytes(DocumentWriter*, const char*, size_t)
     finish();
 }
     
-MediaDocument::MediaDocument(Frame* frame, const KURL& url)
-    : HTMLDocument(frame, url)
-    , m_replaceMediaElementTimer(this, &MediaDocument::replaceMediaElementTimerFired)
+MediaDocument::MediaDocument(Frame* frame, const URL& url)
+    : HTMLDocument(frame, url, MediaDocumentClass)
+    , m_replaceMediaElementTimer(*this, &MediaDocument::replaceMediaElementTimerFired)
 {
-    setCompatibilityMode(QuirksMode);
+    setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
     lockCompatibilityMode();
+    if (frame)
+        m_outgoingReferrer = frame->loader().outgoingReferrer();
 }
 
 MediaDocument::~MediaDocument()
@@ -130,71 +159,71 @@ MediaDocument::~MediaDocument()
     ASSERT(!m_replaceMediaElementTimer.isActive());
 }
 
-PassRefPtr<DocumentParser> MediaDocument::createParser()
+Ref<DocumentParser> MediaDocument::createParser()
 {
-    return MediaDocumentParser::create(this);
+    return MediaDocumentParser::create(*this);
 }
 
-static inline HTMLVideoElement* descendentVideoElement(Node* node)
+static inline HTMLVideoElement* descendantVideoElement(ContainerNode& node)
 {
-    ASSERT(node);
-
-    if (node->hasTagName(videoTag))
-        return static_cast<HTMLVideoElement*>(node);
+    if (is<HTMLVideoElement>(node))
+        return downcast<HTMLVideoElement>(&node);
 
-    RefPtr<NodeList> nodeList = node->getElementsByTagNameNS(videoTag.namespaceURI(), videoTag.localName());
-   
-    if (nodeList.get()->length() > 0)
-        return static_cast<HTMLVideoElement*>(nodeList.get()->item(0));
-
-    return 0;
+    return descendantsOfType<HTMLVideoElement>(node).first();
 }
 
 static inline HTMLVideoElement* ancestorVideoElement(Node* node)
 {
-    while (node && !node->hasTagName(videoTag))
+    while (node && !is<HTMLVideoElement>(*node))
         node = node->parentOrShadowHostNode();
 
-    return static_cast<HTMLVideoElement*>(node);
+    return downcast<HTMLVideoElement>(node);
 }
 
-void MediaDocument::defaultEventHandler(Event* event)
+void MediaDocument::defaultEventHandler(Event& event)
 {
-    // Match the default Quicktime plugin behavior to allow 
+    // Modern media controls have their own event handling to determine when to
+    // pause or resume playback.
+    if (RuntimeEnabledFeatures::sharedFeatures().modernMediaControlsEnabled())
+        return;
+    
+    // Match the default Quicktime plugin behavior to allow
     // clicking and double-clicking to pause and play the media.
-    Node* targetNode = event->target()->toNode();
-    if (!targetNode)
+    if (!is<Node>(event.target()))
         return;
+    auto& targetNode = downcast<Node>(*event.target());
 
-#if !PLATFORM(CHROMIUM)
-    if (HTMLVideoElement* video = ancestorVideoElement(targetNode)) {
-        if (event->type() == eventNames().clickEvent) {
+    if (auto video = makeRefPtr(ancestorVideoElement(&targetNode))) {
+        if (event.type() == eventNames().clickEvent) {
             if (!video->canPlay()) {
                 video->pause();
-                event->setDefaultHandled();
+                event.setDefaultHandled();
             }
-        } else if (event->type() == eventNames().dblclickEvent) {
+        } else if (event.type() == eventNames().dblclickEvent) {
             if (video->canPlay()) {
                 video->play();
-                event->setDefaultHandled();
+                event.setDefaultHandled();
             }
         }
     }
-#endif
 
-    if (event->type() == eventNames().keydownEvent && event->isKeyboardEvent()) {
-        HTMLVideoElement* video = descendentVideoElement(targetNode);
+    if (!is<ContainerNode>(targetNode))
+        return;
+    auto& targetContainer = downcast<ContainerNode>(targetNode);
+
+    if (event.type() == eventNames().keydownEvent && is<KeyboardEvent>(event)) {
+        auto video = makeRefPtr(descendantVideoElement(targetContainer));
         if (!video)
             return;
 
-        KeyboardEvent* keyboardEvent = static_cast<KeyboardEvent*>(event);
-        if (keyboardEvent->keyIdentifier() == "U+0020") { // space
+        auto& keyboardEvent = downcast<KeyboardEvent>(event);
+        if (keyboardEvent.keyIdentifier() == "U+0020") { // space
             if (video->paused()) {
                 if (video->canPlay())
                     video->play();
             } else
                 video->pause();
-            event->setDefaultHandled();
+            keyboardEvent.setDefaultHandled();
         }
     }
 }
@@ -206,36 +235,47 @@ void MediaDocument::mediaElementSawUnsupportedTracks()
     // and let the plugin handle this. Don't do it immediately as this 
     // function may be called directly from a media engine callback, and 
     // replaceChild will destroy the element, media player, and media engine.
-    m_replaceMediaElementTimer.startOneShot(0);
+    m_replaceMediaElementTimer.startOneShot(0_s);
 }
 
-void MediaDocument::replaceMediaElementTimerFired(Timer<MediaDocument>*)
+void MediaDocument::replaceMediaElementTimerFired()
 {
-    HTMLElement* htmlBody = body();
+    auto htmlBody = makeRefPtr(bodyOrFrameset());
     if (!htmlBody)
         return;
 
     // Set body margin width and height to 0 as that is what a PluginDocument uses.
-    htmlBody->setAttribute(marginwidthAttr, "0");
-    htmlBody->setAttribute(marginheightAttr, "0");
+    htmlBody->setAttributeWithoutSynchronization(marginwidthAttr, AtomicString("0", AtomicString::ConstructFromLiteral));
+    htmlBody->setAttributeWithoutSynchronization(marginheightAttr, AtomicString("0", AtomicString::ConstructFromLiteral));
 
-    if (HTMLVideoElement* videoElement = descendentVideoElement(htmlBody)) {
-        RefPtr<Element> element = Document::createElement(embedTag, false);
-        HTMLEmbedElement* embedElement = static_cast<HTMLEmbedElement*>(element.get());
+    if (auto videoElement = makeRefPtr(descendantVideoElement(*htmlBody))) {
+        auto embedElement = HTMLEmbedElement::create(*this);
 
-        embedElement->setAttribute(widthAttr, "100%");
-        embedElement->setAttribute(heightAttr, "100%");
-        embedElement->setAttribute(nameAttr, "plugin");
-        embedElement->setAttribute(srcAttr, url().string());
+        embedElement->setAttributeWithoutSynchronization(widthAttr, AtomicString("100%", AtomicString::ConstructFromLiteral));
+        embedElement->setAttributeWithoutSynchronization(heightAttr, AtomicString("100%", AtomicString::ConstructFromLiteral));
+        embedElement->setAttributeWithoutSynchronization(nameAttr, AtomicString("plugin", AtomicString::ConstructFromLiteral));
+        embedElement->setAttributeWithoutSynchronization(srcAttr, url().string());
 
-        DocumentLoader* documentLoader = loader();
-        ASSERT(documentLoader);
-        if (documentLoader)
-            embedElement->setAttribute(typeAttr, documentLoader->writer()->mimeType());
+        ASSERT(loader());
+        if (auto loader = makeRefPtr(this->loader()))
+            embedElement->setAttributeWithoutSynchronization(typeAttr, loader->writer().mimeType());
 
-        videoElement->parentNode()->replaceChild(embedElement, videoElement, IGNORE_EXCEPTION);
+        videoElement->parentNode()->replaceChild(embedElement, *videoElement);
     }
 }
 
+void MediaDocument::mediaElementNaturalSizeChanged(const IntSize& newSize)
+{
+    if (ownerElement())
+        return;
+
+    if (newSize.isZero())
+        return;
+
+    if (page())
+        page()->chrome().client().imageOrMediaDocumentSizeChanged(newSize);
 }
+
+}
+
 #endif