blob: 7bb107a0d2eec7f1b3b4eaddcd4352f2ae4e88c9 [file] [log] [blame]
/*
* Copyright (C) 2021 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "ModelDocument.h"
#if ENABLE(MODEL_ELEMENT)
#include "Document.h"
#include "DocumentLoader.h"
#include "EventNames.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "HTMLBodyElement.h"
#include "HTMLHeadElement.h"
#include "HTMLHtmlElement.h"
#include "HTMLMetaElement.h"
#include "HTMLModelElement.h"
#include "HTMLNames.h"
#include "HTMLSourceElement.h"
#include "HTMLStyleElement.h"
#include "RawDataDocumentParser.h"
#include <wtf/IsoMallocInlines.h>
#include <wtf/text/StringBuilder.h>
namespace WebCore {
WTF_MAKE_ISO_ALLOCATED_IMPL(ModelDocument);
using namespace HTMLNames;
class ModelDocumentParser final : public RawDataDocumentParser {
public:
static Ref<ModelDocumentParser> create(ModelDocument& document)
{
return adoptRef(*new ModelDocumentParser(document));
}
private:
ModelDocumentParser(ModelDocument& document)
: RawDataDocumentParser { document }
, m_outgoingReferrer { document.outgoingReferrer() }
{
}
void createDocumentStructure();
void appendBytes(DocumentWriter&, const uint8_t*, size_t) final;
void finish() final;
HTMLModelElement* m_modelElement { nullptr };
String m_outgoingReferrer;
};
void ModelDocumentParser::createDocumentStructure()
{
auto& document = *this->document();
auto rootElement = HTMLHtmlElement::create(document);
document.appendChild(rootElement);
document.setCSSTarget(rootElement.ptr());
rootElement->insertedByParser();
if (document.frame())
document.frame()->injectUserScripts(UserScriptInjectionTime::DocumentStart);
auto headElement = HTMLHeadElement::create(document);
rootElement->appendChild(headElement);
auto metaElement = HTMLMetaElement::create(document);
metaElement->setAttributeWithoutSynchronization(nameAttr, "viewport"_s);
metaElement->setAttributeWithoutSynchronization(contentAttr, "width=device-width,initial-scale=1"_s);
headElement->appendChild(metaElement);
auto styleElement = HTMLStyleElement::create(document);
auto styleContent = "body { background-color: white; text-align: center; }\n"
"@media (prefers-color-scheme: dark) { body { background-color: rgb(32, 32, 37); } }\n"
"model { width: 80vw; height: 80vh; }\n"_s;
styleElement->setTextContent(styleContent);
headElement->appendChild(styleElement);
auto body = HTMLBodyElement::create(document);
rootElement->appendChild(body);
auto modelElement = HTMLModelElement::create(HTMLNames::modelTag, document);
m_modelElement = modelElement.ptr();
modelElement->setAttributeWithoutSynchronization(interactiveAttr, emptyAtom());
auto sourceElement = HTMLSourceElement::create(HTMLNames::sourceTag, document);
sourceElement->setAttributeWithoutSynchronization(srcAttr, AtomString { document.url().string() });
if (RefPtr loader = document.loader())
sourceElement->setAttributeWithoutSynchronization(typeAttr, AtomString { loader->responseMIMEType() });
modelElement->appendChild(sourceElement);
body->appendChild(modelElement);
document.setHasVisuallyNonEmptyCustomContent();
auto frame = document.frame();
if (!frame)
return;
frame->loader().activeDocumentLoader()->setMainResourceDataBufferingPolicy(DataBufferingPolicy::DoNotBufferData);
frame->loader().setOutgoingReferrer(document.completeURL(m_outgoingReferrer));
}
void ModelDocumentParser::appendBytes(DocumentWriter&, const uint8_t*, size_t)
{
if (!m_modelElement)
createDocumentStructure();
}
void ModelDocumentParser::finish()
{
document()->finishedParsing();
}
ModelDocument::ModelDocument(Frame* frame, const Settings& settings, const URL& url)
: HTMLDocument(frame, settings, url, { }, { DocumentClass::Model })
{
if (frame)
m_outgoingReferrer = frame->loader().outgoingReferrer();
}
Ref<DocumentParser> ModelDocument::createParser()
{
return ModelDocumentParser::create(*this);
}
}
#endif