mirror of
https://github.com/RGBCube/serenity
synced 2026-01-12 23:31:01 +00:00
Libraries: Move to Userland/Libraries/
This commit is contained in:
parent
dc28c07fa5
commit
13d7c09125
1857 changed files with 266 additions and 274 deletions
46
Userland/Libraries/LibWeb/Bindings/EventListenerWrapper.cpp
Normal file
46
Userland/Libraries/LibWeb/Bindings/EventListenerWrapper.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibJS/Runtime/Function.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibWeb/Bindings/EventListenerWrapper.h>
|
||||
#include <LibWeb/DOM/EventListener.h>
|
||||
|
||||
namespace Web {
|
||||
namespace Bindings {
|
||||
|
||||
EventListenerWrapper::EventListenerWrapper(JS::GlobalObject& global_object, DOM::EventListener& impl)
|
||||
: Wrapper(*global_object.object_prototype())
|
||||
, m_impl(impl)
|
||||
{
|
||||
}
|
||||
|
||||
EventListenerWrapper::~EventListenerWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
49
Userland/Libraries/LibWeb/Bindings/EventListenerWrapper.h
Normal file
49
Userland/Libraries/LibWeb/Bindings/EventListenerWrapper.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Bindings/Wrapper.h>
|
||||
|
||||
namespace Web {
|
||||
namespace Bindings {
|
||||
|
||||
class EventListenerWrapper final : public Wrapper {
|
||||
JS_OBJECT(EventListenerWrapper, Wrapper);
|
||||
|
||||
public:
|
||||
EventListenerWrapper(JS::GlobalObject&, DOM::EventListener&);
|
||||
virtual ~EventListenerWrapper() override;
|
||||
|
||||
DOM::EventListener& impl() { return *m_impl; }
|
||||
const DOM::EventListener& impl() const { return *m_impl; }
|
||||
|
||||
private:
|
||||
NonnullRefPtr<DOM::EventListener> m_impl;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/Bindings/EventTargetWrapperFactory.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
EventTargetWrapper* wrap(JS::GlobalObject& global_object, DOM::EventTarget& target)
|
||||
{
|
||||
return target.create_wrapper(global_object);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
EventTargetWrapper* wrap(JS::GlobalObject&, DOM::EventTarget&);
|
||||
|
||||
}
|
||||
42
Userland/Libraries/LibWeb/Bindings/EventWrapperFactory.cpp
Normal file
42
Userland/Libraries/LibWeb/Bindings/EventWrapperFactory.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/Bindings/EventWrapper.h>
|
||||
#include <LibWeb/Bindings/EventWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/MouseEventWrapper.h>
|
||||
|
||||
namespace Web {
|
||||
namespace Bindings {
|
||||
|
||||
EventWrapper* wrap(JS::GlobalObject& global_object, DOM::Event& event)
|
||||
{
|
||||
if (is<UIEvents::MouseEvent>(event))
|
||||
return static_cast<MouseEventWrapper*>(wrap_impl(global_object, static_cast<UIEvents::MouseEvent&>(event)));
|
||||
return static_cast<EventWrapper*>(wrap_impl(global_object, event));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
36
Userland/Libraries/LibWeb/Bindings/EventWrapperFactory.h
Normal file
36
Userland/Libraries/LibWeb/Bindings/EventWrapperFactory.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
EventWrapper* wrap(JS::GlobalObject&, DOM::Event&);
|
||||
|
||||
}
|
||||
146
Userland/Libraries/LibWeb/Bindings/LocationObject.cpp
Normal file
146
Userland/Libraries/LibWeb/Bindings/LocationObject.cpp
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/FlyString.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibWeb/Bindings/LocationObject.h>
|
||||
#include <LibWeb/Bindings/WindowObject.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Window.h>
|
||||
|
||||
namespace Web {
|
||||
namespace Bindings {
|
||||
|
||||
LocationObject::LocationObject(JS::GlobalObject& global_object)
|
||||
: Object(*global_object.object_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void LocationObject::initialize(JS::GlobalObject& global_object)
|
||||
{
|
||||
Object::initialize(global_object);
|
||||
u8 attr = JS::Attribute::Writable | JS::Attribute::Enumerable;
|
||||
define_native_property("href", href_getter, href_setter, attr);
|
||||
define_native_property("host", host_getter, nullptr, attr);
|
||||
define_native_property("hostname", hostname_getter, nullptr, attr);
|
||||
define_native_property("pathname", pathname_getter, nullptr, attr);
|
||||
define_native_property("hash", hash_getter, nullptr, attr);
|
||||
define_native_property("search", search_getter, nullptr, attr);
|
||||
define_native_property("protocol", protocol_getter, nullptr, attr);
|
||||
|
||||
define_native_function("reload", reload, 0, JS::Attribute::Enumerable);
|
||||
}
|
||||
|
||||
LocationObject::~LocationObject()
|
||||
{
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(LocationObject::href_getter)
|
||||
{
|
||||
auto& window = static_cast<WindowObject&>(global_object);
|
||||
return JS::js_string(vm, window.impl().document().url().to_string());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_SETTER(LocationObject::href_setter)
|
||||
{
|
||||
auto& window = static_cast<WindowObject&>(global_object);
|
||||
auto new_href = value.to_string(global_object);
|
||||
if (vm.exception())
|
||||
return;
|
||||
auto href_url = window.impl().document().complete_url(new_href);
|
||||
if (!href_url.is_valid()) {
|
||||
vm.throw_exception<JS::URIError>(global_object, String::formatted("Invalid URL '{}'", new_href));
|
||||
return;
|
||||
}
|
||||
window.impl().did_set_location_href({}, href_url);
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(LocationObject::pathname_getter)
|
||||
{
|
||||
auto& window = static_cast<WindowObject&>(global_object);
|
||||
return JS::js_string(vm, window.impl().document().url().path());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(LocationObject::hostname_getter)
|
||||
{
|
||||
auto& window = static_cast<WindowObject&>(global_object);
|
||||
return JS::js_string(vm, window.impl().document().url().host());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(LocationObject::host_getter)
|
||||
{
|
||||
auto& window = static_cast<WindowObject&>(global_object);
|
||||
auto url = window.impl().document().url();
|
||||
StringBuilder builder;
|
||||
builder.append(url.host());
|
||||
builder.append(':');
|
||||
builder.appendf("%u", url.port());
|
||||
return JS::js_string(vm, builder.to_string());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(LocationObject::hash_getter)
|
||||
{
|
||||
auto& window = static_cast<WindowObject&>(global_object);
|
||||
auto fragment = window.impl().document().url().fragment();
|
||||
if (!fragment.length())
|
||||
return JS::js_string(vm, "");
|
||||
StringBuilder builder;
|
||||
builder.append('#');
|
||||
builder.append(fragment);
|
||||
return JS::js_string(vm, builder.to_string());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(LocationObject::search_getter)
|
||||
{
|
||||
auto& window = static_cast<WindowObject&>(global_object);
|
||||
auto query = window.impl().document().url().query();
|
||||
if (!query.length())
|
||||
return JS::js_string(vm, "");
|
||||
StringBuilder builder;
|
||||
builder.append('?');
|
||||
builder.append(query);
|
||||
return JS::js_string(vm, builder.to_string());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(LocationObject::protocol_getter)
|
||||
{
|
||||
auto& window = static_cast<WindowObject&>(global_object);
|
||||
StringBuilder builder;
|
||||
builder.append(window.impl().document().url().protocol());
|
||||
builder.append(':');
|
||||
return JS::js_string(vm, builder.to_string());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(LocationObject::reload)
|
||||
{
|
||||
auto& window = static_cast<WindowObject&>(global_object);
|
||||
window.impl().did_call_location_reload({});
|
||||
return JS::js_undefined();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
58
Userland/Libraries/LibWeb/Bindings/LocationObject.h
Normal file
58
Userland/Libraries/LibWeb/Bindings/LocationObject.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web {
|
||||
namespace Bindings {
|
||||
|
||||
class LocationObject final : public JS::Object {
|
||||
JS_OBJECT(LocationObject, JS::Object);
|
||||
|
||||
public:
|
||||
explicit LocationObject(JS::GlobalObject&);
|
||||
virtual void initialize(JS::GlobalObject&) override;
|
||||
virtual ~LocationObject() override;
|
||||
|
||||
private:
|
||||
JS_DECLARE_NATIVE_FUNCTION(reload);
|
||||
|
||||
JS_DECLARE_NATIVE_GETTER(href_getter);
|
||||
JS_DECLARE_NATIVE_SETTER(href_setter);
|
||||
|
||||
JS_DECLARE_NATIVE_GETTER(host_getter);
|
||||
JS_DECLARE_NATIVE_GETTER(hostname_getter);
|
||||
JS_DECLARE_NATIVE_GETTER(pathname_getter);
|
||||
JS_DECLARE_NATIVE_GETTER(hash_getter);
|
||||
JS_DECLARE_NATIVE_GETTER(search_getter);
|
||||
JS_DECLARE_NATIVE_GETTER(protocol_getter);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
69
Userland/Libraries/LibWeb/Bindings/NavigatorObject.cpp
Normal file
69
Userland/Libraries/LibWeb/Bindings/NavigatorObject.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/FlyString.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibWeb/Bindings/NavigatorObject.h>
|
||||
#include <LibWeb/Loader/ResourceLoader.h>
|
||||
|
||||
namespace Web {
|
||||
namespace Bindings {
|
||||
|
||||
NavigatorObject::NavigatorObject(JS::GlobalObject& global_object)
|
||||
: Object(*global_object.object_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void NavigatorObject::initialize(JS::GlobalObject& global_object)
|
||||
{
|
||||
auto& heap = this->heap();
|
||||
auto* languages = JS::Array::create(global_object);
|
||||
languages->indexed_properties().append(js_string(heap, "en-US"));
|
||||
|
||||
define_property("appCodeName", js_string(heap, "Mozilla"));
|
||||
define_property("appName", js_string(heap, "Netscape"));
|
||||
define_property("appVersion", js_string(heap, "4.0"));
|
||||
define_property("language", languages->get(0));
|
||||
define_property("languages", languages);
|
||||
define_property("platform", js_string(heap, "SerenityOS"));
|
||||
define_property("product", js_string(heap, "Gecko"));
|
||||
|
||||
define_native_property("userAgent", user_agent_getter, nullptr);
|
||||
}
|
||||
|
||||
NavigatorObject::~NavigatorObject()
|
||||
{
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(NavigatorObject::user_agent_getter)
|
||||
{
|
||||
return JS::js_string(vm, ResourceLoader::the().user_agent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
48
Userland/Libraries/LibWeb/Bindings/NavigatorObject.h
Normal file
48
Userland/Libraries/LibWeb/Bindings/NavigatorObject.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web {
|
||||
namespace Bindings {
|
||||
|
||||
class NavigatorObject final : public JS::Object {
|
||||
JS_OBJECT(NavigatorObject, JS::Object);
|
||||
|
||||
public:
|
||||
NavigatorObject(JS::GlobalObject&);
|
||||
virtual void initialize(JS::GlobalObject&) override;
|
||||
virtual ~NavigatorObject() override;
|
||||
|
||||
private:
|
||||
JS_DECLARE_NATIVE_GETTER(user_agent_getter);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
347
Userland/Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp
Normal file
347
Userland/Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020, Luke Wilde <luke.wilde@live.co.uk>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/Bindings/CharacterDataWrapper.h>
|
||||
#include <LibWeb/Bindings/CommentWrapper.h>
|
||||
#include <LibWeb/Bindings/DocumentFragmentWrapper.h>
|
||||
#include <LibWeb/Bindings/DocumentTypeWrapper.h>
|
||||
#include <LibWeb/Bindings/DocumentWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLAnchorElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLAreaElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLAudioElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLBRElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLBaseElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLBodyElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLButtonElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLCanvasElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLDListElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLDataElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLDataListElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLDetailsElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLDialogElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLDirectoryElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLDivElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLEmbedElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLFieldSetElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLFontElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLFormElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLFrameElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLFrameSetElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLHRElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLHeadElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLHeadingElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLHtmlElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLIFrameElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLImageElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLInputElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLLIElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLLabelElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLLegendElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLLinkElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLMapElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLMarqueeElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLMenuElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLMetaElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLMeterElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLModElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLOListElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLObjectElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLOptGroupElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLOptionElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLOutputElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLParagraphElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLParamElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLPictureElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLPreElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLProgressElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLQuoteElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLScriptElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLSelectElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLSlotElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLSourceElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLSpanElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLStyleElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLTableCaptionElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLTableCellElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLTableColElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLTableElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLTableRowElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLTableSectionElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLTemplateElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLTextAreaElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLTimeElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLTitleElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLTrackElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLUListElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLUnknownElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLVideoElementWrapper.h>
|
||||
#include <LibWeb/Bindings/NodeWrapper.h>
|
||||
#include <LibWeb/Bindings/NodeWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/SVGPathElementWrapper.h>
|
||||
#include <LibWeb/Bindings/SVGSVGElementWrapper.h>
|
||||
#include <LibWeb/Bindings/TextWrapper.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
#include <LibWeb/HTML/HTMLAnchorElement.h>
|
||||
#include <LibWeb/HTML/HTMLAreaElement.h>
|
||||
#include <LibWeb/HTML/HTMLAudioElement.h>
|
||||
#include <LibWeb/HTML/HTMLBRElement.h>
|
||||
#include <LibWeb/HTML/HTMLBaseElement.h>
|
||||
#include <LibWeb/HTML/HTMLBodyElement.h>
|
||||
#include <LibWeb/HTML/HTMLButtonElement.h>
|
||||
#include <LibWeb/HTML/HTMLCanvasElement.h>
|
||||
#include <LibWeb/HTML/HTMLDListElement.h>
|
||||
#include <LibWeb/HTML/HTMLDataElement.h>
|
||||
#include <LibWeb/HTML/HTMLDataListElement.h>
|
||||
#include <LibWeb/HTML/HTMLDetailsElement.h>
|
||||
#include <LibWeb/HTML/HTMLDialogElement.h>
|
||||
#include <LibWeb/HTML/HTMLDirectoryElement.h>
|
||||
#include <LibWeb/HTML/HTMLDivElement.h>
|
||||
#include <LibWeb/HTML/HTMLEmbedElement.h>
|
||||
#include <LibWeb/HTML/HTMLFieldSetElement.h>
|
||||
#include <LibWeb/HTML/HTMLFontElement.h>
|
||||
#include <LibWeb/HTML/HTMLFormElement.h>
|
||||
#include <LibWeb/HTML/HTMLFrameElement.h>
|
||||
#include <LibWeb/HTML/HTMLFrameSetElement.h>
|
||||
#include <LibWeb/HTML/HTMLHRElement.h>
|
||||
#include <LibWeb/HTML/HTMLHeadElement.h>
|
||||
#include <LibWeb/HTML/HTMLHeadingElement.h>
|
||||
#include <LibWeb/HTML/HTMLHtmlElement.h>
|
||||
#include <LibWeb/HTML/HTMLIFrameElement.h>
|
||||
#include <LibWeb/HTML/HTMLImageElement.h>
|
||||
#include <LibWeb/HTML/HTMLInputElement.h>
|
||||
#include <LibWeb/HTML/HTMLLIElement.h>
|
||||
#include <LibWeb/HTML/HTMLLabelElement.h>
|
||||
#include <LibWeb/HTML/HTMLLegendElement.h>
|
||||
#include <LibWeb/HTML/HTMLLinkElement.h>
|
||||
#include <LibWeb/HTML/HTMLMapElement.h>
|
||||
#include <LibWeb/HTML/HTMLMarqueeElement.h>
|
||||
#include <LibWeb/HTML/HTMLMenuElement.h>
|
||||
#include <LibWeb/HTML/HTMLMetaElement.h>
|
||||
#include <LibWeb/HTML/HTMLMeterElement.h>
|
||||
#include <LibWeb/HTML/HTMLModElement.h>
|
||||
#include <LibWeb/HTML/HTMLOListElement.h>
|
||||
#include <LibWeb/HTML/HTMLObjectElement.h>
|
||||
#include <LibWeb/HTML/HTMLOptGroupElement.h>
|
||||
#include <LibWeb/HTML/HTMLOptionElement.h>
|
||||
#include <LibWeb/HTML/HTMLOutputElement.h>
|
||||
#include <LibWeb/HTML/HTMLParagraphElement.h>
|
||||
#include <LibWeb/HTML/HTMLParamElement.h>
|
||||
#include <LibWeb/HTML/HTMLPictureElement.h>
|
||||
#include <LibWeb/HTML/HTMLPreElement.h>
|
||||
#include <LibWeb/HTML/HTMLProgressElement.h>
|
||||
#include <LibWeb/HTML/HTMLQuoteElement.h>
|
||||
#include <LibWeb/HTML/HTMLScriptElement.h>
|
||||
#include <LibWeb/HTML/HTMLSelectElement.h>
|
||||
#include <LibWeb/HTML/HTMLSlotElement.h>
|
||||
#include <LibWeb/HTML/HTMLSourceElement.h>
|
||||
#include <LibWeb/HTML/HTMLSpanElement.h>
|
||||
#include <LibWeb/HTML/HTMLStyleElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableCaptionElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableCellElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableColElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableRowElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableSectionElement.h>
|
||||
#include <LibWeb/HTML/HTMLTemplateElement.h>
|
||||
#include <LibWeb/HTML/HTMLTextAreaElement.h>
|
||||
#include <LibWeb/HTML/HTMLTimeElement.h>
|
||||
#include <LibWeb/HTML/HTMLTitleElement.h>
|
||||
#include <LibWeb/HTML/HTMLTrackElement.h>
|
||||
#include <LibWeb/HTML/HTMLUListElement.h>
|
||||
#include <LibWeb/HTML/HTMLUnknownElement.h>
|
||||
#include <LibWeb/HTML/HTMLVideoElement.h>
|
||||
#include <LibWeb/SVG/SVGPathElement.h>
|
||||
#include <LibWeb/SVG/SVGSVGElement.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
NodeWrapper* wrap(JS::GlobalObject& global_object, DOM::Node& node)
|
||||
{
|
||||
if (is<DOM::Document>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::Document>(node)));
|
||||
if (is<DOM::DocumentType>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::DocumentType>(node)));
|
||||
if (is<HTML::HTMLAnchorElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLAnchorElement>(node)));
|
||||
if (is<HTML::HTMLAreaElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLAreaElement>(node)));
|
||||
if (is<HTML::HTMLAudioElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLAudioElement>(node)));
|
||||
if (is<HTML::HTMLBaseElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLBaseElement>(node)));
|
||||
if (is<HTML::HTMLBodyElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLBodyElement>(node)));
|
||||
if (is<HTML::HTMLBRElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLBRElement>(node)));
|
||||
if (is<HTML::HTMLButtonElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLButtonElement>(node)));
|
||||
if (is<HTML::HTMLCanvasElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLCanvasElement>(node)));
|
||||
if (is<HTML::HTMLDataElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLDataElement>(node)));
|
||||
if (is<HTML::HTMLDataListElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLDataListElement>(node)));
|
||||
if (is<HTML::HTMLDetailsElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLDetailsElement>(node)));
|
||||
if (is<HTML::HTMLDialogElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLDialogElement>(node)));
|
||||
if (is<HTML::HTMLDirectoryElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLDirectoryElement>(node)));
|
||||
if (is<HTML::HTMLDivElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLDivElement>(node)));
|
||||
if (is<HTML::HTMLDListElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLDListElement>(node)));
|
||||
if (is<HTML::HTMLEmbedElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLEmbedElement>(node)));
|
||||
if (is<HTML::HTMLFieldSetElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLFieldSetElement>(node)));
|
||||
if (is<HTML::HTMLFontElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLFontElement>(node)));
|
||||
if (is<HTML::HTMLFormElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLFormElement>(node)));
|
||||
if (is<HTML::HTMLFrameElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLFrameElement>(node)));
|
||||
if (is<HTML::HTMLFrameSetElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLFrameSetElement>(node)));
|
||||
if (is<HTML::HTMLHeadElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLHeadElement>(node)));
|
||||
if (is<HTML::HTMLHeadingElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLHeadingElement>(node)));
|
||||
if (is<HTML::HTMLHRElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLHRElement>(node)));
|
||||
if (is<HTML::HTMLHtmlElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLHtmlElement>(node)));
|
||||
if (is<HTML::HTMLIFrameElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLIFrameElement>(node)));
|
||||
if (is<HTML::HTMLImageElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLImageElement>(node)));
|
||||
if (is<HTML::HTMLInputElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLInputElement>(node)));
|
||||
if (is<HTML::HTMLLabelElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLLabelElement>(node)));
|
||||
if (is<HTML::HTMLLegendElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLLegendElement>(node)));
|
||||
if (is<HTML::HTMLLIElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLLIElement>(node)));
|
||||
if (is<HTML::HTMLLinkElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLLinkElement>(node)));
|
||||
if (is<HTML::HTMLMapElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLMapElement>(node)));
|
||||
if (is<HTML::HTMLMarqueeElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLMarqueeElement>(node)));
|
||||
if (is<HTML::HTMLMenuElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLMenuElement>(node)));
|
||||
if (is<HTML::HTMLMetaElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLMetaElement>(node)));
|
||||
if (is<HTML::HTMLMeterElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLMeterElement>(node)));
|
||||
if (is<HTML::HTMLModElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLModElement>(node)));
|
||||
if (is<HTML::HTMLObjectElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLObjectElement>(node)));
|
||||
if (is<HTML::HTMLOListElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLOListElement>(node)));
|
||||
if (is<HTML::HTMLOptGroupElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLOptGroupElement>(node)));
|
||||
if (is<HTML::HTMLOptionElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLOptionElement>(node)));
|
||||
if (is<HTML::HTMLOutputElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLOutputElement>(node)));
|
||||
if (is<HTML::HTMLParagraphElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLParagraphElement>(node)));
|
||||
if (is<HTML::HTMLParamElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLParamElement>(node)));
|
||||
if (is<HTML::HTMLPictureElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLPictureElement>(node)));
|
||||
if (is<HTML::HTMLPreElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLPreElement>(node)));
|
||||
if (is<HTML::HTMLProgressElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLProgressElement>(node)));
|
||||
if (is<HTML::HTMLQuoteElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLQuoteElement>(node)));
|
||||
if (is<HTML::HTMLScriptElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLScriptElement>(node)));
|
||||
if (is<HTML::HTMLSelectElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLSelectElement>(node)));
|
||||
if (is<HTML::HTMLSlotElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLSlotElement>(node)));
|
||||
if (is<HTML::HTMLSourceElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLSourceElement>(node)));
|
||||
if (is<HTML::HTMLSpanElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLSpanElement>(node)));
|
||||
if (is<HTML::HTMLStyleElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLStyleElement>(node)));
|
||||
if (is<HTML::HTMLTableCaptionElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLTableCaptionElement>(node)));
|
||||
if (is<HTML::HTMLTableCellElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLTableCellElement>(node)));
|
||||
if (is<HTML::HTMLTableColElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLTableColElement>(node)));
|
||||
if (is<HTML::HTMLTableElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLTableElement>(node)));
|
||||
if (is<HTML::HTMLTableRowElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLTableRowElement>(node)));
|
||||
if (is<HTML::HTMLTableSectionElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLTableSectionElement>(node)));
|
||||
if (is<HTML::HTMLTemplateElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLTemplateElement>(node)));
|
||||
if (is<HTML::HTMLTextAreaElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLTextAreaElement>(node)));
|
||||
if (is<HTML::HTMLTimeElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLTimeElement>(node)));
|
||||
if (is<HTML::HTMLTitleElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLTitleElement>(node)));
|
||||
if (is<HTML::HTMLTrackElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLTrackElement>(node)));
|
||||
if (is<HTML::HTMLUListElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLUListElement>(node)));
|
||||
if (is<HTML::HTMLUnknownElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLUnknownElement>(node)));
|
||||
if (is<HTML::HTMLVideoElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLVideoElement>(node)));
|
||||
if (is<HTML::HTMLElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLElement>(node)));
|
||||
if (is<SVG::SVGSVGElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<SVG::SVGSVGElement>(node)));
|
||||
if (is<SVG::SVGPathElement>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<SVG::SVGPathElement>(node)));
|
||||
if (is<DOM::Element>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::Element>(node)));
|
||||
if (is<DOM::DocumentFragment>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::DocumentFragment>(node)));
|
||||
if (is<DOM::Comment>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::Comment>(node)));
|
||||
if (is<DOM::Text>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::Text>(node)));
|
||||
if (is<DOM::CharacterData>(node))
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::CharacterData>(node)));
|
||||
return static_cast<NodeWrapper*>(wrap_impl(global_object, node));
|
||||
}
|
||||
|
||||
}
|
||||
38
Userland/Libraries/LibWeb/Bindings/NodeWrapperFactory.h
Normal file
38
Userland/Libraries/LibWeb/Bindings/NodeWrapperFactory.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web {
|
||||
namespace Bindings {
|
||||
|
||||
NodeWrapper* wrap(JS::GlobalObject&, DOM::Node&);
|
||||
|
||||
}
|
||||
}
|
||||
62
Userland/Libraries/LibWeb/Bindings/RangeConstructor.cpp
Normal file
62
Userland/Libraries/LibWeb/Bindings/RangeConstructor.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibJS/Heap/Heap.h>
|
||||
#include <LibWeb/Bindings/RangeConstructor.h>
|
||||
#include <LibWeb/Bindings/RangePrototype.h>
|
||||
#include <LibWeb/Bindings/RangeWrapper.h>
|
||||
#include <LibWeb/Bindings/WindowObject.h>
|
||||
#include <LibWeb/DOM/Range.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
RangeConstructor::RangeConstructor(JS::GlobalObject& global_object)
|
||||
: NativeFunction(*global_object.function_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void RangeConstructor::initialize(JS::GlobalObject& global_object)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
NativeFunction::initialize(global_object);
|
||||
auto& window = static_cast<WindowObject&>(global_object);
|
||||
define_property(vm.names.prototype, window.range_prototype(), 0);
|
||||
define_property(vm.names.length, JS::Value(0), JS::Attribute::Configurable);
|
||||
}
|
||||
|
||||
JS::Value RangeConstructor::call()
|
||||
{
|
||||
vm().throw_exception<JS::TypeError>(global_object(), JS::ErrorType::ConstructorWithoutNew, "Range");
|
||||
return {};
|
||||
}
|
||||
|
||||
JS::Value RangeConstructor::construct(Function&)
|
||||
{
|
||||
auto& window = static_cast<WindowObject&>(global_object());
|
||||
return heap().allocate<RangeWrapper>(window, window, DOM::Range::create(window.impl()));
|
||||
}
|
||||
|
||||
}
|
||||
47
Userland/Libraries/LibWeb/Bindings/RangeConstructor.h
Normal file
47
Userland/Libraries/LibWeb/Bindings/RangeConstructor.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
class RangeConstructor final : public JS::NativeFunction {
|
||||
public:
|
||||
explicit RangeConstructor(JS::GlobalObject&);
|
||||
|
||||
void initialize(JS::GlobalObject&) override;
|
||||
|
||||
JS::Value call() override;
|
||||
JS::Value construct(JS::Function& new_target) override;
|
||||
|
||||
private:
|
||||
bool has_constructor() const override { return true; }
|
||||
const char* class_name() const override { return "RangeConstructor"; }
|
||||
};
|
||||
|
||||
}
|
||||
161
Userland/Libraries/LibWeb/Bindings/RangePrototype.cpp
Normal file
161
Userland/Libraries/LibWeb/Bindings/RangePrototype.cpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/Function.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibWeb/Bindings/NodeWrapper.h>
|
||||
#include <LibWeb/Bindings/NodeWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/RangePrototype.h>
|
||||
#include <LibWeb/Bindings/RangeWrapper.h>
|
||||
#include <LibWeb/DOM/Range.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
RangePrototype::RangePrototype(JS::GlobalObject& global_object)
|
||||
: Object(*global_object.object_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void RangePrototype::initialize(JS::GlobalObject& global_object)
|
||||
{
|
||||
auto default_attributes = JS::Attribute::Enumerable | JS::Attribute::Configurable;
|
||||
|
||||
Object::initialize(global_object);
|
||||
|
||||
define_native_function("setStart", set_start, 2);
|
||||
define_native_function("setEnd", set_end, 2);
|
||||
define_native_function("cloneRange", clone_range, 0);
|
||||
|
||||
define_native_property("startContainer", start_container_getter, nullptr, default_attributes);
|
||||
define_native_property("endContainer", end_container_getter, nullptr, default_attributes);
|
||||
define_native_property("startOffset", start_offset_getter, nullptr, default_attributes);
|
||||
define_native_property("endOffset", end_offset_getter, nullptr, default_attributes);
|
||||
}
|
||||
|
||||
static DOM::Range* impl_from(JS::VM& vm, JS::GlobalObject& global_object)
|
||||
{
|
||||
auto* this_object = vm.this_value(global_object).to_object(global_object);
|
||||
if (!this_object)
|
||||
return nullptr;
|
||||
if (StringView("RangeWrapper") != this_object->class_name()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "Range");
|
||||
return nullptr;
|
||||
}
|
||||
return &static_cast<RangeWrapper*>(this_object)->impl();
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(RangePrototype::set_start)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
|
||||
auto arg0 = vm.argument(0).to_object(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
auto arg1 = vm.argument(1).to_number(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
if (!is<NodeWrapper>(arg0)) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "Node");
|
||||
return {};
|
||||
}
|
||||
|
||||
impl->set_start(static_cast<NodeWrapper*>(arg0)->impl(), arg1.as_i32());
|
||||
|
||||
return JS::js_undefined();
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(RangePrototype::set_end)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
|
||||
auto arg0 = vm.argument(0).to_object(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
auto arg1 = vm.argument(1).to_number(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
if (!is<NodeWrapper>(arg0)) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "Node");
|
||||
return {};
|
||||
}
|
||||
|
||||
impl->set_end(static_cast<NodeWrapper*>(arg0)->impl(), arg1.as_i32());
|
||||
|
||||
return JS::js_undefined();
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(RangePrototype::clone_range)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
|
||||
return wrap(global_object, *impl->clone_range());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(RangePrototype::start_container_getter)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
|
||||
return wrap(global_object, *impl->start_container());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(RangePrototype::end_container_getter)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
|
||||
return wrap(global_object, *impl->end_container());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(RangePrototype::start_offset_getter)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
|
||||
return JS::Value(impl->start_offset());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(RangePrototype::end_offset_getter)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
|
||||
return JS::Value(impl->end_offset());
|
||||
}
|
||||
|
||||
}
|
||||
53
Userland/Libraries/LibWeb/Bindings/RangePrototype.h
Normal file
53
Userland/Libraries/LibWeb/Bindings/RangePrototype.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
class RangePrototype final : public JS::Object {
|
||||
JS_OBJECT(RangePrototype, JS::Object);
|
||||
|
||||
public:
|
||||
explicit RangePrototype(JS::GlobalObject&);
|
||||
|
||||
void initialize(JS::GlobalObject&) override;
|
||||
|
||||
private:
|
||||
JS_DECLARE_NATIVE_FUNCTION(set_start);
|
||||
JS_DECLARE_NATIVE_FUNCTION(set_end);
|
||||
JS_DECLARE_NATIVE_FUNCTION(clone_range);
|
||||
|
||||
JS_DECLARE_NATIVE_GETTER(start_container_getter);
|
||||
JS_DECLARE_NATIVE_GETTER(end_container_getter);
|
||||
JS_DECLARE_NATIVE_GETTER(start_offset_getter);
|
||||
JS_DECLARE_NATIVE_GETTER(end_offset_getter);
|
||||
JS_DECLARE_NATIVE_GETTER(collapsed_getter);
|
||||
};
|
||||
|
||||
}
|
||||
47
Userland/Libraries/LibWeb/Bindings/RangeWrapper.cpp
Normal file
47
Userland/Libraries/LibWeb/Bindings/RangeWrapper.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/Bindings/RangePrototype.h>
|
||||
#include <LibWeb/Bindings/RangeWrapper.h>
|
||||
#include <LibWeb/Bindings/WindowObject.h>
|
||||
#include <LibWeb/Bindings/Wrappable.h>
|
||||
#include <LibWeb/DOM/Range.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
RangeWrapper::RangeWrapper(JS::GlobalObject& global_object, DOM::Range& impl)
|
||||
: Wrapper(global_object)
|
||||
, m_impl(impl)
|
||||
{
|
||||
set_prototype(static_cast<WindowObject&>(global_object).range_prototype());
|
||||
}
|
||||
|
||||
RangeWrapper* wrap(JS::GlobalObject& global_object, DOM::Range& impl)
|
||||
{
|
||||
return static_cast<RangeWrapper*>(wrap_impl(global_object, impl));
|
||||
}
|
||||
|
||||
}
|
||||
48
Userland/Libraries/LibWeb/Bindings/RangeWrapper.h
Normal file
48
Userland/Libraries/LibWeb/Bindings/RangeWrapper.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Bindings/Wrapper.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
class RangeWrapper final : public Wrapper {
|
||||
public:
|
||||
RangeWrapper(JS::GlobalObject&, DOM::Range&);
|
||||
|
||||
DOM::Range& impl() { return m_impl; }
|
||||
const DOM::Range& impl() const { return m_impl; }
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "RangeWrapper"; }
|
||||
|
||||
NonnullRefPtr<DOM::Range> m_impl;
|
||||
};
|
||||
|
||||
RangeWrapper* wrap(JS::GlobalObject&, DOM::Range&);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/Bindings/ScriptExecutionContext.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
ScriptExecutionContext::~ScriptExecutionContext()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
43
Userland/Libraries/LibWeb/Bindings/ScriptExecutionContext.h
Normal file
43
Userland/Libraries/LibWeb/Bindings/ScriptExecutionContext.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Weakable.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
class ScriptExecutionContext {
|
||||
public:
|
||||
virtual ~ScriptExecutionContext();
|
||||
|
||||
// FIXME: This should not work this way long-term, interpreters should be on the stack.
|
||||
virtual JS::Interpreter& interpreter() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
361
Userland/Libraries/LibWeb/Bindings/WindowObject.cpp
Normal file
361
Userland/Libraries/LibWeb/Bindings/WindowObject.cpp
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/Base64.h>
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/Function.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibJS/Runtime/Error.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibJS/Runtime/Shape.h>
|
||||
#include <LibTextCodec/Decoder.h>
|
||||
#include <LibWeb/Bindings/DocumentWrapper.h>
|
||||
#include <LibWeb/Bindings/EventWrapper.h>
|
||||
#include <LibWeb/Bindings/EventWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/LocationObject.h>
|
||||
#include <LibWeb/Bindings/NavigatorObject.h>
|
||||
#include <LibWeb/Bindings/NodeWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/PerformanceWrapper.h>
|
||||
#include <LibWeb/Bindings/RangeConstructor.h>
|
||||
#include <LibWeb/Bindings/RangePrototype.h>
|
||||
#include <LibWeb/Bindings/WindowObject.h>
|
||||
#include <LibWeb/Bindings/XMLHttpRequestConstructor.h>
|
||||
#include <LibWeb/Bindings/XMLHttpRequestPrototype.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/Window.h>
|
||||
#include <LibWeb/Origin.h>
|
||||
|
||||
namespace Web {
|
||||
namespace Bindings {
|
||||
|
||||
WindowObject::WindowObject(DOM::Window& impl)
|
||||
: m_impl(impl)
|
||||
{
|
||||
impl.set_wrapper({}, *this);
|
||||
}
|
||||
|
||||
void WindowObject::initialize()
|
||||
{
|
||||
GlobalObject::initialize();
|
||||
|
||||
define_property("window", this, JS::Attribute::Enumerable);
|
||||
define_property("frames", this, JS::Attribute::Enumerable);
|
||||
define_property("self", this, JS::Attribute::Enumerable);
|
||||
define_native_property("document", document_getter, document_setter, JS::Attribute::Enumerable);
|
||||
define_native_property("performance", performance_getter, nullptr, JS::Attribute::Enumerable);
|
||||
define_native_function("alert", alert);
|
||||
define_native_function("confirm", confirm);
|
||||
define_native_function("setInterval", set_interval, 1);
|
||||
define_native_function("setTimeout", set_timeout, 1);
|
||||
define_native_function("clearInterval", clear_interval, 1);
|
||||
define_native_function("clearTimeout", clear_timeout, 1);
|
||||
define_native_function("requestAnimationFrame", request_animation_frame, 1);
|
||||
define_native_function("cancelAnimationFrame", cancel_animation_frame, 1);
|
||||
define_native_function("atob", atob, 1);
|
||||
define_native_function("btoa", btoa, 1);
|
||||
|
||||
// Legacy
|
||||
define_native_property("event", event_getter, nullptr, JS::Attribute::Enumerable);
|
||||
|
||||
define_property("navigator", heap().allocate<NavigatorObject>(*this, *this), JS::Attribute::Enumerable | JS::Attribute::Configurable);
|
||||
define_property("location", heap().allocate<LocationObject>(*this, *this), JS::Attribute::Enumerable | JS::Attribute::Configurable);
|
||||
|
||||
m_xhr_prototype = heap().allocate<XMLHttpRequestPrototype>(*this, *this);
|
||||
add_constructor("XMLHttpRequest", m_xhr_constructor, m_xhr_prototype);
|
||||
|
||||
m_range_prototype = heap().allocate<RangePrototype>(*this, *this);
|
||||
add_constructor("Range", m_range_constructor, m_range_prototype);
|
||||
}
|
||||
|
||||
WindowObject::~WindowObject()
|
||||
{
|
||||
}
|
||||
|
||||
void WindowObject::visit_edges(Visitor& visitor)
|
||||
{
|
||||
GlobalObject::visit_edges(visitor);
|
||||
visitor.visit(m_xhr_constructor);
|
||||
visitor.visit(m_xhr_prototype);
|
||||
visitor.visit(m_range_constructor);
|
||||
visitor.visit(m_range_prototype);
|
||||
}
|
||||
|
||||
Origin WindowObject::origin() const
|
||||
{
|
||||
return impl().document().origin();
|
||||
}
|
||||
|
||||
static DOM::Window* impl_from(JS::VM& vm, JS::GlobalObject& global_object)
|
||||
{
|
||||
auto* this_object = vm.this_value(global_object).to_object(global_object);
|
||||
if (!this_object) {
|
||||
ASSERT_NOT_REACHED();
|
||||
return nullptr;
|
||||
}
|
||||
if (StringView("WindowObject") != this_object->class_name()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "WindowObject");
|
||||
return nullptr;
|
||||
}
|
||||
return &static_cast<WindowObject*>(this_object)->impl();
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(WindowObject::alert)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
String message = "";
|
||||
if (vm.argument_count()) {
|
||||
message = vm.argument(0).to_string(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
}
|
||||
impl->alert(message);
|
||||
return JS::js_undefined();
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(WindowObject::confirm)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
String message = "";
|
||||
if (vm.argument_count()) {
|
||||
message = vm.argument(0).to_string(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
}
|
||||
return JS::Value(impl->confirm(message));
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(WindowObject::set_interval)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
if (!vm.argument_count()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountAtLeastOne, "setInterval");
|
||||
return {};
|
||||
}
|
||||
auto* callback_object = vm.argument(0).to_object(global_object);
|
||||
if (!callback_object)
|
||||
return {};
|
||||
if (!callback_object->is_function()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotAFunctionNoParam);
|
||||
return {};
|
||||
}
|
||||
i32 interval = 0;
|
||||
if (vm.argument_count() >= 2) {
|
||||
interval = vm.argument(1).to_i32(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (interval < 0)
|
||||
interval = 0;
|
||||
}
|
||||
|
||||
auto timer_id = impl->set_interval(*static_cast<JS::Function*>(callback_object), interval);
|
||||
return JS::Value(timer_id);
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(WindowObject::set_timeout)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
if (!vm.argument_count()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountAtLeastOne, "setTimeout");
|
||||
return {};
|
||||
}
|
||||
auto* callback_object = vm.argument(0).to_object(global_object);
|
||||
if (!callback_object)
|
||||
return {};
|
||||
if (!callback_object->is_function()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotAFunctionNoParam);
|
||||
return {};
|
||||
}
|
||||
i32 interval = 0;
|
||||
if (vm.argument_count() >= 2) {
|
||||
interval = vm.argument(1).to_i32(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
if (interval < 0)
|
||||
interval = 0;
|
||||
}
|
||||
|
||||
auto timer_id = impl->set_timeout(*static_cast<JS::Function*>(callback_object), interval);
|
||||
return JS::Value(timer_id);
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(WindowObject::clear_timeout)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
if (!vm.argument_count()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountAtLeastOne, "clearTimeout");
|
||||
return {};
|
||||
}
|
||||
i32 timer_id = vm.argument(0).to_i32(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
impl->clear_timeout(timer_id);
|
||||
return JS::js_undefined();
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(WindowObject::clear_interval)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
if (!vm.argument_count()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountAtLeastOne, "clearInterval");
|
||||
return {};
|
||||
}
|
||||
i32 timer_id = vm.argument(0).to_i32(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
impl->clear_timeout(timer_id);
|
||||
return JS::js_undefined();
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(WindowObject::request_animation_frame)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
if (!vm.argument_count()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountOne, "requestAnimationFrame");
|
||||
return {};
|
||||
}
|
||||
auto* callback_object = vm.argument(0).to_object(global_object);
|
||||
if (!callback_object)
|
||||
return {};
|
||||
if (!callback_object->is_function()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotAFunctionNoParam);
|
||||
return {};
|
||||
}
|
||||
return JS::Value(impl->request_animation_frame(*static_cast<JS::Function*>(callback_object)));
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(WindowObject::cancel_animation_frame)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
if (!vm.argument_count()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountOne, "cancelAnimationFrame");
|
||||
return {};
|
||||
}
|
||||
auto id = vm.argument(0).to_i32(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
impl->cancel_animation_frame(id);
|
||||
return JS::js_undefined();
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(WindowObject::atob)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
if (!vm.argument_count()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountOne, "atob");
|
||||
return {};
|
||||
}
|
||||
auto string = vm.argument(0).to_string(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
auto decoded = decode_base64(StringView(string));
|
||||
|
||||
// decode_base64() returns a byte string. LibJS uses UTF-8 for strings. Use Latin1Decoder to convert bytes 128-255 to UTF-8.
|
||||
auto decoder = TextCodec::decoder_for("windows-1252");
|
||||
ASSERT(decoder);
|
||||
return JS::js_string(vm, decoder->to_utf8(decoded));
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(WindowObject::btoa)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
if (!vm.argument_count()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountOne, "btoa");
|
||||
return {};
|
||||
}
|
||||
auto string = vm.argument(0).to_string(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
|
||||
Vector<u8> byte_string;
|
||||
byte_string.ensure_capacity(string.length());
|
||||
for (u32 code_point : Utf8View(string)) {
|
||||
if (code_point > 0xff) {
|
||||
vm.throw_exception<JS::InvalidCharacterError>(global_object, JS::ErrorType::NotAByteString, "btoa");
|
||||
return {};
|
||||
}
|
||||
byte_string.append(code_point);
|
||||
}
|
||||
|
||||
auto encoded = encode_base64(byte_string.span());
|
||||
return JS::js_string(vm, move(encoded));
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(WindowObject::document_getter)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
return wrap(global_object, impl->document());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_SETTER(WindowObject::document_setter)
|
||||
{
|
||||
// FIXME: Figure out what we should do here. Just ignore attempts to set window.document for now.
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(WindowObject::performance_getter)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
return wrap(global_object, impl->performance());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(WindowObject::event_getter)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
if (!impl->current_event())
|
||||
return JS::js_undefined();
|
||||
return wrap(global_object, const_cast<DOM::Event&>(*impl->current_event()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
88
Userland/Libraries/LibWeb/Bindings/WindowObject.h
Normal file
88
Userland/Libraries/LibWeb/Bindings/WindowObject.h
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <AK/Weakable.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web {
|
||||
namespace Bindings {
|
||||
|
||||
class WindowObject final
|
||||
: public JS::GlobalObject
|
||||
, public Weakable<WindowObject> {
|
||||
public:
|
||||
explicit WindowObject(DOM::Window&);
|
||||
virtual void initialize() override;
|
||||
virtual ~WindowObject() override;
|
||||
|
||||
DOM::Window& impl() { return *m_impl; }
|
||||
const DOM::Window& impl() const { return *m_impl; }
|
||||
|
||||
Origin origin() const;
|
||||
|
||||
XMLHttpRequestPrototype* xhr_prototype() { return m_xhr_prototype; }
|
||||
XMLHttpRequestConstructor* xhr_constructor() { return m_xhr_constructor; }
|
||||
|
||||
RangePrototype* range_prototype() { return m_range_prototype; }
|
||||
RangeConstructor* range_constructor() { return m_range_constructor; }
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "WindowObject"; }
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
JS_DECLARE_NATIVE_GETTER(document_getter);
|
||||
JS_DECLARE_NATIVE_SETTER(document_setter);
|
||||
|
||||
JS_DECLARE_NATIVE_GETTER(performance_getter);
|
||||
|
||||
JS_DECLARE_NATIVE_GETTER(event_getter);
|
||||
|
||||
JS_DECLARE_NATIVE_FUNCTION(alert);
|
||||
JS_DECLARE_NATIVE_FUNCTION(confirm);
|
||||
JS_DECLARE_NATIVE_FUNCTION(set_interval);
|
||||
JS_DECLARE_NATIVE_FUNCTION(set_timeout);
|
||||
JS_DECLARE_NATIVE_FUNCTION(clear_interval);
|
||||
JS_DECLARE_NATIVE_FUNCTION(clear_timeout);
|
||||
JS_DECLARE_NATIVE_FUNCTION(request_animation_frame);
|
||||
JS_DECLARE_NATIVE_FUNCTION(cancel_animation_frame);
|
||||
JS_DECLARE_NATIVE_FUNCTION(atob);
|
||||
JS_DECLARE_NATIVE_FUNCTION(btoa);
|
||||
|
||||
NonnullRefPtr<DOM::Window> m_impl;
|
||||
|
||||
XMLHttpRequestConstructor* m_xhr_constructor { nullptr };
|
||||
XMLHttpRequestPrototype* m_xhr_prototype { nullptr };
|
||||
|
||||
RangePrototype* m_range_prototype { nullptr };
|
||||
RangeConstructor* m_range_constructor { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
44
Userland/Libraries/LibWeb/Bindings/Wrappable.cpp
Normal file
44
Userland/Libraries/LibWeb/Bindings/Wrappable.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/Bindings/Wrappable.h>
|
||||
#include <LibWeb/Bindings/Wrapper.h>
|
||||
|
||||
namespace Web {
|
||||
namespace Bindings {
|
||||
|
||||
Wrappable::~Wrappable()
|
||||
{
|
||||
}
|
||||
|
||||
void Wrappable::set_wrapper(Wrapper& wrapper)
|
||||
{
|
||||
ASSERT(!m_wrapper);
|
||||
m_wrapper = wrapper.make_weak_ptr();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
57
Userland/Libraries/LibWeb/Bindings/Wrappable.h
Normal file
57
Userland/Libraries/LibWeb/Bindings/Wrappable.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <LibJS/Heap/Heap.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
class Wrappable {
|
||||
public:
|
||||
virtual ~Wrappable();
|
||||
|
||||
void set_wrapper(Wrapper&);
|
||||
Wrapper* wrapper() { return m_wrapper; }
|
||||
const Wrapper* wrapper() const { return m_wrapper; }
|
||||
|
||||
private:
|
||||
WeakPtr<Wrapper> m_wrapper;
|
||||
};
|
||||
|
||||
template<class NativeObject>
|
||||
inline Wrapper* wrap_impl(JS::GlobalObject& global_object, NativeObject& native_object)
|
||||
{
|
||||
if (!native_object.wrapper()) {
|
||||
native_object.set_wrapper(*global_object.heap().allocate<typename NativeObject::WrapperType>(global_object, global_object, native_object));
|
||||
}
|
||||
return native_object.wrapper();
|
||||
}
|
||||
|
||||
}
|
||||
49
Userland/Libraries/LibWeb/Bindings/Wrapper.h
Normal file
49
Userland/Libraries/LibWeb/Bindings/Wrapper.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Weakable.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
class Wrapper
|
||||
: public JS::Object
|
||||
, public Weakable<Wrapper> {
|
||||
JS_OBJECT(Wrapper, JS::Object);
|
||||
|
||||
public:
|
||||
protected:
|
||||
explicit Wrapper(Object& prototype)
|
||||
: Object(prototype)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibJS/Heap/Heap.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibWeb/Bindings/WindowObject.h>
|
||||
#include <LibWeb/Bindings/XMLHttpRequestConstructor.h>
|
||||
#include <LibWeb/Bindings/XMLHttpRequestPrototype.h>
|
||||
#include <LibWeb/Bindings/XMLHttpRequestWrapper.h>
|
||||
#include <LibWeb/DOM/XMLHttpRequest.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
XMLHttpRequestConstructor::XMLHttpRequestConstructor(JS::GlobalObject& global_object)
|
||||
: NativeFunction(*global_object.function_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void XMLHttpRequestConstructor::initialize(JS::GlobalObject& global_object)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
NativeFunction::initialize(global_object);
|
||||
auto& window = static_cast<WindowObject&>(global_object);
|
||||
define_property(vm.names.prototype, window.xhr_prototype(), 0);
|
||||
define_property(vm.names.length, JS::Value(1), JS::Attribute::Configurable);
|
||||
|
||||
define_property("UNSENT", JS::Value((i32)XMLHttpRequest::ReadyState::Unsent), JS::Attribute::Enumerable);
|
||||
define_property("OPENED", JS::Value((i32)XMLHttpRequest::ReadyState::Opened), JS::Attribute::Enumerable);
|
||||
define_property("HEADERS_RECEIVED", JS::Value((i32)XMLHttpRequest::ReadyState::HeadersReceived), JS::Attribute::Enumerable);
|
||||
define_property("LOADING", JS::Value((i32)XMLHttpRequest::ReadyState::Loading), JS::Attribute::Enumerable);
|
||||
define_property("DONE", JS::Value((i32)XMLHttpRequest::ReadyState::Done), JS::Attribute::Enumerable);
|
||||
}
|
||||
|
||||
XMLHttpRequestConstructor::~XMLHttpRequestConstructor()
|
||||
{
|
||||
}
|
||||
|
||||
JS::Value XMLHttpRequestConstructor::call()
|
||||
{
|
||||
vm().throw_exception<JS::TypeError>(global_object(), JS::ErrorType::ConstructorWithoutNew, "XMLHttpRequest");
|
||||
return {};
|
||||
}
|
||||
|
||||
JS::Value XMLHttpRequestConstructor::construct(Function&)
|
||||
{
|
||||
auto& window = static_cast<WindowObject&>(global_object());
|
||||
return heap().allocate<XMLHttpRequestWrapper>(window, window, XMLHttpRequest::create(window.impl()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
class XMLHttpRequestConstructor final : public JS::NativeFunction {
|
||||
public:
|
||||
explicit XMLHttpRequestConstructor(JS::GlobalObject&);
|
||||
virtual void initialize(JS::GlobalObject&) override;
|
||||
virtual ~XMLHttpRequestConstructor() override;
|
||||
|
||||
virtual JS::Value call() override;
|
||||
virtual JS::Value construct(JS::Function& new_target) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
virtual const char* class_name() const override { return "XMLHttpRequestConstructor"; }
|
||||
};
|
||||
|
||||
}
|
||||
112
Userland/Libraries/LibWeb/Bindings/XMLHttpRequestPrototype.cpp
Normal file
112
Userland/Libraries/LibWeb/Bindings/XMLHttpRequestPrototype.cpp
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/Function.h>
|
||||
#include <LibJS/Runtime/Error.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibWeb/Bindings/XMLHttpRequestPrototype.h>
|
||||
#include <LibWeb/Bindings/XMLHttpRequestWrapper.h>
|
||||
#include <LibWeb/DOM/XMLHttpRequest.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
XMLHttpRequestPrototype::XMLHttpRequestPrototype(JS::GlobalObject& global_object)
|
||||
: Object(*global_object.object_prototype())
|
||||
{
|
||||
}
|
||||
|
||||
void XMLHttpRequestPrototype::initialize(JS::GlobalObject& global_object)
|
||||
{
|
||||
Object::initialize(global_object);
|
||||
define_native_function("open", open, 2);
|
||||
define_native_function("send", send, 0);
|
||||
define_native_property("readyState", ready_state_getter, nullptr, JS::Attribute::Enumerable | JS::Attribute::Configurable);
|
||||
define_native_property("responseText", response_text_getter, nullptr, JS::Attribute::Enumerable | JS::Attribute::Configurable);
|
||||
|
||||
define_property("UNSENT", JS::Value((i32)XMLHttpRequest::ReadyState::Unsent), JS::Attribute::Enumerable);
|
||||
define_property("OPENED", JS::Value((i32)XMLHttpRequest::ReadyState::Opened), JS::Attribute::Enumerable);
|
||||
define_property("HEADERS_RECEIVED", JS::Value((i32)XMLHttpRequest::ReadyState::HeadersReceived), JS::Attribute::Enumerable);
|
||||
define_property("LOADING", JS::Value((i32)XMLHttpRequest::ReadyState::Loading), JS::Attribute::Enumerable);
|
||||
define_property("DONE", JS::Value((i32)XMLHttpRequest::ReadyState::Done), JS::Attribute::Enumerable);
|
||||
}
|
||||
|
||||
XMLHttpRequestPrototype::~XMLHttpRequestPrototype()
|
||||
{
|
||||
}
|
||||
|
||||
static XMLHttpRequest* impl_from(JS::VM& vm, JS::GlobalObject& global_object)
|
||||
{
|
||||
auto* this_object = vm.this_value(global_object).to_object(global_object);
|
||||
if (!this_object)
|
||||
return nullptr;
|
||||
if (!is<XMLHttpRequestWrapper>(this_object)) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "XMLHttpRequest");
|
||||
return nullptr;
|
||||
}
|
||||
return &static_cast<XMLHttpRequestWrapper*>(this_object)->impl();
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(XMLHttpRequestPrototype::open)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
auto arg0 = vm.argument(0).to_string(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
auto arg1 = vm.argument(1).to_string(global_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
impl->open(arg0, arg1);
|
||||
return JS::js_undefined();
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_FUNCTION(XMLHttpRequestPrototype::send)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
impl->send();
|
||||
return JS::js_undefined();
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(XMLHttpRequestPrototype::ready_state_getter)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
return JS::Value((i32)impl->ready_state());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_GETTER(XMLHttpRequestPrototype::response_text_getter)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
return JS::js_string(vm, impl->response_text());
|
||||
}
|
||||
|
||||
}
|
||||
49
Userland/Libraries/LibWeb/Bindings/XMLHttpRequestPrototype.h
Normal file
49
Userland/Libraries/LibWeb/Bindings/XMLHttpRequestPrototype.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
class XMLHttpRequestPrototype final : public JS::Object {
|
||||
JS_OBJECT(XMLHttpRequestPrototype, JS::Object);
|
||||
|
||||
public:
|
||||
explicit XMLHttpRequestPrototype(JS::GlobalObject&);
|
||||
virtual void initialize(JS::GlobalObject&) override;
|
||||
virtual ~XMLHttpRequestPrototype() override;
|
||||
|
||||
private:
|
||||
JS_DECLARE_NATIVE_FUNCTION(open);
|
||||
JS_DECLARE_NATIVE_FUNCTION(send);
|
||||
|
||||
JS_DECLARE_NATIVE_GETTER(ready_state_getter);
|
||||
JS_DECLARE_NATIVE_GETTER(response_text_getter);
|
||||
};
|
||||
|
||||
}
|
||||
62
Userland/Libraries/LibWeb/Bindings/XMLHttpRequestWrapper.cpp
Normal file
62
Userland/Libraries/LibWeb/Bindings/XMLHttpRequestWrapper.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/FlyString.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
#include <LibWeb/Bindings/WindowObject.h>
|
||||
#include <LibWeb/Bindings/XMLHttpRequestPrototype.h>
|
||||
#include <LibWeb/Bindings/XMLHttpRequestWrapper.h>
|
||||
#include <LibWeb/DOM/XMLHttpRequest.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
XMLHttpRequestWrapper* wrap(JS::GlobalObject& global_object, XMLHttpRequest& impl)
|
||||
{
|
||||
return static_cast<XMLHttpRequestWrapper*>(wrap_impl(global_object, impl));
|
||||
}
|
||||
|
||||
XMLHttpRequestWrapper::XMLHttpRequestWrapper(JS::GlobalObject& global_object, XMLHttpRequest& impl)
|
||||
: EventTargetWrapper(global_object, impl)
|
||||
{
|
||||
set_prototype(static_cast<WindowObject&>(global_object).xhr_prototype());
|
||||
}
|
||||
|
||||
XMLHttpRequestWrapper::~XMLHttpRequestWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
XMLHttpRequest& XMLHttpRequestWrapper::impl()
|
||||
{
|
||||
return static_cast<XMLHttpRequest&>(EventTargetWrapper::impl());
|
||||
}
|
||||
|
||||
const XMLHttpRequest& XMLHttpRequestWrapper::impl() const
|
||||
{
|
||||
return static_cast<const XMLHttpRequest&>(EventTargetWrapper::impl());
|
||||
}
|
||||
|
||||
}
|
||||
47
Userland/Libraries/LibWeb/Bindings/XMLHttpRequestWrapper.h
Normal file
47
Userland/Libraries/LibWeb/Bindings/XMLHttpRequestWrapper.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Bindings/EventTargetWrapper.h>
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
class XMLHttpRequestWrapper final : public EventTargetWrapper {
|
||||
public:
|
||||
XMLHttpRequestWrapper(JS::GlobalObject&, XMLHttpRequest&);
|
||||
virtual ~XMLHttpRequestWrapper() override;
|
||||
|
||||
XMLHttpRequest& impl();
|
||||
const XMLHttpRequest& impl() const;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "XMLHttpRequestWrapper"; }
|
||||
};
|
||||
|
||||
XMLHttpRequestWrapper* wrap(JS::GlobalObject&, XMLHttpRequest&);
|
||||
|
||||
}
|
||||
399
Userland/Libraries/LibWeb/CMakeLists.txt
Normal file
399
Userland/Libraries/LibWeb/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
set(SOURCES
|
||||
Bindings/EventListenerWrapper.cpp
|
||||
Bindings/EventWrapperFactory.cpp
|
||||
Bindings/EventTargetWrapperFactory.cpp
|
||||
Bindings/LocationObject.cpp
|
||||
Bindings/NavigatorObject.cpp
|
||||
Bindings/NodeWrapperFactory.cpp
|
||||
Bindings/ScriptExecutionContext.cpp
|
||||
Bindings/WindowObject.cpp
|
||||
Bindings/Wrappable.cpp
|
||||
Bindings/XMLHttpRequestConstructor.cpp
|
||||
Bindings/XMLHttpRequestPrototype.cpp
|
||||
Bindings/XMLHttpRequestWrapper.cpp
|
||||
Bindings/RangeConstructor.cpp
|
||||
Bindings/RangePrototype.cpp
|
||||
Bindings/RangeWrapper.cpp
|
||||
CSS/DefaultStyleSheetSource.cpp
|
||||
CSS/Length.cpp
|
||||
CSS/Parser/CSSParser.cpp
|
||||
CSS/PropertyID.cpp
|
||||
CSS/PropertyID.h
|
||||
CSS/QuirksModeStyleSheetSource.cpp
|
||||
CSS/Selector.cpp
|
||||
CSS/SelectorEngine.cpp
|
||||
CSS/StyleDeclaration.cpp
|
||||
CSS/StyleInvalidator.cpp
|
||||
CSS/StyleProperties.cpp
|
||||
CSS/StyleResolver.cpp
|
||||
CSS/StyleRule.cpp
|
||||
CSS/StyleSheet.cpp
|
||||
CSS/StyleSheetList.cpp
|
||||
CSS/StyleValue.cpp
|
||||
CSS/ValueID.cpp
|
||||
CSS/ValueID.h
|
||||
DOM/CharacterData.cpp
|
||||
DOM/CharacterData.idl
|
||||
DOM/Comment.cpp
|
||||
DOM/Document.cpp
|
||||
DOM/DocumentFragment.cpp
|
||||
DOM/DocumentType.cpp
|
||||
DOM/DOMImplementation.cpp
|
||||
DOM/Element.cpp
|
||||
DOM/ElementFactory.cpp
|
||||
DOM/Event.cpp
|
||||
DOM/Range.cpp
|
||||
DOM/EventDispatcher.cpp
|
||||
DOM/EventListener.cpp
|
||||
DOM/EventTarget.cpp
|
||||
DOM/Node.cpp
|
||||
DOM/ParentNode.cpp
|
||||
DOM/Position.cpp
|
||||
DOM/ShadowRoot.cpp
|
||||
DOM/Text.cpp
|
||||
DOM/Text.idl
|
||||
DOM/Timer.cpp
|
||||
DOM/Window.cpp
|
||||
DOM/XMLHttpRequest.cpp
|
||||
DOMTreeModel.cpp
|
||||
Dump.cpp
|
||||
FontCache.cpp
|
||||
HTML/AttributeNames.cpp
|
||||
HTML/CanvasRenderingContext2D.cpp
|
||||
HTML/EventNames.cpp
|
||||
HTML/HTMLAnchorElement.cpp
|
||||
HTML/HTMLAreaElement.cpp
|
||||
HTML/HTMLAudioElement.cpp
|
||||
HTML/HTMLBRElement.cpp
|
||||
HTML/HTMLBaseElement.cpp
|
||||
HTML/HTMLBlinkElement.cpp
|
||||
HTML/HTMLBodyElement.cpp
|
||||
HTML/HTMLButtonElement.cpp
|
||||
HTML/HTMLCanvasElement.cpp
|
||||
HTML/HTMLDListElement.cpp
|
||||
HTML/HTMLDataElement.cpp
|
||||
HTML/HTMLDataListElement.cpp
|
||||
HTML/HTMLDetailsElement.cpp
|
||||
HTML/HTMLDialogElement.cpp
|
||||
HTML/HTMLDirectoryElement.cpp
|
||||
HTML/HTMLDivElement.cpp
|
||||
HTML/HTMLElement.cpp
|
||||
HTML/HTMLEmbedElement.cpp
|
||||
HTML/HTMLFieldSetElement.cpp
|
||||
HTML/HTMLFontElement.cpp
|
||||
HTML/HTMLFormElement.cpp
|
||||
HTML/HTMLFrameElement.cpp
|
||||
HTML/HTMLFrameSetElement.cpp
|
||||
HTML/HTMLHRElement.cpp
|
||||
HTML/HTMLHeadElement.cpp
|
||||
HTML/HTMLHeadingElement.cpp
|
||||
HTML/HTMLHtmlElement.cpp
|
||||
HTML/HTMLIFrameElement.cpp
|
||||
HTML/HTMLImageElement.cpp
|
||||
HTML/HTMLInputElement.cpp
|
||||
HTML/HTMLLIElement.cpp
|
||||
HTML/HTMLLabelElement.cpp
|
||||
HTML/HTMLLegendElement.cpp
|
||||
HTML/HTMLLinkElement.cpp
|
||||
HTML/HTMLMapElement.cpp
|
||||
HTML/HTMLMarqueeElement.cpp
|
||||
HTML/HTMLMediaElement.cpp
|
||||
HTML/HTMLMenuElement.cpp
|
||||
HTML/HTMLMetaElement.cpp
|
||||
HTML/HTMLMeterElement.cpp
|
||||
HTML/HTMLModElement.cpp
|
||||
HTML/HTMLOListElement.cpp
|
||||
HTML/HTMLObjectElement.cpp
|
||||
HTML/HTMLOptGroupElement.cpp
|
||||
HTML/HTMLOptionElement.cpp
|
||||
HTML/HTMLOutputElement.cpp
|
||||
HTML/HTMLParagraphElement.cpp
|
||||
HTML/HTMLParamElement.cpp
|
||||
HTML/HTMLPictureElement.cpp
|
||||
HTML/HTMLPreElement.cpp
|
||||
HTML/HTMLProgressElement.cpp
|
||||
HTML/HTMLQuoteElement.cpp
|
||||
HTML/HTMLScriptElement.cpp
|
||||
HTML/HTMLSelectElement.cpp
|
||||
HTML/HTMLSlotElement.cpp
|
||||
HTML/HTMLSourceElement.cpp
|
||||
HTML/HTMLSpanElement.cpp
|
||||
HTML/HTMLStyleElement.cpp
|
||||
HTML/HTMLTableCaptionElement.cpp
|
||||
HTML/HTMLTableCellElement.cpp
|
||||
HTML/HTMLTableColElement.cpp
|
||||
HTML/HTMLTableElement.cpp
|
||||
HTML/HTMLTableRowElement.cpp
|
||||
HTML/HTMLTableSectionElement.cpp
|
||||
HTML/HTMLTemplateElement.cpp
|
||||
HTML/HTMLTextAreaElement.cpp
|
||||
HTML/HTMLTimeElement.cpp
|
||||
HTML/HTMLTitleElement.cpp
|
||||
HTML/HTMLTrackElement.cpp
|
||||
HTML/HTMLUListElement.cpp
|
||||
HTML/HTMLUnknownElement.cpp
|
||||
HTML/HTMLVideoElement.cpp
|
||||
HTML/ImageData.cpp
|
||||
HTML/Parser/Entities.cpp
|
||||
HTML/Parser/HTMLDocumentParser.cpp
|
||||
HTML/Parser/HTMLToken.cpp
|
||||
HTML/Parser/HTMLTokenizer.cpp
|
||||
HTML/Parser/ListOfActiveFormattingElements.cpp
|
||||
HTML/Parser/StackOfOpenElements.cpp
|
||||
HTML/TagNames.cpp
|
||||
HighResolutionTime/Performance.cpp
|
||||
InProcessWebView.cpp
|
||||
Layout/BlockBox.cpp
|
||||
Layout/BlockFormattingContext.cpp
|
||||
Layout/Box.cpp
|
||||
Layout/BoxModelMetrics.cpp
|
||||
Layout/BreakNode.cpp
|
||||
Layout/ButtonBox.cpp
|
||||
Layout/CanvasBox.cpp
|
||||
Layout/CheckBox.cpp
|
||||
Layout/FormattingContext.cpp
|
||||
Layout/FrameBox.cpp
|
||||
Layout/ImageBox.cpp
|
||||
Layout/InitialContainingBlockBox.cpp
|
||||
Layout/InlineFormattingContext.cpp
|
||||
Layout/InlineNode.cpp
|
||||
Layout/LayoutPosition.cpp
|
||||
Layout/LineBox.cpp
|
||||
Layout/LineBoxFragment.cpp
|
||||
Layout/ListItemBox.cpp
|
||||
Layout/ListItemMarkerBox.cpp
|
||||
Layout/Node.cpp
|
||||
Layout/ReplacedBox.cpp
|
||||
Layout/SVGBox.cpp
|
||||
Layout/SVGGraphicsBox.cpp
|
||||
Layout/SVGPathBox.cpp
|
||||
Layout/SVGSVGBox.cpp
|
||||
Layout/TableBox.cpp
|
||||
Layout/TableCellBox.cpp
|
||||
Layout/TableFormattingContext.cpp
|
||||
Layout/TableRowBox.cpp
|
||||
Layout/TableRowGroupBox.cpp
|
||||
Layout/TextNode.cpp
|
||||
Layout/TreeBuilder.cpp
|
||||
Layout/WidgetBox.cpp
|
||||
LayoutTreeModel.cpp
|
||||
Loader/ContentFilter.cpp
|
||||
Loader/FrameLoader.cpp
|
||||
Loader/ImageLoader.cpp
|
||||
Loader/ImageResource.cpp
|
||||
Loader/Resource.cpp
|
||||
Loader/ResourceLoader.cpp
|
||||
Namespace.cpp
|
||||
OutOfProcessWebView.cpp
|
||||
Page/EventHandler.cpp
|
||||
Page/EditEventHandler.cpp
|
||||
Page/Frame.cpp
|
||||
Page/Page.cpp
|
||||
Painting/BorderPainting.cpp
|
||||
Painting/StackingContext.cpp
|
||||
SVG/SVGElement.cpp
|
||||
SVG/SVGGeometryElement.cpp
|
||||
SVG/SVGGraphicsElement.cpp
|
||||
SVG/SVGPathElement.cpp
|
||||
SVG/SVGSVGElement.cpp
|
||||
SVG/TagNames.cpp
|
||||
StylePropertiesModel.cpp
|
||||
UIEvents/EventNames.cpp
|
||||
UIEvents/MouseEvent.cpp
|
||||
URLEncoder.cpp
|
||||
WebContentClient.cpp
|
||||
)
|
||||
|
||||
set(GENERATED_SOURCES
|
||||
../../Services/ProtocolServer/ProtocolClientEndpoint.h
|
||||
../../Services/ProtocolServer/ProtocolServerEndpoint.h
|
||||
../../Services/WebContent/WebContentClientEndpoint.h
|
||||
../../Services/WebContent/WebContentServerEndpoint.h
|
||||
)
|
||||
|
||||
set_property(GLOBAL PROPERTY wrapper_sources)
|
||||
function(add_wrapper_sources)
|
||||
get_property(tmp GLOBAL PROPERTY wrapper_sources)
|
||||
foreach(arg ${ARGV})
|
||||
set(tmp ${tmp}
|
||||
${arg}
|
||||
)
|
||||
endforeach()
|
||||
set_property(GLOBAL PROPERTY wrapper_sources "${tmp}")
|
||||
endfunction(add_wrapper_sources)
|
||||
|
||||
function(libweb_js_wrapper class)
|
||||
get_filename_component(basename ${class} NAME)
|
||||
add_wrapper_sources(Bindings/${basename}Wrapper.cpp Bindings/${basename}Wrapper.h)
|
||||
add_custom_command(
|
||||
OUTPUT Bindings/${basename}Wrapper.h
|
||||
COMMAND ${write_if_different} Bindings/${basename}Wrapper.h CodeGenerators/WrapperGenerator --header ${CMAKE_CURRENT_SOURCE_DIR}/${class}.idl
|
||||
VERBATIM
|
||||
DEPENDS WrapperGenerator
|
||||
MAIN_DEPENDENCY ${class}.idl
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT Bindings/${basename}Wrapper.cpp
|
||||
COMMAND ${write_if_different} Bindings/${basename}Wrapper.cpp CodeGenerators/WrapperGenerator --implementation ${CMAKE_CURRENT_SOURCE_DIR}/${class}.idl
|
||||
VERBATIM
|
||||
DEPENDS WrapperGenerator
|
||||
MAIN_DEPENDENCY ${class}.idl
|
||||
)
|
||||
add_custom_target(generate_${basename}Wrapper.h DEPENDS Bindings/${class}Wrapper.h)
|
||||
add_custom_target(generate_${basename}Wrapper.cpp DEPENDS Bindings/${class}Wrapper.cpp)
|
||||
endfunction()
|
||||
|
||||
libweb_js_wrapper(DOM/CharacterData)
|
||||
libweb_js_wrapper(DOM/Comment)
|
||||
libweb_js_wrapper(DOM/Document)
|
||||
libweb_js_wrapper(DOM/DocumentFragment)
|
||||
libweb_js_wrapper(DOM/DocumentType)
|
||||
libweb_js_wrapper(DOM/DOMImplementation)
|
||||
libweb_js_wrapper(DOM/Element)
|
||||
libweb_js_wrapper(DOM/Event)
|
||||
libweb_js_wrapper(DOM/EventTarget)
|
||||
libweb_js_wrapper(DOM/ShadowRoot)
|
||||
libweb_js_wrapper(DOM/Node)
|
||||
libweb_js_wrapper(DOM/Text)
|
||||
libweb_js_wrapper(HTML/CanvasRenderingContext2D)
|
||||
libweb_js_wrapper(HTML/HTMLAnchorElement)
|
||||
libweb_js_wrapper(HTML/HTMLAreaElement)
|
||||
libweb_js_wrapper(HTML/HTMLAudioElement)
|
||||
libweb_js_wrapper(HTML/HTMLBaseElement)
|
||||
libweb_js_wrapper(HTML/HTMLBodyElement)
|
||||
libweb_js_wrapper(HTML/HTMLBRElement)
|
||||
libweb_js_wrapper(HTML/HTMLButtonElement)
|
||||
libweb_js_wrapper(HTML/HTMLCanvasElement)
|
||||
libweb_js_wrapper(HTML/HTMLDataElement)
|
||||
libweb_js_wrapper(HTML/HTMLDataListElement)
|
||||
libweb_js_wrapper(HTML/HTMLDetailsElement)
|
||||
libweb_js_wrapper(HTML/HTMLDialogElement)
|
||||
libweb_js_wrapper(HTML/HTMLDirectoryElement)
|
||||
libweb_js_wrapper(HTML/HTMLDivElement)
|
||||
libweb_js_wrapper(HTML/HTMLDListElement)
|
||||
libweb_js_wrapper(HTML/HTMLElement)
|
||||
libweb_js_wrapper(HTML/HTMLEmbedElement)
|
||||
libweb_js_wrapper(HTML/HTMLFieldSetElement)
|
||||
libweb_js_wrapper(HTML/HTMLFontElement)
|
||||
libweb_js_wrapper(HTML/HTMLFormElement)
|
||||
libweb_js_wrapper(HTML/HTMLFrameElement)
|
||||
libweb_js_wrapper(HTML/HTMLFrameSetElement)
|
||||
libweb_js_wrapper(HTML/HTMLHeadElement)
|
||||
libweb_js_wrapper(HTML/HTMLHeadingElement)
|
||||
libweb_js_wrapper(HTML/HTMLHRElement)
|
||||
libweb_js_wrapper(HTML/HTMLHtmlElement)
|
||||
libweb_js_wrapper(HTML/HTMLIFrameElement)
|
||||
libweb_js_wrapper(HTML/HTMLImageElement)
|
||||
libweb_js_wrapper(HTML/HTMLInputElement)
|
||||
libweb_js_wrapper(HTML/HTMLLabelElement)
|
||||
libweb_js_wrapper(HTML/HTMLLegendElement)
|
||||
libweb_js_wrapper(HTML/HTMLLIElement)
|
||||
libweb_js_wrapper(HTML/HTMLLinkElement)
|
||||
libweb_js_wrapper(HTML/HTMLMapElement)
|
||||
libweb_js_wrapper(HTML/HTMLMarqueeElement)
|
||||
libweb_js_wrapper(HTML/HTMLMediaElement)
|
||||
libweb_js_wrapper(HTML/HTMLMenuElement)
|
||||
libweb_js_wrapper(HTML/HTMLMetaElement)
|
||||
libweb_js_wrapper(HTML/HTMLMeterElement)
|
||||
libweb_js_wrapper(HTML/HTMLModElement)
|
||||
libweb_js_wrapper(HTML/HTMLObjectElement)
|
||||
libweb_js_wrapper(HTML/HTMLOListElement)
|
||||
libweb_js_wrapper(HTML/HTMLOptGroupElement)
|
||||
libweb_js_wrapper(HTML/HTMLOptionElement)
|
||||
libweb_js_wrapper(HTML/HTMLOutputElement)
|
||||
libweb_js_wrapper(HTML/HTMLParagraphElement)
|
||||
libweb_js_wrapper(HTML/HTMLParamElement)
|
||||
libweb_js_wrapper(HTML/HTMLPictureElement)
|
||||
libweb_js_wrapper(HTML/HTMLPreElement)
|
||||
libweb_js_wrapper(HTML/HTMLProgressElement)
|
||||
libweb_js_wrapper(HTML/HTMLQuoteElement)
|
||||
libweb_js_wrapper(HTML/HTMLScriptElement)
|
||||
libweb_js_wrapper(HTML/HTMLSelectElement)
|
||||
libweb_js_wrapper(HTML/HTMLSlotElement)
|
||||
libweb_js_wrapper(HTML/HTMLSourceElement)
|
||||
libweb_js_wrapper(HTML/HTMLSpanElement)
|
||||
libweb_js_wrapper(HTML/HTMLStyleElement)
|
||||
libweb_js_wrapper(HTML/HTMLTableCaptionElement)
|
||||
libweb_js_wrapper(HTML/HTMLTableCellElement)
|
||||
libweb_js_wrapper(HTML/HTMLTableColElement)
|
||||
libweb_js_wrapper(HTML/HTMLTableElement)
|
||||
libweb_js_wrapper(HTML/HTMLTableRowElement)
|
||||
libweb_js_wrapper(HTML/HTMLTableSectionElement)
|
||||
libweb_js_wrapper(HTML/HTMLTemplateElement)
|
||||
libweb_js_wrapper(HTML/HTMLTextAreaElement)
|
||||
libweb_js_wrapper(HTML/HTMLTimeElement)
|
||||
libweb_js_wrapper(HTML/HTMLTitleElement)
|
||||
libweb_js_wrapper(HTML/HTMLTrackElement)
|
||||
libweb_js_wrapper(HTML/HTMLUListElement)
|
||||
libweb_js_wrapper(HTML/HTMLUnknownElement)
|
||||
libweb_js_wrapper(HTML/HTMLVideoElement)
|
||||
libweb_js_wrapper(HTML/ImageData)
|
||||
libweb_js_wrapper(HTML/SubmitEvent)
|
||||
libweb_js_wrapper(HighResolutionTime/Performance)
|
||||
libweb_js_wrapper(SVG/SVGElement)
|
||||
libweb_js_wrapper(SVG/SVGGeometryElement)
|
||||
libweb_js_wrapper(SVG/SVGGraphicsElement)
|
||||
libweb_js_wrapper(SVG/SVGPathElement)
|
||||
libweb_js_wrapper(SVG/SVGSVGElement)
|
||||
libweb_js_wrapper(UIEvents/MouseEvent)
|
||||
libweb_js_wrapper(UIEvents/UIEvent)
|
||||
|
||||
get_property(WRAPPER_SOURCES GLOBAL PROPERTY wrapper_sources)
|
||||
set(SOURCES ${SOURCES} ${WRAPPER_SOURCES})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT CSS/PropertyID.h
|
||||
COMMAND ${write_if_different} CSS/PropertyID.h CodeGenerators/Generate_CSS_PropertyID_h ${CMAKE_CURRENT_SOURCE_DIR}/CSS/Properties.json
|
||||
VERBATIM
|
||||
DEPENDS Generate_CSS_PropertyID_h
|
||||
MAIN_DEPENDENCY CSS/Properties.json
|
||||
)
|
||||
add_custom_target(generate_PropertyID.h DEPENDS CSS/PropertyID.h)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT CSS/PropertyID.cpp
|
||||
COMMAND /bin/mkdir -p CSS
|
||||
COMMAND ${write_if_different} CSS/PropertyID.cpp CodeGenerators/Generate_CSS_PropertyID_cpp ${CMAKE_CURRENT_SOURCE_DIR}/CSS/Properties.json
|
||||
VERBATIM
|
||||
DEPENDS Generate_CSS_PropertyID_cpp
|
||||
MAIN_DEPENDENCY CSS/Properties.json
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT CSS/ValueID.h
|
||||
COMMAND ${write_if_different} CSS/ValueID.h CodeGenerators/Generate_CSS_ValueID_h ${CMAKE_CURRENT_SOURCE_DIR}/CSS/Identifiers.json
|
||||
VERBATIM
|
||||
DEPENDS Generate_CSS_ValueID_h
|
||||
MAIN_DEPENDENCY CSS/Identifiers.json
|
||||
)
|
||||
add_custom_target(generate_ValueID.h DEPENDS CSS/ValueID.h)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT CSS/ValueID.cpp
|
||||
COMMAND /bin/mkdir -p CSS
|
||||
COMMAND ${write_if_different} CSS/ValueID.cpp CodeGenerators/Generate_CSS_ValueID_cpp ${CMAKE_CURRENT_SOURCE_DIR}/CSS/Identifiers.json
|
||||
VERBATIM
|
||||
DEPENDS Generate_CSS_ValueID_cpp
|
||||
MAIN_DEPENDENCY CSS/Identifiers.json
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT CSS/DefaultStyleSheetSource.cpp
|
||||
COMMAND ${write_if_different} CSS/DefaultStyleSheetSource.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Scripts/GenerateStyleSheetSource.sh default_stylesheet_source ${CMAKE_CURRENT_SOURCE_DIR}/CSS/Default.css
|
||||
VERBATIM
|
||||
DEPENDS Scripts/GenerateStyleSheetSource.sh
|
||||
MAIN_DEPENDENCY CSS/Default.css
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT CSS/QuirksModeStyleSheetSource.cpp
|
||||
COMMAND ${write_if_different} CSS/QuirksModeStyleSheetSource.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Scripts/GenerateStyleSheetSource.sh quirks_mode_stylesheet_source ${CMAKE_CURRENT_SOURCE_DIR}/CSS/QuirksMode.css
|
||||
VERBATIM
|
||||
DEPENDS Scripts/GenerateStyleSheetSource.sh
|
||||
MAIN_DEPENDENCY CSS/Default.css
|
||||
)
|
||||
|
||||
serenity_lib(LibWeb web)
|
||||
target_link_libraries(LibWeb LibCore LibJS LibMarkdown LibGemini LibGUI LibGfx LibTextCodec LibProtocol LibImageDecoderClient)
|
||||
|
||||
add_subdirectory(DumpLayoutTree)
|
||||
3
Userland/Libraries/LibWeb/CSS/.gitignore
vendored
Normal file
3
Userland/Libraries/LibWeb/CSS/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
DefaultStyleSheetSource.cpp
|
||||
PropertyID.cpp
|
||||
PropertyID.h
|
||||
161
Userland/Libraries/LibWeb/CSS/ComputedValues.h
Normal file
161
Userland/Libraries/LibWeb/CSS/ComputedValues.h
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <LibWeb/CSS/LengthBox.h>
|
||||
#include <LibWeb/CSS/StyleValue.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class InitialValues {
|
||||
public:
|
||||
static CSS::Float float_() { return CSS::Float::None; }
|
||||
static CSS::Clear clear() { return CSS::Clear::None; }
|
||||
static CSS::WhiteSpace white_space() { return CSS::WhiteSpace::Normal; }
|
||||
static CSS::TextAlign text_align() { return CSS::TextAlign::Left; }
|
||||
static CSS::Position position() { return CSS::Position::Static; }
|
||||
static CSS::TextDecorationLine text_decoration_line() { return CSS::TextDecorationLine::None; }
|
||||
static CSS::TextTransform text_transform() { return CSS::TextTransform::None; }
|
||||
static CSS::Display display() { return CSS::Display::Inline; }
|
||||
static Color color() { return Color::Black; }
|
||||
static Color background_color() { return Color::Transparent; }
|
||||
static CSS::ListStyleType list_style_type() { return CSS::ListStyleType::Disc; }
|
||||
};
|
||||
|
||||
struct BorderData {
|
||||
public:
|
||||
Color color { Color::Transparent };
|
||||
CSS::LineStyle line_style { CSS::LineStyle::None };
|
||||
float width { 0 };
|
||||
};
|
||||
|
||||
class ComputedValues {
|
||||
public:
|
||||
CSS::Float float_() const { return m_noninherited.float_; }
|
||||
CSS::Clear clear() const { return m_noninherited.clear; }
|
||||
CSS::Display display() const { return m_noninherited.display; }
|
||||
Optional<int> z_index() const { return m_noninherited.z_index; }
|
||||
CSS::TextAlign text_align() const { return m_inherited.text_align; }
|
||||
CSS::TextDecorationLine text_decoration_line() const { return m_noninherited.text_decoration_line; }
|
||||
CSS::TextTransform text_transform() const { return m_inherited.text_transform; }
|
||||
CSS::Position position() const { return m_noninherited.position; }
|
||||
CSS::WhiteSpace white_space() const { return m_inherited.white_space; }
|
||||
const CSS::Length& width() const { return m_noninherited.width; }
|
||||
const CSS::Length& min_width() const { return m_noninherited.min_width; }
|
||||
const CSS::Length& max_width() const { return m_noninherited.max_width; }
|
||||
const CSS::Length& height() const { return m_noninherited.height; }
|
||||
const CSS::Length& min_height() const { return m_noninherited.min_height; }
|
||||
const CSS::Length& max_height() const { return m_noninherited.max_height; }
|
||||
|
||||
const CSS::LengthBox& offset() const { return m_noninherited.offset; }
|
||||
const CSS::LengthBox& margin() const { return m_noninherited.margin; }
|
||||
const CSS::LengthBox& padding() const { return m_noninherited.padding; }
|
||||
|
||||
const BorderData& border_left() const { return m_noninherited.border_left; }
|
||||
const BorderData& border_top() const { return m_noninherited.border_top; }
|
||||
const BorderData& border_right() const { return m_noninherited.border_right; }
|
||||
const BorderData& border_bottom() const { return m_noninherited.border_bottom; }
|
||||
|
||||
Color color() const { return m_inherited.color; }
|
||||
Color background_color() const { return m_noninherited.background_color; }
|
||||
|
||||
CSS::ListStyleType list_style_type() const { return m_inherited.list_style_type; }
|
||||
|
||||
ComputedValues clone_inherited_values() const
|
||||
{
|
||||
ComputedValues clone;
|
||||
clone.m_inherited = m_inherited;
|
||||
return clone;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct {
|
||||
Color color { InitialValues::color() };
|
||||
CSS::TextAlign text_align { InitialValues::text_align() };
|
||||
CSS::TextTransform text_transform { InitialValues::text_transform() };
|
||||
CSS::WhiteSpace white_space { InitialValues::white_space() };
|
||||
CSS::ListStyleType list_style_type { InitialValues::list_style_type() };
|
||||
} m_inherited;
|
||||
|
||||
struct {
|
||||
CSS::Float float_ { InitialValues::float_() };
|
||||
CSS::Clear clear { InitialValues::clear() };
|
||||
CSS::Display display { InitialValues::display() };
|
||||
Optional<int> z_index;
|
||||
CSS::TextDecorationLine text_decoration_line { InitialValues::text_decoration_line() };
|
||||
CSS::Position position { InitialValues::position() };
|
||||
CSS::Length width;
|
||||
CSS::Length min_width;
|
||||
CSS::Length max_width;
|
||||
CSS::Length height;
|
||||
CSS::Length min_height;
|
||||
CSS::Length max_height;
|
||||
CSS::LengthBox offset;
|
||||
CSS::LengthBox margin;
|
||||
CSS::LengthBox padding;
|
||||
BorderData border_left;
|
||||
BorderData border_top;
|
||||
BorderData border_right;
|
||||
BorderData border_bottom;
|
||||
Color background_color { InitialValues::background_color() };
|
||||
} m_noninherited;
|
||||
};
|
||||
|
||||
class ImmutableComputedValues final : public ComputedValues {
|
||||
};
|
||||
|
||||
class MutableComputedValues final : public ComputedValues {
|
||||
public:
|
||||
void set_color(const Color& color) { m_inherited.color = color; }
|
||||
void set_background_color(const Color& color) { m_noninherited.background_color = color; }
|
||||
void set_float(CSS::Float value) { m_noninherited.float_ = value; }
|
||||
void set_clear(CSS::Clear value) { m_noninherited.clear = value; }
|
||||
void set_z_index(Optional<int> value) { m_noninherited.z_index = value; }
|
||||
void set_text_align(CSS::TextAlign text_align) { m_inherited.text_align = text_align; }
|
||||
void set_text_decoration_line(CSS::TextDecorationLine value) { m_noninherited.text_decoration_line = value; }
|
||||
void set_text_transform(CSS::TextTransform value) { m_inherited.text_transform = value; }
|
||||
void set_position(CSS::Position position) { m_noninherited.position = position; }
|
||||
void set_white_space(CSS::WhiteSpace value) { m_inherited.white_space = value; }
|
||||
void set_width(const CSS::Length& width) { m_noninherited.width = width; }
|
||||
void set_min_width(const CSS::Length& width) { m_noninherited.min_width = width; }
|
||||
void set_max_width(const CSS::Length& width) { m_noninherited.max_width = width; }
|
||||
void set_height(const CSS::Length& height) { m_noninherited.height = height; }
|
||||
void set_min_height(const CSS::Length& height) { m_noninherited.min_height = height; }
|
||||
void set_max_height(const CSS::Length& height) { m_noninherited.max_height = height; }
|
||||
void set_offset(const CSS::LengthBox& offset) { m_noninherited.offset = offset; }
|
||||
void set_margin(const CSS::LengthBox& margin) { m_noninherited.margin = margin; }
|
||||
void set_padding(const CSS::LengthBox& padding) { m_noninherited.padding = padding; }
|
||||
void set_list_style_type(CSS::ListStyleType value) { m_inherited.list_style_type = value; }
|
||||
void set_display(CSS::Display value) { m_noninherited.display = value; }
|
||||
BorderData& border_left() { return m_noninherited.border_left; }
|
||||
BorderData& border_top() { return m_noninherited.border_top; }
|
||||
BorderData& border_right() { return m_noninherited.border_right; }
|
||||
BorderData& border_bottom() { return m_noninherited.border_bottom; }
|
||||
};
|
||||
|
||||
}
|
||||
196
Userland/Libraries/LibWeb/CSS/Default.css
Normal file
196
Userland/Libraries/LibWeb/CSS/Default.css
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
html {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
head,
|
||||
link,
|
||||
meta,
|
||||
script,
|
||||
style,
|
||||
title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
font-family: Pebbleton;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace;
|
||||
margin-bottom: 8px;
|
||||
margin-top: 8px;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
u,
|
||||
ins {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
strong,
|
||||
b {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
html,
|
||||
address,
|
||||
blockquote,
|
||||
body,
|
||||
dd,
|
||||
div,
|
||||
dl,
|
||||
dt,
|
||||
fieldset,
|
||||
form,
|
||||
frame,
|
||||
frameset,
|
||||
hgroup,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
noframes,
|
||||
ol,
|
||||
p,
|
||||
ul,
|
||||
center,
|
||||
dir,
|
||||
hr,
|
||||
menu,
|
||||
pre,
|
||||
header,
|
||||
footer,
|
||||
nav,
|
||||
main,
|
||||
article,
|
||||
aside,
|
||||
section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
center {
|
||||
text-align: -libweb-center;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
margin: 8px 0 8px 0;
|
||||
}
|
||||
|
||||
h4,
|
||||
p,
|
||||
blockquote,
|
||||
ul,
|
||||
fieldset,
|
||||
form,
|
||||
ol,
|
||||
dl,
|
||||
dir,
|
||||
menu {
|
||||
margin: 4px 0 4px 0;
|
||||
}
|
||||
|
||||
h5,
|
||||
h6 {
|
||||
margin: 2px 0 2px 0;
|
||||
}
|
||||
|
||||
li {
|
||||
display: list-item;
|
||||
margin-left: 8px;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: -libweb-link;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
border: 1px inset #888888;
|
||||
}
|
||||
|
||||
blink {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
table {
|
||||
display: table;
|
||||
}
|
||||
|
||||
thead {
|
||||
display: table-header-group;
|
||||
vertical-align: middle;
|
||||
border-color: inherit;
|
||||
}
|
||||
|
||||
tbody {
|
||||
display: table-row-group;
|
||||
vertical-align: middle;
|
||||
border-color: inherit;
|
||||
}
|
||||
|
||||
tfoot {
|
||||
display: table-footer-group;
|
||||
vertical-align: middle;
|
||||
border-color: inherit;
|
||||
}
|
||||
|
||||
tr {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
col {
|
||||
display: table-column;
|
||||
}
|
||||
|
||||
colgroup {
|
||||
display: table-column-group;
|
||||
}
|
||||
|
||||
basefont {
|
||||
display: block;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin-left: 25px;
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
padding-left: 20px;
|
||||
}
|
||||
122
Userland/Libraries/LibWeb/CSS/Identifiers.json
Normal file
122
Userland/Libraries/LibWeb/CSS/Identifiers.json
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
[
|
||||
"-libweb-center",
|
||||
"-libweb-link",
|
||||
"-libweb-palette-active-link",
|
||||
"-libweb-palette-active-window-border1",
|
||||
"-libweb-palette-active-window-border2",
|
||||
"-libweb-palette-active-window-title",
|
||||
"-libweb-palette-base",
|
||||
"-libweb-palette-base-text",
|
||||
"-libweb-palette-button",
|
||||
"-libweb-palette-button-text",
|
||||
"-libweb-palette-desktop-background",
|
||||
"-libweb-palette-focus-outline",
|
||||
"-libweb-palette-highlight-window-border1",
|
||||
"-libweb-palette-highlight-window-border2",
|
||||
"-libweb-palette-highlight-window-title",
|
||||
"-libweb-palette-hover-highlight",
|
||||
"-libweb-palette-inactive-selection",
|
||||
"-libweb-palette-inactive-selection-text",
|
||||
"-libweb-palette-inactive-window-border1",
|
||||
"-libweb-palette-inactive-window-border2",
|
||||
"-libweb-palette-inactive-window-title",
|
||||
"-libweb-palette-link",
|
||||
"-libweb-palette-menu-base",
|
||||
"-libweb-palette-menu-base-text",
|
||||
"-libweb-palette-menu-selection",
|
||||
"-libweb-palette-menu-selection-text",
|
||||
"-libweb-palette-menu-stripe",
|
||||
"-libweb-palette-moving-window-border1",
|
||||
"-libweb-palette-moving-window-border2",
|
||||
"-libweb-palette-moving-window-title",
|
||||
"-libweb-palette-rubber-band-border",
|
||||
"-libweb-palette-rubber-band-fill",
|
||||
"-libweb-palette-ruler",
|
||||
"-libweb-palette-ruler-active-text",
|
||||
"-libweb-palette-ruler-border",
|
||||
"-libweb-palette-ruler-inactive-text",
|
||||
"-libweb-palette-selection",
|
||||
"-libweb-palette-selection-text",
|
||||
"-libweb-palette-syntax-comment",
|
||||
"-libweb-palette-syntax-control-keyword",
|
||||
"-libweb-palette-syntax-identifier",
|
||||
"-libweb-palette-syntax-keyword",
|
||||
"-libweb-palette-syntax-number",
|
||||
"-libweb-palette-syntax-operator",
|
||||
"-libweb-palette-syntax-preprocessor-statement",
|
||||
"-libweb-palette-syntax-preprocessor-value",
|
||||
"-libweb-palette-syntax-punctuation",
|
||||
"-libweb-palette-syntax-string",
|
||||
"-libweb-palette-syntax-type",
|
||||
"-libweb-palette-text-cursor",
|
||||
"-libweb-palette-threed-highlight",
|
||||
"-libweb-palette-threed-shadow1",
|
||||
"-libweb-palette-threed-shadow2",
|
||||
"-libweb-palette-visited-link",
|
||||
"-libweb-palette-window",
|
||||
"-libweb-palette-window-text",
|
||||
"absolute",
|
||||
"blink",
|
||||
"block",
|
||||
"bold",
|
||||
"bolder",
|
||||
"both",
|
||||
"capitalize",
|
||||
"center",
|
||||
"circle",
|
||||
"dashed",
|
||||
"decimal",
|
||||
"disc",
|
||||
"dotted",
|
||||
"double",
|
||||
"fixed",
|
||||
"full-size-kana",
|
||||
"full-width",
|
||||
"groove",
|
||||
"hidden",
|
||||
"inline",
|
||||
"inline-block",
|
||||
"inset",
|
||||
"justify",
|
||||
"large",
|
||||
"larger",
|
||||
"left",
|
||||
"lighter",
|
||||
"line-through",
|
||||
"list-item",
|
||||
"lowercase",
|
||||
"medium",
|
||||
"none",
|
||||
"normal",
|
||||
"nowrap",
|
||||
"outset",
|
||||
"overline",
|
||||
"pre",
|
||||
"pre-line",
|
||||
"pre-wrap",
|
||||
"relative",
|
||||
"ridge",
|
||||
"right",
|
||||
"small",
|
||||
"smaller",
|
||||
"solid",
|
||||
"square",
|
||||
"static",
|
||||
"sticky",
|
||||
"table",
|
||||
"table-caption",
|
||||
"table-cell",
|
||||
"table-column",
|
||||
"table-column-group",
|
||||
"table-footer-group",
|
||||
"table-header-group",
|
||||
"table-row",
|
||||
"table-row-group",
|
||||
"underline",
|
||||
"uppercase",
|
||||
"x-large",
|
||||
"x-small",
|
||||
"xx-large",
|
||||
"xx-small",
|
||||
"xxx-large"
|
||||
]
|
||||
103
Userland/Libraries/LibWeb/CSS/Length.cpp
Normal file
103
Userland/Libraries/LibWeb/CSS/Length.cpp
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/CSS/Length.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/HTML/HTMLHtmlElement.h>
|
||||
#include <LibWeb/Page/Frame.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
float Length::relative_length_to_px(const Layout::Node& layout_node) const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Type::Ex:
|
||||
return m_value * layout_node.font().x_height();
|
||||
case Type::Em:
|
||||
return m_value * layout_node.font_size();
|
||||
case Type::Rem:
|
||||
return m_value * layout_node.document().document_element()->layout_node()->font_size();
|
||||
case Type::Vw:
|
||||
return layout_node.document().frame()->viewport_rect().width() * (m_value / 100);
|
||||
case Type::Vh:
|
||||
return layout_node.document().frame()->viewport_rect().height() * (m_value / 100);
|
||||
case Type::Vmin: {
|
||||
auto viewport = layout_node.document().frame()->viewport_rect();
|
||||
|
||||
return min(viewport.width(), viewport.height()) * (m_value / 100);
|
||||
}
|
||||
case Type::Vmax: {
|
||||
auto viewport = layout_node.document().frame()->viewport_rect();
|
||||
|
||||
return max(viewport.width(), viewport.height()) * (m_value / 100);
|
||||
}
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
const char* Length::unit_name() const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Type::Cm:
|
||||
return "cm";
|
||||
case Type::In:
|
||||
return "in";
|
||||
case Type::Px:
|
||||
return "px";
|
||||
case Type::Pt:
|
||||
return "pt";
|
||||
case Type::Mm:
|
||||
return "mm";
|
||||
case Type::Q:
|
||||
return "Q";
|
||||
case Type::Pc:
|
||||
return "pc";
|
||||
case Type::Ex:
|
||||
return "ex";
|
||||
case Type::Em:
|
||||
return "em";
|
||||
case Type::Rem:
|
||||
return "rem";
|
||||
case Type::Auto:
|
||||
return "auto";
|
||||
case Type::Percentage:
|
||||
return "%";
|
||||
case Type::Undefined:
|
||||
return "undefined";
|
||||
case Type::Vh:
|
||||
return "vh";
|
||||
case Type::Vw:
|
||||
return "vw";
|
||||
case Type::Vmax:
|
||||
return "vmax";
|
||||
case Type::Vmin:
|
||||
return "vmin";
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
||||
181
Userland/Libraries/LibWeb/CSS/Length.h
Normal file
181
Userland/Libraries/LibWeb/CSS/Length.h
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class Length {
|
||||
public:
|
||||
enum class Type {
|
||||
Undefined,
|
||||
Percentage,
|
||||
Auto,
|
||||
Cm,
|
||||
In,
|
||||
Mm,
|
||||
Q,
|
||||
Px,
|
||||
Pt,
|
||||
Pc,
|
||||
Ex,
|
||||
Em,
|
||||
Rem,
|
||||
Vh,
|
||||
Vw,
|
||||
Vmax,
|
||||
Vmin,
|
||||
};
|
||||
|
||||
Length() { }
|
||||
Length(int value, Type type)
|
||||
: m_type(type)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
Length(float value, Type type)
|
||||
: m_type(type)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
static Length make_auto() { return Length(0, Type::Auto); }
|
||||
static Length make_px(float value) { return Length(value, Type::Px); }
|
||||
|
||||
Length resolved(const Length& fallback_for_undefined, const Layout::Node& layout_node, float reference_for_percent) const
|
||||
{
|
||||
if (is_undefined())
|
||||
return fallback_for_undefined;
|
||||
if (is_percentage())
|
||||
return make_px(raw_value() / 100.0 * reference_for_percent);
|
||||
if (is_relative())
|
||||
return make_px(to_px(layout_node));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Length resolved_or_auto(const Layout::Node& layout_node, float reference_for_percent) const
|
||||
{
|
||||
return resolved(make_auto(), layout_node, reference_for_percent);
|
||||
}
|
||||
|
||||
Length resolved_or_zero(const Layout::Node& layout_node, float reference_for_percent) const
|
||||
{
|
||||
return resolved(make_px(0), layout_node, reference_for_percent);
|
||||
}
|
||||
|
||||
bool is_undefined_or_auto() const { return m_type == Type::Undefined || m_type == Type::Auto; }
|
||||
bool is_undefined() const { return m_type == Type::Undefined; }
|
||||
bool is_percentage() const { return m_type == Type::Percentage; }
|
||||
bool is_auto() const { return m_type == Type::Auto; }
|
||||
|
||||
bool is_absolute() const
|
||||
{
|
||||
return m_type == Type::Cm
|
||||
|| m_type == Type::In
|
||||
|| m_type == Type::Mm
|
||||
|| m_type == Type::Px
|
||||
|| m_type == Type::Pt
|
||||
|| m_type == Type::Pc
|
||||
|| m_type == Type::Q;
|
||||
}
|
||||
|
||||
bool is_relative() const
|
||||
{
|
||||
return m_type == Type::Ex
|
||||
|| m_type == Type::Em
|
||||
|| m_type == Type::Rem
|
||||
|| m_type == Type::Vh
|
||||
|| m_type == Type::Vw
|
||||
|| m_type == Type::Vmax
|
||||
|| m_type == Type::Vmin;
|
||||
}
|
||||
|
||||
float raw_value() const { return m_value; }
|
||||
ALWAYS_INLINE float to_px(const Layout::Node& layout_node) const
|
||||
{
|
||||
if (is_relative())
|
||||
return relative_length_to_px(layout_node);
|
||||
constexpr float inch_pixels = 96.0f;
|
||||
constexpr float centimeter_pixels = (inch_pixels / 2.54f);
|
||||
switch (m_type) {
|
||||
case Type::Auto:
|
||||
return 0;
|
||||
case Type::Cm:
|
||||
return m_value * centimeter_pixels; // 1cm = 96px/2.54
|
||||
case Type::In:
|
||||
return m_value * inch_pixels; // 1in = 2.54 cm = 96px
|
||||
case Type::Px:
|
||||
return m_value; // 1px = 1/96th of 1in
|
||||
case Type::Pt:
|
||||
return m_value * ((1.0f / 72.0f) * inch_pixels); // 1pt = 1/72th of 1in
|
||||
case Type::Pc:
|
||||
return m_value * ((1.0f / 6.0f) * inch_pixels); // 1pc = 1/6th of 1in
|
||||
case Type::Mm:
|
||||
return m_value * ((1.0f / 10.0f) * centimeter_pixels); // 1mm = 1/10th of 1cm
|
||||
case Type::Q:
|
||||
return m_value * ((1.0f / 40.0f) * centimeter_pixels); // 1Q = 1/40th of 1cm
|
||||
case Type::Undefined:
|
||||
case Type::Percentage:
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
String to_string() const
|
||||
{
|
||||
if (is_auto())
|
||||
return "[auto]";
|
||||
return String::formatted("[{} {}]", m_value, unit_name());
|
||||
}
|
||||
|
||||
bool operator==(const Length& other) const
|
||||
{
|
||||
return m_type == other.m_type && m_value == other.m_value;
|
||||
}
|
||||
|
||||
bool operator!=(const Length& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
float relative_length_to_px(const Layout::Node&) const;
|
||||
|
||||
const char* unit_name() const;
|
||||
|
||||
Type m_type { Type::Undefined };
|
||||
float m_value { 0 };
|
||||
};
|
||||
|
||||
inline const LogStream& operator<<(const LogStream& stream, const Length& value)
|
||||
{
|
||||
return stream << value.to_string();
|
||||
}
|
||||
|
||||
}
|
||||
40
Userland/Libraries/LibWeb/CSS/LengthBox.h
Normal file
40
Userland/Libraries/LibWeb/CSS/LengthBox.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/CSS/Length.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
struct LengthBox {
|
||||
Length top { Length::make_auto() };
|
||||
Length right { Length::make_auto() };
|
||||
Length bottom { Length::make_auto() };
|
||||
Length left { Length::make_auto() };
|
||||
};
|
||||
|
||||
}
|
||||
902
Userland/Libraries/LibWeb/CSS/Parser/CSSParser.cpp
Normal file
902
Userland/Libraries/LibWeb/CSS/Parser/CSSParser.cpp
Normal file
|
|
@ -0,0 +1,902 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/HashMap.h>
|
||||
#include <LibWeb/CSS/Parser/CSSParser.h>
|
||||
#include <LibWeb/CSS/PropertyID.h>
|
||||
#include <LibWeb/CSS/StyleSheet.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define PARSE_ASSERT(x) \
|
||||
if (!(x)) { \
|
||||
dbg() << "CSS PARSER ASSERTION FAILED: " << #x; \
|
||||
dbg() << "At character# " << index << " in CSS: _" << css << "_"; \
|
||||
ASSERT_NOT_REACHED(); \
|
||||
}
|
||||
|
||||
#define PARSE_ERROR() \
|
||||
do { \
|
||||
dbgln("CSS parse error"); \
|
||||
} while (0)
|
||||
|
||||
namespace Web {
|
||||
|
||||
namespace CSS {
|
||||
|
||||
ParsingContext::ParsingContext()
|
||||
{
|
||||
}
|
||||
|
||||
ParsingContext::ParsingContext(const DOM::Document& document)
|
||||
: m_document(&document)
|
||||
{
|
||||
}
|
||||
|
||||
ParsingContext::ParsingContext(const DOM::ParentNode& parent_node)
|
||||
: m_document(&parent_node.document())
|
||||
{
|
||||
}
|
||||
|
||||
bool ParsingContext::in_quirks_mode() const
|
||||
{
|
||||
return m_document ? m_document->in_quirks_mode() : false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static Optional<Color> parse_css_color(const CSS::ParsingContext&, const StringView& view)
|
||||
{
|
||||
if (view.equals_ignoring_case("transparent"))
|
||||
return Color::from_rgba(0x00000000);
|
||||
|
||||
auto color = Color::from_string(view.to_string().to_lowercase());
|
||||
if (color.has_value())
|
||||
return color;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static Optional<float> try_parse_float(const StringView& string)
|
||||
{
|
||||
const char* str = string.characters_without_null_termination();
|
||||
size_t len = string.length();
|
||||
size_t weight = 1;
|
||||
int exp_val = 0;
|
||||
float value = 0.0f;
|
||||
float fraction = 0.0f;
|
||||
bool has_sign = false;
|
||||
bool is_negative = false;
|
||||
bool is_fractional = false;
|
||||
bool is_scientific = false;
|
||||
|
||||
if (str[0] == '-') {
|
||||
is_negative = true;
|
||||
has_sign = true;
|
||||
}
|
||||
if (str[0] == '+') {
|
||||
has_sign = true;
|
||||
}
|
||||
|
||||
for (size_t i = has_sign; i < len; i++) {
|
||||
|
||||
// Looks like we're about to start working on the fractional part
|
||||
if (str[i] == '.') {
|
||||
is_fractional = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str[i] == 'e' || str[i] == 'E') {
|
||||
if (str[i + 1] == '-' || str[i + 1] == '+')
|
||||
exp_val = atoi(str + i + 2);
|
||||
else
|
||||
exp_val = atoi(str + i + 1);
|
||||
|
||||
is_scientific = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str[i] < '0' || str[i] > '9' || exp_val != 0) {
|
||||
return {};
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_fractional) {
|
||||
fraction *= 10;
|
||||
fraction += str[i] - '0';
|
||||
weight *= 10;
|
||||
} else {
|
||||
value = value * 10;
|
||||
value += str[i] - '0';
|
||||
}
|
||||
}
|
||||
|
||||
fraction /= weight;
|
||||
value += fraction;
|
||||
|
||||
if (is_scientific) {
|
||||
bool divide = exp_val < 0;
|
||||
if (divide)
|
||||
exp_val *= -1;
|
||||
|
||||
for (int i = 0; i < exp_val; i++) {
|
||||
if (divide)
|
||||
value /= 10;
|
||||
else
|
||||
value *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
return is_negative ? -value : value;
|
||||
}
|
||||
|
||||
static CSS::Length parse_length(const CSS::ParsingContext& context, const StringView& view, bool& is_bad_length)
|
||||
{
|
||||
CSS::Length::Type type = CSS::Length::Type::Undefined;
|
||||
Optional<float> value;
|
||||
|
||||
if (view.ends_with('%')) {
|
||||
type = CSS::Length::Type::Percentage;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 1));
|
||||
} else if (view.ends_with("px", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Px;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 2));
|
||||
} else if (view.ends_with("pt", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Pt;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 2));
|
||||
} else if (view.ends_with("pc", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Pc;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 2));
|
||||
} else if (view.ends_with("mm", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Mm;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 2));
|
||||
} else if (view.ends_with("rem", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Rem;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 3));
|
||||
} else if (view.ends_with("em", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Em;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 2));
|
||||
} else if (view.ends_with("ex", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Ex;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 2));
|
||||
} else if (view.ends_with("vw", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Vw;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 2));
|
||||
} else if (view.ends_with("vh", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Vh;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 2));
|
||||
} else if (view.ends_with("vmax", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Vmax;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 4));
|
||||
} else if (view.ends_with("vmin", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Vmin;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 4));
|
||||
} else if (view.ends_with("cm", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Cm;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 2));
|
||||
} else if (view.ends_with("in", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::In;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 2));
|
||||
} else if (view.ends_with("Q", CaseSensitivity::CaseInsensitive)) {
|
||||
type = CSS::Length::Type::Q;
|
||||
value = try_parse_float(view.substring_view(0, view.length() - 1));
|
||||
} else if (view == "0") {
|
||||
type = CSS::Length::Type::Px;
|
||||
value = 0;
|
||||
} else if (context.in_quirks_mode()) {
|
||||
type = CSS::Length::Type::Px;
|
||||
value = try_parse_float(view);
|
||||
} else {
|
||||
value = try_parse_float(view);
|
||||
if (value.has_value())
|
||||
is_bad_length = true;
|
||||
}
|
||||
|
||||
if (!value.has_value())
|
||||
return {};
|
||||
|
||||
return CSS::Length(value.value(), type);
|
||||
}
|
||||
|
||||
static bool takes_integer_value(CSS::PropertyID property_id)
|
||||
{
|
||||
return property_id == CSS::PropertyID::ZIndex || property_id == CSS::PropertyID::FontWeight;
|
||||
}
|
||||
|
||||
RefPtr<CSS::StyleValue> parse_css_value(const CSS::ParsingContext& context, const StringView& string, CSS::PropertyID property_id)
|
||||
{
|
||||
bool is_bad_length = false;
|
||||
|
||||
if (takes_integer_value(property_id)) {
|
||||
auto integer = string.to_int();
|
||||
if (integer.has_value())
|
||||
return CSS::LengthStyleValue::create(CSS::Length::make_px(integer.value()));
|
||||
}
|
||||
|
||||
auto length = parse_length(context, string, is_bad_length);
|
||||
if (is_bad_length)
|
||||
return nullptr;
|
||||
if (!length.is_undefined())
|
||||
return CSS::LengthStyleValue::create(length);
|
||||
|
||||
if (string.equals_ignoring_case("inherit"))
|
||||
return CSS::InheritStyleValue::create();
|
||||
if (string.equals_ignoring_case("initial"))
|
||||
return CSS::InitialStyleValue::create();
|
||||
if (string.equals_ignoring_case("auto"))
|
||||
return CSS::LengthStyleValue::create(CSS::Length::make_auto());
|
||||
|
||||
auto value_id = CSS::value_id_from_string(string);
|
||||
if (value_id != CSS::ValueID::Invalid)
|
||||
return CSS::IdentifierStyleValue::create(value_id);
|
||||
|
||||
auto color = parse_css_color(context, string);
|
||||
if (color.has_value())
|
||||
return CSS::ColorStyleValue::create(color.value());
|
||||
|
||||
return CSS::StringStyleValue::create(string);
|
||||
}
|
||||
|
||||
RefPtr<CSS::LengthStyleValue> parse_line_width(const CSS::ParsingContext& context, const StringView& part)
|
||||
{
|
||||
auto value = parse_css_value(context, part);
|
||||
if (value && value->is_length())
|
||||
return static_ptr_cast<CSS::LengthStyleValue>(value);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CSS::ColorStyleValue> parse_color(const CSS::ParsingContext& context, const StringView& part)
|
||||
{
|
||||
auto value = parse_css_value(context, part);
|
||||
if (value && value->is_color())
|
||||
return static_ptr_cast<CSS::ColorStyleValue>(value);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CSS::StringStyleValue> parse_line_style(const CSS::ParsingContext& context, const StringView& part)
|
||||
{
|
||||
auto parsed_value = parse_css_value(context, part);
|
||||
if (!parsed_value || !parsed_value->is_string())
|
||||
return nullptr;
|
||||
auto value = static_ptr_cast<CSS::StringStyleValue>(parsed_value);
|
||||
if (value->to_string() == "dotted")
|
||||
return value;
|
||||
if (value->to_string() == "dashed")
|
||||
return value;
|
||||
if (value->to_string() == "solid")
|
||||
return value;
|
||||
if (value->to_string() == "double")
|
||||
return value;
|
||||
if (value->to_string() == "groove")
|
||||
return value;
|
||||
if (value->to_string() == "ridge")
|
||||
return value;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
class CSSParser {
|
||||
public:
|
||||
CSSParser(const CSS::ParsingContext& context, const StringView& input)
|
||||
: m_context(context)
|
||||
, css(input)
|
||||
{
|
||||
}
|
||||
|
||||
bool next_is(const char* str) const
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if (peek(i) != str[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char peek(size_t offset = 0) const
|
||||
{
|
||||
if ((index + offset) < css.length())
|
||||
return css[index + offset];
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool consume_specific(char ch)
|
||||
{
|
||||
if (peek() != ch) {
|
||||
dbgln("CSSParser: Peeked '{:c}' wanted specific '{:c}'", peek(), ch);
|
||||
}
|
||||
if (!peek()) {
|
||||
PARSE_ERROR();
|
||||
return false;
|
||||
}
|
||||
if (peek() != ch) {
|
||||
PARSE_ERROR();
|
||||
++index;
|
||||
return false;
|
||||
}
|
||||
++index;
|
||||
return true;
|
||||
}
|
||||
|
||||
char consume_one()
|
||||
{
|
||||
PARSE_ASSERT(index < css.length());
|
||||
return css[index++];
|
||||
};
|
||||
|
||||
bool consume_whitespace_or_comments()
|
||||
{
|
||||
size_t original_index = index;
|
||||
bool in_comment = false;
|
||||
for (; index < css.length(); ++index) {
|
||||
char ch = peek();
|
||||
if (isspace(ch))
|
||||
continue;
|
||||
if (!in_comment && ch == '/' && peek(1) == '*') {
|
||||
in_comment = true;
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
if (in_comment && ch == '*' && peek(1) == '/') {
|
||||
in_comment = false;
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
if (in_comment)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
return original_index != index;
|
||||
}
|
||||
|
||||
bool is_valid_selector_char(char ch) const
|
||||
{
|
||||
return isalnum(ch) || ch == '-' || ch == '_' || ch == '(' || ch == ')' || ch == '@';
|
||||
}
|
||||
|
||||
bool is_combinator(char ch) const
|
||||
{
|
||||
return ch == '~' || ch == '>' || ch == '+';
|
||||
}
|
||||
|
||||
Optional<CSS::Selector::SimpleSelector> parse_simple_selector()
|
||||
{
|
||||
auto index_at_start = index;
|
||||
|
||||
if (consume_whitespace_or_comments())
|
||||
return {};
|
||||
|
||||
if (!peek() || peek() == '{' || peek() == ',' || is_combinator(peek()))
|
||||
return {};
|
||||
|
||||
CSS::Selector::SimpleSelector::Type type;
|
||||
|
||||
if (peek() == '*') {
|
||||
type = CSS::Selector::SimpleSelector::Type::Universal;
|
||||
consume_one();
|
||||
return CSS::Selector::SimpleSelector {
|
||||
type,
|
||||
CSS::Selector::SimpleSelector::PseudoClass::None,
|
||||
CSS::Selector::SimpleSelector::PseudoElement::None,
|
||||
String(),
|
||||
CSS::Selector::SimpleSelector::AttributeMatchType::None,
|
||||
String(),
|
||||
String()
|
||||
};
|
||||
}
|
||||
|
||||
if (peek() == '.') {
|
||||
type = CSS::Selector::SimpleSelector::Type::Class;
|
||||
consume_one();
|
||||
} else if (peek() == '#') {
|
||||
type = CSS::Selector::SimpleSelector::Type::Id;
|
||||
consume_one();
|
||||
} else if (isalpha(peek())) {
|
||||
type = CSS::Selector::SimpleSelector::Type::TagName;
|
||||
} else {
|
||||
type = CSS::Selector::SimpleSelector::Type::Universal;
|
||||
}
|
||||
|
||||
if (type != CSS::Selector::SimpleSelector::Type::Universal) {
|
||||
while (is_valid_selector_char(peek()))
|
||||
buffer.append(consume_one());
|
||||
PARSE_ASSERT(!buffer.is_null());
|
||||
}
|
||||
|
||||
auto value = String::copy(buffer);
|
||||
|
||||
if (type == CSS::Selector::SimpleSelector::Type::TagName) {
|
||||
// Some stylesheets use uppercase tag names, so here's a hack to just lowercase them internally.
|
||||
value = value.to_lowercase();
|
||||
}
|
||||
|
||||
CSS::Selector::SimpleSelector simple_selector {
|
||||
type,
|
||||
CSS::Selector::SimpleSelector::PseudoClass::None,
|
||||
CSS::Selector::SimpleSelector::PseudoElement::None,
|
||||
value,
|
||||
CSS::Selector::SimpleSelector::AttributeMatchType::None,
|
||||
String(),
|
||||
String()
|
||||
};
|
||||
buffer.clear();
|
||||
|
||||
if (peek() == '[') {
|
||||
CSS::Selector::SimpleSelector::AttributeMatchType attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::HasAttribute;
|
||||
String attribute_name;
|
||||
String attribute_value;
|
||||
bool in_value = false;
|
||||
consume_specific('[');
|
||||
char expected_end_of_attribute_selector = ']';
|
||||
while (peek() != expected_end_of_attribute_selector) {
|
||||
char ch = consume_one();
|
||||
if (ch == '=' || (ch == '~' && peek() == '=')) {
|
||||
if (ch == '=') {
|
||||
attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::ExactValueMatch;
|
||||
} else if (ch == '~') {
|
||||
consume_one();
|
||||
attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::Contains;
|
||||
}
|
||||
attribute_name = String::copy(buffer);
|
||||
buffer.clear();
|
||||
in_value = true;
|
||||
consume_whitespace_or_comments();
|
||||
if (peek() == '\'') {
|
||||
expected_end_of_attribute_selector = '\'';
|
||||
consume_one();
|
||||
} else if (peek() == '"') {
|
||||
expected_end_of_attribute_selector = '"';
|
||||
consume_one();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// FIXME: This is a hack that will go away when we replace this with a big boy CSS parser.
|
||||
if (ch == '\\')
|
||||
ch = consume_one();
|
||||
buffer.append(ch);
|
||||
}
|
||||
if (in_value)
|
||||
attribute_value = String::copy(buffer);
|
||||
else
|
||||
attribute_name = String::copy(buffer);
|
||||
buffer.clear();
|
||||
simple_selector.attribute_match_type = attribute_match_type;
|
||||
simple_selector.attribute_name = attribute_name;
|
||||
simple_selector.attribute_value = attribute_value;
|
||||
if (expected_end_of_attribute_selector != ']') {
|
||||
if (!consume_specific(expected_end_of_attribute_selector))
|
||||
return {};
|
||||
}
|
||||
consume_whitespace_or_comments();
|
||||
if (!consume_specific(']'))
|
||||
return {};
|
||||
}
|
||||
|
||||
if (peek() == ':') {
|
||||
// FIXME: Implement pseudo elements.
|
||||
[[maybe_unused]] bool is_pseudo_element = false;
|
||||
consume_one();
|
||||
if (peek() == ':') {
|
||||
is_pseudo_element = true;
|
||||
consume_one();
|
||||
}
|
||||
if (next_is("not")) {
|
||||
buffer.append(consume_one());
|
||||
buffer.append(consume_one());
|
||||
buffer.append(consume_one());
|
||||
if (!consume_specific('('))
|
||||
return {};
|
||||
buffer.append('(');
|
||||
while (peek() != ')')
|
||||
buffer.append(consume_one());
|
||||
if (!consume_specific(')'))
|
||||
return {};
|
||||
buffer.append(')');
|
||||
} else {
|
||||
while (is_valid_selector_char(peek()))
|
||||
buffer.append(consume_one());
|
||||
}
|
||||
|
||||
auto pseudo_name = String::copy(buffer);
|
||||
buffer.clear();
|
||||
|
||||
// Ignore for now, otherwise we produce a "false positive" selector
|
||||
// and apply styles to the element itself, not its pseudo element
|
||||
if (is_pseudo_element)
|
||||
return {};
|
||||
|
||||
if (pseudo_name.equals_ignoring_case("link"))
|
||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Link;
|
||||
else if (pseudo_name.equals_ignoring_case("visited"))
|
||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Visited;
|
||||
else if (pseudo_name.equals_ignoring_case("hover"))
|
||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Hover;
|
||||
else if (pseudo_name.equals_ignoring_case("focus"))
|
||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Focus;
|
||||
else if (pseudo_name.equals_ignoring_case("first-child"))
|
||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::FirstChild;
|
||||
else if (pseudo_name.equals_ignoring_case("last-child"))
|
||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::LastChild;
|
||||
else if (pseudo_name.equals_ignoring_case("only-child"))
|
||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::OnlyChild;
|
||||
else if (pseudo_name.equals_ignoring_case("empty"))
|
||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Empty;
|
||||
else if (pseudo_name.equals_ignoring_case("root"))
|
||||
simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Root;
|
||||
else if (pseudo_name.equals_ignoring_case("before"))
|
||||
simple_selector.pseudo_element = CSS::Selector::SimpleSelector::PseudoElement::Before;
|
||||
else if (pseudo_name.equals_ignoring_case("after"))
|
||||
simple_selector.pseudo_element = CSS::Selector::SimpleSelector::PseudoElement::After;
|
||||
}
|
||||
|
||||
if (index == index_at_start) {
|
||||
// We consumed nothing.
|
||||
return {};
|
||||
}
|
||||
|
||||
return simple_selector;
|
||||
}
|
||||
|
||||
Optional<CSS::Selector::ComplexSelector> parse_complex_selector()
|
||||
{
|
||||
auto relation = CSS::Selector::ComplexSelector::Relation::Descendant;
|
||||
|
||||
if (peek() == '{' || peek() == ',')
|
||||
return {};
|
||||
|
||||
if (is_combinator(peek())) {
|
||||
switch (peek()) {
|
||||
case '>':
|
||||
relation = CSS::Selector::ComplexSelector::Relation::ImmediateChild;
|
||||
break;
|
||||
case '+':
|
||||
relation = CSS::Selector::ComplexSelector::Relation::AdjacentSibling;
|
||||
break;
|
||||
case '~':
|
||||
relation = CSS::Selector::ComplexSelector::Relation::GeneralSibling;
|
||||
break;
|
||||
}
|
||||
consume_one();
|
||||
consume_whitespace_or_comments();
|
||||
}
|
||||
|
||||
consume_whitespace_or_comments();
|
||||
|
||||
Vector<CSS::Selector::SimpleSelector> simple_selectors;
|
||||
for (;;) {
|
||||
auto component = parse_simple_selector();
|
||||
if (!component.has_value())
|
||||
break;
|
||||
simple_selectors.append(component.value());
|
||||
// If this assert triggers, we're most likely up to no good.
|
||||
PARSE_ASSERT(simple_selectors.size() < 100);
|
||||
}
|
||||
|
||||
if (simple_selectors.is_empty())
|
||||
return {};
|
||||
|
||||
return CSS::Selector::ComplexSelector { relation, move(simple_selectors) };
|
||||
}
|
||||
|
||||
void parse_selector()
|
||||
{
|
||||
Vector<CSS::Selector::ComplexSelector> complex_selectors;
|
||||
|
||||
for (;;) {
|
||||
auto index_before = index;
|
||||
auto complex_selector = parse_complex_selector();
|
||||
if (complex_selector.has_value())
|
||||
complex_selectors.append(complex_selector.value());
|
||||
consume_whitespace_or_comments();
|
||||
if (!peek() || peek() == ',' || peek() == '{')
|
||||
break;
|
||||
// HACK: If we didn't move forward, just let go.
|
||||
if (index == index_before)
|
||||
break;
|
||||
}
|
||||
|
||||
if (complex_selectors.is_empty())
|
||||
return;
|
||||
complex_selectors.first().relation = CSS::Selector::ComplexSelector::Relation::None;
|
||||
|
||||
current_rule.selectors.append(CSS::Selector(move(complex_selectors)));
|
||||
}
|
||||
|
||||
Optional<CSS::Selector> parse_individual_selector()
|
||||
{
|
||||
parse_selector();
|
||||
if (current_rule.selectors.is_empty())
|
||||
return {};
|
||||
return current_rule.selectors.last();
|
||||
}
|
||||
|
||||
void parse_selector_list()
|
||||
{
|
||||
for (;;) {
|
||||
auto index_before = index;
|
||||
parse_selector();
|
||||
consume_whitespace_or_comments();
|
||||
if (peek() == ',') {
|
||||
consume_one();
|
||||
continue;
|
||||
}
|
||||
if (peek() == '{')
|
||||
break;
|
||||
// HACK: If we didn't move forward, just let go.
|
||||
if (index_before == index)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_valid_property_name_char(char ch) const
|
||||
{
|
||||
return ch && !isspace(ch) && ch != ':';
|
||||
}
|
||||
|
||||
bool is_valid_property_value_char(char ch) const
|
||||
{
|
||||
return ch && ch != '!' && ch != ';' && ch != '}';
|
||||
}
|
||||
|
||||
struct ValueAndImportant {
|
||||
String value;
|
||||
bool important { false };
|
||||
};
|
||||
|
||||
ValueAndImportant consume_css_value()
|
||||
{
|
||||
buffer.clear();
|
||||
|
||||
int paren_nesting_level = 0;
|
||||
bool important = false;
|
||||
|
||||
for (;;) {
|
||||
char ch = peek();
|
||||
if (ch == '(') {
|
||||
++paren_nesting_level;
|
||||
buffer.append(consume_one());
|
||||
continue;
|
||||
}
|
||||
if (ch == ')') {
|
||||
PARSE_ASSERT(paren_nesting_level > 0);
|
||||
--paren_nesting_level;
|
||||
buffer.append(consume_one());
|
||||
continue;
|
||||
}
|
||||
if (paren_nesting_level > 0) {
|
||||
buffer.append(consume_one());
|
||||
continue;
|
||||
}
|
||||
if (next_is("!important")) {
|
||||
consume_specific('!');
|
||||
consume_specific('i');
|
||||
consume_specific('m');
|
||||
consume_specific('p');
|
||||
consume_specific('o');
|
||||
consume_specific('r');
|
||||
consume_specific('t');
|
||||
consume_specific('a');
|
||||
consume_specific('n');
|
||||
consume_specific('t');
|
||||
important = true;
|
||||
continue;
|
||||
}
|
||||
if (next_is("/*")) {
|
||||
consume_whitespace_or_comments();
|
||||
continue;
|
||||
}
|
||||
if (!ch)
|
||||
break;
|
||||
if (ch == '\\') {
|
||||
consume_one();
|
||||
buffer.append(consume_one());
|
||||
continue;
|
||||
}
|
||||
if (ch == '}')
|
||||
break;
|
||||
if (ch == ';')
|
||||
break;
|
||||
buffer.append(consume_one());
|
||||
}
|
||||
|
||||
// Remove trailing whitespace.
|
||||
while (!buffer.is_empty() && isspace(buffer.last()))
|
||||
buffer.take_last();
|
||||
|
||||
auto string = String::copy(buffer);
|
||||
buffer.clear();
|
||||
|
||||
return { string, important };
|
||||
}
|
||||
|
||||
Optional<CSS::StyleProperty> parse_property()
|
||||
{
|
||||
consume_whitespace_or_comments();
|
||||
if (peek() == ';') {
|
||||
consume_one();
|
||||
return {};
|
||||
}
|
||||
if (peek() == '}')
|
||||
return {};
|
||||
buffer.clear();
|
||||
while (is_valid_property_name_char(peek()))
|
||||
buffer.append(consume_one());
|
||||
auto property_name = String::copy(buffer);
|
||||
buffer.clear();
|
||||
consume_whitespace_or_comments();
|
||||
if (!consume_specific(':'))
|
||||
return {};
|
||||
consume_whitespace_or_comments();
|
||||
|
||||
auto [property_value, important] = consume_css_value();
|
||||
|
||||
consume_whitespace_or_comments();
|
||||
|
||||
if (peek() && peek() != '}') {
|
||||
if (!consume_specific(';'))
|
||||
return {};
|
||||
}
|
||||
|
||||
auto property_id = CSS::property_id_from_string(property_name);
|
||||
if (property_id == CSS::PropertyID::Invalid) {
|
||||
dbg() << "CSSParser: Unrecognized property '" << property_name << "'";
|
||||
}
|
||||
auto value = parse_css_value(m_context, property_value, property_id);
|
||||
if (!value)
|
||||
return {};
|
||||
return CSS::StyleProperty { property_id, value.release_nonnull(), important };
|
||||
}
|
||||
|
||||
void parse_declaration()
|
||||
{
|
||||
for (;;) {
|
||||
auto property = parse_property();
|
||||
if (property.has_value())
|
||||
current_rule.properties.append(property.value());
|
||||
consume_whitespace_or_comments();
|
||||
if (!peek() || peek() == '}')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void parse_rule()
|
||||
{
|
||||
consume_whitespace_or_comments();
|
||||
if (!peek())
|
||||
return;
|
||||
|
||||
// FIXME: We ignore @-rules for now.
|
||||
if (peek() == '@') {
|
||||
while (peek() != '{')
|
||||
consume_one();
|
||||
int level = 0;
|
||||
for (;;) {
|
||||
auto ch = consume_one();
|
||||
if (ch == '{') {
|
||||
++level;
|
||||
} else if (ch == '}') {
|
||||
--level;
|
||||
if (level == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
consume_whitespace_or_comments();
|
||||
return;
|
||||
}
|
||||
|
||||
parse_selector_list();
|
||||
if (!consume_specific('{')) {
|
||||
PARSE_ERROR();
|
||||
return;
|
||||
}
|
||||
parse_declaration();
|
||||
if (!consume_specific('}')) {
|
||||
PARSE_ERROR();
|
||||
return;
|
||||
}
|
||||
rules.append(CSS::StyleRule::create(move(current_rule.selectors), CSS::StyleDeclaration::create(move(current_rule.properties))));
|
||||
consume_whitespace_or_comments();
|
||||
}
|
||||
|
||||
RefPtr<CSS::StyleSheet> parse_sheet()
|
||||
{
|
||||
if (peek(0) == (char)0xef && peek(1) == (char)0xbb && peek(2) == (char)0xbf) {
|
||||
// HACK: Skip UTF-8 BOM.
|
||||
index += 3;
|
||||
}
|
||||
|
||||
while (peek()) {
|
||||
parse_rule();
|
||||
}
|
||||
|
||||
return CSS::StyleSheet::create(move(rules));
|
||||
}
|
||||
|
||||
RefPtr<CSS::StyleDeclaration> parse_standalone_declaration()
|
||||
{
|
||||
consume_whitespace_or_comments();
|
||||
for (;;) {
|
||||
auto property = parse_property();
|
||||
if (property.has_value())
|
||||
current_rule.properties.append(property.value());
|
||||
consume_whitespace_or_comments();
|
||||
if (!peek())
|
||||
break;
|
||||
}
|
||||
return CSS::StyleDeclaration::create(move(current_rule.properties));
|
||||
}
|
||||
|
||||
private:
|
||||
CSS::ParsingContext m_context;
|
||||
|
||||
NonnullRefPtrVector<CSS::StyleRule> rules;
|
||||
|
||||
struct CurrentRule {
|
||||
Vector<CSS::Selector> selectors;
|
||||
Vector<CSS::StyleProperty> properties;
|
||||
};
|
||||
|
||||
CurrentRule current_rule;
|
||||
Vector<char> buffer;
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
StringView css;
|
||||
};
|
||||
|
||||
Optional<CSS::Selector> parse_selector(const CSS::ParsingContext& context, const StringView& selector_text)
|
||||
{
|
||||
CSSParser parser(context, selector_text);
|
||||
return parser.parse_individual_selector();
|
||||
}
|
||||
|
||||
RefPtr<CSS::StyleSheet> parse_css(const CSS::ParsingContext& context, const StringView& css)
|
||||
{
|
||||
if (css.is_empty())
|
||||
return CSS::StyleSheet::create({});
|
||||
CSSParser parser(context, css);
|
||||
return parser.parse_sheet();
|
||||
}
|
||||
|
||||
RefPtr<CSS::StyleDeclaration> parse_css_declaration(const CSS::ParsingContext& context, const StringView& css)
|
||||
{
|
||||
if (css.is_empty())
|
||||
return CSS::StyleDeclaration::create({});
|
||||
CSSParser parser(context, css);
|
||||
return parser.parse_standalone_declaration();
|
||||
}
|
||||
|
||||
RefPtr<CSS::StyleValue> parse_html_length(const DOM::Document& document, const StringView& string)
|
||||
{
|
||||
auto integer = string.to_int();
|
||||
if (integer.has_value())
|
||||
return CSS::LengthStyleValue::create(CSS::Length::make_px(integer.value()));
|
||||
return parse_css_value(CSS::ParsingContext(document), string);
|
||||
}
|
||||
|
||||
}
|
||||
59
Userland/Libraries/LibWeb/CSS/Parser/CSSParser.h
Normal file
59
Userland/Libraries/LibWeb/CSS/Parser/CSSParser.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <LibWeb/CSS/StyleSheet.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
class ParsingContext {
|
||||
public:
|
||||
ParsingContext();
|
||||
explicit ParsingContext(const DOM::Document&);
|
||||
explicit ParsingContext(const DOM::ParentNode&);
|
||||
|
||||
bool in_quirks_mode() const;
|
||||
|
||||
private:
|
||||
const DOM::Document* m_document { nullptr };
|
||||
};
|
||||
}
|
||||
|
||||
namespace Web {
|
||||
|
||||
RefPtr<CSS::StyleSheet> parse_css(const CSS::ParsingContext&, const StringView&);
|
||||
RefPtr<CSS::StyleDeclaration> parse_css_declaration(const CSS::ParsingContext&, const StringView&);
|
||||
RefPtr<CSS::StyleValue> parse_css_value(const CSS::ParsingContext&, const StringView&, CSS::PropertyID property_id = CSS::PropertyID::Invalid);
|
||||
Optional<CSS::Selector> parse_selector(const CSS::ParsingContext&, const StringView&);
|
||||
|
||||
RefPtr<CSS::LengthStyleValue> parse_line_width(const CSS::ParsingContext&, const StringView&);
|
||||
RefPtr<CSS::ColorStyleValue> parse_color(const CSS::ParsingContext&, const StringView&);
|
||||
RefPtr<CSS::StringStyleValue> parse_line_style(const CSS::ParsingContext&, const StringView&);
|
||||
|
||||
RefPtr<CSS::StyleValue> parse_html_length(const DOM::Document&, const StringView&);
|
||||
|
||||
}
|
||||
368
Userland/Libraries/LibWeb/CSS/Properties.json
Normal file
368
Userland/Libraries/LibWeb/CSS/Properties.json
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
{
|
||||
"background": {
|
||||
},
|
||||
"background-attachment": {
|
||||
"inherited": false,
|
||||
"initial": "scroll"
|
||||
},
|
||||
"background-color": {
|
||||
"inherited": false,
|
||||
"initial": "transparent"
|
||||
},
|
||||
"background-image": {
|
||||
"inherited": false,
|
||||
"initial": "none"
|
||||
},
|
||||
"background-position": {
|
||||
"inherited": false,
|
||||
"initial": "0% 0%"
|
||||
},
|
||||
"background-repeat": {
|
||||
"inherited": false,
|
||||
"initial": "repeat"
|
||||
},
|
||||
"border": {
|
||||
"longhands": [
|
||||
"border-width",
|
||||
"border-style",
|
||||
"border-color"
|
||||
]
|
||||
},
|
||||
"border-top": {
|
||||
"longhands": [
|
||||
"border-top-width",
|
||||
"border-top-style",
|
||||
"border-top-color"
|
||||
]
|
||||
},
|
||||
"border-right": {
|
||||
"longhands": [
|
||||
"border-right-width",
|
||||
"border-right-style",
|
||||
"border-right-color"
|
||||
]
|
||||
},
|
||||
"border-bottom": {
|
||||
"longhands": [
|
||||
"border-bottom-width",
|
||||
"border-bottom-style",
|
||||
"border-bottom-color"
|
||||
]
|
||||
},
|
||||
"border-left": {
|
||||
"longhands": [
|
||||
"border-left-width",
|
||||
"border-left-style",
|
||||
"border-left-color"
|
||||
]
|
||||
},
|
||||
"border-bottom-color": {
|
||||
"initial": "currentColor",
|
||||
"inherited": false
|
||||
},
|
||||
"border-bottom-style": {
|
||||
"initial": "none",
|
||||
"inherited": false
|
||||
},
|
||||
"border-bottom-width": {
|
||||
"initial": "medium",
|
||||
"inherited": false
|
||||
},
|
||||
"border-color": {
|
||||
"longhands": [
|
||||
"border-top-color",
|
||||
"border-right-color",
|
||||
"border-bottom-color",
|
||||
"border-left-color"
|
||||
]
|
||||
},
|
||||
"border-collapse": {
|
||||
"inherited": true,
|
||||
"initial": "separate"
|
||||
},
|
||||
"border-left-color": {
|
||||
"initial": "currentColor",
|
||||
"inherited": false
|
||||
},
|
||||
"border-left-style": {
|
||||
"initial": "none",
|
||||
"inherited": false
|
||||
},
|
||||
"border-left-width": {
|
||||
"initial": "medium",
|
||||
"inherited": false
|
||||
},
|
||||
"border-right-color": {
|
||||
"initial": "currentColor",
|
||||
"inherited": false
|
||||
},
|
||||
"border-right-style": {
|
||||
"initial": "none",
|
||||
"inherited": false
|
||||
},
|
||||
"border-right-width": {
|
||||
"initial": "medium",
|
||||
"inherited": false
|
||||
},
|
||||
"border-spacing": {
|
||||
"inherited": true,
|
||||
"initial": "0"
|
||||
},
|
||||
"border-style": {
|
||||
"longhands": [
|
||||
"border-top-style",
|
||||
"border-right-style",
|
||||
"border-bottom-style",
|
||||
"border-left-style"
|
||||
]
|
||||
},
|
||||
"border-top-color": {
|
||||
"initial": "currentColor",
|
||||
"inherited": false
|
||||
},
|
||||
"border-top-style": {
|
||||
"initial": "none",
|
||||
"inherited": false
|
||||
},
|
||||
"border-top-width": {
|
||||
"initial": "medium",
|
||||
"inherited": false
|
||||
},
|
||||
"border-width": {
|
||||
"longhands": [
|
||||
"border-top-width",
|
||||
"border-right-width",
|
||||
"border-bottom-width",
|
||||
"border-left-width"
|
||||
]
|
||||
},
|
||||
"bottom": {
|
||||
"inherited": false,
|
||||
"initial": "auto"
|
||||
},
|
||||
"caption-side": {
|
||||
"inherited": true,
|
||||
"initial": "top"
|
||||
},
|
||||
"clear": {
|
||||
"inherited": false,
|
||||
"initial": "none"
|
||||
},
|
||||
"clip": {
|
||||
"inherited": true,
|
||||
"initial": "auto"
|
||||
},
|
||||
"color": {
|
||||
"inherited": true,
|
||||
"initial": ""
|
||||
},
|
||||
"cursor": {
|
||||
"inherited": true,
|
||||
"initial": "auto"
|
||||
},
|
||||
"direction": {
|
||||
"inherited": true,
|
||||
"initial": "ltr"
|
||||
},
|
||||
"display": {
|
||||
"inherited": false,
|
||||
"initial": "inline"
|
||||
},
|
||||
"float": {
|
||||
"inherited": false,
|
||||
"initial": "none"
|
||||
},
|
||||
"font-family": {
|
||||
"inherited": true,
|
||||
"initial": "sans-serif"
|
||||
},
|
||||
"font-size": {
|
||||
"inherited": true,
|
||||
"initial": "medium"
|
||||
},
|
||||
"font-style": {
|
||||
"inherited": true,
|
||||
"initial": "normal"
|
||||
},
|
||||
"font-variant": {
|
||||
"inherited": true,
|
||||
"initial": "normal"
|
||||
},
|
||||
"font-weight": {
|
||||
"inherited": true,
|
||||
"initial": "normal"
|
||||
},
|
||||
"height": {
|
||||
"inherited": false,
|
||||
"initial": "auto"
|
||||
},
|
||||
"left": {
|
||||
"inherited": false,
|
||||
"initial": "auto"
|
||||
},
|
||||
"letter-spacing": {
|
||||
"inherited": true,
|
||||
"initial": "normal"
|
||||
},
|
||||
"line-height": {
|
||||
"inherited": true,
|
||||
"initial": "normal"
|
||||
},
|
||||
"list-style": {
|
||||
"longhands": [
|
||||
"list-style-type",
|
||||
"list-style-position",
|
||||
"list-style-image"
|
||||
]
|
||||
},
|
||||
"list-style-image": {
|
||||
"inherited": true,
|
||||
"initial": "none"
|
||||
},
|
||||
"list-style-position": {
|
||||
"inherited": true,
|
||||
"initial": "outside"
|
||||
},
|
||||
"list-style-type": {
|
||||
"inherited": true,
|
||||
"initial": "disc"
|
||||
},
|
||||
"margin": {
|
||||
"longhands": [
|
||||
"margin-top",
|
||||
"margin-right",
|
||||
"margin-bottom",
|
||||
"margin-left"
|
||||
]
|
||||
},
|
||||
"margin-bottom": {
|
||||
"inherited": false,
|
||||
"initial": "0"
|
||||
},
|
||||
"margin-left": {
|
||||
"inherited": false,
|
||||
"initial": "0"
|
||||
},
|
||||
"margin-right": {
|
||||
"inherited": false,
|
||||
"initial": "0"
|
||||
},
|
||||
"margin-top": {
|
||||
"inherited": false,
|
||||
"initial": "0"
|
||||
},
|
||||
"max-height": {
|
||||
"inherited": false,
|
||||
"initial": "none"
|
||||
},
|
||||
"max-width": {
|
||||
"inherited": false,
|
||||
"initial": "none"
|
||||
},
|
||||
"min-height": {
|
||||
"inherited": false,
|
||||
"initial": "0"
|
||||
},
|
||||
"min-width": {
|
||||
"inherited": false,
|
||||
"initial": "0"
|
||||
},
|
||||
"padding": {
|
||||
"longhands": [
|
||||
"padding-top",
|
||||
"padding-right",
|
||||
"padding-bottom",
|
||||
"padding-left"
|
||||
]
|
||||
},
|
||||
"padding-bottom": {
|
||||
"inherited": false,
|
||||
"initial": "0"
|
||||
},
|
||||
"padding-left": {
|
||||
"inherited": false,
|
||||
"initial": "0"
|
||||
},
|
||||
"padding-right": {
|
||||
"inherited": false,
|
||||
"initial": "0"
|
||||
},
|
||||
"padding-top": {
|
||||
"inherited": false,
|
||||
"initial": "0"
|
||||
},
|
||||
"position": {
|
||||
"inherited": false,
|
||||
"initial": "static"
|
||||
},
|
||||
"right": {
|
||||
"inherited": false,
|
||||
"initial": "auto"
|
||||
},
|
||||
"text-align": {
|
||||
"inherited": true,
|
||||
"initial": "left"
|
||||
},
|
||||
"text-decoration": {
|
||||
"inherited": false,
|
||||
"initial": "none",
|
||||
"longhands": [
|
||||
"text-decoration-color",
|
||||
"text-decoration-line",
|
||||
"text-decoration-style",
|
||||
"text-decoration-thickness"
|
||||
]
|
||||
},
|
||||
"text-decoration-color": {
|
||||
"inherited": false,
|
||||
"initial": "none"
|
||||
},
|
||||
"text-decoration-line": {
|
||||
"inherited": false,
|
||||
"initial": "none"
|
||||
},
|
||||
"text-decoration-style": {
|
||||
"inherited": false,
|
||||
"initial": "none"
|
||||
},
|
||||
"text-decoration-thickness": {
|
||||
"inherited": false,
|
||||
"initial": "none"
|
||||
},
|
||||
"text-indent": {
|
||||
"inherited": true,
|
||||
"initial": "0"
|
||||
},
|
||||
"text-transform": {
|
||||
"inherited": true,
|
||||
"initial": "none"
|
||||
},
|
||||
"top": {
|
||||
"inherited": false,
|
||||
"initial": "auto"
|
||||
},
|
||||
"vertical-align": {
|
||||
"inherited": false,
|
||||
"initial": "baseline"
|
||||
},
|
||||
"visibility": {
|
||||
"inherited": true,
|
||||
"initial": "visible"
|
||||
},
|
||||
"width": {
|
||||
"inherited": false,
|
||||
"initial": "auto"
|
||||
},
|
||||
"white-space": {
|
||||
"inherited": true,
|
||||
"initial": "normal"
|
||||
},
|
||||
"word-spacing": {
|
||||
"inherited": true,
|
||||
"initial": "normal"
|
||||
},
|
||||
"z-index": {
|
||||
"inherited": false,
|
||||
"initial": "auto"
|
||||
}
|
||||
}
|
||||
3
Userland/Libraries/LibWeb/CSS/QuirksMode.css
Normal file
3
Userland/Libraries/LibWeb/CSS/QuirksMode.css
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
table {
|
||||
text-align: left;
|
||||
}
|
||||
67
Userland/Libraries/LibWeb/CSS/Selector.cpp
Normal file
67
Userland/Libraries/LibWeb/CSS/Selector.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/CSS/Selector.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
Selector::Selector(Vector<ComplexSelector>&& component_lists)
|
||||
: m_complex_selectors(move(component_lists))
|
||||
{
|
||||
}
|
||||
|
||||
Selector::~Selector()
|
||||
{
|
||||
}
|
||||
|
||||
u32 Selector::specificity() const
|
||||
{
|
||||
unsigned ids = 0;
|
||||
unsigned tag_names = 0;
|
||||
unsigned classes = 0;
|
||||
|
||||
for (auto& list : m_complex_selectors) {
|
||||
for (auto& simple_selector : list.compound_selector) {
|
||||
switch (simple_selector.type) {
|
||||
case SimpleSelector::Type::Id:
|
||||
++ids;
|
||||
break;
|
||||
case SimpleSelector::Type::Class:
|
||||
++classes;
|
||||
break;
|
||||
case SimpleSelector::Type::TagName:
|
||||
++tag_names;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ids * 0x10000 + classes * 0x100 + tag_names;
|
||||
}
|
||||
|
||||
}
|
||||
106
Userland/Libraries/LibWeb/CSS/Selector.h
Normal file
106
Userland/Libraries/LibWeb/CSS/Selector.h
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/Vector.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class Selector {
|
||||
public:
|
||||
struct SimpleSelector {
|
||||
enum class Type {
|
||||
Invalid,
|
||||
Universal,
|
||||
TagName,
|
||||
Id,
|
||||
Class,
|
||||
};
|
||||
Type type { Type::Invalid };
|
||||
|
||||
enum class PseudoClass {
|
||||
None,
|
||||
Link,
|
||||
Visited,
|
||||
Hover,
|
||||
Focus,
|
||||
FirstChild,
|
||||
LastChild,
|
||||
OnlyChild,
|
||||
Empty,
|
||||
Root,
|
||||
};
|
||||
PseudoClass pseudo_class { PseudoClass::None };
|
||||
|
||||
enum class PseudoElement {
|
||||
None,
|
||||
Before,
|
||||
After,
|
||||
};
|
||||
PseudoElement pseudo_element { PseudoElement::None };
|
||||
|
||||
FlyString value;
|
||||
|
||||
enum class AttributeMatchType {
|
||||
None,
|
||||
HasAttribute,
|
||||
ExactValueMatch,
|
||||
Contains,
|
||||
};
|
||||
|
||||
AttributeMatchType attribute_match_type { AttributeMatchType::None };
|
||||
FlyString attribute_name;
|
||||
String attribute_value;
|
||||
};
|
||||
|
||||
struct ComplexSelector {
|
||||
enum class Relation {
|
||||
None,
|
||||
ImmediateChild,
|
||||
Descendant,
|
||||
AdjacentSibling,
|
||||
GeneralSibling,
|
||||
};
|
||||
Relation relation { Relation::None };
|
||||
|
||||
using CompoundSelector = Vector<SimpleSelector>;
|
||||
CompoundSelector compound_selector;
|
||||
};
|
||||
|
||||
explicit Selector(Vector<ComplexSelector>&&);
|
||||
~Selector();
|
||||
|
||||
const Vector<ComplexSelector>& complex_selectors() const { return m_complex_selectors; }
|
||||
|
||||
u32 specificity() const;
|
||||
|
||||
private:
|
||||
Vector<ComplexSelector> m_complex_selectors;
|
||||
};
|
||||
|
||||
}
|
||||
172
Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
Normal file
172
Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/CSS/SelectorEngine.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/DOM/Text.h>
|
||||
#include <LibWeb/HTML/AttributeNames.h>
|
||||
#include <LibWeb/HTML/HTMLElement.h>
|
||||
|
||||
namespace Web::SelectorEngine {
|
||||
|
||||
static bool matches_hover_pseudo_class(const DOM::Element& element)
|
||||
{
|
||||
auto* hovered_node = element.document().hovered_node();
|
||||
if (!hovered_node)
|
||||
return false;
|
||||
if (&element == hovered_node)
|
||||
return true;
|
||||
return element.is_ancestor_of(*hovered_node);
|
||||
}
|
||||
|
||||
static bool matches(const CSS::Selector::SimpleSelector& component, const DOM::Element& element)
|
||||
{
|
||||
switch (component.pseudo_element) {
|
||||
case CSS::Selector::SimpleSelector::PseudoElement::None:
|
||||
break;
|
||||
default:
|
||||
// FIXME: Implement pseudo-elements.
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (component.pseudo_class) {
|
||||
case CSS::Selector::SimpleSelector::PseudoClass::None:
|
||||
break;
|
||||
case CSS::Selector::SimpleSelector::PseudoClass::Link:
|
||||
if (!element.is_link())
|
||||
return false;
|
||||
break;
|
||||
case CSS::Selector::SimpleSelector::PseudoClass::Visited:
|
||||
// FIXME: Maybe match this selector sometimes?
|
||||
return false;
|
||||
case CSS::Selector::SimpleSelector::PseudoClass::Hover:
|
||||
if (!matches_hover_pseudo_class(element))
|
||||
return false;
|
||||
break;
|
||||
case CSS::Selector::SimpleSelector::PseudoClass::Focus:
|
||||
// FIXME: Implement matches_focus_pseudo_class(element)
|
||||
return false;
|
||||
case CSS::Selector::SimpleSelector::PseudoClass::FirstChild:
|
||||
if (element.previous_element_sibling())
|
||||
return false;
|
||||
break;
|
||||
case CSS::Selector::SimpleSelector::PseudoClass::LastChild:
|
||||
if (element.next_element_sibling())
|
||||
return false;
|
||||
break;
|
||||
case CSS::Selector::SimpleSelector::PseudoClass::OnlyChild:
|
||||
if (element.previous_element_sibling() || element.next_element_sibling())
|
||||
return false;
|
||||
break;
|
||||
case CSS::Selector::SimpleSelector::PseudoClass::Empty:
|
||||
if (element.first_child_of_type<DOM::Element>() || element.first_child_of_type<DOM::Text>())
|
||||
return false;
|
||||
break;
|
||||
case CSS::Selector::SimpleSelector::PseudoClass::Root:
|
||||
if (!is<HTML::HTMLElement>(element))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (component.attribute_match_type) {
|
||||
case CSS::Selector::SimpleSelector::AttributeMatchType::HasAttribute:
|
||||
if (!element.has_attribute(component.attribute_name))
|
||||
return false;
|
||||
break;
|
||||
case CSS::Selector::SimpleSelector::AttributeMatchType::ExactValueMatch:
|
||||
if (element.attribute(component.attribute_name) != component.attribute_value)
|
||||
return false;
|
||||
break;
|
||||
case CSS::Selector::SimpleSelector::AttributeMatchType::Contains:
|
||||
if (!element.attribute(component.attribute_name).split(' ').contains_slow(component.attribute_value))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (component.type) {
|
||||
case CSS::Selector::SimpleSelector::Type::Universal:
|
||||
return true;
|
||||
case CSS::Selector::SimpleSelector::Type::Id:
|
||||
return component.value == element.attribute(HTML::AttributeNames::id);
|
||||
case CSS::Selector::SimpleSelector::Type::Class:
|
||||
return element.has_class(component.value);
|
||||
case CSS::Selector::SimpleSelector::Type::TagName:
|
||||
return component.value == element.local_name();
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
static bool matches(const CSS::Selector& selector, int component_list_index, const DOM::Element& element)
|
||||
{
|
||||
auto& component_list = selector.complex_selectors()[component_list_index];
|
||||
for (auto& component : component_list.compound_selector) {
|
||||
if (!matches(component, element))
|
||||
return false;
|
||||
}
|
||||
switch (component_list.relation) {
|
||||
case CSS::Selector::ComplexSelector::Relation::None:
|
||||
return true;
|
||||
case CSS::Selector::ComplexSelector::Relation::Descendant:
|
||||
ASSERT(component_list_index != 0);
|
||||
for (auto* ancestor = element.parent(); ancestor; ancestor = ancestor->parent()) {
|
||||
if (!is<DOM::Element>(*ancestor))
|
||||
continue;
|
||||
if (matches(selector, component_list_index - 1, downcast<DOM::Element>(*ancestor)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case CSS::Selector::ComplexSelector::Relation::ImmediateChild:
|
||||
ASSERT(component_list_index != 0);
|
||||
if (!element.parent() || !is<DOM::Element>(*element.parent()))
|
||||
return false;
|
||||
return matches(selector, component_list_index - 1, downcast<DOM::Element>(*element.parent()));
|
||||
case CSS::Selector::ComplexSelector::Relation::AdjacentSibling:
|
||||
ASSERT(component_list_index != 0);
|
||||
if (auto* sibling = element.previous_element_sibling())
|
||||
return matches(selector, component_list_index - 1, *sibling);
|
||||
return false;
|
||||
case CSS::Selector::ComplexSelector::Relation::GeneralSibling:
|
||||
ASSERT(component_list_index != 0);
|
||||
for (auto* sibling = element.previous_element_sibling(); sibling; sibling = sibling->previous_element_sibling()) {
|
||||
if (matches(selector, component_list_index - 1, *sibling))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
bool matches(const CSS::Selector& selector, const DOM::Element& element)
|
||||
{
|
||||
ASSERT(!selector.complex_selectors().is_empty());
|
||||
return matches(selector, selector.complex_selectors().size() - 1, element);
|
||||
}
|
||||
|
||||
}
|
||||
36
Userland/Libraries/LibWeb/CSS/SelectorEngine.h
Normal file
36
Userland/Libraries/LibWeb/CSS/SelectorEngine.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/CSS/Selector.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
|
||||
namespace Web::SelectorEngine {
|
||||
|
||||
bool matches(const CSS::Selector&, const DOM::Element&);
|
||||
|
||||
}
|
||||
40
Userland/Libraries/LibWeb/CSS/StyleDeclaration.cpp
Normal file
40
Userland/Libraries/LibWeb/CSS/StyleDeclaration.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/CSS/StyleDeclaration.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
StyleDeclaration::StyleDeclaration(Vector<StyleProperty>&& properties)
|
||||
: m_properties(move(properties))
|
||||
{
|
||||
}
|
||||
|
||||
StyleDeclaration::~StyleDeclaration()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
58
Userland/Libraries/LibWeb/CSS/StyleDeclaration.h
Normal file
58
Userland/Libraries/LibWeb/CSS/StyleDeclaration.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibWeb/CSS/StyleValue.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
struct StyleProperty {
|
||||
CSS::PropertyID property_id;
|
||||
NonnullRefPtr<StyleValue> value;
|
||||
bool important { false };
|
||||
};
|
||||
|
||||
class StyleDeclaration : public RefCounted<StyleDeclaration> {
|
||||
public:
|
||||
static NonnullRefPtr<StyleDeclaration> create(Vector<StyleProperty>&& properties)
|
||||
{
|
||||
return adopt(*new StyleDeclaration(move(properties)));
|
||||
}
|
||||
|
||||
~StyleDeclaration();
|
||||
|
||||
const Vector<StyleProperty>& properties() const { return m_properties; }
|
||||
|
||||
private:
|
||||
explicit StyleDeclaration(Vector<StyleProperty>&&);
|
||||
|
||||
Vector<StyleProperty> m_properties;
|
||||
};
|
||||
|
||||
}
|
||||
74
Userland/Libraries/LibWeb/CSS/StyleInvalidator.cpp
Normal file
74
Userland/Libraries/LibWeb/CSS/StyleInvalidator.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/CSS/StyleInvalidator.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
StyleInvalidator::StyleInvalidator(DOM::Document& document)
|
||||
: m_document(document)
|
||||
{
|
||||
if (!m_document.should_invalidate_styles_on_attribute_changes())
|
||||
return;
|
||||
auto& style_resolver = m_document.style_resolver();
|
||||
m_document.for_each_in_subtree_of_type<DOM::Element>([&](auto& element) {
|
||||
m_elements_and_matching_rules_before.set(&element, style_resolver.collect_matching_rules(element));
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
StyleInvalidator::~StyleInvalidator()
|
||||
{
|
||||
if (!m_document.should_invalidate_styles_on_attribute_changes())
|
||||
return;
|
||||
auto& style_resolver = m_document.style_resolver();
|
||||
m_document.for_each_in_subtree_of_type<DOM::Element>([&](auto& element) {
|
||||
auto maybe_matching_rules_before = m_elements_and_matching_rules_before.get(&element);
|
||||
if (!maybe_matching_rules_before.has_value()) {
|
||||
element.set_needs_style_update(true);
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
auto& matching_rules_before = maybe_matching_rules_before.value();
|
||||
auto matching_rules_after = style_resolver.collect_matching_rules(element);
|
||||
if (matching_rules_before.size() != matching_rules_after.size()) {
|
||||
element.set_needs_style_update(true);
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
style_resolver.sort_matching_rules(matching_rules_before);
|
||||
style_resolver.sort_matching_rules(matching_rules_after);
|
||||
for (size_t i = 0; i < matching_rules_before.size(); ++i) {
|
||||
if (matching_rules_before[i].rule != matching_rules_after[i].rule) {
|
||||
element.set_needs_style_update(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
46
Userland/Libraries/LibWeb/CSS/StyleInvalidator.h
Normal file
46
Userland/Libraries/LibWeb/CSS/StyleInvalidator.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <LibWeb/CSS/StyleResolver.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class StyleInvalidator {
|
||||
public:
|
||||
explicit StyleInvalidator(DOM::Document&);
|
||||
~StyleInvalidator();
|
||||
|
||||
private:
|
||||
DOM::Document& m_document;
|
||||
HashMap<DOM::Element*, Vector<MatchingRule>> m_elements_and_matching_rules_before;
|
||||
};
|
||||
|
||||
}
|
||||
484
Userland/Libraries/LibWeb/CSS/StyleProperties.cpp
Normal file
484
Userland/Libraries/LibWeb/CSS/StyleProperties.cpp
Normal file
|
|
@ -0,0 +1,484 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibCore/DirIterator.h>
|
||||
#include <LibGfx/FontDatabase.h>
|
||||
#include <LibWeb/CSS/StyleProperties.h>
|
||||
#include <LibWeb/FontCache.h>
|
||||
#include <ctype.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
StyleProperties::StyleProperties()
|
||||
{
|
||||
}
|
||||
|
||||
StyleProperties::StyleProperties(const StyleProperties& other)
|
||||
: m_property_values(other.m_property_values)
|
||||
{
|
||||
if (other.m_font) {
|
||||
m_font = other.m_font->clone();
|
||||
} else {
|
||||
m_font = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NonnullRefPtr<StyleProperties> StyleProperties::clone() const
|
||||
{
|
||||
return adopt(*new StyleProperties(*this));
|
||||
}
|
||||
|
||||
void StyleProperties::set_property(CSS::PropertyID id, NonnullRefPtr<StyleValue> value)
|
||||
{
|
||||
m_property_values.set((unsigned)id, move(value));
|
||||
}
|
||||
|
||||
void StyleProperties::set_property(CSS::PropertyID id, const StringView& value)
|
||||
{
|
||||
m_property_values.set((unsigned)id, StringStyleValue::create(value));
|
||||
}
|
||||
|
||||
Optional<NonnullRefPtr<StyleValue>> StyleProperties::property(CSS::PropertyID id) const
|
||||
{
|
||||
auto it = m_property_values.find((unsigned)id);
|
||||
if (it == m_property_values.end())
|
||||
return {};
|
||||
return it->value;
|
||||
}
|
||||
|
||||
Length StyleProperties::length_or_fallback(CSS::PropertyID id, const Length& fallback) const
|
||||
{
|
||||
auto value = property(id);
|
||||
if (!value.has_value())
|
||||
return fallback;
|
||||
return value.value()->to_length();
|
||||
}
|
||||
|
||||
LengthBox StyleProperties::length_box(CSS::PropertyID left_id, CSS::PropertyID top_id, CSS::PropertyID right_id, CSS::PropertyID bottom_id, const CSS::Length& default_value) const
|
||||
{
|
||||
LengthBox box;
|
||||
box.left = length_or_fallback(left_id, default_value);
|
||||
box.top = length_or_fallback(top_id, default_value);
|
||||
box.right = length_or_fallback(right_id, default_value);
|
||||
box.bottom = length_or_fallback(bottom_id, default_value);
|
||||
return box;
|
||||
}
|
||||
|
||||
String StyleProperties::string_or_fallback(CSS::PropertyID id, const StringView& fallback) const
|
||||
{
|
||||
auto value = property(id);
|
||||
if (!value.has_value())
|
||||
return fallback;
|
||||
return value.value()->to_string();
|
||||
}
|
||||
|
||||
Color StyleProperties::color_or_fallback(CSS::PropertyID id, const DOM::Document& document, Color fallback) const
|
||||
{
|
||||
auto value = property(id);
|
||||
if (!value.has_value())
|
||||
return fallback;
|
||||
return value.value()->to_color(document);
|
||||
}
|
||||
|
||||
void StyleProperties::load_font() const
|
||||
{
|
||||
auto family_value = string_or_fallback(CSS::PropertyID::FontFamily, "Katica");
|
||||
auto font_size = property(CSS::PropertyID::FontSize).value_or(IdentifierStyleValue::create(CSS::ValueID::Medium));
|
||||
auto font_weight = property(CSS::PropertyID::FontWeight).value_or(IdentifierStyleValue::create(CSS::ValueID::Normal));
|
||||
|
||||
auto family_parts = family_value.split(',');
|
||||
auto family = family_parts[0];
|
||||
|
||||
if (family.is_one_of("monospace", "ui-monospace"))
|
||||
family = "Csilla";
|
||||
else if (family.is_one_of("serif", "sans-serif", "cursive", "fantasy", "ui-serif", "ui-sans-serif", "ui-rounded"))
|
||||
family = "Katica";
|
||||
|
||||
int weight = 400;
|
||||
if (font_weight->is_identifier()) {
|
||||
switch (static_cast<const IdentifierStyleValue&>(*font_weight).id()) {
|
||||
case CSS::ValueID::Normal:
|
||||
weight = 400;
|
||||
break;
|
||||
case CSS::ValueID::Bold:
|
||||
weight = 700;
|
||||
break;
|
||||
case CSS::ValueID::Lighter:
|
||||
// FIXME: This should be relative to the parent.
|
||||
weight = 400;
|
||||
break;
|
||||
case CSS::ValueID::Bolder:
|
||||
// FIXME: This should be relative to the parent.
|
||||
weight = 700;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (font_weight->is_length()) {
|
||||
// FIXME: This isn't really a length, it's a numeric value..
|
||||
int font_weight_integer = font_weight->to_length().raw_value();
|
||||
if (font_weight_integer <= 400)
|
||||
weight = 400;
|
||||
if (font_weight_integer <= 700)
|
||||
weight = 700;
|
||||
weight = 900;
|
||||
}
|
||||
|
||||
int size = 10;
|
||||
if (font_size->is_identifier()) {
|
||||
switch (static_cast<const IdentifierStyleValue&>(*font_size).id()) {
|
||||
case CSS::ValueID::XxSmall:
|
||||
case CSS::ValueID::XSmall:
|
||||
case CSS::ValueID::Small:
|
||||
case CSS::ValueID::Medium:
|
||||
// FIXME: Should be based on "user's default font size"
|
||||
size = 10;
|
||||
break;
|
||||
case CSS::ValueID::Large:
|
||||
case CSS::ValueID::XLarge:
|
||||
case CSS::ValueID::XxLarge:
|
||||
case CSS::ValueID::XxxLarge:
|
||||
// FIXME: Should be based on "user's default font size"
|
||||
size = 12;
|
||||
break;
|
||||
case CSS::ValueID::Smaller:
|
||||
// FIXME: This should be relative to the parent.
|
||||
size = 10;
|
||||
break;
|
||||
case CSS::ValueID::Larger:
|
||||
// FIXME: This should be relative to the parent.
|
||||
size = 12;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (font_size->is_length()) {
|
||||
// FIXME: This isn't really a length, it's a numeric value..
|
||||
int font_size_integer = font_size->to_length().raw_value();
|
||||
if (font_size_integer <= 10)
|
||||
size = 10;
|
||||
else if (font_size_integer <= 12)
|
||||
size = 12;
|
||||
else
|
||||
size = 14;
|
||||
}
|
||||
|
||||
FontSelector font_selector { family, size, weight };
|
||||
|
||||
auto found_font = FontCache::the().get(font_selector);
|
||||
if (found_font) {
|
||||
m_font = found_font;
|
||||
return;
|
||||
}
|
||||
|
||||
Gfx::FontDatabase::the().for_each_font([&](auto& font) {
|
||||
if (font.family() == family && font.weight() == weight && font.presentation_size() == size)
|
||||
found_font = font;
|
||||
});
|
||||
|
||||
if (!found_font) {
|
||||
dbgln("Font not found: '{}' {} {}", family, size, weight);
|
||||
found_font = Gfx::FontDatabase::default_font();
|
||||
}
|
||||
|
||||
m_font = found_font;
|
||||
FontCache::the().set(font_selector, *m_font);
|
||||
}
|
||||
|
||||
float StyleProperties::line_height(const Layout::Node& layout_node) const
|
||||
{
|
||||
auto line_height_length = length_or_fallback(CSS::PropertyID::LineHeight, Length::make_auto());
|
||||
if (line_height_length.is_absolute())
|
||||
return (float)line_height_length.to_px(layout_node);
|
||||
return (float)font().glyph_height() * 1.4f;
|
||||
}
|
||||
|
||||
Optional<int> StyleProperties::z_index() const
|
||||
{
|
||||
auto value = property(CSS::PropertyID::ZIndex);
|
||||
if (!value.has_value())
|
||||
return {};
|
||||
return static_cast<int>(value.value()->to_length().raw_value());
|
||||
}
|
||||
|
||||
Optional<CSS::Position> StyleProperties::position() const
|
||||
{
|
||||
auto value = property(CSS::PropertyID::Position);
|
||||
if (!value.has_value() || !value.value()->is_identifier())
|
||||
return {};
|
||||
switch (static_cast<const IdentifierStyleValue&>(*value.value()).id()) {
|
||||
case CSS::ValueID::Static:
|
||||
return CSS::Position::Static;
|
||||
case CSS::ValueID::Relative:
|
||||
return CSS::Position::Relative;
|
||||
case CSS::ValueID::Absolute:
|
||||
return CSS::Position::Absolute;
|
||||
case CSS::ValueID::Fixed:
|
||||
return CSS::Position::Fixed;
|
||||
case CSS::ValueID::Sticky:
|
||||
return CSS::Position::Sticky;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
bool StyleProperties::operator==(const StyleProperties& other) const
|
||||
{
|
||||
if (m_property_values.size() != other.m_property_values.size())
|
||||
return false;
|
||||
|
||||
for (auto& it : m_property_values) {
|
||||
auto jt = other.m_property_values.find(it.key);
|
||||
if (jt == other.m_property_values.end())
|
||||
return false;
|
||||
auto& my_value = *it.value;
|
||||
auto& other_value = *jt->value;
|
||||
if (my_value.type() != other_value.type())
|
||||
return false;
|
||||
if (my_value != other_value)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Optional<CSS::TextAlign> StyleProperties::text_align() const
|
||||
{
|
||||
auto value = property(CSS::PropertyID::TextAlign);
|
||||
if (!value.has_value() || !value.value()->is_identifier())
|
||||
return {};
|
||||
|
||||
switch (static_cast<const IdentifierStyleValue&>(*value.value()).id()) {
|
||||
case CSS::ValueID::Left:
|
||||
return CSS::TextAlign::Left;
|
||||
case CSS::ValueID::Center:
|
||||
return CSS::TextAlign::Center;
|
||||
case CSS::ValueID::Right:
|
||||
return CSS::TextAlign::Right;
|
||||
case CSS::ValueID::Justify:
|
||||
return CSS::TextAlign::Justify;
|
||||
case CSS::ValueID::LibwebCenter:
|
||||
return CSS::TextAlign::LibwebCenter;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Optional<CSS::WhiteSpace> StyleProperties::white_space() const
|
||||
{
|
||||
auto value = property(CSS::PropertyID::WhiteSpace);
|
||||
if (!value.has_value() || !value.value()->is_identifier())
|
||||
return {};
|
||||
switch (static_cast<const IdentifierStyleValue&>(*value.value()).id()) {
|
||||
case CSS::ValueID::Normal:
|
||||
return CSS::WhiteSpace::Normal;
|
||||
case CSS::ValueID::Nowrap:
|
||||
return CSS::WhiteSpace::Nowrap;
|
||||
case CSS::ValueID::Pre:
|
||||
return CSS::WhiteSpace::Pre;
|
||||
case CSS::ValueID::PreLine:
|
||||
return CSS::WhiteSpace::PreLine;
|
||||
case CSS::ValueID::PreWrap:
|
||||
return CSS::WhiteSpace::PreWrap;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Optional<CSS::LineStyle> StyleProperties::line_style(CSS::PropertyID property_id) const
|
||||
{
|
||||
auto value = property(property_id);
|
||||
if (!value.has_value() || !value.value()->is_identifier())
|
||||
return {};
|
||||
switch (static_cast<const IdentifierStyleValue&>(*value.value()).id()) {
|
||||
case CSS::ValueID::None:
|
||||
return CSS::LineStyle::None;
|
||||
case CSS::ValueID::Hidden:
|
||||
return CSS::LineStyle::Hidden;
|
||||
case CSS::ValueID::Dotted:
|
||||
return CSS::LineStyle::Dotted;
|
||||
case CSS::ValueID::Dashed:
|
||||
return CSS::LineStyle::Dashed;
|
||||
case CSS::ValueID::Solid:
|
||||
return CSS::LineStyle::Solid;
|
||||
case CSS::ValueID::Double:
|
||||
return CSS::LineStyle::Double;
|
||||
case CSS::ValueID::Groove:
|
||||
return CSS::LineStyle::Groove;
|
||||
case CSS::ValueID::Ridge:
|
||||
return CSS::LineStyle::Ridge;
|
||||
case CSS::ValueID::Inset:
|
||||
return CSS::LineStyle::Inset;
|
||||
case CSS::ValueID::Outset:
|
||||
return CSS::LineStyle::Outset;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Optional<CSS::Float> StyleProperties::float_() const
|
||||
{
|
||||
auto value = property(CSS::PropertyID::Float);
|
||||
if (!value.has_value() || !value.value()->is_identifier())
|
||||
return {};
|
||||
switch (static_cast<const IdentifierStyleValue&>(*value.value()).id()) {
|
||||
case CSS::ValueID::None:
|
||||
return CSS::Float::None;
|
||||
case CSS::ValueID::Left:
|
||||
return CSS::Float::Left;
|
||||
case CSS::ValueID::Right:
|
||||
return CSS::Float::Right;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Optional<CSS::Clear> StyleProperties::clear() const
|
||||
{
|
||||
auto value = property(CSS::PropertyID::Clear);
|
||||
if (!value.has_value() || !value.value()->is_identifier())
|
||||
return {};
|
||||
switch (static_cast<const IdentifierStyleValue&>(*value.value()).id()) {
|
||||
case CSS::ValueID::None:
|
||||
return CSS::Clear::None;
|
||||
case CSS::ValueID::Left:
|
||||
return CSS::Clear::Left;
|
||||
case CSS::ValueID::Right:
|
||||
return CSS::Clear::Right;
|
||||
case CSS::ValueID::Both:
|
||||
return CSS::Clear::Both;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
CSS::Display StyleProperties::display() const
|
||||
{
|
||||
auto value = property(CSS::PropertyID::Display);
|
||||
if (!value.has_value() || !value.value()->is_identifier())
|
||||
return CSS::Display::Inline;
|
||||
switch (static_cast<const IdentifierStyleValue&>(*value.value()).id()) {
|
||||
case CSS::ValueID::None:
|
||||
return CSS::Display::None;
|
||||
case CSS::ValueID::Block:
|
||||
return CSS::Display::Block;
|
||||
case CSS::ValueID::Inline:
|
||||
return CSS::Display::Inline;
|
||||
case CSS::ValueID::InlineBlock:
|
||||
return CSS::Display::InlineBlock;
|
||||
case CSS::ValueID::ListItem:
|
||||
return CSS::Display::ListItem;
|
||||
case CSS::ValueID::Table:
|
||||
return CSS::Display::Table;
|
||||
case CSS::ValueID::TableRow:
|
||||
return CSS::Display::TableRow;
|
||||
case CSS::ValueID::TableCell:
|
||||
return CSS::Display::TableCell;
|
||||
case CSS::ValueID::TableColumn:
|
||||
return CSS::Display::TableColumn;
|
||||
case CSS::ValueID::TableColumnGroup:
|
||||
return CSS::Display::TableColumnGroup;
|
||||
case CSS::ValueID::TableCaption:
|
||||
return CSS::Display::TableCaption;
|
||||
case CSS::ValueID::TableRowGroup:
|
||||
return CSS::Display::TableRowGroup;
|
||||
case CSS::ValueID::TableHeaderGroup:
|
||||
return CSS::Display::TableHeaderGroup;
|
||||
case CSS::ValueID::TableFooterGroup:
|
||||
return CSS::Display::TableFooterGroup;
|
||||
default:
|
||||
return CSS::Display::Block;
|
||||
}
|
||||
}
|
||||
|
||||
Optional<CSS::TextDecorationLine> StyleProperties::text_decoration_line() const
|
||||
{
|
||||
auto value = property(CSS::PropertyID::TextDecorationLine);
|
||||
if (!value.has_value() || !value.value()->is_identifier())
|
||||
return {};
|
||||
switch (static_cast<const IdentifierStyleValue&>(*value.value()).id()) {
|
||||
case CSS::ValueID::None:
|
||||
return CSS::TextDecorationLine::None;
|
||||
case CSS::ValueID::Underline:
|
||||
return CSS::TextDecorationLine::Underline;
|
||||
case CSS::ValueID::Overline:
|
||||
return CSS::TextDecorationLine::Overline;
|
||||
case CSS::ValueID::LineThrough:
|
||||
return CSS::TextDecorationLine::LineThrough;
|
||||
case CSS::ValueID::Blink:
|
||||
return CSS::TextDecorationLine::Blink;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Optional<CSS::TextTransform> StyleProperties::text_transform() const
|
||||
{
|
||||
auto value = property(CSS::PropertyID::TextTransform);
|
||||
if (!value.has_value())
|
||||
return {};
|
||||
switch (value.value()->to_identifier()) {
|
||||
case CSS::ValueID::None:
|
||||
return CSS::TextTransform::None;
|
||||
case CSS::ValueID::Lowercase:
|
||||
return CSS::TextTransform::Lowercase;
|
||||
case CSS::ValueID::Uppercase:
|
||||
return CSS::TextTransform::Uppercase;
|
||||
case CSS::ValueID::Capitalize:
|
||||
return CSS::TextTransform::Capitalize;
|
||||
case CSS::ValueID::FullWidth:
|
||||
return CSS::TextTransform::FullWidth;
|
||||
case CSS::ValueID::FullSizeKana:
|
||||
return CSS::TextTransform::FullSizeKana;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Optional<CSS::ListStyleType> StyleProperties::list_style_type() const
|
||||
{
|
||||
auto value = property(CSS::PropertyID::ListStyleType);
|
||||
if (!value.has_value())
|
||||
return {};
|
||||
|
||||
switch (value.value()->to_identifier()) {
|
||||
case CSS::ValueID::None:
|
||||
return CSS::ListStyleType::None;
|
||||
case CSS::ValueID::Disc:
|
||||
return CSS::ListStyleType::Disc;
|
||||
case CSS::ValueID::Circle:
|
||||
return CSS::ListStyleType::Circle;
|
||||
case CSS::ValueID::Square:
|
||||
return CSS::ListStyleType::Square;
|
||||
case CSS::ValueID::Decimal:
|
||||
return CSS::ListStyleType::Decimal;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
96
Userland/Libraries/LibWeb/CSS/StyleProperties.h
Normal file
96
Userland/Libraries/LibWeb/CSS/StyleProperties.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <LibGfx/Font.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibWeb/CSS/LengthBox.h>
|
||||
#include <LibWeb/CSS/StyleValue.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class StyleProperties : public RefCounted<StyleProperties> {
|
||||
public:
|
||||
StyleProperties();
|
||||
|
||||
explicit StyleProperties(const StyleProperties&);
|
||||
|
||||
static NonnullRefPtr<StyleProperties> create() { return adopt(*new StyleProperties); }
|
||||
|
||||
NonnullRefPtr<StyleProperties> clone() const;
|
||||
|
||||
template<typename Callback>
|
||||
inline void for_each_property(Callback callback) const
|
||||
{
|
||||
for (auto& it : m_property_values)
|
||||
callback((CSS::PropertyID)it.key, *it.value);
|
||||
}
|
||||
|
||||
void set_property(CSS::PropertyID, NonnullRefPtr<StyleValue> value);
|
||||
void set_property(CSS::PropertyID, const StringView&);
|
||||
Optional<NonnullRefPtr<StyleValue>> property(CSS::PropertyID) const;
|
||||
|
||||
Length length_or_fallback(CSS::PropertyID, const Length& fallback) const;
|
||||
LengthBox length_box(CSS::PropertyID left_id, CSS::PropertyID top_id, CSS::PropertyID right_id, CSS::PropertyID bottom_id, const CSS::Length& default_value) const;
|
||||
String string_or_fallback(CSS::PropertyID, const StringView& fallback) const;
|
||||
Color color_or_fallback(CSS::PropertyID, const DOM::Document&, Color fallback) const;
|
||||
Optional<CSS::TextAlign> text_align() const;
|
||||
CSS::Display display() const;
|
||||
Optional<CSS::Float> float_() const;
|
||||
Optional<CSS::Clear> clear() const;
|
||||
Optional<CSS::WhiteSpace> white_space() const;
|
||||
Optional<CSS::LineStyle> line_style(CSS::PropertyID) const;
|
||||
Optional<CSS::TextDecorationLine> text_decoration_line() const;
|
||||
Optional<CSS::TextTransform> text_transform() const;
|
||||
Optional<CSS::ListStyleType> list_style_type() const;
|
||||
|
||||
const Gfx::Font& font() const
|
||||
{
|
||||
if (!m_font)
|
||||
load_font();
|
||||
return *m_font;
|
||||
}
|
||||
|
||||
float line_height(const Layout::Node&) const;
|
||||
|
||||
bool operator==(const StyleProperties&) const;
|
||||
bool operator!=(const StyleProperties& other) const { return !(*this == other); }
|
||||
|
||||
Optional<CSS::Position> position() const;
|
||||
Optional<int> z_index() const;
|
||||
|
||||
private:
|
||||
HashMap<unsigned, NonnullRefPtr<StyleValue>> m_property_values;
|
||||
|
||||
void load_font() const;
|
||||
|
||||
mutable RefPtr<Gfx::Font> m_font;
|
||||
};
|
||||
|
||||
}
|
||||
598
Userland/Libraries/LibWeb/CSS/StyleResolver.cpp
Normal file
598
Userland/Libraries/LibWeb/CSS/StyleResolver.cpp
Normal file
|
|
@ -0,0 +1,598 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/QuickSort.h>
|
||||
#include <LibWeb/CSS/Parser/CSSParser.h>
|
||||
#include <LibWeb/CSS/SelectorEngine.h>
|
||||
#include <LibWeb/CSS/StyleResolver.h>
|
||||
#include <LibWeb/CSS/StyleSheet.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/Dump.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
StyleResolver::StyleResolver(DOM::Document& document)
|
||||
: m_document(document)
|
||||
{
|
||||
}
|
||||
|
||||
StyleResolver::~StyleResolver()
|
||||
{
|
||||
}
|
||||
|
||||
static StyleSheet& default_stylesheet()
|
||||
{
|
||||
static StyleSheet* sheet;
|
||||
if (!sheet) {
|
||||
extern const char default_stylesheet_source[];
|
||||
String css = default_stylesheet_source;
|
||||
sheet = parse_css(CSS::ParsingContext(), css).leak_ref();
|
||||
}
|
||||
return *sheet;
|
||||
}
|
||||
|
||||
static StyleSheet& quirks_mode_stylesheet()
|
||||
{
|
||||
static StyleSheet* sheet;
|
||||
if (!sheet) {
|
||||
extern const char quirks_mode_stylesheet_source[];
|
||||
String css = quirks_mode_stylesheet_source;
|
||||
sheet = parse_css(CSS::ParsingContext(), css).leak_ref();
|
||||
}
|
||||
return *sheet;
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
void StyleResolver::for_each_stylesheet(Callback callback) const
|
||||
{
|
||||
callback(default_stylesheet());
|
||||
if (document().in_quirks_mode())
|
||||
callback(quirks_mode_stylesheet());
|
||||
for (auto& sheet : document().style_sheets().sheets()) {
|
||||
callback(sheet);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<MatchingRule> StyleResolver::collect_matching_rules(const DOM::Element& element) const
|
||||
{
|
||||
Vector<MatchingRule> matching_rules;
|
||||
|
||||
size_t style_sheet_index = 0;
|
||||
for_each_stylesheet([&](auto& sheet) {
|
||||
size_t rule_index = 0;
|
||||
for (auto& rule : sheet.rules()) {
|
||||
size_t selector_index = 0;
|
||||
for (auto& selector : rule.selectors()) {
|
||||
if (SelectorEngine::matches(selector, element)) {
|
||||
matching_rules.append({ rule, style_sheet_index, rule_index, selector_index });
|
||||
break;
|
||||
}
|
||||
++selector_index;
|
||||
}
|
||||
++rule_index;
|
||||
}
|
||||
++style_sheet_index;
|
||||
});
|
||||
|
||||
return matching_rules;
|
||||
}
|
||||
|
||||
void StyleResolver::sort_matching_rules(Vector<MatchingRule>& matching_rules) const
|
||||
{
|
||||
quick_sort(matching_rules, [&](MatchingRule& a, MatchingRule& b) {
|
||||
auto& a_selector = a.rule->selectors()[a.selector_index];
|
||||
auto& b_selector = b.rule->selectors()[b.selector_index];
|
||||
auto a_specificity = a_selector.specificity();
|
||||
auto b_specificity = b_selector.specificity();
|
||||
if (a_selector.specificity() == b_selector.specificity()) {
|
||||
if (a.style_sheet_index == b.style_sheet_index)
|
||||
return a.rule_index < b.rule_index;
|
||||
return a.style_sheet_index < b.style_sheet_index;
|
||||
}
|
||||
return a_specificity < b_specificity;
|
||||
});
|
||||
}
|
||||
|
||||
bool StyleResolver::is_inherited_property(CSS::PropertyID property_id)
|
||||
{
|
||||
static HashTable<CSS::PropertyID> inherited_properties;
|
||||
if (inherited_properties.is_empty()) {
|
||||
inherited_properties.set(CSS::PropertyID::BorderCollapse);
|
||||
inherited_properties.set(CSS::PropertyID::BorderSpacing);
|
||||
inherited_properties.set(CSS::PropertyID::Color);
|
||||
inherited_properties.set(CSS::PropertyID::FontFamily);
|
||||
inherited_properties.set(CSS::PropertyID::FontSize);
|
||||
inherited_properties.set(CSS::PropertyID::FontStyle);
|
||||
inherited_properties.set(CSS::PropertyID::FontVariant);
|
||||
inherited_properties.set(CSS::PropertyID::FontWeight);
|
||||
inherited_properties.set(CSS::PropertyID::LetterSpacing);
|
||||
inherited_properties.set(CSS::PropertyID::LineHeight);
|
||||
inherited_properties.set(CSS::PropertyID::ListStyle);
|
||||
inherited_properties.set(CSS::PropertyID::ListStyleImage);
|
||||
inherited_properties.set(CSS::PropertyID::ListStylePosition);
|
||||
inherited_properties.set(CSS::PropertyID::ListStyleType);
|
||||
inherited_properties.set(CSS::PropertyID::TextAlign);
|
||||
inherited_properties.set(CSS::PropertyID::TextIndent);
|
||||
inherited_properties.set(CSS::PropertyID::TextTransform);
|
||||
inherited_properties.set(CSS::PropertyID::Visibility);
|
||||
inherited_properties.set(CSS::PropertyID::WhiteSpace);
|
||||
inherited_properties.set(CSS::PropertyID::WordSpacing);
|
||||
|
||||
// FIXME: This property is not supposed to be inherited, but we currently
|
||||
// rely on inheritance to propagate decorations into line boxes.
|
||||
inherited_properties.set(CSS::PropertyID::TextDecorationLine);
|
||||
}
|
||||
return inherited_properties.contains(property_id);
|
||||
}
|
||||
|
||||
static Vector<String> split_on_whitespace(const StringView& string)
|
||||
{
|
||||
if (string.is_empty())
|
||||
return {};
|
||||
|
||||
Vector<String> v;
|
||||
size_t substart = 0;
|
||||
for (size_t i = 0; i < string.length(); ++i) {
|
||||
char ch = string.characters_without_null_termination()[i];
|
||||
if (isspace(ch)) {
|
||||
size_t sublen = i - substart;
|
||||
if (sublen != 0)
|
||||
v.append(string.substring_view(substart, sublen));
|
||||
substart = i + 1;
|
||||
}
|
||||
}
|
||||
size_t taillen = string.length() - substart;
|
||||
if (taillen != 0)
|
||||
v.append(string.substring_view(substart, taillen));
|
||||
return v;
|
||||
}
|
||||
|
||||
enum class Edge {
|
||||
Top,
|
||||
Right,
|
||||
Bottom,
|
||||
Left,
|
||||
All,
|
||||
};
|
||||
|
||||
static bool contains(Edge a, Edge b)
|
||||
{
|
||||
return a == b || b == Edge::All;
|
||||
}
|
||||
|
||||
static inline void set_property_border_width(StyleProperties& style, const StyleValue& value, Edge edge)
|
||||
{
|
||||
ASSERT(value.is_length());
|
||||
if (contains(Edge::Top, edge))
|
||||
style.set_property(CSS::PropertyID::BorderTopWidth, value);
|
||||
if (contains(Edge::Right, edge))
|
||||
style.set_property(CSS::PropertyID::BorderRightWidth, value);
|
||||
if (contains(Edge::Bottom, edge))
|
||||
style.set_property(CSS::PropertyID::BorderBottomWidth, value);
|
||||
if (contains(Edge::Left, edge))
|
||||
style.set_property(CSS::PropertyID::BorderLeftWidth, value);
|
||||
}
|
||||
|
||||
static inline void set_property_border_color(StyleProperties& style, const StyleValue& value, Edge edge)
|
||||
{
|
||||
ASSERT(value.is_color());
|
||||
if (contains(Edge::Top, edge))
|
||||
style.set_property(CSS::PropertyID::BorderTopColor, value);
|
||||
if (contains(Edge::Right, edge))
|
||||
style.set_property(CSS::PropertyID::BorderRightColor, value);
|
||||
if (contains(Edge::Bottom, edge))
|
||||
style.set_property(CSS::PropertyID::BorderBottomColor, value);
|
||||
if (contains(Edge::Left, edge))
|
||||
style.set_property(CSS::PropertyID::BorderLeftColor, value);
|
||||
}
|
||||
|
||||
static inline void set_property_border_style(StyleProperties& style, const StyleValue& value, Edge edge)
|
||||
{
|
||||
ASSERT(value.is_string());
|
||||
if (contains(Edge::Top, edge))
|
||||
style.set_property(CSS::PropertyID::BorderTopStyle, value);
|
||||
if (contains(Edge::Right, edge))
|
||||
style.set_property(CSS::PropertyID::BorderRightStyle, value);
|
||||
if (contains(Edge::Bottom, edge))
|
||||
style.set_property(CSS::PropertyID::BorderBottomStyle, value);
|
||||
if (contains(Edge::Left, edge))
|
||||
style.set_property(CSS::PropertyID::BorderLeftStyle, value);
|
||||
}
|
||||
|
||||
static void set_property_expanding_shorthands(StyleProperties& style, CSS::PropertyID property_id, const StyleValue& value, DOM::Document& document)
|
||||
{
|
||||
CSS::ParsingContext context(document);
|
||||
|
||||
if (property_id == CSS::PropertyID::TextDecoration) {
|
||||
switch (value.to_identifier()) {
|
||||
case CSS::ValueID::None:
|
||||
case CSS::ValueID::Underline:
|
||||
case CSS::ValueID::Overline:
|
||||
case CSS::ValueID::LineThrough:
|
||||
case CSS::ValueID::Blink:
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::TextDecorationLine, value, document);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::Border) {
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BorderTop, value, document);
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BorderRight, value, document);
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BorderBottom, value, document);
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BorderLeft, value, document);
|
||||
return;
|
||||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::BorderTop
|
||||
|| property_id == CSS::PropertyID::BorderRight
|
||||
|| property_id == CSS::PropertyID::BorderBottom
|
||||
|| property_id == CSS::PropertyID::BorderLeft) {
|
||||
|
||||
Edge edge = Edge::All;
|
||||
switch (property_id) {
|
||||
case CSS::PropertyID::BorderTop:
|
||||
edge = Edge::Top;
|
||||
break;
|
||||
case CSS::PropertyID::BorderRight:
|
||||
edge = Edge::Right;
|
||||
break;
|
||||
case CSS::PropertyID::BorderBottom:
|
||||
edge = Edge::Bottom;
|
||||
break;
|
||||
case CSS::PropertyID::BorderLeft:
|
||||
edge = Edge::Left;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
auto parts = split_on_whitespace(value.to_string());
|
||||
if (value.is_length()) {
|
||||
set_property_border_width(style, value, edge);
|
||||
return;
|
||||
}
|
||||
if (value.is_color()) {
|
||||
set_property_border_color(style, value, edge);
|
||||
return;
|
||||
}
|
||||
if (value.is_string()) {
|
||||
auto parts = split_on_whitespace(value.to_string());
|
||||
|
||||
if (parts.size() == 1) {
|
||||
if (auto value = parse_line_style(context, parts[0])) {
|
||||
set_property_border_style(style, value.release_nonnull(), edge);
|
||||
set_property_border_color(style, ColorStyleValue::create(Gfx::Color::Black), edge);
|
||||
set_property_border_width(style, LengthStyleValue::create(Length(3, Length::Type::Px)), edge);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<LengthStyleValue> line_width_value;
|
||||
RefPtr<ColorStyleValue> color_value;
|
||||
RefPtr<StringStyleValue> line_style_value;
|
||||
|
||||
for (auto& part : parts) {
|
||||
if (auto value = parse_line_width(context, part)) {
|
||||
if (line_width_value)
|
||||
return;
|
||||
line_width_value = move(value);
|
||||
continue;
|
||||
}
|
||||
if (auto value = parse_color(context, part)) {
|
||||
if (color_value)
|
||||
return;
|
||||
color_value = move(value);
|
||||
continue;
|
||||
}
|
||||
if (auto value = parse_line_style(context, part)) {
|
||||
if (line_style_value)
|
||||
return;
|
||||
line_style_value = move(value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (line_width_value)
|
||||
set_property_border_width(style, line_width_value.release_nonnull(), edge);
|
||||
if (color_value)
|
||||
set_property_border_color(style, color_value.release_nonnull(), edge);
|
||||
if (line_style_value)
|
||||
set_property_border_style(style, line_style_value.release_nonnull(), edge);
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::BorderStyle) {
|
||||
auto parts = split_on_whitespace(value.to_string());
|
||||
if (value.is_string() && parts.size() == 3) {
|
||||
auto top = parse_css_value(context, parts[0]);
|
||||
auto right = parse_css_value(context, parts[1]);
|
||||
auto bottom = parse_css_value(context, parts[2]);
|
||||
auto left = parse_css_value(context, parts[1]);
|
||||
if (top && right && bottom && left) {
|
||||
style.set_property(CSS::PropertyID::BorderTopStyle, *top);
|
||||
style.set_property(CSS::PropertyID::BorderRightStyle, *right);
|
||||
style.set_property(CSS::PropertyID::BorderBottomStyle, *bottom);
|
||||
style.set_property(CSS::PropertyID::BorderLeftStyle, *left);
|
||||
}
|
||||
} else {
|
||||
style.set_property(CSS::PropertyID::BorderTopStyle, value);
|
||||
style.set_property(CSS::PropertyID::BorderRightStyle, value);
|
||||
style.set_property(CSS::PropertyID::BorderBottomStyle, value);
|
||||
style.set_property(CSS::PropertyID::BorderLeftStyle, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::BorderWidth) {
|
||||
auto parts = split_on_whitespace(value.to_string());
|
||||
if (value.is_string() && parts.size() == 2) {
|
||||
auto vertical_border_width = parse_css_value(context, parts[0]);
|
||||
auto horizontal_border_width = parse_css_value(context, parts[1]);
|
||||
if (vertical_border_width && horizontal_border_width) {
|
||||
style.set_property(CSS::PropertyID::BorderTopWidth, *vertical_border_width);
|
||||
style.set_property(CSS::PropertyID::BorderRightWidth, *horizontal_border_width);
|
||||
style.set_property(CSS::PropertyID::BorderBottomWidth, *vertical_border_width);
|
||||
style.set_property(CSS::PropertyID::BorderLeftWidth, *horizontal_border_width);
|
||||
}
|
||||
} else {
|
||||
style.set_property(CSS::PropertyID::BorderTopWidth, value);
|
||||
style.set_property(CSS::PropertyID::BorderRightWidth, value);
|
||||
style.set_property(CSS::PropertyID::BorderBottomWidth, value);
|
||||
style.set_property(CSS::PropertyID::BorderLeftWidth, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::BorderColor) {
|
||||
auto parts = split_on_whitespace(value.to_string());
|
||||
if (value.is_string() && parts.size() == 4) {
|
||||
auto top = parse_css_value(context, parts[0]);
|
||||
auto right = parse_css_value(context, parts[1]);
|
||||
auto bottom = parse_css_value(context, parts[2]);
|
||||
auto left = parse_css_value(context, parts[3]);
|
||||
if (top && right && bottom && left) {
|
||||
style.set_property(CSS::PropertyID::BorderTopColor, *top);
|
||||
style.set_property(CSS::PropertyID::BorderRightColor, *right);
|
||||
style.set_property(CSS::PropertyID::BorderBottomColor, *bottom);
|
||||
style.set_property(CSS::PropertyID::BorderLeftColor, *left);
|
||||
}
|
||||
} else {
|
||||
style.set_property(CSS::PropertyID::BorderTopColor, value);
|
||||
style.set_property(CSS::PropertyID::BorderRightColor, value);
|
||||
style.set_property(CSS::PropertyID::BorderBottomColor, value);
|
||||
style.set_property(CSS::PropertyID::BorderLeftColor, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::Background) {
|
||||
if (value.is_identifier() && static_cast<const IdentifierStyleValue&>(value).id() == CSS::ValueID::None) {
|
||||
style.set_property(CSS::PropertyID::BackgroundColor, ColorStyleValue::create(Color::Transparent));
|
||||
return;
|
||||
}
|
||||
auto parts = split_on_whitespace(value.to_string());
|
||||
NonnullRefPtrVector<StyleValue> values;
|
||||
for (auto& part : parts) {
|
||||
auto value = parse_css_value(context, part);
|
||||
if (!value)
|
||||
return;
|
||||
values.append(value.release_nonnull());
|
||||
}
|
||||
|
||||
// HACK: Disallow more than one color value in a 'background' shorthand
|
||||
size_t color_value_count = 0;
|
||||
for (auto& value : values)
|
||||
color_value_count += value.is_color();
|
||||
|
||||
if (values[0].is_color() && color_value_count == 1)
|
||||
style.set_property(CSS::PropertyID::BackgroundColor, values[0]);
|
||||
|
||||
for (auto& value : values) {
|
||||
if (!value.is_string())
|
||||
continue;
|
||||
auto string = value.to_string();
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundImage, value, document);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::BackgroundImage) {
|
||||
if (!value.is_string())
|
||||
return;
|
||||
auto string = value.to_string();
|
||||
if (!string.starts_with("url("))
|
||||
return;
|
||||
if (!string.ends_with(')'))
|
||||
return;
|
||||
auto url = string.substring_view(4, string.length() - 5);
|
||||
if (url.length() >= 2 && url.starts_with('"') && url.ends_with('"'))
|
||||
url = url.substring_view(1, url.length() - 2);
|
||||
else if (url.length() >= 2 && url.starts_with('\'') && url.ends_with('\''))
|
||||
url = url.substring_view(1, url.length() - 2);
|
||||
|
||||
auto background_image_value = ImageStyleValue::create(document.complete_url(url), document);
|
||||
style.set_property(CSS::PropertyID::BackgroundImage, move(background_image_value));
|
||||
return;
|
||||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::Margin) {
|
||||
if (value.is_length()) {
|
||||
style.set_property(CSS::PropertyID::MarginTop, value);
|
||||
style.set_property(CSS::PropertyID::MarginRight, value);
|
||||
style.set_property(CSS::PropertyID::MarginBottom, value);
|
||||
style.set_property(CSS::PropertyID::MarginLeft, value);
|
||||
return;
|
||||
}
|
||||
if (value.is_string()) {
|
||||
auto parts = split_on_whitespace(value.to_string());
|
||||
if (value.is_string() && parts.size() == 2) {
|
||||
auto vertical = parse_css_value(context, parts[0]);
|
||||
auto horizontal = parse_css_value(context, parts[1]);
|
||||
if (vertical && horizontal) {
|
||||
style.set_property(CSS::PropertyID::MarginTop, *vertical);
|
||||
style.set_property(CSS::PropertyID::MarginBottom, *vertical);
|
||||
style.set_property(CSS::PropertyID::MarginLeft, *horizontal);
|
||||
style.set_property(CSS::PropertyID::MarginRight, *horizontal);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (value.is_string() && parts.size() == 3) {
|
||||
auto top = parse_css_value(context, parts[0]);
|
||||
auto horizontal = parse_css_value(context, parts[1]);
|
||||
auto bottom = parse_css_value(context, parts[2]);
|
||||
if (top && horizontal && bottom) {
|
||||
style.set_property(CSS::PropertyID::MarginTop, *top);
|
||||
style.set_property(CSS::PropertyID::MarginBottom, *bottom);
|
||||
style.set_property(CSS::PropertyID::MarginLeft, *horizontal);
|
||||
style.set_property(CSS::PropertyID::MarginRight, *horizontal);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (value.is_string() && parts.size() == 4) {
|
||||
auto top = parse_css_value(context, parts[0]);
|
||||
auto right = parse_css_value(context, parts[1]);
|
||||
auto bottom = parse_css_value(context, parts[2]);
|
||||
auto left = parse_css_value(context, parts[3]);
|
||||
if (top && right && bottom && left) {
|
||||
style.set_property(CSS::PropertyID::MarginTop, *top);
|
||||
style.set_property(CSS::PropertyID::MarginBottom, *bottom);
|
||||
style.set_property(CSS::PropertyID::MarginLeft, *left);
|
||||
style.set_property(CSS::PropertyID::MarginRight, *right);
|
||||
}
|
||||
return;
|
||||
}
|
||||
dbg() << "Unsure what to do with CSS margin value '" << value.to_string() << "'";
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::Padding) {
|
||||
if (value.is_length()) {
|
||||
style.set_property(CSS::PropertyID::PaddingTop, value);
|
||||
style.set_property(CSS::PropertyID::PaddingRight, value);
|
||||
style.set_property(CSS::PropertyID::PaddingBottom, value);
|
||||
style.set_property(CSS::PropertyID::PaddingLeft, value);
|
||||
return;
|
||||
}
|
||||
if (value.is_string()) {
|
||||
auto parts = split_on_whitespace(value.to_string());
|
||||
if (value.is_string() && parts.size() == 2) {
|
||||
auto vertical = parse_css_value(context, parts[0]);
|
||||
auto horizontal = parse_css_value(context, parts[1]);
|
||||
if (vertical && horizontal) {
|
||||
style.set_property(CSS::PropertyID::PaddingTop, *vertical);
|
||||
style.set_property(CSS::PropertyID::PaddingBottom, *vertical);
|
||||
style.set_property(CSS::PropertyID::PaddingLeft, *horizontal);
|
||||
style.set_property(CSS::PropertyID::PaddingRight, *horizontal);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (value.is_string() && parts.size() == 3) {
|
||||
auto top = parse_css_value(context, parts[0]);
|
||||
auto horizontal = parse_css_value(context, parts[1]);
|
||||
auto bottom = parse_css_value(context, parts[2]);
|
||||
if (top && bottom && horizontal) {
|
||||
style.set_property(CSS::PropertyID::PaddingTop, *top);
|
||||
style.set_property(CSS::PropertyID::PaddingBottom, *bottom);
|
||||
style.set_property(CSS::PropertyID::PaddingLeft, *horizontal);
|
||||
style.set_property(CSS::PropertyID::PaddingRight, *horizontal);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (value.is_string() && parts.size() == 4) {
|
||||
auto top = parse_css_value(context, parts[0]);
|
||||
auto right = parse_css_value(context, parts[1]);
|
||||
auto bottom = parse_css_value(context, parts[2]);
|
||||
auto left = parse_css_value(context, parts[3]);
|
||||
if (top && bottom && left && right) {
|
||||
style.set_property(CSS::PropertyID::PaddingTop, *top);
|
||||
style.set_property(CSS::PropertyID::PaddingBottom, *bottom);
|
||||
style.set_property(CSS::PropertyID::PaddingLeft, *left);
|
||||
style.set_property(CSS::PropertyID::PaddingRight, *right);
|
||||
}
|
||||
return;
|
||||
}
|
||||
dbg() << "Unsure what to do with CSS padding value '" << value.to_string() << "'";
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::ListStyle) {
|
||||
auto parts = split_on_whitespace(value.to_string());
|
||||
if (!parts.is_empty()) {
|
||||
auto value = parse_css_value(context, parts[0]);
|
||||
if (!value)
|
||||
return;
|
||||
style.set_property(CSS::PropertyID::ListStyleType, value.release_nonnull());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
style.set_property(property_id, value);
|
||||
}
|
||||
|
||||
NonnullRefPtr<StyleProperties> StyleResolver::resolve_style(const DOM::Element& element) const
|
||||
{
|
||||
auto style = StyleProperties::create();
|
||||
|
||||
if (auto* parent_style = element.parent_element() ? element.parent_element()->specified_css_values() : nullptr) {
|
||||
parent_style->for_each_property([&](auto property_id, auto& value) {
|
||||
if (is_inherited_property(property_id))
|
||||
set_property_expanding_shorthands(style, property_id, value, m_document);
|
||||
});
|
||||
}
|
||||
|
||||
element.apply_presentational_hints(*style);
|
||||
|
||||
auto matching_rules = collect_matching_rules(element);
|
||||
sort_matching_rules(matching_rules);
|
||||
|
||||
for (auto& match : matching_rules) {
|
||||
for (auto& property : match.rule->declaration().properties()) {
|
||||
set_property_expanding_shorthands(style, property.property_id, property.value, m_document);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto* inline_style = element.inline_style()) {
|
||||
for (auto& property : inline_style->properties()) {
|
||||
set_property_expanding_shorthands(style, property.property_id, property.value, m_document);
|
||||
}
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
}
|
||||
65
Userland/Libraries/LibWeb/CSS/StyleResolver.h
Normal file
65
Userland/Libraries/LibWeb/CSS/StyleResolver.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtrVector.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <LibWeb/CSS/StyleProperties.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
struct MatchingRule {
|
||||
RefPtr<StyleRule> rule;
|
||||
size_t style_sheet_index { 0 };
|
||||
size_t rule_index { 0 };
|
||||
size_t selector_index { 0 };
|
||||
};
|
||||
|
||||
class StyleResolver {
|
||||
public:
|
||||
explicit StyleResolver(DOM::Document&);
|
||||
~StyleResolver();
|
||||
|
||||
DOM::Document& document() { return m_document; }
|
||||
const DOM::Document& document() const { return m_document; }
|
||||
|
||||
NonnullRefPtr<StyleProperties> resolve_style(const DOM::Element&) const;
|
||||
|
||||
Vector<MatchingRule> collect_matching_rules(const DOM::Element&) const;
|
||||
void sort_matching_rules(Vector<MatchingRule>&) const;
|
||||
|
||||
static bool is_inherited_property(CSS::PropertyID);
|
||||
|
||||
private:
|
||||
template<typename Callback>
|
||||
void for_each_stylesheet(Callback) const;
|
||||
|
||||
DOM::Document& m_document;
|
||||
};
|
||||
|
||||
}
|
||||
41
Userland/Libraries/LibWeb/CSS/StyleRule.cpp
Normal file
41
Userland/Libraries/LibWeb/CSS/StyleRule.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/CSS/StyleRule.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
StyleRule::StyleRule(Vector<Selector>&& selectors, NonnullRefPtr<StyleDeclaration>&& declaration)
|
||||
: m_selectors(move(selectors))
|
||||
, m_declaration(move(declaration))
|
||||
{
|
||||
}
|
||||
|
||||
StyleRule::~StyleRule()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
57
Userland/Libraries/LibWeb/CSS/StyleRule.h
Normal file
57
Userland/Libraries/LibWeb/CSS/StyleRule.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtrVector.h>
|
||||
#include <LibWeb/CSS/Selector.h>
|
||||
#include <LibWeb/CSS/StyleDeclaration.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class StyleRule : public RefCounted<StyleRule> {
|
||||
AK_MAKE_NONCOPYABLE(StyleRule);
|
||||
AK_MAKE_NONMOVABLE(StyleRule);
|
||||
|
||||
public:
|
||||
static NonnullRefPtr<StyleRule> create(Vector<Selector>&& selectors, NonnullRefPtr<StyleDeclaration>&& declaration)
|
||||
{
|
||||
return adopt(*new StyleRule(move(selectors), move(declaration)));
|
||||
}
|
||||
|
||||
~StyleRule();
|
||||
|
||||
const Vector<Selector>& selectors() const { return m_selectors; }
|
||||
const StyleDeclaration& declaration() const { return m_declaration; }
|
||||
|
||||
private:
|
||||
StyleRule(Vector<Selector>&&, NonnullRefPtr<StyleDeclaration>&&);
|
||||
|
||||
Vector<Selector> m_selectors;
|
||||
NonnullRefPtr<StyleDeclaration> m_declaration;
|
||||
};
|
||||
|
||||
}
|
||||
40
Userland/Libraries/LibWeb/CSS/StyleSheet.cpp
Normal file
40
Userland/Libraries/LibWeb/CSS/StyleSheet.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/CSS/StyleSheet.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
StyleSheet::StyleSheet(NonnullRefPtrVector<StyleRule>&& rules)
|
||||
: m_rules(move(rules))
|
||||
{
|
||||
}
|
||||
|
||||
StyleSheet::~StyleSheet()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
52
Userland/Libraries/LibWeb/CSS/StyleSheet.h
Normal file
52
Userland/Libraries/LibWeb/CSS/StyleSheet.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtrVector.h>
|
||||
#include <LibWeb/CSS/StyleRule.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class StyleSheet : public RefCounted<StyleSheet> {
|
||||
public:
|
||||
static NonnullRefPtr<StyleSheet> create(NonnullRefPtrVector<StyleRule>&& rules)
|
||||
{
|
||||
return adopt(*new StyleSheet(move(rules)));
|
||||
}
|
||||
|
||||
~StyleSheet();
|
||||
|
||||
const NonnullRefPtrVector<StyleRule>& rules() const { return m_rules; }
|
||||
NonnullRefPtrVector<StyleRule>& rules() { return m_rules; }
|
||||
|
||||
private:
|
||||
explicit StyleSheet(NonnullRefPtrVector<StyleRule>&&);
|
||||
|
||||
NonnullRefPtrVector<StyleRule> m_rules;
|
||||
};
|
||||
|
||||
}
|
||||
41
Userland/Libraries/LibWeb/CSS/StyleSheetList.cpp
Normal file
41
Userland/Libraries/LibWeb/CSS/StyleSheetList.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/CSS/StyleSheetList.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
void StyleSheetList::add_sheet(NonnullRefPtr<StyleSheet> sheet)
|
||||
{
|
||||
m_sheets.append(move(sheet));
|
||||
}
|
||||
|
||||
StyleSheetList::StyleSheetList(DOM::Document& document)
|
||||
: m_document(document)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
52
Userland/Libraries/LibWeb/CSS/StyleSheetList.h
Normal file
52
Userland/Libraries/LibWeb/CSS/StyleSheetList.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/RefCounted.h>
|
||||
#include <LibWeb/CSS/StyleSheet.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class StyleSheetList : public RefCounted<StyleSheetList> {
|
||||
public:
|
||||
static NonnullRefPtr<StyleSheetList> create(DOM::Document& document)
|
||||
{
|
||||
return adopt(*new StyleSheetList(document));
|
||||
}
|
||||
|
||||
void add_sheet(NonnullRefPtr<StyleSheet>);
|
||||
|
||||
const NonnullRefPtrVector<StyleSheet>& sheets() const { return m_sheets; }
|
||||
|
||||
private:
|
||||
explicit StyleSheetList(DOM::Document&);
|
||||
|
||||
DOM::Document& m_document;
|
||||
NonnullRefPtrVector<StyleSheet> m_sheets;
|
||||
};
|
||||
|
||||
}
|
||||
194
Userland/Libraries/LibWeb/CSS/StyleValue.cpp
Normal file
194
Userland/Libraries/LibWeb/CSS/StyleValue.cpp
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/ByteBuffer.h>
|
||||
#include <LibGfx/PNGLoader.h>
|
||||
#include <LibGfx/Palette.h>
|
||||
#include <LibWeb/CSS/StyleValue.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/InProcessWebView.h>
|
||||
#include <LibWeb/Loader/LoadRequest.h>
|
||||
#include <LibWeb/Loader/ResourceLoader.h>
|
||||
#include <LibWeb/Page/Frame.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
StyleValue::StyleValue(Type type)
|
||||
: m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
StyleValue::~StyleValue()
|
||||
{
|
||||
}
|
||||
|
||||
String IdentifierStyleValue::to_string() const
|
||||
{
|
||||
return CSS::string_from_value_id(m_id);
|
||||
}
|
||||
|
||||
Color IdentifierStyleValue::to_color(const DOM::Document& document) const
|
||||
{
|
||||
if (id() == CSS::ValueID::LibwebLink)
|
||||
return document.link_color();
|
||||
|
||||
ASSERT(document.page());
|
||||
auto palette = document.page()->palette();
|
||||
switch (id()) {
|
||||
case CSS::ValueID::LibwebPaletteDesktopBackground:
|
||||
return palette.color(ColorRole::DesktopBackground);
|
||||
case CSS::ValueID::LibwebPaletteActiveWindowBorder1:
|
||||
return palette.color(ColorRole::ActiveWindowBorder1);
|
||||
case CSS::ValueID::LibwebPaletteActiveWindowBorder2:
|
||||
return palette.color(ColorRole::ActiveWindowBorder2);
|
||||
case CSS::ValueID::LibwebPaletteActiveWindowTitle:
|
||||
return palette.color(ColorRole::ActiveWindowTitle);
|
||||
case CSS::ValueID::LibwebPaletteInactiveWindowBorder1:
|
||||
return palette.color(ColorRole::InactiveWindowBorder1);
|
||||
case CSS::ValueID::LibwebPaletteInactiveWindowBorder2:
|
||||
return palette.color(ColorRole::InactiveWindowBorder2);
|
||||
case CSS::ValueID::LibwebPaletteInactiveWindowTitle:
|
||||
return palette.color(ColorRole::InactiveWindowTitle);
|
||||
case CSS::ValueID::LibwebPaletteMovingWindowBorder1:
|
||||
return palette.color(ColorRole::MovingWindowBorder1);
|
||||
case CSS::ValueID::LibwebPaletteMovingWindowBorder2:
|
||||
return palette.color(ColorRole::MovingWindowBorder2);
|
||||
case CSS::ValueID::LibwebPaletteMovingWindowTitle:
|
||||
return palette.color(ColorRole::MovingWindowTitle);
|
||||
case CSS::ValueID::LibwebPaletteHighlightWindowBorder1:
|
||||
return palette.color(ColorRole::HighlightWindowBorder1);
|
||||
case CSS::ValueID::LibwebPaletteHighlightWindowBorder2:
|
||||
return palette.color(ColorRole::HighlightWindowBorder2);
|
||||
case CSS::ValueID::LibwebPaletteHighlightWindowTitle:
|
||||
return palette.color(ColorRole::HighlightWindowTitle);
|
||||
case CSS::ValueID::LibwebPaletteMenuStripe:
|
||||
return palette.color(ColorRole::MenuStripe);
|
||||
case CSS::ValueID::LibwebPaletteMenuBase:
|
||||
return palette.color(ColorRole::MenuBase);
|
||||
case CSS::ValueID::LibwebPaletteMenuBaseText:
|
||||
return palette.color(ColorRole::MenuBaseText);
|
||||
case CSS::ValueID::LibwebPaletteMenuSelection:
|
||||
return palette.color(ColorRole::MenuSelection);
|
||||
case CSS::ValueID::LibwebPaletteMenuSelectionText:
|
||||
return palette.color(ColorRole::MenuSelectionText);
|
||||
case CSS::ValueID::LibwebPaletteWindow:
|
||||
return palette.color(ColorRole::Window);
|
||||
case CSS::ValueID::LibwebPaletteWindowText:
|
||||
return palette.color(ColorRole::WindowText);
|
||||
case CSS::ValueID::LibwebPaletteButton:
|
||||
return palette.color(ColorRole::Button);
|
||||
case CSS::ValueID::LibwebPaletteButtonText:
|
||||
return palette.color(ColorRole::ButtonText);
|
||||
case CSS::ValueID::LibwebPaletteBase:
|
||||
return palette.color(ColorRole::Base);
|
||||
case CSS::ValueID::LibwebPaletteBaseText:
|
||||
return palette.color(ColorRole::BaseText);
|
||||
case CSS::ValueID::LibwebPaletteThreedHighlight:
|
||||
return palette.color(ColorRole::ThreedHighlight);
|
||||
case CSS::ValueID::LibwebPaletteThreedShadow1:
|
||||
return palette.color(ColorRole::ThreedShadow1);
|
||||
case CSS::ValueID::LibwebPaletteThreedShadow2:
|
||||
return palette.color(ColorRole::ThreedShadow2);
|
||||
case CSS::ValueID::LibwebPaletteHoverHighlight:
|
||||
return palette.color(ColorRole::HoverHighlight);
|
||||
case CSS::ValueID::LibwebPaletteSelection:
|
||||
return palette.color(ColorRole::Selection);
|
||||
case CSS::ValueID::LibwebPaletteSelectionText:
|
||||
return palette.color(ColorRole::SelectionText);
|
||||
case CSS::ValueID::LibwebPaletteInactiveSelection:
|
||||
return palette.color(ColorRole::InactiveSelection);
|
||||
case CSS::ValueID::LibwebPaletteInactiveSelectionText:
|
||||
return palette.color(ColorRole::InactiveSelectionText);
|
||||
case CSS::ValueID::LibwebPaletteRubberBandFill:
|
||||
return palette.color(ColorRole::RubberBandFill);
|
||||
case CSS::ValueID::LibwebPaletteRubberBandBorder:
|
||||
return palette.color(ColorRole::RubberBandBorder);
|
||||
case CSS::ValueID::LibwebPaletteLink:
|
||||
return palette.color(ColorRole::Link);
|
||||
case CSS::ValueID::LibwebPaletteActiveLink:
|
||||
return palette.color(ColorRole::ActiveLink);
|
||||
case CSS::ValueID::LibwebPaletteVisitedLink:
|
||||
return palette.color(ColorRole::VisitedLink);
|
||||
case CSS::ValueID::LibwebPaletteRuler:
|
||||
return palette.color(ColorRole::Ruler);
|
||||
case CSS::ValueID::LibwebPaletteRulerBorder:
|
||||
return palette.color(ColorRole::RulerBorder);
|
||||
case CSS::ValueID::LibwebPaletteRulerActiveText:
|
||||
return palette.color(ColorRole::RulerActiveText);
|
||||
case CSS::ValueID::LibwebPaletteRulerInactiveText:
|
||||
return palette.color(ColorRole::RulerInactiveText);
|
||||
case CSS::ValueID::LibwebPaletteTextCursor:
|
||||
return palette.color(ColorRole::TextCursor);
|
||||
case CSS::ValueID::LibwebPaletteFocusOutline:
|
||||
return palette.color(ColorRole::FocusOutline);
|
||||
case CSS::ValueID::LibwebPaletteSyntaxComment:
|
||||
return palette.color(ColorRole::SyntaxComment);
|
||||
case CSS::ValueID::LibwebPaletteSyntaxNumber:
|
||||
return palette.color(ColorRole::SyntaxNumber);
|
||||
case CSS::ValueID::LibwebPaletteSyntaxString:
|
||||
return palette.color(ColorRole::SyntaxString);
|
||||
case CSS::ValueID::LibwebPaletteSyntaxType:
|
||||
return palette.color(ColorRole::SyntaxType);
|
||||
case CSS::ValueID::LibwebPaletteSyntaxPunctuation:
|
||||
return palette.color(ColorRole::SyntaxPunctuation);
|
||||
case CSS::ValueID::LibwebPaletteSyntaxOperator:
|
||||
return palette.color(ColorRole::SyntaxOperator);
|
||||
case CSS::ValueID::LibwebPaletteSyntaxKeyword:
|
||||
return palette.color(ColorRole::SyntaxKeyword);
|
||||
case CSS::ValueID::LibwebPaletteSyntaxControlKeyword:
|
||||
return palette.color(ColorRole::SyntaxControlKeyword);
|
||||
case CSS::ValueID::LibwebPaletteSyntaxIdentifier:
|
||||
return palette.color(ColorRole::SyntaxIdentifier);
|
||||
case CSS::ValueID::LibwebPaletteSyntaxPreprocessorStatement:
|
||||
return palette.color(ColorRole::SyntaxPreprocessorStatement);
|
||||
case CSS::ValueID::LibwebPaletteSyntaxPreprocessorValue:
|
||||
return palette.color(ColorRole::SyntaxPreprocessorValue);
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
ImageStyleValue::ImageStyleValue(const URL& url, DOM::Document& document)
|
||||
: StyleValue(Type::Image)
|
||||
, m_url(url)
|
||||
, m_document(document)
|
||||
{
|
||||
LoadRequest request;
|
||||
request.set_url(url);
|
||||
set_resource(ResourceLoader::the().load_resource(Resource::Type::Image, request));
|
||||
}
|
||||
|
||||
void ImageStyleValue::resource_did_load()
|
||||
{
|
||||
if (!m_document)
|
||||
return;
|
||||
m_bitmap = resource()->bitmap();
|
||||
// FIXME: Do less than a full repaint if possible?
|
||||
if (m_document->frame())
|
||||
m_document->frame()->set_needs_display({});
|
||||
}
|
||||
|
||||
}
|
||||
357
Userland/Libraries/LibWeb/CSS/StyleValue.h
Normal file
357
Userland/Libraries/LibWeb/CSS/StyleValue.h
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/URL.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/Color.h>
|
||||
#include <LibWeb/CSS/Length.h>
|
||||
#include <LibWeb/CSS/PropertyID.h>
|
||||
#include <LibWeb/CSS/ValueID.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/Loader/ImageResource.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
enum class Position {
|
||||
Static,
|
||||
Relative,
|
||||
Absolute,
|
||||
Fixed,
|
||||
Sticky,
|
||||
};
|
||||
|
||||
enum class TextAlign {
|
||||
Left,
|
||||
Center,
|
||||
Right,
|
||||
Justify,
|
||||
LibwebCenter,
|
||||
};
|
||||
|
||||
enum class TextDecorationLine {
|
||||
None,
|
||||
Underline,
|
||||
Overline,
|
||||
LineThrough,
|
||||
Blink,
|
||||
};
|
||||
|
||||
enum class TextTransform {
|
||||
None,
|
||||
Capitalize,
|
||||
Uppercase,
|
||||
Lowercase,
|
||||
FullWidth,
|
||||
FullSizeKana,
|
||||
};
|
||||
|
||||
enum class Display {
|
||||
None,
|
||||
Block,
|
||||
Inline,
|
||||
InlineBlock,
|
||||
ListItem,
|
||||
Table,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableHeaderGroup,
|
||||
TableRowGroup,
|
||||
TableFooterGroup,
|
||||
TableColumn,
|
||||
TableColumnGroup,
|
||||
TableCaption,
|
||||
};
|
||||
|
||||
enum class WhiteSpace {
|
||||
Normal,
|
||||
Pre,
|
||||
Nowrap,
|
||||
PreLine,
|
||||
PreWrap,
|
||||
};
|
||||
|
||||
enum class Float {
|
||||
None,
|
||||
Left,
|
||||
Right,
|
||||
};
|
||||
|
||||
enum class Clear {
|
||||
None,
|
||||
Left,
|
||||
Right,
|
||||
Both,
|
||||
};
|
||||
|
||||
enum class LineStyle {
|
||||
None,
|
||||
Hidden,
|
||||
Dotted,
|
||||
Dashed,
|
||||
Solid,
|
||||
Double,
|
||||
Groove,
|
||||
Ridge,
|
||||
Inset,
|
||||
Outset,
|
||||
};
|
||||
|
||||
enum class ListStyleType {
|
||||
None,
|
||||
Disc,
|
||||
Circle,
|
||||
Square,
|
||||
Decimal,
|
||||
};
|
||||
|
||||
class StyleValue : public RefCounted<StyleValue> {
|
||||
public:
|
||||
virtual ~StyleValue();
|
||||
|
||||
enum class Type {
|
||||
Invalid,
|
||||
Inherit,
|
||||
Initial,
|
||||
String,
|
||||
Length,
|
||||
Color,
|
||||
Identifier,
|
||||
Image,
|
||||
Position,
|
||||
};
|
||||
|
||||
Type type() const { return m_type; }
|
||||
|
||||
bool is_inherit() const { return type() == Type::Inherit; }
|
||||
bool is_initial() const { return type() == Type::Initial; }
|
||||
bool is_color() const { return type() == Type::Color; }
|
||||
bool is_identifier() const { return type() == Type::Identifier; }
|
||||
bool is_image() const { return type() == Type::Image; }
|
||||
bool is_string() const { return type() == Type::String; }
|
||||
bool is_length() const { return type() == Type::Length; }
|
||||
bool is_position() const { return type() == Type::Position; }
|
||||
|
||||
virtual String to_string() const = 0;
|
||||
virtual Length to_length() const { return Length::make_auto(); }
|
||||
virtual Color to_color(const DOM::Document&) const { return {}; }
|
||||
|
||||
CSS::ValueID to_identifier() const;
|
||||
|
||||
virtual bool is_auto() const { return false; }
|
||||
|
||||
bool operator==(const StyleValue& other) const { return equals(other); }
|
||||
bool operator!=(const StyleValue& other) const { return !(*this == other); }
|
||||
|
||||
virtual bool equals(const StyleValue& other) const
|
||||
{
|
||||
if (type() != other.type())
|
||||
return false;
|
||||
return to_string() == other.to_string();
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit StyleValue(Type);
|
||||
|
||||
private:
|
||||
Type m_type { Type::Invalid };
|
||||
};
|
||||
|
||||
class StringStyleValue : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<StringStyleValue> create(const String& string)
|
||||
{
|
||||
return adopt(*new StringStyleValue(string));
|
||||
}
|
||||
virtual ~StringStyleValue() override { }
|
||||
|
||||
String to_string() const override { return m_string; }
|
||||
|
||||
private:
|
||||
explicit StringStyleValue(const String& string)
|
||||
: StyleValue(Type::String)
|
||||
, m_string(string)
|
||||
{
|
||||
}
|
||||
|
||||
String m_string;
|
||||
};
|
||||
|
||||
class LengthStyleValue : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<LengthStyleValue> create(const Length& length)
|
||||
{
|
||||
return adopt(*new LengthStyleValue(length));
|
||||
}
|
||||
virtual ~LengthStyleValue() override { }
|
||||
|
||||
virtual String to_string() const override { return m_length.to_string(); }
|
||||
virtual Length to_length() const override { return m_length; }
|
||||
|
||||
const Length& length() const { return m_length; }
|
||||
|
||||
virtual bool is_auto() const override { return m_length.is_auto(); }
|
||||
|
||||
virtual bool equals(const StyleValue& other) const override
|
||||
{
|
||||
if (type() != other.type())
|
||||
return false;
|
||||
return m_length == static_cast<const LengthStyleValue&>(other).m_length;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit LengthStyleValue(const Length& length)
|
||||
: StyleValue(Type::Length)
|
||||
, m_length(length)
|
||||
{
|
||||
}
|
||||
|
||||
Length m_length;
|
||||
};
|
||||
|
||||
class InitialStyleValue final : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<InitialStyleValue> create() { return adopt(*new InitialStyleValue); }
|
||||
virtual ~InitialStyleValue() override { }
|
||||
|
||||
String to_string() const override { return "initial"; }
|
||||
|
||||
private:
|
||||
InitialStyleValue()
|
||||
: StyleValue(Type::Initial)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class InheritStyleValue final : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<InheritStyleValue> create() { return adopt(*new InheritStyleValue); }
|
||||
virtual ~InheritStyleValue() override { }
|
||||
|
||||
String to_string() const override { return "inherit"; }
|
||||
|
||||
private:
|
||||
InheritStyleValue()
|
||||
: StyleValue(Type::Inherit)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ColorStyleValue : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<ColorStyleValue> create(Color color)
|
||||
{
|
||||
return adopt(*new ColorStyleValue(color));
|
||||
}
|
||||
virtual ~ColorStyleValue() override { }
|
||||
|
||||
Color color() const { return m_color; }
|
||||
String to_string() const override { return m_color.to_string(); }
|
||||
Color to_color(const DOM::Document&) const override { return m_color; }
|
||||
|
||||
virtual bool equals(const StyleValue& other) const override
|
||||
{
|
||||
if (type() != other.type())
|
||||
return false;
|
||||
return m_color == static_cast<const ColorStyleValue&>(other).m_color;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit ColorStyleValue(Color color)
|
||||
: StyleValue(Type::Color)
|
||||
, m_color(color)
|
||||
{
|
||||
}
|
||||
|
||||
Color m_color;
|
||||
};
|
||||
|
||||
class IdentifierStyleValue final : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<IdentifierStyleValue> create(CSS::ValueID id)
|
||||
{
|
||||
return adopt(*new IdentifierStyleValue(id));
|
||||
}
|
||||
virtual ~IdentifierStyleValue() override { }
|
||||
|
||||
CSS::ValueID id() const { return m_id; }
|
||||
|
||||
virtual String to_string() const override;
|
||||
virtual Color to_color(const DOM::Document&) const override;
|
||||
|
||||
virtual bool equals(const StyleValue& other) const override
|
||||
{
|
||||
if (type() != other.type())
|
||||
return false;
|
||||
return m_id == static_cast<const IdentifierStyleValue&>(other).m_id;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit IdentifierStyleValue(CSS::ValueID id)
|
||||
: StyleValue(Type::Identifier)
|
||||
, m_id(id)
|
||||
{
|
||||
}
|
||||
|
||||
CSS::ValueID m_id { CSS::ValueID::Invalid };
|
||||
};
|
||||
|
||||
class ImageStyleValue final
|
||||
: public StyleValue
|
||||
, public ImageResourceClient {
|
||||
public:
|
||||
static NonnullRefPtr<ImageStyleValue> create(const URL& url, DOM::Document& document) { return adopt(*new ImageStyleValue(url, document)); }
|
||||
virtual ~ImageStyleValue() override { }
|
||||
|
||||
String to_string() const override { return String::formatted("Image({})", m_url.to_string()); }
|
||||
|
||||
const Gfx::Bitmap* bitmap() const { return m_bitmap; }
|
||||
|
||||
private:
|
||||
ImageStyleValue(const URL&, DOM::Document&);
|
||||
|
||||
// ^ResourceClient
|
||||
virtual void resource_did_load() override;
|
||||
|
||||
URL m_url;
|
||||
WeakPtr<DOM::Document> m_document;
|
||||
RefPtr<Gfx::Bitmap> m_bitmap;
|
||||
};
|
||||
|
||||
inline CSS::ValueID StyleValue::to_identifier() const
|
||||
{
|
||||
if (is_identifier())
|
||||
return static_cast<const IdentifierStyleValue&>(*this).id();
|
||||
return CSS::ValueID::Invalid;
|
||||
}
|
||||
|
||||
}
|
||||
11
Userland/Libraries/LibWeb/CodeGenerators/CMakeLists.txt
Normal file
11
Userland/Libraries/LibWeb/CodeGenerators/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
add_executable(Generate_CSS_PropertyID_h Generate_CSS_PropertyID_h.cpp)
|
||||
add_executable(Generate_CSS_PropertyID_cpp Generate_CSS_PropertyID_cpp.cpp)
|
||||
add_executable(Generate_CSS_ValueID_h Generate_CSS_ValueID_h.cpp)
|
||||
add_executable(Generate_CSS_ValueID_cpp Generate_CSS_ValueID_cpp.cpp)
|
||||
add_executable(WrapperGenerator WrapperGenerator.cpp)
|
||||
target_compile_options(WrapperGenerator PUBLIC -g)
|
||||
target_link_libraries(Generate_CSS_PropertyID_h LagomCore)
|
||||
target_link_libraries(Generate_CSS_PropertyID_cpp LagomCore)
|
||||
target_link_libraries(Generate_CSS_ValueID_h LagomCore)
|
||||
target_link_libraries(Generate_CSS_ValueID_cpp LagomCore)
|
||||
target_link_libraries(WrapperGenerator LagomCore)
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/ByteBuffer.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <AK/SourceGenerator.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static String title_casify(const String& dashy_name)
|
||||
{
|
||||
auto parts = dashy_name.split('-');
|
||||
StringBuilder builder;
|
||||
for (auto& part : parts) {
|
||||
if (part.is_empty())
|
||||
continue;
|
||||
builder.append(toupper(part[0]));
|
||||
if (part.length() == 1)
|
||||
continue;
|
||||
builder.append(part.substring_view(1, part.length() - 1));
|
||||
}
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
warnln("usage: {} <path/to/CSS/Properties.json>", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
auto file = Core::File::construct(argv[1]);
|
||||
if (!file->open(Core::IODevice::ReadOnly))
|
||||
return 1;
|
||||
|
||||
auto json = JsonValue::from_string(file->read_all());
|
||||
ASSERT(json.has_value());
|
||||
ASSERT(json.value().is_object());
|
||||
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
|
||||
generator.append(R"~~~(
|
||||
#include <AK/Assertions.h>
|
||||
#include <LibWeb/CSS/PropertyID.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
PropertyID property_id_from_string(const StringView& string)
|
||||
{
|
||||
)~~~");
|
||||
|
||||
json.value().as_object().for_each_member([&](auto& name, auto& value) {
|
||||
ASSERT(value.is_object());
|
||||
|
||||
auto member_generator = generator.fork();
|
||||
member_generator.set("name", name);
|
||||
member_generator.set("name:titlecase", title_casify(name));
|
||||
member_generator.append(R"~~~(
|
||||
if (string.equals_ignoring_case("@name@"))
|
||||
return PropertyID::@name:titlecase@;
|
||||
)~~~");
|
||||
});
|
||||
|
||||
generator.append(R"~~~(
|
||||
return PropertyID::Invalid;
|
||||
}
|
||||
|
||||
const char* string_from_property_id(PropertyID property_id) {
|
||||
switch (property_id) {
|
||||
)~~~");
|
||||
|
||||
json.value().as_object().for_each_member([&](auto& name, auto& value) {
|
||||
ASSERT(value.is_object());
|
||||
|
||||
auto member_generator = generator.fork();
|
||||
member_generator.set("name", name);
|
||||
member_generator.set("name:titlecase", title_casify(name));
|
||||
member_generator.append(R"~~~(
|
||||
case PropertyID::@name:titlecase@:
|
||||
return "@name@";
|
||||
)~~~");
|
||||
});
|
||||
|
||||
generator.append(R"~~~(
|
||||
default:
|
||||
return "(invalid CSS::PropertyID)";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Web::CSS
|
||||
)~~~");
|
||||
|
||||
outln("{}", generator.as_string_view());
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/ByteBuffer.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <AK/SourceGenerator.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static String title_casify(const String& dashy_name)
|
||||
{
|
||||
auto parts = dashy_name.split('-');
|
||||
StringBuilder builder;
|
||||
for (auto& part : parts) {
|
||||
if (part.is_empty())
|
||||
continue;
|
||||
builder.append(toupper(part[0]));
|
||||
if (part.length() == 1)
|
||||
continue;
|
||||
builder.append(part.substring_view(1, part.length() - 1));
|
||||
}
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
warnln("usage: {} <path/to/CSS/Properties.json>", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
auto file = Core::File::construct(argv[1]);
|
||||
if (!file->open(Core::IODevice::ReadOnly))
|
||||
return 1;
|
||||
|
||||
auto json = JsonValue::from_string(file->read_all());
|
||||
ASSERT(json.has_value());
|
||||
ASSERT(json.value().is_object());
|
||||
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
generator.append(R"~~~(
|
||||
#pragma once
|
||||
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Traits.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
enum class PropertyID {
|
||||
Invalid,
|
||||
)~~~");
|
||||
|
||||
json.value().as_object().for_each_member([&](auto& name, auto& value) {
|
||||
ASSERT(value.is_object());
|
||||
|
||||
auto member_generator = generator.fork();
|
||||
member_generator.set("name:titlecase", title_casify(name));
|
||||
|
||||
member_generator.append(R"~~~(
|
||||
@name:titlecase@,
|
||||
)~~~");
|
||||
});
|
||||
|
||||
generator.append(R"~~~(
|
||||
};
|
||||
|
||||
PropertyID property_id_from_string(const StringView&);
|
||||
const char* string_from_property_id(PropertyID);
|
||||
|
||||
} // namespace Web::CSS
|
||||
|
||||
namespace AK {
|
||||
template<>
|
||||
struct Traits<Web::CSS::PropertyID> : public GenericTraits<Web::CSS::PropertyID> {
|
||||
static unsigned hash(Web::CSS::PropertyID property_id) { return int_hash((unsigned)property_id); }
|
||||
};
|
||||
} // namespace AK
|
||||
)~~~");
|
||||
|
||||
outln("{}", generator.as_string_view());
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/ByteBuffer.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <AK/SourceGenerator.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static String title_casify(const String& dashy_name)
|
||||
{
|
||||
auto parts = dashy_name.split('-');
|
||||
StringBuilder builder;
|
||||
for (auto& part : parts) {
|
||||
if (part.is_empty())
|
||||
continue;
|
||||
builder.append(toupper(part[0]));
|
||||
if (part.length() == 1)
|
||||
continue;
|
||||
builder.append(part.substring_view(1, part.length() - 1));
|
||||
}
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
warnln("usage: {} <path/to/CSS/Identifiers.json>", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
auto file = Core::File::construct(argv[1]);
|
||||
if (!file->open(Core::IODevice::ReadOnly))
|
||||
return 1;
|
||||
|
||||
auto json = JsonValue::from_string(file->read_all());
|
||||
ASSERT(json.has_value());
|
||||
ASSERT(json.value().is_array());
|
||||
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
|
||||
generator.append(R"~~~(
|
||||
#include <AK/Assertions.h>
|
||||
#include <LibWeb/CSS/ValueID.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
ValueID value_id_from_string(const StringView& string)
|
||||
{
|
||||
)~~~");
|
||||
|
||||
json.value().as_array().for_each([&](auto& name) {
|
||||
auto member_generator = generator.fork();
|
||||
member_generator.set("name", name.to_string());
|
||||
member_generator.set("name:titlecase", title_casify(name.to_string()));
|
||||
member_generator.append(R"~~~(
|
||||
if (string.equals_ignoring_case("@name@"))
|
||||
return ValueID::@name:titlecase@;
|
||||
)~~~");
|
||||
});
|
||||
|
||||
generator.append(R"~~~(
|
||||
return ValueID::Invalid;
|
||||
}
|
||||
|
||||
const char* string_from_value_id(ValueID value_id) {
|
||||
switch (value_id) {
|
||||
)~~~");
|
||||
|
||||
json.value().as_array().for_each([&](auto& name) {
|
||||
auto member_generator = generator.fork();
|
||||
member_generator.set("name", name.to_string());
|
||||
member_generator.set("name:titlecase", title_casify(name.to_string()));
|
||||
member_generator.append(R"~~~(
|
||||
case ValueID::@name:titlecase@:
|
||||
return "@name@";
|
||||
)~~~");
|
||||
});
|
||||
|
||||
generator.append(R"~~~(
|
||||
default:
|
||||
return "(invalid CSS::ValueID)";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Web::CSS
|
||||
)~~~");
|
||||
|
||||
outln("{}", generator.as_string_view());
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/ByteBuffer.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <AK/SourceGenerator.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static String title_casify(const String& dashy_name)
|
||||
{
|
||||
auto parts = dashy_name.split('-');
|
||||
StringBuilder builder;
|
||||
for (auto& part : parts) {
|
||||
if (part.is_empty())
|
||||
continue;
|
||||
builder.append(toupper(part[0]));
|
||||
if (part.length() == 1)
|
||||
continue;
|
||||
builder.append(part.substring_view(1, part.length() - 1));
|
||||
}
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
warnln("usage: {} <path/to/CSS/Identifiers.json>", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
auto file = Core::File::construct(argv[1]);
|
||||
if (!file->open(Core::IODevice::ReadOnly))
|
||||
return 1;
|
||||
|
||||
auto json = JsonValue::from_string(file->read_all());
|
||||
ASSERT(json.has_value());
|
||||
ASSERT(json.value().is_array());
|
||||
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
generator.append(R"~~~(
|
||||
#pragma once
|
||||
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Traits.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
enum class ValueID {
|
||||
Invalid,
|
||||
)~~~");
|
||||
|
||||
json.value().as_array().for_each([&](auto& name) {
|
||||
auto member_generator = generator.fork();
|
||||
member_generator.set("name:titlecase", title_casify(name.to_string()));
|
||||
|
||||
member_generator.append(R"~~~(
|
||||
@name:titlecase@,
|
||||
)~~~");
|
||||
});
|
||||
|
||||
generator.append(R"~~~(
|
||||
};
|
||||
|
||||
ValueID value_id_from_string(const StringView&);
|
||||
const char* string_from_value_id(ValueID);
|
||||
|
||||
}
|
||||
|
||||
)~~~");
|
||||
|
||||
outln("{}", generator.as_string_view());
|
||||
}
|
||||
951
Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp
Normal file
951
Userland/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp
Normal file
|
|
@ -0,0 +1,951 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/ByteBuffer.h>
|
||||
#include <AK/GenericLexer.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <AK/SourceGenerator.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static String snake_name(const StringView& title_name)
|
||||
{
|
||||
StringBuilder builder;
|
||||
bool first = true;
|
||||
bool last_was_uppercase = false;
|
||||
for (auto ch : title_name) {
|
||||
if (isupper(ch)) {
|
||||
if (!first && !last_was_uppercase)
|
||||
builder.append('_');
|
||||
builder.append(tolower(ch));
|
||||
} else {
|
||||
builder.append(ch);
|
||||
}
|
||||
first = false;
|
||||
last_was_uppercase = isupper(ch);
|
||||
}
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
static String make_input_acceptable_cpp(const String& input)
|
||||
{
|
||||
if (input.is_one_of("class", "template", "for", "default", "char")) {
|
||||
StringBuilder builder;
|
||||
builder.append(input);
|
||||
builder.append('_');
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
String input_without_dashes = input;
|
||||
input_without_dashes.replace("-", "_");
|
||||
|
||||
return input_without_dashes;
|
||||
}
|
||||
|
||||
static void report_parsing_error(StringView message, StringView filename, StringView input, size_t offset)
|
||||
{
|
||||
// FIXME: Spaghetti code ahead.
|
||||
|
||||
size_t lineno = 1;
|
||||
size_t colno = 1;
|
||||
size_t start_line = 0;
|
||||
size_t line_length = 0;
|
||||
for (size_t index = 0; index < input.length(); ++index) {
|
||||
if (offset == index)
|
||||
colno = index - start_line + 1;
|
||||
|
||||
if (input[index] == '\n') {
|
||||
if (index >= offset)
|
||||
break;
|
||||
|
||||
start_line = index + 1;
|
||||
line_length = 0;
|
||||
++lineno;
|
||||
} else {
|
||||
++line_length;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder error_message;
|
||||
error_message.appendff("{}\n", input.substring_view(start_line, line_length));
|
||||
for (size_t i = 0; i < colno - 1; ++i)
|
||||
error_message.append(' ');
|
||||
error_message.append("\033[1;31m^\n");
|
||||
error_message.appendff("{}:{}: error: {}\033[0m\n", filename, lineno, message);
|
||||
|
||||
warnln("{}", error_message.string_view());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
namespace IDL {
|
||||
|
||||
struct Type {
|
||||
String name;
|
||||
bool nullable { false };
|
||||
};
|
||||
|
||||
struct Parameter {
|
||||
Type type;
|
||||
String name;
|
||||
bool optional { false };
|
||||
};
|
||||
|
||||
struct Function {
|
||||
Type return_type;
|
||||
String name;
|
||||
Vector<Parameter> parameters;
|
||||
HashMap<String, String> extended_attributes;
|
||||
|
||||
size_t length() const
|
||||
{
|
||||
// FIXME: This seems to produce a length that is way over what it's supposed to be.
|
||||
// For example, getElementsByTagName has its length set to 20 when it should be 1.
|
||||
size_t length = 0;
|
||||
for (auto& parameter : parameters) {
|
||||
if (!parameter.optional)
|
||||
length++;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
};
|
||||
|
||||
struct Attribute {
|
||||
bool readonly { false };
|
||||
bool unsigned_ { false };
|
||||
Type type;
|
||||
String name;
|
||||
HashMap<String, String> extended_attributes;
|
||||
|
||||
// Added for convenience after parsing
|
||||
String getter_callback_name;
|
||||
String setter_callback_name;
|
||||
};
|
||||
|
||||
struct Interface {
|
||||
String name;
|
||||
String parent_name;
|
||||
|
||||
Vector<Attribute> attributes;
|
||||
Vector<Function> functions;
|
||||
|
||||
// Added for convenience after parsing
|
||||
String wrapper_class;
|
||||
String wrapper_base_class;
|
||||
String fully_qualified_name;
|
||||
};
|
||||
|
||||
static OwnPtr<Interface> parse_interface(StringView filename, const StringView& input)
|
||||
{
|
||||
auto interface = make<Interface>();
|
||||
|
||||
GenericLexer lexer(input);
|
||||
|
||||
auto assert_specific = [&](char ch) {
|
||||
if (!lexer.consume_specific(ch))
|
||||
report_parsing_error(String::formatted("expected '{}'", ch), filename, input, lexer.tell());
|
||||
};
|
||||
|
||||
auto consume_whitespace = [&] {
|
||||
bool consumed = true;
|
||||
while (consumed) {
|
||||
consumed = lexer.consume_while([](char ch) { return isspace(ch); }).length() > 0;
|
||||
|
||||
if (lexer.consume_specific("//")) {
|
||||
lexer.consume_until('\n');
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto assert_string = [&](const StringView& expected) {
|
||||
if (!lexer.consume_specific(expected))
|
||||
report_parsing_error(String::formatted("expected '{}'", expected), filename, input, lexer.tell());
|
||||
};
|
||||
|
||||
assert_string("interface");
|
||||
consume_whitespace();
|
||||
interface->name = lexer.consume_until([](auto ch) { return isspace(ch); });
|
||||
consume_whitespace();
|
||||
if (lexer.consume_specific(':')) {
|
||||
consume_whitespace();
|
||||
interface->parent_name = lexer.consume_until([](auto ch) { return isspace(ch); });
|
||||
consume_whitespace();
|
||||
}
|
||||
assert_specific('{');
|
||||
|
||||
auto parse_type = [&] {
|
||||
auto name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == '?'; });
|
||||
auto nullable = lexer.consume_specific('?');
|
||||
return Type { name, nullable };
|
||||
};
|
||||
|
||||
auto parse_attribute = [&](HashMap<String, String>& extended_attributes) {
|
||||
bool readonly = lexer.consume_specific("readonly");
|
||||
if (readonly)
|
||||
consume_whitespace();
|
||||
|
||||
if (lexer.consume_specific("attribute"))
|
||||
consume_whitespace();
|
||||
|
||||
bool unsigned_ = lexer.consume_specific("unsigned");
|
||||
if (unsigned_)
|
||||
consume_whitespace();
|
||||
|
||||
auto type = parse_type();
|
||||
consume_whitespace();
|
||||
auto name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ';'; });
|
||||
consume_whitespace();
|
||||
assert_specific(';');
|
||||
Attribute attribute;
|
||||
attribute.readonly = readonly;
|
||||
attribute.unsigned_ = unsigned_;
|
||||
attribute.type = type;
|
||||
attribute.name = name;
|
||||
attribute.getter_callback_name = String::formatted("{}_getter", snake_name(attribute.name));
|
||||
attribute.setter_callback_name = String::formatted("{}_setter", snake_name(attribute.name));
|
||||
attribute.extended_attributes = move(extended_attributes);
|
||||
interface->attributes.append(move(attribute));
|
||||
};
|
||||
|
||||
auto parse_function = [&](HashMap<String, String>& extended_attributes) {
|
||||
auto return_type = parse_type();
|
||||
consume_whitespace();
|
||||
auto name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == '('; });
|
||||
consume_whitespace();
|
||||
assert_specific('(');
|
||||
|
||||
Vector<Parameter> parameters;
|
||||
|
||||
for (;;) {
|
||||
if (lexer.consume_specific(')'))
|
||||
break;
|
||||
bool optional = lexer.consume_specific("optional");
|
||||
if (optional)
|
||||
consume_whitespace();
|
||||
auto type = parse_type();
|
||||
consume_whitespace();
|
||||
auto name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ',' || ch == ')'; });
|
||||
parameters.append({ move(type), move(name), optional });
|
||||
if (lexer.consume_specific(')'))
|
||||
break;
|
||||
assert_specific(',');
|
||||
consume_whitespace();
|
||||
}
|
||||
|
||||
consume_whitespace();
|
||||
assert_specific(';');
|
||||
|
||||
interface->functions.append(Function { return_type, name, move(parameters), move(extended_attributes) });
|
||||
};
|
||||
|
||||
auto parse_extended_attributes = [&] {
|
||||
HashMap<String, String> extended_attributes;
|
||||
for (;;) {
|
||||
consume_whitespace();
|
||||
if (lexer.consume_specific(']'))
|
||||
break;
|
||||
auto name = lexer.consume_until([](auto ch) { return ch == ']' || ch == '=' || ch == ','; });
|
||||
if (lexer.consume_specific('=')) {
|
||||
auto value = lexer.consume_until([](auto ch) { return ch == ']' || ch == ','; });
|
||||
extended_attributes.set(name, value);
|
||||
} else {
|
||||
extended_attributes.set(name, {});
|
||||
}
|
||||
lexer.consume_specific(',');
|
||||
}
|
||||
consume_whitespace();
|
||||
return extended_attributes;
|
||||
};
|
||||
|
||||
for (;;) {
|
||||
HashMap<String, String> extended_attributes;
|
||||
|
||||
consume_whitespace();
|
||||
|
||||
if (lexer.consume_specific('}')) {
|
||||
consume_whitespace();
|
||||
assert_specific(';');
|
||||
break;
|
||||
}
|
||||
|
||||
if (lexer.consume_specific('[')) {
|
||||
extended_attributes = parse_extended_attributes();
|
||||
}
|
||||
|
||||
if (lexer.next_is("readonly") || lexer.next_is("attribute")) {
|
||||
parse_attribute(extended_attributes);
|
||||
continue;
|
||||
}
|
||||
|
||||
parse_function(extended_attributes);
|
||||
}
|
||||
|
||||
interface->wrapper_class = String::formatted("{}Wrapper", interface->name);
|
||||
interface->wrapper_base_class = String::formatted("{}Wrapper", interface->parent_name.is_empty() ? String::empty() : interface->parent_name);
|
||||
|
||||
return interface;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void generate_header(const IDL::Interface&);
|
||||
static void generate_implementation(const IDL::Interface&);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Core::ArgsParser args_parser;
|
||||
const char* path = nullptr;
|
||||
bool header_mode = false;
|
||||
bool implementation_mode = false;
|
||||
args_parser.add_option(header_mode, "Generate the wrapper .h file", "header", 'H');
|
||||
args_parser.add_option(implementation_mode, "Generate the wrapper .cpp file", "implementation", 'I');
|
||||
args_parser.add_positional_argument(path, "IDL file", "idl-file");
|
||||
args_parser.parse(argc, argv);
|
||||
|
||||
auto file_or_error = Core::File::open(path, Core::IODevice::ReadOnly);
|
||||
if (file_or_error.is_error()) {
|
||||
fprintf(stderr, "Cannot open %s\n", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LexicalPath lexical_path(path);
|
||||
auto namespace_ = lexical_path.parts().at(lexical_path.parts().size() - 2);
|
||||
|
||||
auto data = file_or_error.value()->read_all();
|
||||
auto interface = IDL::parse_interface(path, data);
|
||||
|
||||
if (!interface) {
|
||||
warnln("Cannot parse {}", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (namespace_.is_one_of("DOM", "HTML", "UIEvents", "HighResolutionTime", "SVG")) {
|
||||
StringBuilder builder;
|
||||
builder.append(namespace_);
|
||||
builder.append("::");
|
||||
builder.append(interface->name);
|
||||
interface->fully_qualified_name = builder.to_string();
|
||||
} else {
|
||||
interface->fully_qualified_name = interface->name;
|
||||
}
|
||||
|
||||
#if 0
|
||||
dbgln("Attributes:");
|
||||
for (auto& attribute : interface->attributes) {
|
||||
dbg() << " " << (attribute.readonly ? "Readonly " : "")
|
||||
<< attribute.type.name << (attribute.type.nullable ? "?" : "")
|
||||
<< " " << attribute.name;
|
||||
}
|
||||
|
||||
dbgln("Functions:");
|
||||
for (auto& function : interface->functions) {
|
||||
dbg() << " " << function.return_type.name << (function.return_type.nullable ? "?" : "")
|
||||
<< " " << function.name;
|
||||
for (auto& parameter : function.parameters) {
|
||||
dbg() << " " << parameter.type.name << (parameter.type.nullable ? "?" : "") << " " << parameter.name;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (header_mode)
|
||||
generate_header(*interface);
|
||||
|
||||
if (implementation_mode)
|
||||
generate_implementation(*interface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool should_emit_wrapper_factory(const IDL::Interface& interface)
|
||||
{
|
||||
// FIXME: This is very hackish.
|
||||
if (interface.name == "Event")
|
||||
return false;
|
||||
if (interface.name == "EventTarget")
|
||||
return false;
|
||||
if (interface.name == "Node")
|
||||
return false;
|
||||
if (interface.name == "Text")
|
||||
return false;
|
||||
if (interface.name == "Document")
|
||||
return false;
|
||||
if (interface.name == "DocumentType")
|
||||
return false;
|
||||
if (interface.name.ends_with("Element"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_wrappable_type(const IDL::Type& type)
|
||||
{
|
||||
if (type.name == "Node")
|
||||
return true;
|
||||
if (type.name == "Document")
|
||||
return true;
|
||||
if (type.name == "Text")
|
||||
return true;
|
||||
if (type.name == "DocumentType")
|
||||
return true;
|
||||
if (type.name.ends_with("Element"))
|
||||
return true;
|
||||
if (type.name == "ImageData")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void generate_header(const IDL::Interface& interface)
|
||||
{
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
|
||||
generator.set("name", interface.name);
|
||||
generator.set("fully_qualified_name", interface.fully_qualified_name);
|
||||
generator.set("wrapper_base_class", interface.wrapper_base_class);
|
||||
generator.set("wrapper_class", interface.wrapper_class);
|
||||
generator.set("wrapper_class:snakecase", snake_name(interface.wrapper_class));
|
||||
|
||||
generator.append(R"~~~(
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Bindings/Wrapper.h>
|
||||
|
||||
// FIXME: This is very strange.
|
||||
#if __has_include(<LibWeb/DOM/@name@.h>)
|
||||
# include <LibWeb/DOM/@name@.h>
|
||||
#elif __has_include(<LibWeb/HTML/@name@.h>)
|
||||
# include <LibWeb/HTML/@name@.h>
|
||||
#elif __has_include(<LibWeb/UIEvents/@name@.h>)
|
||||
# include <LibWeb/UIEvents/@name@.h>
|
||||
#elif __has_include(<LibWeb/HighResolutionTime/@name@.h>)
|
||||
# include <LibWeb/HighResolutionTime/@name@.h>
|
||||
#elif __has_include(<LibWeb/SVG/@name@.h>)
|
||||
# include <LibWeb/SVG/@name@.h>
|
||||
#endif
|
||||
)~~~");
|
||||
|
||||
if (interface.wrapper_base_class != "Wrapper") {
|
||||
generator.append(R"~~~(
|
||||
#include <LibWeb/Bindings/@wrapper_base_class@.h>
|
||||
)~~~");
|
||||
}
|
||||
|
||||
generator.append(R"~~~(
|
||||
namespace Web::Bindings {
|
||||
|
||||
class @wrapper_class@ : public @wrapper_base_class@ {
|
||||
JS_OBJECT(@wrapper_class@, @wrapper_base_class@);
|
||||
public:
|
||||
@wrapper_class@(JS::GlobalObject&, @fully_qualified_name@&);
|
||||
virtual void initialize(JS::GlobalObject&) override;
|
||||
virtual ~@wrapper_class@() override;
|
||||
)~~~");
|
||||
|
||||
if (interface.wrapper_base_class == "Wrapper") {
|
||||
generator.append(R"~~~(
|
||||
@fully_qualified_name@& impl() { return *m_impl; }
|
||||
const @fully_qualified_name@& impl() const { return *m_impl; }
|
||||
)~~~");
|
||||
} else {
|
||||
generator.append(R"~~~(
|
||||
@fully_qualified_name@& impl() { return static_cast<@fully_qualified_name@&>(@wrapper_base_class@::impl()); }
|
||||
const @fully_qualified_name@& impl() const { return static_cast<const @fully_qualified_name@&>(@wrapper_base_class@::impl()); }
|
||||
)~~~");
|
||||
}
|
||||
|
||||
generator.append(R"~~~(
|
||||
private:
|
||||
)~~~");
|
||||
|
||||
for (auto& function : interface.functions) {
|
||||
auto function_generator = generator.fork();
|
||||
function_generator.set("function.name:snakecase", snake_name(function.name));
|
||||
function_generator.append(R"~~~(
|
||||
JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@);
|
||||
)~~~");
|
||||
}
|
||||
|
||||
for (auto& attribute : interface.attributes) {
|
||||
auto attribute_generator = generator.fork();
|
||||
attribute_generator.set("attribute.name:snakecase", snake_name(attribute.name));
|
||||
attribute_generator.append(R"~~~(
|
||||
JS_DECLARE_NATIVE_GETTER(@attribute.name:snakecase@_getter);
|
||||
)~~~");
|
||||
|
||||
if (!attribute.readonly) {
|
||||
attribute_generator.append(R"~~~(
|
||||
JS_DECLARE_NATIVE_SETTER(@attribute.name:snakecase@_setter);
|
||||
)~~~");
|
||||
}
|
||||
}
|
||||
|
||||
if (interface.wrapper_base_class == "Wrapper") {
|
||||
generator.append(R"~~~(
|
||||
NonnullRefPtr<@fully_qualified_name@> m_impl;
|
||||
)~~~");
|
||||
}
|
||||
|
||||
generator.append(R"~~~(
|
||||
};
|
||||
)~~~");
|
||||
|
||||
if (should_emit_wrapper_factory(interface)) {
|
||||
generator.append(R"~~~(
|
||||
@wrapper_class@* wrap(JS::GlobalObject&, @fully_qualified_name@&);
|
||||
)~~~");
|
||||
}
|
||||
|
||||
generator.append(R"~~~(
|
||||
} // namespace Web::Bindings
|
||||
)~~~");
|
||||
|
||||
outln("{}", generator.as_string_view());
|
||||
}
|
||||
|
||||
void generate_implementation(const IDL::Interface& interface)
|
||||
{
|
||||
StringBuilder builder;
|
||||
SourceGenerator generator { builder };
|
||||
|
||||
generator.set("wrapper_class", interface.wrapper_class);
|
||||
generator.set("wrapper_base_class", interface.wrapper_base_class);
|
||||
generator.set("fully_qualified_name", interface.fully_qualified_name);
|
||||
|
||||
generator.append(R"~~~(
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/Error.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Uint8ClampedArray.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
#include <LibWeb/Bindings/@wrapper_class@.h>
|
||||
#include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>
|
||||
#include <LibWeb/Bindings/CommentWrapper.h>
|
||||
#include <LibWeb/Bindings/DOMImplementationWrapper.h>
|
||||
#include <LibWeb/Bindings/DocumentFragmentWrapper.h>
|
||||
#include <LibWeb/Bindings/DocumentTypeWrapper.h>
|
||||
#include <LibWeb/Bindings/DocumentWrapper.h>
|
||||
#include <LibWeb/Bindings/EventTargetWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/HTMLCanvasElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLHeadElementWrapper.h>
|
||||
#include <LibWeb/Bindings/HTMLImageElementWrapper.h>
|
||||
#include <LibWeb/Bindings/ImageDataWrapper.h>
|
||||
#include <LibWeb/Bindings/NodeWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/TextWrapper.h>
|
||||
#include <LibWeb/Bindings/WindowObject.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/DOM/EventListener.h>
|
||||
#include <LibWeb/HTML/HTMLElement.h>
|
||||
#include <LibWeb/Origin.h>
|
||||
|
||||
// FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
|
||||
using namespace Web::DOM;
|
||||
using namespace Web::HTML;
|
||||
|
||||
namespace Web::Bindings {
|
||||
|
||||
)~~~");
|
||||
|
||||
if (interface.wrapper_base_class == "Wrapper") {
|
||||
generator.append(R"~~~(
|
||||
@wrapper_class@::@wrapper_class@(JS::GlobalObject& global_object, @fully_qualified_name@& impl)
|
||||
: Wrapper(*global_object.object_prototype())
|
||||
, m_impl(impl)
|
||||
{
|
||||
}
|
||||
)~~~");
|
||||
} else {
|
||||
generator.append(R"~~~(
|
||||
@wrapper_class@::@wrapper_class@(JS::GlobalObject& global_object, @fully_qualified_name@& impl)
|
||||
: @wrapper_base_class@(global_object, impl)
|
||||
{
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
|
||||
generator.append(R"~~~(
|
||||
void @wrapper_class@::initialize(JS::GlobalObject& global_object)
|
||||
{
|
||||
[[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable | JS::Attribute::Configurable;
|
||||
|
||||
@wrapper_base_class@::initialize(global_object);
|
||||
)~~~");
|
||||
|
||||
for (auto& attribute : interface.attributes) {
|
||||
auto attribute_generator = generator.fork();
|
||||
attribute_generator.set("attribute.name", attribute.name);
|
||||
attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name);
|
||||
|
||||
if (attribute.readonly)
|
||||
attribute_generator.set("attribute.setter_callback", "nullptr");
|
||||
else
|
||||
attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name);
|
||||
|
||||
attribute_generator.append(R"~~~(
|
||||
define_native_property("@attribute.name@", @attribute.getter_callback@, @attribute.setter_callback@, default_attributes);
|
||||
)~~~");
|
||||
}
|
||||
|
||||
for (auto& function : interface.functions) {
|
||||
auto function_generator = generator.fork();
|
||||
function_generator.set("function.name", function.name);
|
||||
function_generator.set("function.name:snakecase", snake_name(function.name));
|
||||
function_generator.set("function.name:length", String::number(function.name.length()));
|
||||
|
||||
function_generator.append(R"~~~(
|
||||
define_native_function("@function.name@", @function.name:snakecase@, @function.name:length@, default_attributes);
|
||||
)~~~");
|
||||
}
|
||||
|
||||
generator.append(R"~~~(
|
||||
}
|
||||
|
||||
@wrapper_class@::~@wrapper_class@()
|
||||
{
|
||||
}
|
||||
)~~~");
|
||||
|
||||
if (!interface.attributes.is_empty() || !interface.functions.is_empty()) {
|
||||
generator.append(R"~~~(
|
||||
static @fully_qualified_name@* impl_from(JS::VM& vm, JS::GlobalObject& global_object)
|
||||
{
|
||||
auto* this_object = vm.this_value(global_object).to_object(global_object);
|
||||
if (!this_object)
|
||||
return {};
|
||||
if (!is<@wrapper_class@>(this_object)) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "@fully_qualified_name@");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &static_cast<@wrapper_class@*>(this_object)->impl();
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
|
||||
auto generate_to_cpp = [&](auto& parameter, auto& js_name, const auto& js_suffix, auto cpp_name, bool return_void = false, bool legacy_null_to_empty_string = false, bool optional = false) {
|
||||
auto scoped_generator = generator.fork();
|
||||
scoped_generator.set("cpp_name", cpp_name);
|
||||
scoped_generator.set("js_name", js_name);
|
||||
scoped_generator.set("js_suffix", js_suffix);
|
||||
scoped_generator.set("legacy_null_to_empty_string", legacy_null_to_empty_string ? "true" : "false");
|
||||
scoped_generator.set("parameter.type.name", parameter.type.name);
|
||||
|
||||
if (return_void)
|
||||
scoped_generator.set("return_statement", "return;");
|
||||
else
|
||||
scoped_generator.set("return_statement", "return {};");
|
||||
|
||||
// FIXME: Add support for optional to all types
|
||||
if (parameter.type.name == "DOMString") {
|
||||
if (!optional) {
|
||||
scoped_generator.append(R"~~~(
|
||||
auto @cpp_name@ = @js_name@@js_suffix@.to_string(global_object, @legacy_null_to_empty_string@);
|
||||
if (vm.exception())
|
||||
@return_statement@
|
||||
)~~~");
|
||||
} else {
|
||||
scoped_generator.append(R"~~~(
|
||||
String @cpp_name@;
|
||||
if (!@js_name@@js_suffix@.is_undefined()) {
|
||||
@cpp_name@ = @js_name@@js_suffix@.to_string(global_object, @legacy_null_to_empty_string@);
|
||||
if (vm.exception())
|
||||
@return_statement@
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
} else if (parameter.type.name == "EventListener") {
|
||||
scoped_generator.append(R"~~~(
|
||||
if (!@js_name@@js_suffix@.is_function()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "Function");
|
||||
@return_statement@
|
||||
}
|
||||
auto @cpp_name@ = adopt(*new EventListener(JS::make_handle(&@js_name@@js_suffix@.as_function())));
|
||||
)~~~");
|
||||
} else if (is_wrappable_type(parameter.type)) {
|
||||
scoped_generator.append(R"~~~(
|
||||
auto @cpp_name@_object = @js_name@@js_suffix@.to_object(global_object);
|
||||
if (vm.exception())
|
||||
@return_statement@
|
||||
|
||||
if (!is<@parameter.type.name@Wrapper>(@cpp_name@_object)) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "@parameter.type.name@");
|
||||
@return_statement@
|
||||
}
|
||||
|
||||
auto& @cpp_name@ = static_cast<@parameter.type.name@Wrapper*>(@cpp_name@_object)->impl();
|
||||
)~~~");
|
||||
} else if (parameter.type.name == "double") {
|
||||
scoped_generator.append(R"~~~(
|
||||
auto @cpp_name@ = @js_name@@js_suffix@.to_double(global_object);
|
||||
if (vm.exception())
|
||||
@return_statement@
|
||||
)~~~");
|
||||
} else if (parameter.type.name == "boolean") {
|
||||
scoped_generator.append(R"~~~(
|
||||
auto @cpp_name@ = @js_name@@js_suffix@.to_boolean();
|
||||
)~~~");
|
||||
} else {
|
||||
dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type.name);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
};
|
||||
|
||||
auto generate_arguments = [&](auto& parameters, auto& arguments_builder, bool return_void = false) {
|
||||
auto arguments_generator = generator.fork();
|
||||
|
||||
Vector<String> parameter_names;
|
||||
size_t argument_index = 0;
|
||||
for (auto& parameter : parameters) {
|
||||
parameter_names.append(snake_name(parameter.name));
|
||||
arguments_generator.set("argument.index", String::number(argument_index));
|
||||
|
||||
arguments_generator.append(R"~~~(
|
||||
auto arg@argument.index@ = vm.argument(@argument.index@);
|
||||
)~~~");
|
||||
// FIXME: Parameters can have [LegacyNullToEmptyString] attached.
|
||||
generate_to_cpp(parameter, "arg", String::number(argument_index), snake_name(parameter.name), return_void, false, parameter.optional);
|
||||
++argument_index;
|
||||
}
|
||||
|
||||
arguments_builder.join(", ", parameter_names);
|
||||
};
|
||||
|
||||
auto generate_return_statement = [&](auto& return_type) {
|
||||
auto scoped_generator = generator.fork();
|
||||
scoped_generator.set("return_type", return_type.name);
|
||||
|
||||
if (return_type.name == "undefined") {
|
||||
scoped_generator.append(R"~~~(
|
||||
return JS::js_undefined();
|
||||
)~~~");
|
||||
return;
|
||||
}
|
||||
|
||||
if (return_type.nullable) {
|
||||
if (return_type.name == "DOMString") {
|
||||
scoped_generator.append(R"~~~(
|
||||
if (retval.is_null())
|
||||
return JS::js_null();
|
||||
)~~~");
|
||||
} else {
|
||||
scoped_generator.append(R"~~~(
|
||||
if (!retval)
|
||||
return JS::js_null();
|
||||
)~~~");
|
||||
}
|
||||
}
|
||||
|
||||
if (return_type.name == "DOMString") {
|
||||
scoped_generator.append(R"~~~(
|
||||
return JS::js_string(vm, retval);
|
||||
)~~~");
|
||||
} else if (return_type.name == "ArrayFromVector") {
|
||||
// FIXME: Remove this fake type hack once it's no longer needed.
|
||||
// Basically once we have NodeList we can throw this out.
|
||||
scoped_generator.append(R"~~~(
|
||||
auto* new_array = JS::Array::create(global_object);
|
||||
for (auto& element : retval)
|
||||
new_array->indexed_properties().append(wrap(global_object, element));
|
||||
|
||||
return new_array;
|
||||
)~~~");
|
||||
} else if (return_type.name == "long" || return_type.name == "double" || return_type.name == "boolean" || return_type.name == "short") {
|
||||
scoped_generator.append(R"~~~(
|
||||
return JS::Value(retval);
|
||||
)~~~");
|
||||
} else if (return_type.name == "Uint8ClampedArray") {
|
||||
scoped_generator.append(R"~~~(
|
||||
return retval;
|
||||
)~~~");
|
||||
} else {
|
||||
scoped_generator.append(R"~~~(
|
||||
return wrap(global_object, const_cast<@return_type@&>(*retval));
|
||||
)~~~");
|
||||
}
|
||||
};
|
||||
|
||||
for (auto& attribute : interface.attributes) {
|
||||
auto attribute_generator = generator.fork();
|
||||
attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name);
|
||||
attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name);
|
||||
attribute_generator.set("attribute.name:snakecase", snake_name(attribute.name));
|
||||
|
||||
if (attribute.extended_attributes.contains("Reflect")) {
|
||||
auto attribute_name = attribute.extended_attributes.get("Reflect").value();
|
||||
if (attribute_name.is_null())
|
||||
attribute_name = attribute.name;
|
||||
attribute_name = make_input_acceptable_cpp(attribute_name);
|
||||
|
||||
attribute_generator.set("attribute.reflect_name", attribute_name);
|
||||
} else {
|
||||
attribute_generator.set("attribute.reflect_name", snake_name(attribute.name));
|
||||
}
|
||||
|
||||
attribute_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_GETTER(@wrapper_class@::@attribute.getter_callback@)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
)~~~");
|
||||
|
||||
if (attribute.extended_attributes.contains("ReturnNullIfCrossOrigin")) {
|
||||
attribute_generator.append(R"~~~(
|
||||
if (!impl->may_access_from_origin(static_cast<WindowObject&>(global_object).origin()))
|
||||
return JS::js_null();
|
||||
)~~~");
|
||||
}
|
||||
|
||||
if (attribute.extended_attributes.contains("Reflect")) {
|
||||
if (attribute.type.name != "boolean") {
|
||||
attribute_generator.append(R"~~~(
|
||||
auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@);
|
||||
)~~~");
|
||||
} else {
|
||||
attribute_generator.append(R"~~~(
|
||||
auto retval = impl->has_attribute(HTML::AttributeNames::@attribute.reflect_name@);
|
||||
)~~~");
|
||||
}
|
||||
} else {
|
||||
attribute_generator.append(R"~~~(
|
||||
auto retval = impl->@attribute.name:snakecase@();
|
||||
)~~~");
|
||||
}
|
||||
|
||||
generate_return_statement(attribute.type);
|
||||
|
||||
attribute_generator.append(R"~~~(
|
||||
}
|
||||
)~~~");
|
||||
|
||||
if (!attribute.readonly) {
|
||||
attribute_generator.append(R"~~~(
|
||||
JS_DEFINE_NATIVE_SETTER(@wrapper_class@::@attribute.setter_callback@)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return;
|
||||
)~~~");
|
||||
|
||||
generate_to_cpp(attribute, "value", "", "cpp_value", true, attribute.extended_attributes.contains("LegacyNullToEmptyString"));
|
||||
|
||||
if (attribute.extended_attributes.contains("Reflect")) {
|
||||
if (attribute.type.name != "boolean") {
|
||||
attribute_generator.append(R"~~~(
|
||||
impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, cpp_value);
|
||||
)~~~");
|
||||
} else {
|
||||
attribute_generator.append(R"~~~(
|
||||
if (!cpp_value)
|
||||
impl->remove_attribute(HTML::AttributeNames::@attribute.reflect_name@);
|
||||
else
|
||||
impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, String::empty());
|
||||
)~~~");
|
||||
}
|
||||
} else {
|
||||
attribute_generator.append(R"~~~(
|
||||
impl->set_@attribute.name:snakecase@(cpp_value);
|
||||
)~~~");
|
||||
}
|
||||
|
||||
attribute_generator.append(R"~~~(
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation: Functions
|
||||
for (auto& function : interface.functions) {
|
||||
auto function_generator = generator.fork();
|
||||
function_generator.set("function.name", function.name);
|
||||
function_generator.set("function.name:snakecase", snake_name(function.name));
|
||||
function_generator.set("function.nargs", String::number(function.length()));
|
||||
|
||||
function_generator.append(R"~~~(\
|
||||
JS_DEFINE_NATIVE_FUNCTION(@wrapper_class@::@function.name:snakecase@)
|
||||
{
|
||||
auto* impl = impl_from(vm, global_object);
|
||||
if (!impl)
|
||||
return {};
|
||||
)~~~");
|
||||
|
||||
if (function.length() > 0) {
|
||||
if (function.length() == 1) {
|
||||
function_generator.set(".bad_arg_count", "JS::ErrorType::BadArgCountOne");
|
||||
function_generator.set(".arg_count_suffix", "");
|
||||
} else {
|
||||
function_generator.set(".bad_arg_count", "JS::ErrorType::BadArgCountMany");
|
||||
function_generator.set(".arg_count_suffix", String::formatted(", \"{}\"", function.length()));
|
||||
}
|
||||
|
||||
function_generator.append(R"~~~(
|
||||
if (vm.argument_count() < @function.nargs@) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, @.bad_arg_count@, "@function.name@"@.arg_count_suffix@);
|
||||
return {};
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
|
||||
StringBuilder arguments_builder;
|
||||
generate_arguments(function.parameters, arguments_builder);
|
||||
|
||||
function_generator.set(".arguments", arguments_builder.string_view());
|
||||
|
||||
if (function.return_type.name != "undefined") {
|
||||
function_generator.append(R"~~~(
|
||||
auto retval = impl->@function.name:snakecase@(@.arguments@);
|
||||
)~~~");
|
||||
} else {
|
||||
function_generator.append(R"~~~(
|
||||
impl->@function.name:snakecase@(@.arguments@);
|
||||
)~~~");
|
||||
}
|
||||
|
||||
generate_return_statement(function.return_type);
|
||||
|
||||
function_generator.append(R"~~~(
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
|
||||
if (should_emit_wrapper_factory(interface)) {
|
||||
generator.append(R"~~~(
|
||||
@wrapper_class@* wrap(JS::GlobalObject& global_object, @fully_qualified_name@& impl)
|
||||
{
|
||||
return static_cast<@wrapper_class@*>(wrap_impl(global_object, impl));
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
|
||||
generator.append(R"~~~(
|
||||
} // namespace Web::Bindings
|
||||
)~~~");
|
||||
|
||||
outln("{}", generator.as_string_view());
|
||||
}
|
||||
51
Userland/Libraries/LibWeb/DOM/Attribute.h
Normal file
51
Userland/Libraries/LibWeb/DOM/Attribute.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
class Attribute {
|
||||
public:
|
||||
Attribute(const FlyString& name, const String& value)
|
||||
: m_name(name)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
const FlyString& name() const { return m_name; }
|
||||
const String& value() const { return m_value; }
|
||||
|
||||
void set_value(const String& value) { m_value = value; }
|
||||
|
||||
private:
|
||||
FlyString m_name;
|
||||
String m_value;
|
||||
};
|
||||
|
||||
}
|
||||
41
Userland/Libraries/LibWeb/DOM/CharacterData.cpp
Normal file
41
Userland/Libraries/LibWeb/DOM/CharacterData.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/DOM/CharacterData.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
CharacterData::CharacterData(Document& document, NodeType type, const String& data)
|
||||
: Node(document, type)
|
||||
, m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
CharacterData::~CharacterData()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
57
Userland/Libraries/LibWeb/DOM/CharacterData.h
Normal file
57
Userland/Libraries/LibWeb/DOM/CharacterData.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
#include <LibWeb/DOM/NonDocumentTypeChildNode.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class CharacterData
|
||||
: public Node
|
||||
, public NonDocumentTypeChildNode<CharacterData> {
|
||||
public:
|
||||
using WrapperType = Bindings::CharacterDataWrapper;
|
||||
|
||||
virtual ~CharacterData() override;
|
||||
|
||||
const String& data() const { return m_data; }
|
||||
void set_data(const String& data) { m_data = data; }
|
||||
|
||||
unsigned length() const { return m_data.length(); }
|
||||
|
||||
virtual String text_content() const override { return m_data; }
|
||||
|
||||
protected:
|
||||
explicit CharacterData(Document&, NodeType, const String&);
|
||||
|
||||
private:
|
||||
String m_data;
|
||||
};
|
||||
|
||||
}
|
||||
9
Userland/Libraries/LibWeb/DOM/CharacterData.idl
Normal file
9
Userland/Libraries/LibWeb/DOM/CharacterData.idl
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
interface CharacterData : Node {
|
||||
|
||||
attribute DOMString data;
|
||||
readonly attribute unsigned long length;
|
||||
|
||||
readonly attribute Element? nextElementSibling;
|
||||
readonly attribute Element? previousElementSibling;
|
||||
|
||||
};
|
||||
41
Userland/Libraries/LibWeb/DOM/Comment.cpp
Normal file
41
Userland/Libraries/LibWeb/DOM/Comment.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/DOM/Comment.h>
|
||||
#include <LibWeb/Layout/TextNode.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
Comment::Comment(Document& document, const String& data)
|
||||
: CharacterData(document, NodeType::COMMENT_NODE, data)
|
||||
{
|
||||
}
|
||||
|
||||
Comment::~Comment()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
44
Userland/Libraries/LibWeb/DOM/Comment.h
Normal file
44
Userland/Libraries/LibWeb/DOM/Comment.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibWeb/DOM/CharacterData.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class Comment final : public CharacterData {
|
||||
public:
|
||||
using WrapperType = Bindings::CommentWrapper;
|
||||
|
||||
explicit Comment(Document&, const String&);
|
||||
virtual ~Comment() override;
|
||||
|
||||
virtual FlyString node_name() const override { return "#comment"; }
|
||||
};
|
||||
|
||||
}
|
||||
3
Userland/Libraries/LibWeb/DOM/Comment.idl
Normal file
3
Userland/Libraries/LibWeb/DOM/Comment.idl
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
interface Comment : CharacterData {
|
||||
|
||||
};
|
||||
75
Userland/Libraries/LibWeb/DOM/DOMImplementation.cpp
Normal file
75
Userland/Libraries/LibWeb/DOM/DOMImplementation.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/DOM/DOMImplementation.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/DocumentType.h>
|
||||
#include <LibWeb/DOM/ElementFactory.h>
|
||||
#include <LibWeb/DOM/Text.h>
|
||||
#include <LibWeb/Namespace.h>
|
||||
#include <LibWeb/Origin.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
DOMImplementation::DOMImplementation(Document& document)
|
||||
: m_document(document)
|
||||
{
|
||||
}
|
||||
|
||||
const NonnullRefPtr<Document> DOMImplementation::create_htmldocument(const String& title) const
|
||||
{
|
||||
auto html_document = Document::create();
|
||||
|
||||
html_document->set_content_type("text/html");
|
||||
html_document->set_ready_for_post_load_tasks(true);
|
||||
|
||||
auto doctype = adopt(*new DocumentType(html_document));
|
||||
doctype->set_name("html");
|
||||
html_document->append_child(doctype);
|
||||
|
||||
auto html_element = create_element(html_document, HTML::TagNames::html, Namespace::HTML);
|
||||
html_document->append_child(html_element);
|
||||
|
||||
auto head_element = create_element(html_document, HTML::TagNames::head, Namespace::HTML);
|
||||
html_element->append_child(head_element);
|
||||
|
||||
if (!title.is_null()) {
|
||||
auto title_element = create_element(html_document, HTML::TagNames::title, Namespace::HTML);
|
||||
head_element->append_child(title_element);
|
||||
|
||||
auto text_node = adopt(*new Text(html_document, title));
|
||||
title_element->append_child(text_node);
|
||||
}
|
||||
|
||||
auto body_element = create_element(html_document, HTML::TagNames::body, Namespace::HTML);
|
||||
html_element->append_child(body_element);
|
||||
|
||||
html_document->set_origin(m_document.origin());
|
||||
|
||||
return html_document;
|
||||
}
|
||||
|
||||
}
|
||||
60
Userland/Libraries/LibWeb/DOM/DOMImplementation.h
Normal file
60
Userland/Libraries/LibWeb/DOM/DOMImplementation.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/Weakable.h>
|
||||
#include <LibWeb/Bindings/Wrappable.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class DOMImplementation final
|
||||
: public RefCounted<DOMImplementation>
|
||||
, public Weakable<DOMImplementation>
|
||||
, public Bindings::Wrappable {
|
||||
public:
|
||||
using WrapperType = Bindings::DOMImplementationWrapper;
|
||||
|
||||
static NonnullRefPtr<DOMImplementation> create(Document& document)
|
||||
{
|
||||
return adopt(*new DOMImplementation(document));
|
||||
}
|
||||
|
||||
// FIXME: snake_case in WrapperGenerator turns "createHTMLDocument" into "create_htmldocument"
|
||||
const NonnullRefPtr<Document> create_htmldocument(const String& title) const;
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
|
||||
bool has_feature() const { return true; }
|
||||
|
||||
private:
|
||||
explicit DOMImplementation(Document&);
|
||||
|
||||
Document& m_document;
|
||||
};
|
||||
|
||||
}
|
||||
7
Userland/Libraries/LibWeb/DOM/DOMImplementation.idl
Normal file
7
Userland/Libraries/LibWeb/DOM/DOMImplementation.idl
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
interface DOMImplementation {
|
||||
|
||||
Document createHTMLDocument(optional DOMString title);
|
||||
|
||||
boolean hasFeature();
|
||||
|
||||
};
|
||||
690
Userland/Libraries/LibWeb/DOM/Document.cpp
Normal file
690
Userland/Libraries/LibWeb/DOM/Document.cpp
Normal file
|
|
@ -0,0 +1,690 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/StringBuilder.h>
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibCore/Timer.h>
|
||||
#include <LibGUI/Application.h>
|
||||
#include <LibGUI/DisplayLink.h>
|
||||
#include <LibGUI/MessageBox.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Parser.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibWeb/Bindings/DocumentWrapper.h>
|
||||
#include <LibWeb/Bindings/WindowObject.h>
|
||||
#include <LibWeb/CSS/StyleResolver.h>
|
||||
#include <LibWeb/DOM/Comment.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/DocumentFragment.h>
|
||||
#include <LibWeb/DOM/DocumentType.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/DOM/ElementFactory.h>
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/Text.h>
|
||||
#include <LibWeb/DOM/Window.h>
|
||||
#include <LibWeb/Dump.h>
|
||||
#include <LibWeb/HTML/AttributeNames.h>
|
||||
#include <LibWeb/HTML/EventNames.h>
|
||||
#include <LibWeb/HTML/HTMLBodyElement.h>
|
||||
#include <LibWeb/HTML/HTMLFrameSetElement.h>
|
||||
#include <LibWeb/HTML/HTMLHeadElement.h>
|
||||
#include <LibWeb/HTML/HTMLHtmlElement.h>
|
||||
#include <LibWeb/HTML/HTMLScriptElement.h>
|
||||
#include <LibWeb/HTML/HTMLTitleElement.h>
|
||||
#include <LibWeb/InProcessWebView.h>
|
||||
#include <LibWeb/Layout/BlockFormattingContext.h>
|
||||
#include <LibWeb/Layout/InitialContainingBlockBox.h>
|
||||
#include <LibWeb/Layout/TreeBuilder.h>
|
||||
#include <LibWeb/Namespace.h>
|
||||
#include <LibWeb/Origin.h>
|
||||
#include <LibWeb/Page/Frame.h>
|
||||
#include <LibWeb/SVG/TagNames.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
Document::Document(const URL& url)
|
||||
: ParentNode(*this, NodeType::DOCUMENT_NODE)
|
||||
, m_style_resolver(make<CSS::StyleResolver>(*this))
|
||||
, m_style_sheets(CSS::StyleSheetList::create(*this))
|
||||
, m_url(url)
|
||||
, m_window(Window::create_with_document(*this))
|
||||
, m_implementation(DOMImplementation::create(*this))
|
||||
{
|
||||
m_style_update_timer = Core::Timer::create_single_shot(0, [this] {
|
||||
update_style();
|
||||
});
|
||||
|
||||
m_forced_layout_timer = Core::Timer::create_single_shot(0, [this] {
|
||||
force_layout();
|
||||
});
|
||||
}
|
||||
|
||||
Document::~Document()
|
||||
{
|
||||
}
|
||||
|
||||
void Document::removed_last_ref()
|
||||
{
|
||||
ASSERT(!ref_count());
|
||||
ASSERT(!m_deletion_has_begun);
|
||||
|
||||
if (m_referencing_node_count) {
|
||||
// The document has reached ref_count==0 but still has nodes keeping it alive.
|
||||
// At this point, sever all the node links we control.
|
||||
// If nodes remain elsewhere (e.g JS wrappers), they will keep the document alive.
|
||||
|
||||
// NOTE: This makes sure we stay alive across for the duration of the cleanup below.
|
||||
increment_referencing_node_count();
|
||||
|
||||
m_focused_element = nullptr;
|
||||
m_hovered_node = nullptr;
|
||||
m_pending_parsing_blocking_script = nullptr;
|
||||
m_inspected_node = nullptr;
|
||||
m_scripts_to_execute_when_parsing_has_finished.clear();
|
||||
m_scripts_to_execute_as_soon_as_possible.clear();
|
||||
m_associated_inert_template_document = nullptr;
|
||||
|
||||
m_interpreter = nullptr;
|
||||
|
||||
{
|
||||
// Gather up all the descendants of this document and prune them from the tree.
|
||||
// FIXME: This could definitely be more elegant.
|
||||
NonnullRefPtrVector<Node> descendants;
|
||||
for_each_in_subtree([&](auto& node) {
|
||||
if (&node != this)
|
||||
descendants.append(node);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
for (auto& node : descendants) {
|
||||
ASSERT(&node.document() == this);
|
||||
ASSERT(!node.is_document());
|
||||
if (node.parent())
|
||||
node.parent()->remove_child(node);
|
||||
}
|
||||
}
|
||||
|
||||
m_in_removed_last_ref = false;
|
||||
decrement_referencing_node_count();
|
||||
return;
|
||||
}
|
||||
|
||||
m_in_removed_last_ref = false;
|
||||
m_deletion_has_begun = true;
|
||||
delete this;
|
||||
}
|
||||
|
||||
Origin Document::origin() const
|
||||
{
|
||||
if (!m_url.is_valid())
|
||||
return {};
|
||||
return { m_url.protocol(), m_url.host(), m_url.port() };
|
||||
}
|
||||
|
||||
void Document::set_origin(const Origin& origin)
|
||||
{
|
||||
m_url.set_protocol(origin.protocol());
|
||||
m_url.set_host(origin.host());
|
||||
m_url.set_port(origin.port());
|
||||
}
|
||||
|
||||
void Document::schedule_style_update()
|
||||
{
|
||||
if (m_style_update_timer->is_active())
|
||||
return;
|
||||
m_style_update_timer->start();
|
||||
}
|
||||
|
||||
void Document::schedule_forced_layout()
|
||||
{
|
||||
if (m_forced_layout_timer->is_active())
|
||||
return;
|
||||
m_forced_layout_timer->start();
|
||||
}
|
||||
|
||||
bool Document::is_child_allowed(const Node& node) const
|
||||
{
|
||||
switch (node.type()) {
|
||||
case NodeType::DOCUMENT_NODE:
|
||||
case NodeType::TEXT_NODE:
|
||||
return false;
|
||||
case NodeType::COMMENT_NODE:
|
||||
return true;
|
||||
case NodeType::DOCUMENT_TYPE_NODE:
|
||||
return !first_child_of_type<DocumentType>();
|
||||
case NodeType::ELEMENT_NODE:
|
||||
return !first_child_of_type<Element>();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const Element* Document::document_element() const
|
||||
{
|
||||
return first_child_of_type<Element>();
|
||||
}
|
||||
|
||||
const HTML::HTMLHtmlElement* Document::html_element() const
|
||||
{
|
||||
auto* html = document_element();
|
||||
if (is<HTML::HTMLHtmlElement>(html))
|
||||
return downcast<HTML::HTMLHtmlElement>(html);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const HTML::HTMLHeadElement* Document::head() const
|
||||
{
|
||||
auto* html = html_element();
|
||||
if (!html)
|
||||
return nullptr;
|
||||
return html->first_child_of_type<HTML::HTMLHeadElement>();
|
||||
}
|
||||
|
||||
const HTML::HTMLElement* Document::body() const
|
||||
{
|
||||
auto* html = html_element();
|
||||
if (!html)
|
||||
return nullptr;
|
||||
auto* first_body = html->first_child_of_type<HTML::HTMLBodyElement>();
|
||||
if (first_body)
|
||||
return first_body;
|
||||
auto* first_frameset = html->first_child_of_type<HTML::HTMLFrameSetElement>();
|
||||
if (first_frameset)
|
||||
return first_frameset;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Document::set_body(HTML::HTMLElement& new_body)
|
||||
{
|
||||
if (!is<HTML::HTMLBodyElement>(new_body) && !is<HTML::HTMLFrameSetElement>(new_body)) {
|
||||
// FIXME: throw a "HierarchyRequestError" DOMException.
|
||||
return;
|
||||
}
|
||||
|
||||
auto* existing_body = body();
|
||||
if (existing_body) {
|
||||
TODO();
|
||||
return;
|
||||
}
|
||||
|
||||
auto* html = document_element();
|
||||
if (!html) {
|
||||
// FIXME: throw a "HierarchyRequestError" DOMException.
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Implement this once there's a non-const first_child_of_type:
|
||||
// "Otherwise, the body element is null, but there's a document element. Append the new value to the document element."
|
||||
TODO();
|
||||
}
|
||||
|
||||
String Document::title() const
|
||||
{
|
||||
auto* head_element = head();
|
||||
if (!head_element)
|
||||
return {};
|
||||
|
||||
auto* title_element = head_element->first_child_of_type<HTML::HTMLTitleElement>();
|
||||
if (!title_element)
|
||||
return {};
|
||||
|
||||
auto raw_title = title_element->text_content();
|
||||
|
||||
StringBuilder builder;
|
||||
bool last_was_space = false;
|
||||
for (auto code_point : Utf8View(raw_title)) {
|
||||
if (isspace(code_point)) {
|
||||
last_was_space = true;
|
||||
} else {
|
||||
if (last_was_space && !builder.is_empty())
|
||||
builder.append(' ');
|
||||
builder.append_code_point(code_point);
|
||||
last_was_space = false;
|
||||
}
|
||||
}
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
void Document::set_title(const String& title)
|
||||
{
|
||||
auto* head_element = const_cast<HTML::HTMLHeadElement*>(head());
|
||||
if (!head_element)
|
||||
return;
|
||||
|
||||
RefPtr<HTML::HTMLTitleElement> title_element = head_element->first_child_of_type<HTML::HTMLTitleElement>();
|
||||
if (!title_element) {
|
||||
title_element = static_ptr_cast<HTML::HTMLTitleElement>(create_element(HTML::TagNames::title));
|
||||
head_element->append_child(*title_element);
|
||||
}
|
||||
|
||||
while (RefPtr<Node> child = title_element->first_child())
|
||||
title_element->remove_child(child.release_nonnull());
|
||||
|
||||
title_element->append_child(adopt(*new Text(*this, title)));
|
||||
|
||||
if (auto* page = this->page())
|
||||
page->client().page_did_change_title(title);
|
||||
}
|
||||
|
||||
void Document::attach_to_frame(Badge<Frame>, Frame& frame)
|
||||
{
|
||||
m_frame = frame;
|
||||
update_layout();
|
||||
}
|
||||
|
||||
void Document::detach_from_frame(Badge<Frame>, Frame& frame)
|
||||
{
|
||||
ASSERT(&frame == m_frame);
|
||||
tear_down_layout_tree();
|
||||
m_frame = nullptr;
|
||||
}
|
||||
|
||||
void Document::tear_down_layout_tree()
|
||||
{
|
||||
if (!m_layout_root)
|
||||
return;
|
||||
|
||||
// Gather up all the layout nodes in a vector and detach them from parents
|
||||
// while the vector keeps them alive.
|
||||
|
||||
NonnullRefPtrVector<Layout::Node> layout_nodes;
|
||||
|
||||
m_layout_root->for_each_in_subtree([&](auto& layout_node) {
|
||||
layout_nodes.append(layout_node);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
for (auto& layout_node : layout_nodes) {
|
||||
if (layout_node.parent())
|
||||
layout_node.parent()->remove_child(layout_node);
|
||||
}
|
||||
|
||||
m_layout_root = nullptr;
|
||||
}
|
||||
|
||||
Color Document::background_color(const Palette& palette) const
|
||||
{
|
||||
auto default_color = palette.base();
|
||||
auto* body_element = body();
|
||||
if (!body_element)
|
||||
return default_color;
|
||||
|
||||
auto* body_layout_node = body_element->layout_node();
|
||||
if (!body_layout_node)
|
||||
return default_color;
|
||||
|
||||
auto color = body_layout_node->computed_values().background_color();
|
||||
if (!color.alpha())
|
||||
return default_color;
|
||||
return color;
|
||||
}
|
||||
|
||||
RefPtr<Gfx::Bitmap> Document::background_image() const
|
||||
{
|
||||
auto* body_element = body();
|
||||
if (!body_element)
|
||||
return {};
|
||||
|
||||
auto* body_layout_node = body_element->layout_node();
|
||||
if (!body_layout_node)
|
||||
return {};
|
||||
|
||||
auto background_image = body_layout_node->background_image();
|
||||
if (!background_image)
|
||||
return {};
|
||||
return background_image->bitmap();
|
||||
}
|
||||
|
||||
URL Document::complete_url(const String& string) const
|
||||
{
|
||||
return m_url.complete_url(string);
|
||||
}
|
||||
|
||||
void Document::invalidate_layout()
|
||||
{
|
||||
tear_down_layout_tree();
|
||||
}
|
||||
|
||||
void Document::force_layout()
|
||||
{
|
||||
invalidate_layout();
|
||||
update_layout();
|
||||
}
|
||||
|
||||
void Document::update_layout()
|
||||
{
|
||||
if (!frame())
|
||||
return;
|
||||
|
||||
if (!m_layout_root) {
|
||||
Layout::TreeBuilder tree_builder;
|
||||
m_layout_root = static_ptr_cast<Layout::InitialContainingBlockBox>(tree_builder.build(*this));
|
||||
}
|
||||
|
||||
Layout::BlockFormattingContext root_formatting_context(*m_layout_root, nullptr);
|
||||
root_formatting_context.run(*m_layout_root, Layout::LayoutMode::Default);
|
||||
|
||||
m_layout_root->set_needs_display();
|
||||
|
||||
if (frame()->is_main_frame()) {
|
||||
if (auto* page = this->page())
|
||||
page->client().page_did_layout();
|
||||
}
|
||||
}
|
||||
|
||||
static void update_style_recursively(DOM::Node& node)
|
||||
{
|
||||
node.for_each_child([&](auto& child) {
|
||||
if (child.needs_style_update()) {
|
||||
if (is<Element>(child))
|
||||
downcast<Element>(child).recompute_style();
|
||||
child.set_needs_style_update(false);
|
||||
}
|
||||
if (child.child_needs_style_update()) {
|
||||
update_style_recursively(child);
|
||||
child.set_child_needs_style_update(false);
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
void Document::update_style()
|
||||
{
|
||||
update_style_recursively(*this);
|
||||
update_layout();
|
||||
}
|
||||
|
||||
RefPtr<Layout::Node> Document::create_layout_node()
|
||||
{
|
||||
return adopt(*new Layout::InitialContainingBlockBox(*this, CSS::StyleProperties::create()));
|
||||
}
|
||||
|
||||
void Document::set_link_color(Color color)
|
||||
{
|
||||
m_link_color = color;
|
||||
}
|
||||
|
||||
void Document::set_active_link_color(Color color)
|
||||
{
|
||||
m_active_link_color = color;
|
||||
}
|
||||
|
||||
void Document::set_visited_link_color(Color color)
|
||||
{
|
||||
m_visited_link_color = color;
|
||||
}
|
||||
|
||||
const Layout::InitialContainingBlockBox* Document::layout_node() const
|
||||
{
|
||||
return static_cast<const Layout::InitialContainingBlockBox*>(Node::layout_node());
|
||||
}
|
||||
|
||||
Layout::InitialContainingBlockBox* Document::layout_node()
|
||||
{
|
||||
return static_cast<Layout::InitialContainingBlockBox*>(Node::layout_node());
|
||||
}
|
||||
|
||||
void Document::set_inspected_node(Node* node)
|
||||
{
|
||||
if (m_inspected_node == node)
|
||||
return;
|
||||
|
||||
if (m_inspected_node && m_inspected_node->layout_node())
|
||||
m_inspected_node->layout_node()->set_needs_display();
|
||||
|
||||
m_inspected_node = node;
|
||||
|
||||
if (m_inspected_node && m_inspected_node->layout_node())
|
||||
m_inspected_node->layout_node()->set_needs_display();
|
||||
}
|
||||
|
||||
void Document::set_hovered_node(Node* node)
|
||||
{
|
||||
if (m_hovered_node == node)
|
||||
return;
|
||||
|
||||
RefPtr<Node> old_hovered_node = move(m_hovered_node);
|
||||
m_hovered_node = node;
|
||||
|
||||
invalidate_style();
|
||||
}
|
||||
|
||||
NonnullRefPtrVector<Element> Document::get_elements_by_name(const String& name) const
|
||||
{
|
||||
NonnullRefPtrVector<Element> elements;
|
||||
for_each_in_subtree_of_type<Element>([&](auto& element) {
|
||||
if (element.attribute(HTML::AttributeNames::name) == name)
|
||||
elements.append(element);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return elements;
|
||||
}
|
||||
|
||||
NonnullRefPtrVector<Element> Document::get_elements_by_tag_name(const FlyString& tag_name) const
|
||||
{
|
||||
NonnullRefPtrVector<Element> elements;
|
||||
for_each_in_subtree_of_type<Element>([&](auto& element) {
|
||||
if (element.local_name() == tag_name)
|
||||
elements.append(element);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return elements;
|
||||
}
|
||||
|
||||
NonnullRefPtrVector<Element> Document::get_elements_by_class_name(const FlyString& class_name) const
|
||||
{
|
||||
NonnullRefPtrVector<Element> elements;
|
||||
for_each_in_subtree_of_type<Element>([&](auto& element) {
|
||||
if (element.has_class(class_name))
|
||||
elements.append(element);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return elements;
|
||||
}
|
||||
|
||||
Color Document::link_color() const
|
||||
{
|
||||
if (m_link_color.has_value())
|
||||
return m_link_color.value();
|
||||
if (!page())
|
||||
return Color::Blue;
|
||||
return page()->palette().link();
|
||||
}
|
||||
|
||||
Color Document::active_link_color() const
|
||||
{
|
||||
if (m_active_link_color.has_value())
|
||||
return m_active_link_color.value();
|
||||
if (!page())
|
||||
return Color::Red;
|
||||
return page()->palette().active_link();
|
||||
}
|
||||
|
||||
Color Document::visited_link_color() const
|
||||
{
|
||||
if (m_visited_link_color.has_value())
|
||||
return m_visited_link_color.value();
|
||||
if (!page())
|
||||
return Color::Magenta;
|
||||
return page()->palette().visited_link();
|
||||
}
|
||||
|
||||
static JS::VM& main_thread_vm()
|
||||
{
|
||||
static RefPtr<JS::VM> vm;
|
||||
if (!vm) {
|
||||
vm = JS::VM::create();
|
||||
vm->set_should_log_exceptions(true);
|
||||
}
|
||||
return *vm;
|
||||
}
|
||||
|
||||
JS::Interpreter& Document::interpreter()
|
||||
{
|
||||
if (!m_interpreter)
|
||||
m_interpreter = JS::Interpreter::create<Bindings::WindowObject>(main_thread_vm(), *m_window);
|
||||
return *m_interpreter;
|
||||
}
|
||||
|
||||
JS::Value Document::run_javascript(const StringView& source)
|
||||
{
|
||||
auto parser = JS::Parser(JS::Lexer(source));
|
||||
auto program = parser.parse_program();
|
||||
if (parser.has_errors()) {
|
||||
parser.print_errors();
|
||||
return JS::js_undefined();
|
||||
}
|
||||
auto& interpreter = document().interpreter();
|
||||
auto result = interpreter.run(interpreter.global_object(), *program);
|
||||
if (interpreter.exception())
|
||||
interpreter.vm().clear_exception();
|
||||
return result;
|
||||
}
|
||||
|
||||
NonnullRefPtr<Element> Document::create_element(const String& tag_name)
|
||||
{
|
||||
// FIXME: Let namespace be the HTML namespace, if this is an HTML document or this’s content type is "application/xhtml+xml", and null otherwise.
|
||||
return DOM::create_element(*this, tag_name, Namespace::HTML);
|
||||
}
|
||||
|
||||
NonnullRefPtr<DocumentFragment> Document::create_document_fragment()
|
||||
{
|
||||
return adopt(*new DocumentFragment(*this));
|
||||
}
|
||||
|
||||
NonnullRefPtr<Text> Document::create_text_node(const String& data)
|
||||
{
|
||||
return adopt(*new Text(*this, data));
|
||||
}
|
||||
|
||||
NonnullRefPtr<Comment> Document::create_comment(const String& data)
|
||||
{
|
||||
return adopt(*new Comment(*this, data));
|
||||
}
|
||||
|
||||
void Document::set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement* script)
|
||||
{
|
||||
m_pending_parsing_blocking_script = script;
|
||||
}
|
||||
|
||||
NonnullRefPtr<HTML::HTMLScriptElement> Document::take_pending_parsing_blocking_script(Badge<HTML::HTMLDocumentParser>)
|
||||
{
|
||||
return m_pending_parsing_blocking_script.release_nonnull();
|
||||
}
|
||||
|
||||
void Document::add_script_to_execute_when_parsing_has_finished(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement& script)
|
||||
{
|
||||
m_scripts_to_execute_when_parsing_has_finished.append(script);
|
||||
}
|
||||
|
||||
NonnullRefPtrVector<HTML::HTMLScriptElement> Document::take_scripts_to_execute_when_parsing_has_finished(Badge<HTML::HTMLDocumentParser>)
|
||||
{
|
||||
return move(m_scripts_to_execute_when_parsing_has_finished);
|
||||
}
|
||||
|
||||
void Document::add_script_to_execute_as_soon_as_possible(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement& script)
|
||||
{
|
||||
m_scripts_to_execute_as_soon_as_possible.append(script);
|
||||
}
|
||||
|
||||
NonnullRefPtrVector<HTML::HTMLScriptElement> Document::take_scripts_to_execute_as_soon_as_possible(Badge<HTML::HTMLDocumentParser>)
|
||||
{
|
||||
return move(m_scripts_to_execute_as_soon_as_possible);
|
||||
}
|
||||
|
||||
void Document::adopt_node(Node& subtree_root)
|
||||
{
|
||||
subtree_root.for_each_in_subtree([&](auto& node) {
|
||||
node.set_document({}, *this);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
const DocumentType* Document::doctype() const
|
||||
{
|
||||
return first_child_of_type<DocumentType>();
|
||||
}
|
||||
|
||||
const String& Document::compat_mode() const
|
||||
{
|
||||
static String back_compat = "BackCompat";
|
||||
static String css1_compat = "CSS1Compat";
|
||||
|
||||
if (m_quirks_mode == QuirksMode::Yes)
|
||||
return back_compat;
|
||||
|
||||
return css1_compat;
|
||||
}
|
||||
|
||||
bool Document::is_editable() const
|
||||
{
|
||||
return m_editable;
|
||||
}
|
||||
|
||||
void Document::set_focused_element(Element* element)
|
||||
{
|
||||
if (m_focused_element == element)
|
||||
return;
|
||||
|
||||
m_focused_element = element;
|
||||
|
||||
if (m_layout_root)
|
||||
m_layout_root->set_needs_display();
|
||||
}
|
||||
|
||||
void Document::set_ready_state(const String& ready_state)
|
||||
{
|
||||
m_ready_state = ready_state;
|
||||
dispatch_event(Event::create(HTML::EventNames::readystatechange));
|
||||
}
|
||||
|
||||
Page* Document::page()
|
||||
{
|
||||
return m_frame ? m_frame->page() : nullptr;
|
||||
}
|
||||
|
||||
const Page* Document::page() const
|
||||
{
|
||||
return m_frame ? m_frame->page() : nullptr;
|
||||
}
|
||||
|
||||
EventTarget* Document::get_parent(const Event& event)
|
||||
{
|
||||
if (event.type() == HTML::EventNames::load)
|
||||
return nullptr;
|
||||
|
||||
return &window();
|
||||
}
|
||||
|
||||
void Document::completely_finish_loading()
|
||||
{
|
||||
// FIXME: This needs to handle iframes.
|
||||
dispatch_event(DOM::Event::create(HTML::EventNames::load));
|
||||
}
|
||||
|
||||
}
|
||||
295
Userland/Libraries/LibWeb/DOM/Document.h
Normal file
295
Userland/Libraries/LibWeb/DOM/Document.h
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/Function.h>
|
||||
#include <AK/NonnullRefPtrVector.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/URL.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <LibCore/Forward.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibWeb/Bindings/ScriptExecutionContext.h>
|
||||
#include <LibWeb/CSS/StyleResolver.h>
|
||||
#include <LibWeb/CSS/StyleSheet.h>
|
||||
#include <LibWeb/CSS/StyleSheetList.h>
|
||||
#include <LibWeb/DOM/DOMImplementation.h>
|
||||
#include <LibWeb/DOM/NonElementParentNode.h>
|
||||
#include <LibWeb/DOM/ParentNode.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
enum class QuirksMode {
|
||||
No,
|
||||
Limited,
|
||||
Yes
|
||||
};
|
||||
|
||||
class Document
|
||||
: public ParentNode
|
||||
, public NonElementParentNode<Document>
|
||||
, public Bindings::ScriptExecutionContext {
|
||||
public:
|
||||
using WrapperType = Bindings::DocumentWrapper;
|
||||
|
||||
static NonnullRefPtr<Document> create(const URL& url = "about:blank") { return adopt(*new Document(url)); }
|
||||
virtual ~Document() override;
|
||||
|
||||
bool should_invalidate_styles_on_attribute_changes() const { return m_should_invalidate_styles_on_attribute_changes; }
|
||||
void set_should_invalidate_styles_on_attribute_changes(bool b) { m_should_invalidate_styles_on_attribute_changes = b; }
|
||||
|
||||
void set_url(const URL& url) { m_url = url; }
|
||||
URL url() const { return m_url; }
|
||||
|
||||
Origin origin() const;
|
||||
void set_origin(const Origin& origin);
|
||||
|
||||
bool is_scripting_enabled() const { return true; }
|
||||
|
||||
URL complete_url(const String&) const;
|
||||
|
||||
CSS::StyleResolver& style_resolver() { return *m_style_resolver; }
|
||||
const CSS::StyleResolver& style_resolver() const { return *m_style_resolver; }
|
||||
|
||||
CSS::StyleSheetList& style_sheets() { return *m_style_sheets; }
|
||||
const CSS::StyleSheetList& style_sheets() const { return *m_style_sheets; }
|
||||
|
||||
virtual FlyString node_name() const override { return "#document"; }
|
||||
|
||||
void set_hovered_node(Node*);
|
||||
Node* hovered_node() { return m_hovered_node; }
|
||||
const Node* hovered_node() const { return m_hovered_node; }
|
||||
|
||||
void set_inspected_node(Node*);
|
||||
Node* inspected_node() { return m_inspected_node; }
|
||||
const Node* inspected_node() const { return m_inspected_node; }
|
||||
|
||||
const Element* document_element() const;
|
||||
const HTML::HTMLHtmlElement* html_element() const;
|
||||
const HTML::HTMLHeadElement* head() const;
|
||||
const HTML::HTMLElement* body() const;
|
||||
void set_body(HTML::HTMLElement& new_body);
|
||||
|
||||
String title() const;
|
||||
void set_title(const String&);
|
||||
|
||||
void attach_to_frame(Badge<Frame>, Frame&);
|
||||
void detach_from_frame(Badge<Frame>, Frame&);
|
||||
|
||||
Frame* frame() { return m_frame.ptr(); }
|
||||
const Frame* frame() const { return m_frame.ptr(); }
|
||||
|
||||
Page* page();
|
||||
const Page* page() const;
|
||||
|
||||
Color background_color(const Gfx::Palette&) const;
|
||||
RefPtr<Gfx::Bitmap> background_image() const;
|
||||
|
||||
Color link_color() const;
|
||||
void set_link_color(Color);
|
||||
|
||||
Color active_link_color() const;
|
||||
void set_active_link_color(Color);
|
||||
|
||||
Color visited_link_color() const;
|
||||
void set_visited_link_color(Color);
|
||||
|
||||
void force_layout();
|
||||
void invalidate_layout();
|
||||
|
||||
void update_style();
|
||||
void update_layout();
|
||||
|
||||
virtual bool is_child_allowed(const Node&) const override;
|
||||
|
||||
const Layout::InitialContainingBlockBox* layout_node() const;
|
||||
Layout::InitialContainingBlockBox* layout_node();
|
||||
|
||||
void schedule_style_update();
|
||||
void schedule_forced_layout();
|
||||
|
||||
NonnullRefPtrVector<Element> get_elements_by_name(const String&) const;
|
||||
NonnullRefPtrVector<Element> get_elements_by_tag_name(const FlyString&) const;
|
||||
NonnullRefPtrVector<Element> get_elements_by_class_name(const FlyString&) const;
|
||||
|
||||
const String& source() const { return m_source; }
|
||||
void set_source(const String& source) { m_source = source; }
|
||||
|
||||
virtual JS::Interpreter& interpreter() override;
|
||||
|
||||
JS::Value run_javascript(const StringView&);
|
||||
|
||||
NonnullRefPtr<Element> create_element(const String& tag_name);
|
||||
NonnullRefPtr<DocumentFragment> create_document_fragment();
|
||||
NonnullRefPtr<Text> create_text_node(const String& data);
|
||||
NonnullRefPtr<Comment> create_comment(const String& data);
|
||||
|
||||
void set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement*);
|
||||
HTML::HTMLScriptElement* pending_parsing_blocking_script() { return m_pending_parsing_blocking_script; }
|
||||
NonnullRefPtr<HTML::HTMLScriptElement> take_pending_parsing_blocking_script(Badge<HTML::HTMLDocumentParser>);
|
||||
|
||||
void add_script_to_execute_when_parsing_has_finished(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement&);
|
||||
NonnullRefPtrVector<HTML::HTMLScriptElement> take_scripts_to_execute_when_parsing_has_finished(Badge<HTML::HTMLDocumentParser>);
|
||||
|
||||
void add_script_to_execute_as_soon_as_possible(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement&);
|
||||
NonnullRefPtrVector<HTML::HTMLScriptElement> take_scripts_to_execute_as_soon_as_possible(Badge<HTML::HTMLDocumentParser>);
|
||||
|
||||
QuirksMode mode() const { return m_quirks_mode; }
|
||||
bool in_quirks_mode() const { return m_quirks_mode == QuirksMode::Yes; }
|
||||
void set_quirks_mode(QuirksMode mode) { m_quirks_mode = mode; }
|
||||
|
||||
void adopt_node(Node&);
|
||||
|
||||
const DocumentType* doctype() const;
|
||||
const String& compat_mode() const;
|
||||
|
||||
void set_editable(bool editable) { m_editable = editable; }
|
||||
virtual bool is_editable() const final;
|
||||
|
||||
Element* focused_element() { return m_focused_element; }
|
||||
const Element* focused_element() const { return m_focused_element; }
|
||||
|
||||
void set_focused_element(Element*);
|
||||
|
||||
bool created_for_appropriate_template_contents() const { return m_created_for_appropriate_template_contents; }
|
||||
void set_created_for_appropriate_template_contents(bool value) { m_created_for_appropriate_template_contents = value; }
|
||||
|
||||
Document* associated_inert_template_document() { return m_associated_inert_template_document; }
|
||||
const Document* associated_inert_template_document() const { return m_associated_inert_template_document; }
|
||||
void set_associated_inert_template_document(Document& document) { m_associated_inert_template_document = document; }
|
||||
|
||||
const String& ready_state() const { return m_ready_state; }
|
||||
void set_ready_state(const String&);
|
||||
|
||||
void ref_from_node(Badge<Node>)
|
||||
{
|
||||
increment_referencing_node_count();
|
||||
}
|
||||
|
||||
void unref_from_node(Badge<Node>)
|
||||
{
|
||||
decrement_referencing_node_count();
|
||||
}
|
||||
|
||||
void removed_last_ref();
|
||||
|
||||
Window& window() { return *m_window; }
|
||||
|
||||
const String& content_type() const { return m_content_type; }
|
||||
void set_content_type(const String& content_type) { m_content_type = content_type; }
|
||||
|
||||
const String& encoding() const { return m_encoding; }
|
||||
void set_encoding(const String& encoding) { m_encoding = encoding; }
|
||||
|
||||
// NOTE: These are intended for the JS bindings
|
||||
const String& character_set() const { return encoding(); }
|
||||
const String& charset() const { return encoding(); }
|
||||
const String& input_encoding() const { return encoding(); }
|
||||
|
||||
bool ready_for_post_load_tasks() const { return m_ready_for_post_load_tasks; }
|
||||
void set_ready_for_post_load_tasks(bool ready) { m_ready_for_post_load_tasks = ready; }
|
||||
|
||||
void completely_finish_loading();
|
||||
|
||||
const NonnullRefPtr<DOMImplementation> implementation() const { return m_implementation; }
|
||||
|
||||
virtual EventTarget* get_parent(const Event&) override;
|
||||
|
||||
private:
|
||||
explicit Document(const URL&);
|
||||
|
||||
virtual RefPtr<Layout::Node> create_layout_node() override;
|
||||
|
||||
void tear_down_layout_tree();
|
||||
|
||||
void increment_referencing_node_count()
|
||||
{
|
||||
ASSERT(!m_deletion_has_begun);
|
||||
++m_referencing_node_count;
|
||||
}
|
||||
|
||||
void decrement_referencing_node_count()
|
||||
{
|
||||
ASSERT(!m_deletion_has_begun);
|
||||
ASSERT(m_referencing_node_count);
|
||||
--m_referencing_node_count;
|
||||
if (!m_referencing_node_count && !ref_count()) {
|
||||
m_deletion_has_begun = true;
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned m_referencing_node_count { 0 };
|
||||
|
||||
OwnPtr<CSS::StyleResolver> m_style_resolver;
|
||||
RefPtr<CSS::StyleSheetList> m_style_sheets;
|
||||
RefPtr<Node> m_hovered_node;
|
||||
RefPtr<Node> m_inspected_node;
|
||||
WeakPtr<Frame> m_frame;
|
||||
URL m_url;
|
||||
|
||||
RefPtr<Window> m_window;
|
||||
|
||||
RefPtr<Layout::InitialContainingBlockBox> m_layout_root;
|
||||
|
||||
Optional<Color> m_link_color;
|
||||
Optional<Color> m_active_link_color;
|
||||
Optional<Color> m_visited_link_color;
|
||||
|
||||
RefPtr<Core::Timer> m_style_update_timer;
|
||||
RefPtr<Core::Timer> m_forced_layout_timer;
|
||||
|
||||
String m_source;
|
||||
|
||||
OwnPtr<JS::Interpreter> m_interpreter;
|
||||
|
||||
RefPtr<HTML::HTMLScriptElement> m_pending_parsing_blocking_script;
|
||||
NonnullRefPtrVector<HTML::HTMLScriptElement> m_scripts_to_execute_when_parsing_has_finished;
|
||||
NonnullRefPtrVector<HTML::HTMLScriptElement> m_scripts_to_execute_as_soon_as_possible;
|
||||
|
||||
QuirksMode m_quirks_mode { QuirksMode::No };
|
||||
bool m_editable { false };
|
||||
|
||||
WeakPtr<Element> m_focused_element;
|
||||
|
||||
bool m_created_for_appropriate_template_contents { false };
|
||||
RefPtr<Document> m_associated_inert_template_document;
|
||||
|
||||
String m_ready_state { "loading" };
|
||||
String m_content_type { "application/xml" };
|
||||
String m_encoding { "UTF-8" };
|
||||
|
||||
bool m_ready_for_post_load_tasks { false };
|
||||
|
||||
NonnullRefPtr<DOMImplementation> m_implementation;
|
||||
|
||||
bool m_should_invalidate_styles_on_attribute_changes { true };
|
||||
};
|
||||
|
||||
}
|
||||
37
Userland/Libraries/LibWeb/DOM/Document.idl
Normal file
37
Userland/Libraries/LibWeb/DOM/Document.idl
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
interface Document : Node {
|
||||
|
||||
readonly attribute DOMImplementation implementation;
|
||||
|
||||
readonly attribute DOMString characterSet;
|
||||
readonly attribute DOMString charset;
|
||||
readonly attribute DOMString inputEncoding;
|
||||
readonly attribute DOMString contentType;
|
||||
|
||||
Element? getElementById(DOMString id);
|
||||
ArrayFromVector getElementsByName(DOMString name);
|
||||
ArrayFromVector getElementsByTagName(DOMString tagName);
|
||||
ArrayFromVector getElementsByClassName(DOMString className);
|
||||
|
||||
readonly attribute Element? firstElementChild;
|
||||
readonly attribute Element? lastElementChild;
|
||||
|
||||
Element? querySelector(DOMString selectors);
|
||||
ArrayFromVector querySelectorAll(DOMString selectors);
|
||||
|
||||
Element createElement(DOMString tagName);
|
||||
DocumentFragment createDocumentFragment();
|
||||
Text createTextNode(DOMString data);
|
||||
Comment createComment(DOMString data);
|
||||
|
||||
readonly attribute DOMString compatMode;
|
||||
readonly attribute DocumentType? doctype;
|
||||
|
||||
readonly attribute Element? documentElement;
|
||||
attribute HTMLElement? body;
|
||||
readonly attribute HTMLHeadElement? head;
|
||||
|
||||
readonly attribute DOMString readyState;
|
||||
|
||||
attribute DOMString title;
|
||||
|
||||
};
|
||||
40
Userland/Libraries/LibWeb/DOM/DocumentFragment.cpp
Normal file
40
Userland/Libraries/LibWeb/DOM/DocumentFragment.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Luke Wilde <luke.wilde@live.co.uk>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/DOM/DocumentFragment.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
DocumentFragment::DocumentFragment(Document& document)
|
||||
: ParentNode(document, NodeType::DOCUMENT_FRAGMENT_NODE)
|
||||
{
|
||||
}
|
||||
|
||||
DocumentFragment::~DocumentFragment()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
56
Userland/Libraries/LibWeb/DOM/DocumentFragment.h
Normal file
56
Userland/Libraries/LibWeb/DOM/DocumentFragment.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/DOM/NonElementParentNode.h>
|
||||
#include <LibWeb/DOM/ParentNode.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class DocumentFragment
|
||||
: public ParentNode
|
||||
, public NonElementParentNode<DocumentFragment> {
|
||||
public:
|
||||
using WrapperType = Bindings::DocumentFragmentWrapper;
|
||||
|
||||
explicit DocumentFragment(Document& document);
|
||||
virtual ~DocumentFragment() override;
|
||||
|
||||
virtual FlyString node_name() const override { return "#document-fragment"; }
|
||||
|
||||
RefPtr<Element> host() { return m_host; }
|
||||
const RefPtr<Element> host() const { return m_host; }
|
||||
|
||||
void set_host(Element& host) { m_host = host; }
|
||||
|
||||
private:
|
||||
RefPtr<Element> m_host;
|
||||
};
|
||||
|
||||
}
|
||||
11
Userland/Libraries/LibWeb/DOM/DocumentFragment.idl
Normal file
11
Userland/Libraries/LibWeb/DOM/DocumentFragment.idl
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
interface DocumentFragment : Node {
|
||||
|
||||
Element? getElementById(DOMString id);
|
||||
|
||||
readonly attribute Element? firstElementChild;
|
||||
readonly attribute Element? lastElementChild;
|
||||
|
||||
Element? querySelector(DOMString selectors);
|
||||
ArrayFromVector querySelectorAll(DOMString selectors);
|
||||
|
||||
};
|
||||
40
Userland/Libraries/LibWeb/DOM/DocumentType.cpp
Normal file
40
Userland/Libraries/LibWeb/DOM/DocumentType.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/DOM/DocumentType.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
DocumentType::DocumentType(Document& document)
|
||||
: Node(document, NodeType::DOCUMENT_TYPE_NODE)
|
||||
{
|
||||
}
|
||||
|
||||
DocumentType::~DocumentType()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
58
Userland/Libraries/LibWeb/DOM/DocumentType.h
Normal file
58
Userland/Libraries/LibWeb/DOM/DocumentType.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class DocumentType final : public Node {
|
||||
public:
|
||||
using WrapperType = Bindings::DocumentTypeWrapper;
|
||||
|
||||
explicit DocumentType(Document&);
|
||||
virtual ~DocumentType() override;
|
||||
|
||||
virtual FlyString node_name() const override { return "#doctype"; }
|
||||
|
||||
const String& name() const { return m_name; }
|
||||
void set_name(const String& name) { m_name = name; }
|
||||
|
||||
const String& public_id() const { return m_public_id; }
|
||||
void set_public_id(const String& public_id) { m_public_id = public_id; }
|
||||
|
||||
const String& system_id() const { return m_system_id; }
|
||||
void set_system_id(const String& system_id) { m_system_id = system_id; }
|
||||
|
||||
private:
|
||||
String m_name;
|
||||
String m_public_id;
|
||||
String m_system_id;
|
||||
};
|
||||
|
||||
}
|
||||
7
Userland/Libraries/LibWeb/DOM/DocumentType.idl
Normal file
7
Userland/Libraries/LibWeb/DOM/DocumentType.idl
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
interface DocumentType : Node {
|
||||
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute DOMString publicId;
|
||||
readonly attribute DOMString systemId;
|
||||
|
||||
};
|
||||
335
Userland/Libraries/LibWeb/DOM/Element.cpp
Normal file
335
Userland/Libraries/LibWeb/DOM/Element.cpp
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/StringBuilder.h>
|
||||
#include <LibWeb/CSS/Length.h>
|
||||
#include <LibWeb/CSS/Parser/CSSParser.h>
|
||||
#include <LibWeb/CSS/PropertyID.h>
|
||||
#include <LibWeb/CSS/StyleInvalidator.h>
|
||||
#include <LibWeb/CSS/StyleResolver.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/DocumentFragment.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/DOM/Text.h>
|
||||
#include <LibWeb/Dump.h>
|
||||
#include <LibWeb/HTML/Parser/HTMLDocumentParser.h>
|
||||
#include <LibWeb/Layout/BlockBox.h>
|
||||
#include <LibWeb/Layout/InlineNode.h>
|
||||
#include <LibWeb/Layout/ListItemBox.h>
|
||||
#include <LibWeb/Layout/TableBox.h>
|
||||
#include <LibWeb/Layout/TableCellBox.h>
|
||||
#include <LibWeb/Layout/TableRowBox.h>
|
||||
#include <LibWeb/Layout/TableRowGroupBox.h>
|
||||
#include <LibWeb/Layout/TreeBuilder.h>
|
||||
#include <LibWeb/Layout/WidgetBox.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
Element::Element(Document& document, const QualifiedName& qualified_name)
|
||||
: ParentNode(document, NodeType::ELEMENT_NODE)
|
||||
, m_qualified_name(qualified_name)
|
||||
{
|
||||
}
|
||||
|
||||
Element::~Element()
|
||||
{
|
||||
}
|
||||
|
||||
Attribute* Element::find_attribute(const FlyString& name)
|
||||
{
|
||||
for (auto& attribute : m_attributes) {
|
||||
if (attribute.name() == name)
|
||||
return &attribute;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Attribute* Element::find_attribute(const FlyString& name) const
|
||||
{
|
||||
for (auto& attribute : m_attributes) {
|
||||
if (attribute.name() == name)
|
||||
return &attribute;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
String Element::attribute(const FlyString& name) const
|
||||
{
|
||||
if (auto* attribute = find_attribute(name))
|
||||
return attribute->value();
|
||||
return {};
|
||||
}
|
||||
|
||||
void Element::set_attribute(const FlyString& name, const String& value)
|
||||
{
|
||||
CSS::StyleInvalidator style_invalidator(document());
|
||||
|
||||
if (auto* attribute = find_attribute(name))
|
||||
attribute->set_value(value);
|
||||
else
|
||||
m_attributes.empend(name, value);
|
||||
|
||||
parse_attribute(name, value);
|
||||
}
|
||||
|
||||
void Element::remove_attribute(const FlyString& name)
|
||||
{
|
||||
CSS::StyleInvalidator style_invalidator(document());
|
||||
|
||||
m_attributes.remove_first_matching([&](auto& attribute) { return attribute.name() == name; });
|
||||
}
|
||||
|
||||
bool Element::has_class(const FlyString& class_name) const
|
||||
{
|
||||
for (auto& class_ : m_classes) {
|
||||
if (class_ == class_name)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<Layout::Node> Element::create_layout_node()
|
||||
{
|
||||
auto style = document().style_resolver().resolve_style(*this);
|
||||
const_cast<Element&>(*this).m_specified_css_values = style;
|
||||
auto display = style->display();
|
||||
|
||||
if (display == CSS::Display::None)
|
||||
return nullptr;
|
||||
|
||||
if (local_name() == "noscript" && document().is_scripting_enabled())
|
||||
return nullptr;
|
||||
|
||||
if (display == CSS::Display::Block)
|
||||
return adopt(*new Layout::BlockBox(document(), this, move(style)));
|
||||
|
||||
if (display == CSS::Display::Inline) {
|
||||
if (style->float_().value_or(CSS::Float::None) != CSS::Float::None)
|
||||
return adopt(*new Layout::BlockBox(document(), this, move(style)));
|
||||
return adopt(*new Layout::InlineNode(document(), *this, move(style)));
|
||||
}
|
||||
|
||||
if (display == CSS::Display::ListItem)
|
||||
return adopt(*new Layout::ListItemBox(document(), *this, move(style)));
|
||||
if (display == CSS::Display::Table)
|
||||
return adopt(*new Layout::TableBox(document(), this, move(style)));
|
||||
if (display == CSS::Display::TableRow)
|
||||
return adopt(*new Layout::TableRowBox(document(), this, move(style)));
|
||||
if (display == CSS::Display::TableCell)
|
||||
return adopt(*new Layout::TableCellBox(document(), this, move(style)));
|
||||
if (display == CSS::Display::TableRowGroup || display == CSS::Display::TableHeaderGroup || display == CSS::Display::TableFooterGroup)
|
||||
return adopt(*new Layout::TableRowGroupBox(document(), *this, move(style)));
|
||||
if (display == CSS::Display::InlineBlock) {
|
||||
auto inline_block = adopt(*new Layout::BlockBox(document(), this, move(style)));
|
||||
inline_block->set_inline(true);
|
||||
return inline_block;
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void Element::parse_attribute(const FlyString& name, const String& value)
|
||||
{
|
||||
if (name == HTML::AttributeNames::class_) {
|
||||
auto new_classes = value.split_view(' ');
|
||||
m_classes.clear();
|
||||
m_classes.ensure_capacity(new_classes.size());
|
||||
for (auto& new_class : new_classes) {
|
||||
m_classes.unchecked_append(new_class);
|
||||
}
|
||||
} else if (name == HTML::AttributeNames::style) {
|
||||
m_inline_style = parse_css_declaration(CSS::ParsingContext(document()), value);
|
||||
set_needs_style_update(true);
|
||||
}
|
||||
}
|
||||
|
||||
enum class StyleDifference {
|
||||
None,
|
||||
NeedsRepaint,
|
||||
NeedsRelayout,
|
||||
};
|
||||
|
||||
static StyleDifference compute_style_difference(const CSS::StyleProperties& old_style, const CSS::StyleProperties& new_style, const Document& document)
|
||||
{
|
||||
if (old_style == new_style)
|
||||
return StyleDifference::None;
|
||||
|
||||
bool needs_repaint = false;
|
||||
bool needs_relayout = false;
|
||||
|
||||
if (new_style.display() != old_style.display())
|
||||
needs_relayout = true;
|
||||
|
||||
if (new_style.color_or_fallback(CSS::PropertyID::Color, document, Color::Black) != old_style.color_or_fallback(CSS::PropertyID::Color, document, Color::Black))
|
||||
needs_repaint = true;
|
||||
else if (new_style.color_or_fallback(CSS::PropertyID::BackgroundColor, document, Color::Black) != old_style.color_or_fallback(CSS::PropertyID::BackgroundColor, document, Color::Black))
|
||||
needs_repaint = true;
|
||||
|
||||
if (needs_relayout)
|
||||
return StyleDifference::NeedsRelayout;
|
||||
if (needs_repaint)
|
||||
return StyleDifference::NeedsRepaint;
|
||||
return StyleDifference::None;
|
||||
}
|
||||
|
||||
void Element::recompute_style()
|
||||
{
|
||||
set_needs_style_update(false);
|
||||
ASSERT(parent());
|
||||
auto old_specified_css_values = m_specified_css_values;
|
||||
auto new_specified_css_values = document().style_resolver().resolve_style(*this);
|
||||
m_specified_css_values = new_specified_css_values;
|
||||
if (!layout_node()) {
|
||||
if (new_specified_css_values->display() == CSS::Display::None)
|
||||
return;
|
||||
// We need a new layout tree here!
|
||||
Layout::TreeBuilder tree_builder;
|
||||
tree_builder.build(*this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't bother with style on widgets. NATIVE LOOK & FEEL BABY!
|
||||
if (is<Layout::WidgetBox>(layout_node()))
|
||||
return;
|
||||
|
||||
auto diff = StyleDifference::NeedsRelayout;
|
||||
if (old_specified_css_values)
|
||||
diff = compute_style_difference(*old_specified_css_values, *new_specified_css_values, document());
|
||||
if (diff == StyleDifference::None)
|
||||
return;
|
||||
layout_node()->apply_style(*new_specified_css_values);
|
||||
if (diff == StyleDifference::NeedsRelayout) {
|
||||
document().schedule_forced_layout();
|
||||
return;
|
||||
}
|
||||
if (diff == StyleDifference::NeedsRepaint) {
|
||||
layout_node()->set_needs_display();
|
||||
}
|
||||
}
|
||||
|
||||
NonnullRefPtr<CSS::StyleProperties> Element::computed_style()
|
||||
{
|
||||
// FIXME: This implementation is not doing anything it's supposed to.
|
||||
auto properties = m_specified_css_values->clone();
|
||||
if (layout_node() && layout_node()->has_style()) {
|
||||
CSS::PropertyID box_model_metrics[] = {
|
||||
CSS::PropertyID::MarginTop,
|
||||
CSS::PropertyID::MarginBottom,
|
||||
CSS::PropertyID::MarginLeft,
|
||||
CSS::PropertyID::MarginRight,
|
||||
CSS::PropertyID::PaddingTop,
|
||||
CSS::PropertyID::PaddingBottom,
|
||||
CSS::PropertyID::PaddingLeft,
|
||||
CSS::PropertyID::PaddingRight,
|
||||
CSS::PropertyID::BorderTopWidth,
|
||||
CSS::PropertyID::BorderBottomWidth,
|
||||
CSS::PropertyID::BorderLeftWidth,
|
||||
CSS::PropertyID::BorderRightWidth,
|
||||
};
|
||||
for (CSS::PropertyID id : box_model_metrics) {
|
||||
auto prop = m_specified_css_values->property(id);
|
||||
if (prop.has_value())
|
||||
properties->set_property(id, prop.value());
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
void Element::set_inner_html(StringView markup)
|
||||
{
|
||||
auto new_children = HTML::HTMLDocumentParser::parse_html_fragment(*this, markup);
|
||||
remove_all_children();
|
||||
while (!new_children.is_empty()) {
|
||||
append_child(new_children.take_first());
|
||||
}
|
||||
|
||||
set_needs_style_update(true);
|
||||
document().invalidate_layout();
|
||||
}
|
||||
|
||||
String Element::inner_html() const
|
||||
{
|
||||
auto escape_string = [](const StringView& string, bool attribute_mode) -> String {
|
||||
// https://html.spec.whatwg.org/multipage/parsing.html#escapingString
|
||||
StringBuilder builder;
|
||||
for (auto& ch : string) {
|
||||
if (ch == '&')
|
||||
builder.append("&");
|
||||
// FIXME: also replace U+00A0 NO-BREAK SPACE with
|
||||
else if (ch == '"' && attribute_mode)
|
||||
builder.append(""");
|
||||
else if (ch == '<' && !attribute_mode)
|
||||
builder.append("<");
|
||||
else if (ch == '>' && !attribute_mode)
|
||||
builder.append(">");
|
||||
else
|
||||
builder.append(ch);
|
||||
}
|
||||
return builder.to_string();
|
||||
};
|
||||
|
||||
StringBuilder builder;
|
||||
|
||||
Function<void(const Node&)> recurse = [&](auto& node) {
|
||||
for (auto* child = node.first_child(); child; child = child->next_sibling()) {
|
||||
if (child->is_element()) {
|
||||
auto& element = downcast<Element>(*child);
|
||||
builder.append('<');
|
||||
builder.append(element.local_name());
|
||||
element.for_each_attribute([&](auto& name, auto& value) {
|
||||
builder.append(' ');
|
||||
builder.append(name);
|
||||
builder.append('=');
|
||||
builder.append('"');
|
||||
builder.append(escape_string(value, true));
|
||||
builder.append('"');
|
||||
});
|
||||
builder.append('>');
|
||||
|
||||
recurse(*child);
|
||||
|
||||
// FIXME: This should be skipped for void elements
|
||||
builder.append("</");
|
||||
builder.append(element.local_name());
|
||||
builder.append('>');
|
||||
}
|
||||
if (child->is_text()) {
|
||||
auto& text = downcast<Text>(*child);
|
||||
builder.append(escape_string(text.data(), false));
|
||||
}
|
||||
// FIXME: Also handle Comment, ProcessingInstruction, DocumentType
|
||||
}
|
||||
};
|
||||
recurse(*this);
|
||||
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
bool Element::is_focused() const
|
||||
{
|
||||
return document().focused_element() == this;
|
||||
}
|
||||
|
||||
}
|
||||
127
Userland/Libraries/LibWeb/DOM/Element.h
Normal file
127
Userland/Libraries/LibWeb/DOM/Element.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibWeb/DOM/Attribute.h>
|
||||
#include <LibWeb/DOM/NonDocumentTypeChildNode.h>
|
||||
#include <LibWeb/DOM/ParentNode.h>
|
||||
#include <LibWeb/HTML/AttributeNames.h>
|
||||
#include <LibWeb/HTML/TagNames.h>
|
||||
#include <LibWeb/Layout/Node.h>
|
||||
#include <LibWeb/QualifiedName.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class Element
|
||||
: public ParentNode
|
||||
, public NonDocumentTypeChildNode<Element> {
|
||||
|
||||
public:
|
||||
using WrapperType = Bindings::ElementWrapper;
|
||||
|
||||
Element(Document&, const QualifiedName& qualified_name);
|
||||
virtual ~Element() override;
|
||||
|
||||
virtual FlyString node_name() const final { return m_qualified_name.local_name(); }
|
||||
const FlyString& local_name() const { return m_qualified_name.local_name(); }
|
||||
|
||||
// NOTE: This is for the JS bindings
|
||||
const FlyString& tag_name() const { return local_name(); }
|
||||
|
||||
const FlyString& namespace_() const { return m_qualified_name.namespace_(); }
|
||||
|
||||
// NOTE: This is for the JS bindings
|
||||
const FlyString& namespace_uri() const { return namespace_(); }
|
||||
|
||||
bool has_attribute(const FlyString& name) const { return !attribute(name).is_null(); }
|
||||
bool has_attributes() const { return !m_attributes.is_empty(); }
|
||||
String attribute(const FlyString& name) const;
|
||||
String get_attribute(const FlyString& name) const { return attribute(name); }
|
||||
void set_attribute(const FlyString& name, const String& value);
|
||||
void remove_attribute(const FlyString& name);
|
||||
|
||||
template<typename Callback>
|
||||
void for_each_attribute(Callback callback) const
|
||||
{
|
||||
for (auto& attribute : m_attributes)
|
||||
callback(attribute.name(), attribute.value());
|
||||
}
|
||||
|
||||
bool has_class(const FlyString&) const;
|
||||
const Vector<FlyString>& class_names() const { return m_classes; }
|
||||
|
||||
virtual void apply_presentational_hints(CSS::StyleProperties&) const { }
|
||||
virtual void parse_attribute(const FlyString& name, const String& value);
|
||||
|
||||
void recompute_style();
|
||||
|
||||
Layout::NodeWithStyle* layout_node() { return static_cast<Layout::NodeWithStyle*>(Node::layout_node()); }
|
||||
const Layout::NodeWithStyle* layout_node() const { return static_cast<const Layout::NodeWithStyle*>(Node::layout_node()); }
|
||||
|
||||
String name() const { return attribute(HTML::AttributeNames::name); }
|
||||
|
||||
const CSS::StyleProperties* specified_css_values() const { return m_specified_css_values.ptr(); }
|
||||
NonnullRefPtr<CSS::StyleProperties> computed_style();
|
||||
|
||||
const CSS::StyleDeclaration* inline_style() const { return m_inline_style; }
|
||||
|
||||
// FIXME: innerHTML also appears on shadow roots. https://w3c.github.io/DOM-Parsing/#dom-innerhtml
|
||||
String inner_html() const;
|
||||
void set_inner_html(StringView);
|
||||
|
||||
bool is_focused() const;
|
||||
virtual bool is_focusable() const { return false; }
|
||||
|
||||
protected:
|
||||
RefPtr<Layout::Node> create_layout_node() override;
|
||||
|
||||
private:
|
||||
Attribute* find_attribute(const FlyString& name);
|
||||
const Attribute* find_attribute(const FlyString& name) const;
|
||||
|
||||
QualifiedName m_qualified_name;
|
||||
Vector<Attribute> m_attributes;
|
||||
|
||||
RefPtr<CSS::StyleDeclaration> m_inline_style;
|
||||
|
||||
RefPtr<CSS::StyleProperties> m_specified_css_values;
|
||||
|
||||
Vector<FlyString> m_classes;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace AK {
|
||||
template<>
|
||||
inline bool is<Web::DOM::Element>(const Web::DOM::Node& input)
|
||||
{
|
||||
return input.is_element();
|
||||
}
|
||||
|
||||
}
|
||||
23
Userland/Libraries/LibWeb/DOM/Element.idl
Normal file
23
Userland/Libraries/LibWeb/DOM/Element.idl
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
interface Element : Node {
|
||||
readonly attribute DOMString? namespaceURI;
|
||||
readonly attribute DOMString tagName;
|
||||
|
||||
DOMString? getAttribute(DOMString qualifiedName);
|
||||
undefined setAttribute(DOMString qualifiedName, DOMString value);
|
||||
undefined removeAttribute(DOMString qualifiedName);
|
||||
boolean hasAttribute(DOMString qualifiedName);
|
||||
boolean hasAttributes();
|
||||
|
||||
readonly attribute Element? firstElementChild;
|
||||
readonly attribute Element? lastElementChild;
|
||||
|
||||
Element? querySelector(DOMString selectors);
|
||||
ArrayFromVector querySelectorAll(DOMString selectors);
|
||||
|
||||
[LegacyNullToEmptyString] attribute DOMString innerHTML;
|
||||
[Reflect] attribute DOMString id;
|
||||
[Reflect=class] attribute DOMString className;
|
||||
|
||||
readonly attribute Element? nextElementSibling;
|
||||
readonly attribute Element? previousElementSibling;
|
||||
};
|
||||
264
Userland/Libraries/LibWeb/DOM/ElementFactory.cpp
Normal file
264
Userland/Libraries/LibWeb/DOM/ElementFactory.cpp
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020, Luke Wilde <luke.wilde@live.co.uk>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibWeb/DOM/ElementFactory.h>
|
||||
#include <LibWeb/HTML/HTMLAnchorElement.h>
|
||||
#include <LibWeb/HTML/HTMLAreaElement.h>
|
||||
#include <LibWeb/HTML/HTMLAudioElement.h>
|
||||
#include <LibWeb/HTML/HTMLBRElement.h>
|
||||
#include <LibWeb/HTML/HTMLBaseElement.h>
|
||||
#include <LibWeb/HTML/HTMLBlinkElement.h>
|
||||
#include <LibWeb/HTML/HTMLBodyElement.h>
|
||||
#include <LibWeb/HTML/HTMLButtonElement.h>
|
||||
#include <LibWeb/HTML/HTMLCanvasElement.h>
|
||||
#include <LibWeb/HTML/HTMLDListElement.h>
|
||||
#include <LibWeb/HTML/HTMLDataElement.h>
|
||||
#include <LibWeb/HTML/HTMLDataListElement.h>
|
||||
#include <LibWeb/HTML/HTMLDetailsElement.h>
|
||||
#include <LibWeb/HTML/HTMLDialogElement.h>
|
||||
#include <LibWeb/HTML/HTMLDirectoryElement.h>
|
||||
#include <LibWeb/HTML/HTMLDivElement.h>
|
||||
#include <LibWeb/HTML/HTMLEmbedElement.h>
|
||||
#include <LibWeb/HTML/HTMLFieldSetElement.h>
|
||||
#include <LibWeb/HTML/HTMLFontElement.h>
|
||||
#include <LibWeb/HTML/HTMLFormElement.h>
|
||||
#include <LibWeb/HTML/HTMLFrameElement.h>
|
||||
#include <LibWeb/HTML/HTMLFrameSetElement.h>
|
||||
#include <LibWeb/HTML/HTMLHRElement.h>
|
||||
#include <LibWeb/HTML/HTMLHeadElement.h>
|
||||
#include <LibWeb/HTML/HTMLHeadingElement.h>
|
||||
#include <LibWeb/HTML/HTMLHtmlElement.h>
|
||||
#include <LibWeb/HTML/HTMLIFrameElement.h>
|
||||
#include <LibWeb/HTML/HTMLImageElement.h>
|
||||
#include <LibWeb/HTML/HTMLInputElement.h>
|
||||
#include <LibWeb/HTML/HTMLLIElement.h>
|
||||
#include <LibWeb/HTML/HTMLLabelElement.h>
|
||||
#include <LibWeb/HTML/HTMLLegendElement.h>
|
||||
#include <LibWeb/HTML/HTMLLinkElement.h>
|
||||
#include <LibWeb/HTML/HTMLMapElement.h>
|
||||
#include <LibWeb/HTML/HTMLMarqueeElement.h>
|
||||
#include <LibWeb/HTML/HTMLMenuElement.h>
|
||||
#include <LibWeb/HTML/HTMLMetaElement.h>
|
||||
#include <LibWeb/HTML/HTMLMeterElement.h>
|
||||
#include <LibWeb/HTML/HTMLModElement.h>
|
||||
#include <LibWeb/HTML/HTMLOListElement.h>
|
||||
#include <LibWeb/HTML/HTMLObjectElement.h>
|
||||
#include <LibWeb/HTML/HTMLOptGroupElement.h>
|
||||
#include <LibWeb/HTML/HTMLOptionElement.h>
|
||||
#include <LibWeb/HTML/HTMLOutputElement.h>
|
||||
#include <LibWeb/HTML/HTMLParagraphElement.h>
|
||||
#include <LibWeb/HTML/HTMLParamElement.h>
|
||||
#include <LibWeb/HTML/HTMLPictureElement.h>
|
||||
#include <LibWeb/HTML/HTMLPreElement.h>
|
||||
#include <LibWeb/HTML/HTMLProgressElement.h>
|
||||
#include <LibWeb/HTML/HTMLQuoteElement.h>
|
||||
#include <LibWeb/HTML/HTMLScriptElement.h>
|
||||
#include <LibWeb/HTML/HTMLSelectElement.h>
|
||||
#include <LibWeb/HTML/HTMLSlotElement.h>
|
||||
#include <LibWeb/HTML/HTMLSourceElement.h>
|
||||
#include <LibWeb/HTML/HTMLSpanElement.h>
|
||||
#include <LibWeb/HTML/HTMLStyleElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableCaptionElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableCellElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableColElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableRowElement.h>
|
||||
#include <LibWeb/HTML/HTMLTableSectionElement.h>
|
||||
#include <LibWeb/HTML/HTMLTemplateElement.h>
|
||||
#include <LibWeb/HTML/HTMLTextAreaElement.h>
|
||||
#include <LibWeb/HTML/HTMLTimeElement.h>
|
||||
#include <LibWeb/HTML/HTMLTitleElement.h>
|
||||
#include <LibWeb/HTML/HTMLTrackElement.h>
|
||||
#include <LibWeb/HTML/HTMLUListElement.h>
|
||||
#include <LibWeb/HTML/HTMLUnknownElement.h>
|
||||
#include <LibWeb/HTML/HTMLVideoElement.h>
|
||||
#include <LibWeb/SVG/SVGPathElement.h>
|
||||
#include <LibWeb/SVG/SVGSVGElement.h>
|
||||
#include <LibWeb/SVG/TagNames.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
NonnullRefPtr<Element> create_element(Document& document, const FlyString& tag_name, const FlyString& namespace_)
|
||||
{
|
||||
auto lowercase_tag_name = tag_name.to_lowercase();
|
||||
// FIXME: Add prefix when we support it.
|
||||
auto qualified_name = QualifiedName(tag_name, {}, namespace_);
|
||||
if (lowercase_tag_name == HTML::TagNames::a)
|
||||
return adopt(*new HTML::HTMLAnchorElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::area)
|
||||
return adopt(*new HTML::HTMLAreaElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::audio)
|
||||
return adopt(*new HTML::HTMLAudioElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::base)
|
||||
return adopt(*new HTML::HTMLBaseElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::blink)
|
||||
return adopt(*new HTML::HTMLBlinkElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::body)
|
||||
return adopt(*new HTML::HTMLBodyElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::br)
|
||||
return adopt(*new HTML::HTMLBRElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::button)
|
||||
return adopt(*new HTML::HTMLButtonElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::canvas)
|
||||
return adopt(*new HTML::HTMLCanvasElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::data)
|
||||
return adopt(*new HTML::HTMLDataElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::datalist)
|
||||
return adopt(*new HTML::HTMLDataListElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::details)
|
||||
return adopt(*new HTML::HTMLDetailsElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::dialog)
|
||||
return adopt(*new HTML::HTMLDialogElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::dir)
|
||||
return adopt(*new HTML::HTMLDirectoryElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::div)
|
||||
return adopt(*new HTML::HTMLDivElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::dl)
|
||||
return adopt(*new HTML::HTMLDListElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::embed)
|
||||
return adopt(*new HTML::HTMLEmbedElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::fieldset)
|
||||
return adopt(*new HTML::HTMLFieldSetElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::font)
|
||||
return adopt(*new HTML::HTMLFontElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::form)
|
||||
return adopt(*new HTML::HTMLFormElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::frame)
|
||||
return adopt(*new HTML::HTMLFrameElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::frameset)
|
||||
return adopt(*new HTML::HTMLFrameSetElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::head)
|
||||
return adopt(*new HTML::HTMLHeadElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(HTML::TagNames::h1, HTML::TagNames::h2, HTML::TagNames::h3, HTML::TagNames::h4, HTML::TagNames::h5, HTML::TagNames::h6))
|
||||
return adopt(*new HTML::HTMLHeadingElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::hr)
|
||||
return adopt(*new HTML::HTMLHRElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::html)
|
||||
return adopt(*new HTML::HTMLHtmlElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::iframe)
|
||||
return adopt(*new HTML::HTMLIFrameElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::img)
|
||||
return adopt(*new HTML::HTMLImageElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::input)
|
||||
return adopt(*new HTML::HTMLInputElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::label)
|
||||
return adopt(*new HTML::HTMLLabelElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::legend)
|
||||
return adopt(*new HTML::HTMLLegendElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::li)
|
||||
return adopt(*new HTML::HTMLLIElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::link)
|
||||
return adopt(*new HTML::HTMLLinkElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::map)
|
||||
return adopt(*new HTML::HTMLMapElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::marquee)
|
||||
return adopt(*new HTML::HTMLMarqueeElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::menu)
|
||||
return adopt(*new HTML::HTMLMenuElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::meta)
|
||||
return adopt(*new HTML::HTMLMetaElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::meter)
|
||||
return adopt(*new HTML::HTMLMeterElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(HTML::TagNames::ins, HTML::TagNames::del))
|
||||
return adopt(*new HTML::HTMLModElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::object)
|
||||
return adopt(*new HTML::HTMLObjectElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::ol)
|
||||
return adopt(*new HTML::HTMLOListElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::optgroup)
|
||||
return adopt(*new HTML::HTMLOptGroupElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::option)
|
||||
return adopt(*new HTML::HTMLOptionElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::output)
|
||||
return adopt(*new HTML::HTMLOutputElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::p)
|
||||
return adopt(*new HTML::HTMLParagraphElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::param)
|
||||
return adopt(*new HTML::HTMLParamElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::picture)
|
||||
return adopt(*new HTML::HTMLPictureElement(document, qualified_name));
|
||||
// NOTE: The obsolete elements "listing" and "xmp" are explicitly mapped to HTMLPreElement in the specification.
|
||||
if (lowercase_tag_name.is_one_of(HTML::TagNames::pre, HTML::TagNames::listing, HTML::TagNames::xmp))
|
||||
return adopt(*new HTML::HTMLPreElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::progress)
|
||||
return adopt(*new HTML::HTMLProgressElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(HTML::TagNames::blockquote, HTML::TagNames::q))
|
||||
return adopt(*new HTML::HTMLQuoteElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::script)
|
||||
return adopt(*new HTML::HTMLScriptElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::select)
|
||||
return adopt(*new HTML::HTMLSelectElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::slot)
|
||||
return adopt(*new HTML::HTMLSlotElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::source)
|
||||
return adopt(*new HTML::HTMLSourceElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::span)
|
||||
return adopt(*new HTML::HTMLSpanElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::style)
|
||||
return adopt(*new HTML::HTMLStyleElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::caption)
|
||||
return adopt(*new HTML::HTMLTableCaptionElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(Web::HTML::TagNames::td, Web::HTML::TagNames::th))
|
||||
return adopt(*new HTML::HTMLTableCellElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(HTML::TagNames::colgroup, HTML::TagNames::col))
|
||||
return adopt(*new HTML::HTMLTableColElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::table)
|
||||
return adopt(*new HTML::HTMLTableElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::tr)
|
||||
return adopt(*new HTML::HTMLTableRowElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(HTML::TagNames::tbody, HTML::TagNames::thead, HTML::TagNames::tfoot))
|
||||
return adopt(*new HTML::HTMLTableSectionElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::template_)
|
||||
return adopt(*new HTML::HTMLTemplateElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::textarea)
|
||||
return adopt(*new HTML::HTMLTextAreaElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::time)
|
||||
return adopt(*new HTML::HTMLTimeElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::title)
|
||||
return adopt(*new HTML::HTMLTitleElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::track)
|
||||
return adopt(*new HTML::HTMLTrackElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::ul)
|
||||
return adopt(*new HTML::HTMLUListElement(document, qualified_name));
|
||||
if (lowercase_tag_name == HTML::TagNames::video)
|
||||
return adopt(*new HTML::HTMLVideoElement(document, qualified_name));
|
||||
if (lowercase_tag_name.is_one_of(
|
||||
HTML::TagNames::article, HTML::TagNames::section, HTML::TagNames::nav, HTML::TagNames::aside, HTML::TagNames::hgroup, HTML::TagNames::header, HTML::TagNames::footer, HTML::TagNames::address, HTML::TagNames::dt, HTML::TagNames::dd, HTML::TagNames::figure, HTML::TagNames::figcaption, HTML::TagNames::main, HTML::TagNames::em, HTML::TagNames::strong, HTML::TagNames::small, HTML::TagNames::s, HTML::TagNames::cite, HTML::TagNames::dfn, HTML::TagNames::abbr, HTML::TagNames::ruby, HTML::TagNames::rt, HTML::TagNames::rp, HTML::TagNames::code, HTML::TagNames::var, HTML::TagNames::samp, HTML::TagNames::kbd, HTML::TagNames::sub, HTML::TagNames::sup, HTML::TagNames::i, HTML::TagNames::b, HTML::TagNames::u, HTML::TagNames::mark, HTML::TagNames::bdi, HTML::TagNames::bdo, HTML::TagNames::wbr, HTML::TagNames::summary, HTML::TagNames::noscript,
|
||||
// Obsolete
|
||||
HTML::TagNames::acronym, HTML::TagNames::basefont, HTML::TagNames::big, HTML::TagNames::center, HTML::TagNames::nobr, HTML::TagNames::noembed, HTML::TagNames::noframes, HTML::TagNames::plaintext, HTML::TagNames::rb, HTML::TagNames::rtc, HTML::TagNames::strike, HTML::TagNames::tt))
|
||||
return adopt(*new HTML::HTMLElement(document, qualified_name));
|
||||
if (lowercase_tag_name == SVG::TagNames::svg)
|
||||
return adopt(*new SVG::SVGSVGElement(document, qualified_name));
|
||||
if (lowercase_tag_name == SVG::TagNames::path)
|
||||
return adopt(*new SVG::SVGPathElement(document, qualified_name));
|
||||
|
||||
// FIXME: If name is a valid custom element name, then return HTMLElement.
|
||||
|
||||
return adopt(*new HTML::HTMLUnknownElement(document, qualified_name));
|
||||
}
|
||||
|
||||
}
|
||||
35
Userland/Libraries/LibWeb/DOM/ElementFactory.h
Normal file
35
Userland/Libraries/LibWeb/DOM/ElementFactory.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
NonnullRefPtr<Element> create_element(Document&, const FlyString& tag_name, const FlyString& namespace_);
|
||||
|
||||
}
|
||||
59
Userland/Libraries/LibWeb/DOM/Event.cpp
Normal file
59
Userland/Libraries/LibWeb/DOM/Event.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/Assertions.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
#include <LibWeb/DOM/ShadowRoot.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
void Event::append_to_path(EventTarget& invocation_target, RefPtr<EventTarget> shadow_adjusted_target, RefPtr<EventTarget> related_target, TouchTargetList& touch_targets, bool slot_in_closed_tree)
|
||||
{
|
||||
bool invocation_target_in_shadow_tree = false;
|
||||
bool root_of_closed_tree = false;
|
||||
|
||||
if (is<Node>(invocation_target)) {
|
||||
auto& invocation_target_node = downcast<Node>(invocation_target);
|
||||
if (is<ShadowRoot>(invocation_target_node.root()))
|
||||
invocation_target_in_shadow_tree = true;
|
||||
if (is<ShadowRoot>(invocation_target_node)) {
|
||||
auto& invocation_target_shadow_root = downcast<ShadowRoot>(invocation_target_node);
|
||||
root_of_closed_tree = invocation_target_shadow_root.closed();
|
||||
}
|
||||
}
|
||||
|
||||
m_path.append({ invocation_target, invocation_target_in_shadow_tree, shadow_adjusted_target, related_target, touch_targets, root_of_closed_tree, slot_in_closed_tree, m_path.size() });
|
||||
}
|
||||
|
||||
void Event::set_cancelled_flag()
|
||||
{
|
||||
if (m_cancelable && !m_in_passive_listener)
|
||||
m_cancelled = true;
|
||||
}
|
||||
|
||||
}
|
||||
186
Userland/Libraries/LibWeb/DOM/Event.h
Normal file
186
Userland/Libraries/LibWeb/DOM/Event.h
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibWeb/Bindings/Wrappable.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class Event
|
||||
: public RefCounted<Event>
|
||||
, public Bindings::Wrappable {
|
||||
public:
|
||||
using WrapperType = Bindings::EventWrapper;
|
||||
|
||||
enum Phase : u16 {
|
||||
None = 0,
|
||||
CapturingPhase = 1,
|
||||
AtTarget = 2,
|
||||
BubblingPhase = 3,
|
||||
};
|
||||
|
||||
using TouchTargetList = Vector<RefPtr<EventTarget>>;
|
||||
|
||||
struct PathEntry {
|
||||
RefPtr<EventTarget> invocation_target;
|
||||
bool invocation_target_in_shadow_tree { false };
|
||||
RefPtr<EventTarget> shadow_adjusted_target;
|
||||
RefPtr<EventTarget> related_target;
|
||||
TouchTargetList touch_target_list;
|
||||
bool root_of_closed_tree { false };
|
||||
bool slot_in_closed_tree { false };
|
||||
size_t index;
|
||||
};
|
||||
|
||||
using Path = Vector<PathEntry>;
|
||||
|
||||
static NonnullRefPtr<Event> create(const FlyString& event_name)
|
||||
{
|
||||
return adopt(*new Event(event_name));
|
||||
}
|
||||
|
||||
virtual ~Event() { }
|
||||
|
||||
const FlyString& type() const { return m_type; }
|
||||
void set_type(const StringView& type) { m_type = type; }
|
||||
|
||||
RefPtr<EventTarget> target() const { return m_target; }
|
||||
void set_target(EventTarget* target) { m_target = target; }
|
||||
|
||||
// NOTE: This is intended for the JS bindings.
|
||||
RefPtr<EventTarget> src_target() const { return target(); }
|
||||
|
||||
RefPtr<EventTarget> related_target() const { return m_related_target; }
|
||||
void set_related_target(EventTarget* related_target) { m_related_target = related_target; }
|
||||
|
||||
bool should_stop_propagation() const { return m_stop_propagation; }
|
||||
void set_stop_propagation(bool stop_propagation) { m_stop_propagation = stop_propagation; }
|
||||
|
||||
bool should_stop_immediate_propagation() const { return m_stop_immediate_propagation; }
|
||||
void set_stop_immediate_propagation(bool stop_immediate_propagation) { m_stop_immediate_propagation = stop_immediate_propagation; }
|
||||
|
||||
bool cancelled() const { return m_cancelled; }
|
||||
void set_cancelled(bool cancelled) { m_cancelled = cancelled; }
|
||||
|
||||
bool in_passive_listener() const { return m_in_passive_listener; }
|
||||
void set_in_passive_listener(bool in_passive_listener) { m_in_passive_listener = in_passive_listener; }
|
||||
|
||||
bool composed() const { return m_composed; }
|
||||
void set_composed(bool composed) { m_composed = composed; }
|
||||
|
||||
bool initialized() const { return m_initialized; }
|
||||
void set_initialized(bool initialized) { m_initialized = initialized; }
|
||||
|
||||
bool dispatched() const { return m_dispatch; }
|
||||
void set_dispatched(bool dispatched) { m_dispatch = dispatched; }
|
||||
|
||||
void prevent_default() { set_cancelled_flag(); }
|
||||
bool default_prevented() const { return cancelled(); }
|
||||
|
||||
u16 event_phase() const { return m_phase; }
|
||||
void set_phase(Phase phase) { m_phase = phase; }
|
||||
|
||||
RefPtr<EventTarget> current_target() const { return m_current_target; }
|
||||
void set_current_target(EventTarget* current_target) { m_current_target = current_target; }
|
||||
|
||||
bool return_value() const { return !m_cancelled; }
|
||||
void set_return_value(bool return_value)
|
||||
{
|
||||
if (!return_value)
|
||||
set_cancelled_flag();
|
||||
}
|
||||
|
||||
void append_to_path(EventTarget&, RefPtr<EventTarget>, RefPtr<EventTarget>, TouchTargetList&, bool);
|
||||
Path& path() { return m_path; }
|
||||
const Path& path() const { return m_path; }
|
||||
void clear_path() { m_path.clear(); }
|
||||
|
||||
void set_touch_target_list(TouchTargetList& touch_target_list) { m_touch_target_list = touch_target_list; }
|
||||
TouchTargetList& touch_target_list() { return m_touch_target_list; };
|
||||
void clear_touch_target_list() { m_touch_target_list.clear(); }
|
||||
|
||||
bool bubbles() const { return m_bubbles; }
|
||||
void set_bubbles(bool bubbles) { m_bubbles = bubbles; }
|
||||
|
||||
bool cancelable() const { return m_cancelable; }
|
||||
void set_cancelable(bool cancelable) { m_cancelable = cancelable; }
|
||||
|
||||
bool is_trusted() const { return m_is_trusted; }
|
||||
void set_is_trusted(bool is_trusted) { m_is_trusted = is_trusted; }
|
||||
|
||||
void stop_propagation() { m_stop_propagation = true; }
|
||||
|
||||
bool cancel_bubble() const { return m_stop_propagation; }
|
||||
void set_cancel_bubble(bool cancel_bubble)
|
||||
{
|
||||
if (cancel_bubble)
|
||||
m_stop_propagation = true;
|
||||
}
|
||||
|
||||
void stop_immediate_propagation()
|
||||
{
|
||||
m_stop_propagation = true;
|
||||
m_stop_immediate_propagation = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit Event(const FlyString& type)
|
||||
: m_type(type)
|
||||
, m_initialized(true)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
FlyString m_type;
|
||||
RefPtr<EventTarget> m_target;
|
||||
RefPtr<EventTarget> m_related_target;
|
||||
RefPtr<EventTarget> m_current_target;
|
||||
|
||||
Phase m_phase { None };
|
||||
|
||||
bool m_bubbles { false };
|
||||
bool m_cancelable { false };
|
||||
|
||||
bool m_stop_propagation { false };
|
||||
bool m_stop_immediate_propagation { false };
|
||||
bool m_cancelled { false };
|
||||
bool m_in_passive_listener { false };
|
||||
bool m_composed { false };
|
||||
bool m_initialized { false };
|
||||
bool m_dispatch { false };
|
||||
|
||||
bool m_is_trusted { true };
|
||||
|
||||
Path m_path;
|
||||
TouchTargetList m_touch_target_list;
|
||||
|
||||
void set_cancelled_flag();
|
||||
};
|
||||
|
||||
}
|
||||
23
Userland/Libraries/LibWeb/DOM/Event.idl
Normal file
23
Userland/Libraries/LibWeb/DOM/Event.idl
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
interface Event {
|
||||
|
||||
readonly attribute DOMString type;
|
||||
readonly attribute EventTarget? target;
|
||||
readonly attribute EventTarget? srcTarget;
|
||||
readonly attribute EventTarget? currentTarget;
|
||||
|
||||
readonly attribute unsigned short eventPhase;
|
||||
|
||||
undefined stopPropagation();
|
||||
attribute boolean cancelBubble;
|
||||
undefined stopImmediatePropagation();
|
||||
|
||||
readonly attribute boolean bubbles;
|
||||
readonly attribute boolean cancelable;
|
||||
attribute boolean returnValue;
|
||||
undefined preventDefault();
|
||||
readonly attribute boolean defaultPrevented;
|
||||
readonly attribute boolean composed;
|
||||
|
||||
readonly attribute boolean isTrusted;
|
||||
|
||||
};
|
||||
332
Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp
Normal file
332
Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <AK/Assertions.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibWeb/Bindings/EventTargetWrapper.h>
|
||||
#include <LibWeb/Bindings/EventTargetWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/EventWrapper.h>
|
||||
#include <LibWeb/Bindings/EventWrapperFactory.h>
|
||||
#include <LibWeb/Bindings/ScriptExecutionContext.h>
|
||||
#include <LibWeb/Bindings/WindowObject.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/EventDispatcher.h>
|
||||
#include <LibWeb/DOM/EventListener.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
#include <LibWeb/DOM/Node.h>
|
||||
#include <LibWeb/DOM/ShadowRoot.h>
|
||||
#include <LibWeb/DOM/Window.h>
|
||||
#include <LibWeb/HTML/EventNames.h>
|
||||
#include <LibWeb/UIEvents/MouseEvent.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
// FIXME: This shouldn't be here, as retargeting is not only used by the event dispatcher.
|
||||
// When moving this function, it needs to be generalized. https://dom.spec.whatwg.org/#retarget
|
||||
static EventTarget* retarget(EventTarget* left, [[maybe_unused]] EventTarget* right)
|
||||
{
|
||||
// FIXME
|
||||
for (;;) {
|
||||
if (!is<Node>(left))
|
||||
return left;
|
||||
|
||||
auto* left_node = downcast<Node>(left);
|
||||
auto* left_root = left_node->root();
|
||||
if (!is<ShadowRoot>(left_root))
|
||||
return left;
|
||||
|
||||
// FIXME: If right is a node and left’s root is a shadow-including inclusive ancestor of right, return left.
|
||||
|
||||
auto* left_shadow_root = downcast<ShadowRoot>(left_root);
|
||||
left = left_shadow_root->host();
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke
|
||||
bool EventDispatcher::inner_invoke(Event& event, Vector<EventTarget::EventListenerRegistration>& listeners, Event::Phase phase, bool invocation_target_in_shadow_tree)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
for (auto& listener : listeners) {
|
||||
if (listener.listener->removed())
|
||||
continue;
|
||||
|
||||
if (event.type() != listener.listener->type())
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
|
||||
if (phase == Event::Phase::CapturingPhase && !listener.listener->capture())
|
||||
continue;
|
||||
|
||||
if (phase == Event::Phase::BubblingPhase && listener.listener->capture())
|
||||
continue;
|
||||
|
||||
if (listener.listener->once())
|
||||
event.current_target()->remove_from_event_listener_list(listener.listener);
|
||||
|
||||
auto& function = listener.listener->function();
|
||||
auto& global = function.global_object();
|
||||
|
||||
RefPtr<Event> current_event;
|
||||
|
||||
if (is<Bindings::WindowObject>(global)) {
|
||||
auto& bindings_window_global = downcast<Bindings::WindowObject>(global);
|
||||
auto& window_impl = bindings_window_global.impl();
|
||||
current_event = window_impl.current_event();
|
||||
if (!invocation_target_in_shadow_tree)
|
||||
window_impl.set_current_event(&event);
|
||||
}
|
||||
|
||||
if (listener.listener->passive())
|
||||
event.set_in_passive_listener(true);
|
||||
|
||||
auto* this_value = Bindings::wrap(global, *event.current_target());
|
||||
auto* wrapped_event = Bindings::wrap(global, event);
|
||||
auto& vm = global.vm();
|
||||
[[maybe_unused]] auto rc = vm.call(listener.listener->function(), this_value, wrapped_event);
|
||||
if (vm.exception()) {
|
||||
vm.clear_exception();
|
||||
// FIXME: Set legacyOutputDidListenersThrowFlag if given. (Only used by IndexedDB currently)
|
||||
}
|
||||
|
||||
event.set_in_passive_listener(false);
|
||||
if (is<Bindings::WindowObject>(global)) {
|
||||
auto& bindings_window_global = downcast<Bindings::WindowObject>(global);
|
||||
auto& window_impl = bindings_window_global.impl();
|
||||
window_impl.set_current_event(current_event);
|
||||
}
|
||||
|
||||
if (event.should_stop_immediate_propagation())
|
||||
return found;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#concept-event-listener-invoke
|
||||
void EventDispatcher::invoke(Event::PathEntry& struct_, Event& event, Event::Phase phase)
|
||||
{
|
||||
auto last_valid_shadow_adjusted_target = event.path().last_matching([&struct_](auto& entry) {
|
||||
return entry.index <= struct_.index && !entry.shadow_adjusted_target.is_null();
|
||||
});
|
||||
|
||||
ASSERT(last_valid_shadow_adjusted_target.has_value());
|
||||
|
||||
event.set_target(last_valid_shadow_adjusted_target.value().shadow_adjusted_target);
|
||||
event.set_related_target(struct_.related_target);
|
||||
event.set_touch_target_list(struct_.touch_target_list);
|
||||
|
||||
if (event.should_stop_propagation())
|
||||
return;
|
||||
|
||||
event.set_current_target(struct_.invocation_target);
|
||||
|
||||
// NOTE: This is an intentional copy. Any event listeners added after this point will not be invoked.
|
||||
auto listeners = event.current_target()->listeners();
|
||||
bool invocation_target_in_shadow_tree = struct_.invocation_target_in_shadow_tree;
|
||||
|
||||
bool found = inner_invoke(event, listeners, phase, invocation_target_in_shadow_tree);
|
||||
|
||||
if (!found && event.is_trusted()) {
|
||||
auto original_event_type = event.type();
|
||||
|
||||
if (event.type() == "animationend")
|
||||
event.set_type("webkitAnimationEnd");
|
||||
else if (event.type() == "animationiteration")
|
||||
event.set_type("webkitAnimationIteration");
|
||||
else if (event.type() == "animationstart")
|
||||
event.set_type("webkitAnimationStart");
|
||||
else if (event.type() == "transitionend")
|
||||
event.set_type("webkitTransitionEnd");
|
||||
else
|
||||
return;
|
||||
|
||||
inner_invoke(event, listeners, phase, invocation_target_in_shadow_tree);
|
||||
event.set_type(original_event_type);
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#concept-event-dispatch
|
||||
bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<Event> event, bool legacy_target_override)
|
||||
{
|
||||
event->set_dispatched(true);
|
||||
RefPtr<EventTarget> target_override;
|
||||
|
||||
if (!legacy_target_override) {
|
||||
target_override = target;
|
||||
} else {
|
||||
// NOTE: This can be done because legacy_target_override is only set for events targeted at Window.
|
||||
target_override = downcast<Window>(*target).document();
|
||||
}
|
||||
|
||||
RefPtr<EventTarget> activation_target;
|
||||
RefPtr<EventTarget> related_target = retarget(event->related_target(), target);
|
||||
|
||||
bool clear_targets = false;
|
||||
|
||||
if (related_target != target || event->related_target() == target) {
|
||||
Event::TouchTargetList touch_targets;
|
||||
|
||||
for (auto& touch_target : event->touch_target_list()) {
|
||||
touch_targets.append(retarget(touch_target, target));
|
||||
}
|
||||
|
||||
event->append_to_path(*target, target_override, related_target, touch_targets, false);
|
||||
|
||||
bool is_activation_event = is<UIEvents::MouseEvent>(*event) && event->type() == HTML::EventNames::click;
|
||||
|
||||
if (is_activation_event && target->activation_behaviour)
|
||||
activation_target = target;
|
||||
|
||||
// FIXME: Let slottable be target, if target is a slottable and is assigned, and null otherwise.
|
||||
|
||||
bool slot_in_closed_tree = false;
|
||||
auto* parent = target->get_parent(event);
|
||||
|
||||
while (parent) {
|
||||
// FIXME: If slottable is non-null:
|
||||
|
||||
// FIXME: If parent is a slottable and is assigned, then set slottable to parent.
|
||||
|
||||
related_target = retarget(event->related_target(), parent);
|
||||
touch_targets.clear();
|
||||
|
||||
for (auto& touch_target : event->touch_target_list()) {
|
||||
touch_targets.append(retarget(touch_target, parent));
|
||||
}
|
||||
|
||||
// FIXME: or parent is a node and target’s root is a shadow-including inclusive ancestor of parent, then:
|
||||
if (is<Window>(parent)) {
|
||||
if (is_activation_event && event->bubbles() && !activation_target && parent->activation_behaviour)
|
||||
activation_target = parent;
|
||||
|
||||
event->append_to_path(*parent, nullptr, related_target, touch_targets, slot_in_closed_tree);
|
||||
} else if (related_target == parent) {
|
||||
parent = nullptr;
|
||||
} else {
|
||||
target = *parent;
|
||||
|
||||
if (is_activation_event && !activation_target && target->activation_behaviour)
|
||||
activation_target = target;
|
||||
|
||||
event->append_to_path(*parent, target, related_target, touch_targets, slot_in_closed_tree);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
parent = parent->get_parent(event);
|
||||
}
|
||||
|
||||
slot_in_closed_tree = false;
|
||||
}
|
||||
|
||||
auto clear_targets_struct = event->path().last_matching([](auto& entry) {
|
||||
return !entry.shadow_adjusted_target.is_null();
|
||||
});
|
||||
|
||||
ASSERT(clear_targets_struct.has_value());
|
||||
|
||||
if (is<Node>(clear_targets_struct.value().shadow_adjusted_target.ptr())) {
|
||||
auto& shadow_adjusted_target_node = downcast<Node>(*clear_targets_struct.value().shadow_adjusted_target);
|
||||
if (is<ShadowRoot>(shadow_adjusted_target_node.root()))
|
||||
clear_targets = true;
|
||||
}
|
||||
|
||||
if (!clear_targets && is<Node>(clear_targets_struct.value().related_target.ptr())) {
|
||||
auto& related_target_node = downcast<Node>(*clear_targets_struct.value().related_target);
|
||||
if (is<ShadowRoot>(related_target_node.root()))
|
||||
clear_targets = true;
|
||||
}
|
||||
|
||||
if (!clear_targets) {
|
||||
for (auto touch_target : clear_targets_struct.value().touch_target_list) {
|
||||
if (is<Node>(*touch_target.ptr())) {
|
||||
auto& touch_target_node = downcast<Node>(*touch_target.ptr());
|
||||
if (is<ShadowRoot>(touch_target_node.root())) {
|
||||
clear_targets = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (activation_target && activation_target->legacy_pre_activation_behaviour)
|
||||
activation_target->legacy_pre_activation_behaviour();
|
||||
|
||||
for (ssize_t i = event->path().size() - 1; i >= 0; --i) {
|
||||
auto& entry = event->path().at(i);
|
||||
|
||||
if (entry.shadow_adjusted_target)
|
||||
event->set_phase(Event::Phase::AtTarget);
|
||||
else
|
||||
event->set_phase(Event::Phase::CapturingPhase);
|
||||
|
||||
invoke(entry, event, Event::Phase::CapturingPhase);
|
||||
}
|
||||
|
||||
for (auto& entry : event->path()) {
|
||||
if (entry.shadow_adjusted_target) {
|
||||
event->set_phase(Event::Phase::AtTarget);
|
||||
} else {
|
||||
if (!event->bubbles())
|
||||
continue;
|
||||
|
||||
event->set_phase(Event::Phase::BubblingPhase);
|
||||
}
|
||||
|
||||
invoke(entry, event, Event::Phase::BubblingPhase);
|
||||
}
|
||||
}
|
||||
|
||||
event->set_phase(Event::Phase::None);
|
||||
event->set_current_target(nullptr);
|
||||
event->clear_path();
|
||||
event->set_dispatched(false);
|
||||
event->set_stop_propagation(false);
|
||||
event->set_stop_immediate_propagation(false);
|
||||
|
||||
if (clear_targets) {
|
||||
event->set_target(nullptr);
|
||||
event->set_related_target(nullptr);
|
||||
event->clear_touch_target_list();
|
||||
}
|
||||
|
||||
if (activation_target) {
|
||||
if (!event->cancelled()) {
|
||||
// NOTE: Since activation_target is set, it will have activation behaviour.
|
||||
activation_target->activation_behaviour(event);
|
||||
} else {
|
||||
if (activation_target->legacy_cancelled_activation_behaviour)
|
||||
activation_target->legacy_cancelled_activation_behaviour();
|
||||
}
|
||||
}
|
||||
|
||||
return !event->cancelled();
|
||||
}
|
||||
|
||||
}
|
||||
43
Userland/Libraries/LibWeb/DOM/EventDispatcher.h
Normal file
43
Userland/Libraries/LibWeb/DOM/EventDispatcher.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class EventDispatcher {
|
||||
public:
|
||||
static bool dispatch(NonnullRefPtr<EventTarget>, NonnullRefPtr<Event>, bool legacy_target_override = false);
|
||||
|
||||
private:
|
||||
static void invoke(Event::PathEntry&, Event&, Event::Phase);
|
||||
static bool inner_invoke(Event&, Vector<EventTarget::EventListenerRegistration>&, Event::Phase, bool);
|
||||
};
|
||||
|
||||
}
|
||||
38
Userland/Libraries/LibWeb/DOM/EventListener.cpp
Normal file
38
Userland/Libraries/LibWeb/DOM/EventListener.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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 <LibJS/Runtime/Function.h>
|
||||
#include <LibWeb/DOM/EventListener.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
JS::Function& EventListener::function()
|
||||
{
|
||||
ASSERT(m_function.cell());
|
||||
return *m_function.cell();
|
||||
}
|
||||
|
||||
}
|
||||
72
Userland/Libraries/LibWeb/DOM/EventListener.h
Normal file
72
Userland/Libraries/LibWeb/DOM/EventListener.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/RefCounted.h>
|
||||
#include <LibJS/Heap/Handle.h>
|
||||
#include <LibWeb/Bindings/Wrappable.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class EventListener
|
||||
: public RefCounted<EventListener>
|
||||
, public Bindings::Wrappable {
|
||||
public:
|
||||
using WrapperType = Bindings::EventListenerWrapper;
|
||||
|
||||
explicit EventListener(JS::Handle<JS::Function> function)
|
||||
: m_function(move(function))
|
||||
{
|
||||
}
|
||||
|
||||
JS::Function& function();
|
||||
|
||||
const FlyString& type() const { return m_type; }
|
||||
void set_type(const FlyString& type) { m_type = type; }
|
||||
|
||||
bool capture() const { return m_capture; }
|
||||
void set_capture(bool capture) { m_capture = capture; }
|
||||
|
||||
bool passive() const { return m_passive; }
|
||||
void set_passive(bool passive) { m_capture = passive; }
|
||||
|
||||
bool once() const { return m_once; }
|
||||
void set_once(bool once) { m_once = once; }
|
||||
|
||||
bool removed() const { return m_removed; }
|
||||
void set_removed(bool removed) { m_removed = removed; }
|
||||
|
||||
private:
|
||||
FlyString m_type;
|
||||
JS::Handle<JS::Function> m_function;
|
||||
bool m_capture { false };
|
||||
bool m_passive { false };
|
||||
bool m_once { false };
|
||||
bool m_removed { false };
|
||||
};
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue