diff options
Diffstat (limited to 'Libraries/LibWeb/Page')
-rw-r--r-- | Libraries/LibWeb/Page/EventHandler.cpp | 230 | ||||
-rw-r--r-- | Libraries/LibWeb/Page/EventHandler.h | 58 | ||||
-rw-r--r-- | Libraries/LibWeb/Page/Frame.cpp | 171 | ||||
-rw-r--r-- | Libraries/LibWeb/Page/Frame.h | 102 | ||||
-rw-r--r-- | Libraries/LibWeb/Page/Page.cpp | 68 | ||||
-rw-r--r-- | Libraries/LibWeb/Page/Page.h | 91 |
6 files changed, 720 insertions, 0 deletions
diff --git a/Libraries/LibWeb/Page/EventHandler.cpp b/Libraries/LibWeb/Page/EventHandler.cpp new file mode 100644 index 0000000000..0bb63b83b4 --- /dev/null +++ b/Libraries/LibWeb/Page/EventHandler.cpp @@ -0,0 +1,230 @@ +/* + * 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 <LibGUI/Event.h> +#include <LibGUI/Window.h> +#include <LibJS/Runtime/Value.h> +#include <LibWeb/DOM/Document.h> +#include <LibWeb/HTML/HTMLAnchorElement.h> +#include <LibWeb/HTML/HTMLIFrameElement.h> +#include <LibWeb/Layout/LayoutDocument.h> +#include <LibWeb/Page/EventHandler.h> +#include <LibWeb/Page/Frame.h> +#include <LibWeb/PageView.h> +#include <LibWeb/UIEvents/MouseEvent.h> + +namespace Web { + +static Gfx::IntPoint compute_mouse_event_offset(const Gfx::IntPoint& position, const LayoutNode& layout_node) +{ + auto top_left_of_layout_node = layout_node.box_type_agnostic_position(); + return { + position.x() - static_cast<int>(top_left_of_layout_node.x()), + position.y() - static_cast<int>(top_left_of_layout_node.y()) + }; +} + +EventHandler::EventHandler(Badge<Frame>, Frame& frame) + : m_frame(frame) +{ +} + +EventHandler::~EventHandler() +{ +} + +const LayoutDocument* EventHandler::layout_root() const +{ + if (!m_frame.document()) + return nullptr; + return m_frame.document()->layout_node(); +} + +LayoutDocument* EventHandler::layout_root() +{ + if (!m_frame.document()) + return nullptr; + return m_frame.document()->layout_node(); +} + +bool EventHandler::handle_mouseup(const Gfx::IntPoint& position, unsigned button, unsigned modifiers) +{ + if (!layout_root()) + return false; + bool handled_event = false; + + auto result = layout_root()->hit_test(position); + if (result.layout_node && result.layout_node->node()) { + RefPtr<DOM::Node> node = result.layout_node->node(); + if (is<HTML::HTMLIFrameElement>(*node)) { + if (auto* subframe = downcast<HTML::HTMLIFrameElement>(*node).hosted_frame()) + return subframe->event_handler().handle_mouseup(position.translated(compute_mouse_event_offset({}, *result.layout_node)), button, modifiers); + return false; + } + auto offset = compute_mouse_event_offset(position, *result.layout_node); + node->dispatch_event(UIEvents::MouseEvent::create("mouseup", offset.x(), offset.y())); + handled_event = true; + } + + if (button == GUI::MouseButton::Left) { + dump_selection("MouseUp"); + m_in_mouse_selection = false; + } + return handled_event; +} + +bool EventHandler::handle_mousedown(const Gfx::IntPoint& position, unsigned button, unsigned modifiers) +{ + if (!layout_root()) + return false; + NonnullRefPtr document = *m_frame.document(); + auto& page_client = m_frame.page().client(); + + auto result = layout_root()->hit_test(position); + if (!result.layout_node) + return false; + + RefPtr<DOM::Node> node = result.layout_node->node(); + document->set_hovered_node(node); + if (!node) + return false; + + if (is<HTML::HTMLIFrameElement>(*node)) { + if (auto* subframe = downcast<HTML::HTMLIFrameElement>(*node).hosted_frame()) + return subframe->event_handler().handle_mousedown(position.translated(compute_mouse_event_offset({}, *result.layout_node)), button, modifiers); + return false; + } + + auto offset = compute_mouse_event_offset(position, *result.layout_node); + node->dispatch_event(UIEvents::MouseEvent::create("mousedown", offset.x(), offset.y())); + if (!layout_root()) + return true; + + if (RefPtr<HTML::HTMLAnchorElement> link = node->enclosing_link_element()) { + auto href = link->href(); + auto url = document->complete_url(href); + dbg() << "Web::EventHandler: Clicking on a link to " << url; + if (button == GUI::MouseButton::Left) { + auto href = link->href(); + auto url = document->complete_url(href); + if (href.starts_with("javascript:")) { + document->run_javascript(href.substring_view(11, href.length() - 11)); + } else if (href.starts_with('#')) { + auto anchor = href.substring_view(1, href.length() - 1); + m_frame.scroll_to_anchor(anchor); + } else { + if (m_frame.is_main_frame()) { + page_client.page_did_click_link(url, link->target(), modifiers); + } else { + // FIXME: Handle different targets! + m_frame.loader().load(url, FrameLoader::Type::Navigation); + } + } + } else if (button == GUI::MouseButton::Right) { + page_client.page_did_request_link_context_menu(m_frame.to_main_frame_position(position), url, link->target(), modifiers); + } else if (button == GUI::MouseButton::Middle) { + page_client.page_did_middle_click_link(url, link->target(), modifiers); + } + } else { + if (button == GUI::MouseButton::Left) { + layout_root()->selection().set({ result.layout_node, result.index_in_node }, {}); + dump_selection("MouseDown"); + m_in_mouse_selection = true; + } else if (button == GUI::MouseButton::Right) { + page_client.page_did_request_context_menu(m_frame.to_main_frame_position(position)); + } + } + return true; +} + +bool EventHandler::handle_mousemove(const Gfx::IntPoint& position, unsigned buttons, unsigned modifiers) +{ + if (!layout_root()) + return false; + auto& document = *m_frame.document(); + auto& page_client = m_frame.page().client(); + + bool hovered_node_changed = false; + bool is_hovering_link = false; + auto result = layout_root()->hit_test(position); + const HTML::HTMLAnchorElement* hovered_link_element = nullptr; + if (result.layout_node) { + RefPtr<DOM::Node> node = result.layout_node->node(); + + if (node && is<HTML::HTMLIFrameElement>(*node)) { + if (auto* subframe = downcast<HTML::HTMLIFrameElement>(*node).hosted_frame()) + return subframe->event_handler().handle_mousemove(position.translated(compute_mouse_event_offset({}, *result.layout_node)), buttons, modifiers); + return false; + } + + hovered_node_changed = node != document.hovered_node(); + document.set_hovered_node(node); + if (node) { + hovered_link_element = node->enclosing_link_element(); + if (hovered_link_element) { +#ifdef HTML_DEBUG + dbg() << "PageView: hovering over a link to " << hovered_link_element->href(); +#endif + is_hovering_link = true; + } + auto offset = compute_mouse_event_offset(position, *result.layout_node); + node->dispatch_event(UIEvents::MouseEvent::create("mousemove", offset.x(), offset.y())); + if (!layout_root()) + return true; + } + if (m_in_mouse_selection) { + layout_root()->selection().set_end({ result.layout_node, result.index_in_node }); + dump_selection("MouseMove"); + page_client.page_did_change_selection(); + } + } + page_client.page_did_request_cursor_change(is_hovering_link ? GUI::StandardCursor::Hand : GUI::StandardCursor::None); + if (hovered_node_changed) { + RefPtr<HTML::HTMLElement> hovered_html_element = document.hovered_node() ? document.hovered_node()->enclosing_html_element() : nullptr; + if (hovered_html_element && !hovered_html_element->title().is_null()) { + page_client.page_did_enter_tooltip_area(m_frame.to_main_frame_position(position), hovered_html_element->title()); + } else { + page_client.page_did_leave_tooltip_area(); + } + if (is_hovering_link) + page_client.page_did_hover_link(document.complete_url(hovered_link_element->href())); + else + page_client.page_did_unhover_link(); + } + return true; +} + +void EventHandler::dump_selection(const char* event_name) const +{ + UNUSED_PARAM(event_name); +#ifdef SELECTION_DEBUG + dbg() << event_name << " selection start: " + << layout_root()->selection().start().layout_node << ":" << layout_root()->selection().start().index_in_node << ", end: " + << layout_root()->selection().end().layout_node << ":" << layout_root()->selection().end().index_in_node; +#endif +} + +} diff --git a/Libraries/LibWeb/Page/EventHandler.h b/Libraries/LibWeb/Page/EventHandler.h new file mode 100644 index 0000000000..9a06a83c2e --- /dev/null +++ b/Libraries/LibWeb/Page/EventHandler.h @@ -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 <AK/Forward.h> +#include <LibGUI/Forward.h> +#include <LibGfx/Forward.h> +#include <LibWeb/Forward.h> + +namespace Web { + +class Frame; + +class EventHandler { +public: + explicit EventHandler(Badge<Frame>, Frame&); + ~EventHandler(); + + bool handle_mouseup(const Gfx::IntPoint&, unsigned button, unsigned modifiers); + bool handle_mousedown(const Gfx::IntPoint&, unsigned button, unsigned modifiers); + bool handle_mousemove(const Gfx::IntPoint&, unsigned buttons, unsigned modifiers); + +private: + LayoutDocument* layout_root(); + const LayoutDocument* layout_root() const; + + void dump_selection(const char* event_name) const; + + Frame& m_frame; + + bool m_in_mouse_selection { false }; +}; + +} diff --git a/Libraries/LibWeb/Page/Frame.cpp b/Libraries/LibWeb/Page/Frame.cpp new file mode 100644 index 0000000000..5262c8bd36 --- /dev/null +++ b/Libraries/LibWeb/Page/Frame.cpp @@ -0,0 +1,171 @@ +/* + * 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/Document.h> +#include <LibWeb/HTML/HTMLAnchorElement.h> +#include <LibWeb/Layout/LayoutDocument.h> +#include <LibWeb/Layout/LayoutWidget.h> +#include <LibWeb/Page/Frame.h> +#include <LibWeb/PageView.h> + +namespace Web { + +Frame::Frame(DOM::Element& host_element, Frame& main_frame) + : m_page(main_frame.page()) + , m_main_frame(main_frame) + , m_loader(*this) + , m_event_handler({}, *this) + , m_host_element(host_element.make_weak_ptr()) +{ +} + +Frame::Frame(Page& page) + : m_page(page) + , m_main_frame(*this) + , m_loader(*this) + , m_event_handler({}, *this) +{ +} + +Frame::~Frame() +{ +} + +void Frame::set_document(DOM::Document* document) +{ + if (m_document == document) + return; + + if (m_document) + m_document->detach_from_frame({}, *this); + + m_document = document; + + if (m_document) + m_document->attach_to_frame({}, *this); + + page().client().page_did_set_document_in_main_frame(m_document); +} + +void Frame::set_size(const Gfx::IntSize& size) +{ + if (m_size == size) + return; + m_size = size; + if (m_document) + m_document->layout(); +} + +void Frame::set_viewport_rect(const Gfx::IntRect& rect) +{ + if (m_viewport_rect == rect) + return; + m_viewport_rect = rect; + + if (m_document && m_document->layout_node()) + m_document->layout_node()->did_set_viewport_rect({}, rect); +} + +void Frame::set_needs_display(const Gfx::IntRect& rect) +{ + if (!m_viewport_rect.intersects(rect)) + return; + + if (is_main_frame()) { + page().client().page_did_invalidate(to_main_frame_rect(rect)); + return; + } + + if (host_element() && host_element()->layout_node()) + host_element()->layout_node()->set_needs_display(); +} + +void Frame::did_scroll(Badge<PageView>) +{ + if (!m_document) + return; + if (!m_document->layout_node()) + return; + m_document->layout_node()->for_each_in_subtree_of_type<LayoutWidget>([&](auto& layout_widget) { + layout_widget.update_widget(); + return IterationDecision::Continue; + }); +} + +void Frame::scroll_to_anchor(const String& fragment) +{ + if (!document()) + return; + + const auto* element = document()->get_element_by_id(fragment); + if (!element) { + auto candidates = document()->get_elements_by_name(fragment); + for (auto* candidate : candidates) { + if (is<HTML::HTMLAnchorElement>(*candidate)) { + element = downcast<HTML::HTMLAnchorElement>(candidate); + break; + } + } + } + + if (!element || !element->layout_node()) + return; + + auto& layout_node = *element->layout_node(); + + Gfx::FloatRect float_rect { layout_node.box_type_agnostic_position(), { (float)viewport_rect().width(), (float)viewport_rect().height() } }; + if (is<LayoutBox>(layout_node)) { + auto& layout_box = downcast<LayoutBox>(layout_node); + auto padding_box = layout_box.box_model().padding_box(layout_box); + float_rect.move_by(-padding_box.left, -padding_box.top); + } + + page().client().page_did_request_scroll_into_view(enclosing_int_rect(float_rect)); +} + +Gfx::IntRect Frame::to_main_frame_rect(const Gfx::IntRect& a_rect) +{ + auto rect = a_rect; + rect.set_location(to_main_frame_position(a_rect.location())); + return rect; +} + +Gfx::IntPoint Frame::to_main_frame_position(const Gfx::IntPoint& a_position) +{ + auto position = a_position; + for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { + if (ancestor->is_main_frame()) + break; + if (!ancestor->host_element()) + return {}; + if (!ancestor->host_element()->layout_node()) + return {}; + position.move_by(ancestor->host_element()->layout_node()->box_type_agnostic_position().to_type<int>()); + } + return position; +} + +} diff --git a/Libraries/LibWeb/Page/Frame.h b/Libraries/LibWeb/Page/Frame.h new file mode 100644 index 0000000000..07d2bf8a1a --- /dev/null +++ b/Libraries/LibWeb/Page/Frame.h @@ -0,0 +1,102 @@ +/* + * 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/Function.h> +#include <AK/Noncopyable.h> +#include <AK/RefPtr.h> +#include <AK/WeakPtr.h> +#include <LibGfx/Bitmap.h> +#include <LibGfx/Rect.h> +#include <LibGfx/Size.h> +#include <LibWeb/Loader/FrameLoader.h> +#include <LibWeb/Page/EventHandler.h> +#include <LibWeb/TreeNode.h> + +namespace Web { + +class Frame : public TreeNode<Frame> { +public: + static NonnullRefPtr<Frame> create_subframe(DOM::Element& host_element, Frame& main_frame) { return adopt(*new Frame(host_element, main_frame)); } + static NonnullRefPtr<Frame> create(Page& page) { return adopt(*new Frame(page)); } + ~Frame(); + + bool is_main_frame() const { return this == &m_main_frame; } + + const DOM::Document* document() const { return m_document; } + DOM::Document* document() { return m_document; } + + void set_document(DOM::Document*); + + Page& page() { return m_page; } + const Page& page() const { return m_page; } + + const Gfx::IntSize& size() const { return m_size; } + void set_size(const Gfx::IntSize&); + + void set_needs_display(const Gfx::IntRect&); + + void set_viewport_rect(const Gfx::IntRect&); + Gfx::IntRect viewport_rect() const { return m_viewport_rect; } + + void did_scroll(Badge<PageView>); + + FrameLoader& loader() { return m_loader; } + const FrameLoader& loader() const { return m_loader; } + + EventHandler& event_handler() { return m_event_handler; } + const EventHandler& event_handler() const { return m_event_handler; } + + void scroll_to(const Gfx::IntPoint&); + void scroll_to_anchor(const String&); + + Frame& main_frame() { return m_main_frame; } + const Frame& main_frame() const { return m_main_frame; } + + DOM::Element* host_element() { return m_host_element; } + const DOM::Element* host_element() const { return m_host_element; } + + Gfx::IntPoint to_main_frame_position(const Gfx::IntPoint&); + Gfx::IntRect to_main_frame_rect(const Gfx::IntRect&); + +private: + explicit Frame(DOM::Element& host_element, Frame& main_frame); + explicit Frame(Page&); + + Page& m_page; + Frame& m_main_frame; + + FrameLoader m_loader; + EventHandler m_event_handler; + + WeakPtr<DOM::Element> m_host_element; + RefPtr<DOM::Document> m_document; + Gfx::IntSize m_size; + Gfx::IntRect m_viewport_rect; +}; + +} diff --git a/Libraries/LibWeb/Page/Page.cpp b/Libraries/LibWeb/Page/Page.cpp new file mode 100644 index 0000000000..f02cfc9385 --- /dev/null +++ b/Libraries/LibWeb/Page/Page.cpp @@ -0,0 +1,68 @@ +/* + * 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/Page/Frame.h> +#include <LibWeb/Page/Page.h> +#include <LibWeb/PageView.h> + +namespace Web { + +Page::Page(PageClient& client) + : m_client(client) +{ + m_main_frame = Frame::create(*this); +} + +Page::~Page() +{ +} + +void Page::load(const URL& url) +{ + main_frame().loader().load(url, FrameLoader::Type::Navigation); +} + +Gfx::Palette Page::palette() const +{ + return m_client.palette(); +} + +bool Page::handle_mouseup(const Gfx::IntPoint& position, unsigned button, unsigned modifiers) +{ + return main_frame().event_handler().handle_mouseup(position, button, modifiers); +} + +bool Page::handle_mousedown(const Gfx::IntPoint& position, unsigned button, unsigned modifiers) +{ + return main_frame().event_handler().handle_mousedown(position, button, modifiers); +} + +bool Page::handle_mousemove(const Gfx::IntPoint& position, unsigned buttons, unsigned modifiers) +{ + return main_frame().event_handler().handle_mousemove(position, buttons, modifiers); +} + +} diff --git a/Libraries/LibWeb/Page/Page.h b/Libraries/LibWeb/Page/Page.h new file mode 100644 index 0000000000..a0bf0b635f --- /dev/null +++ b/Libraries/LibWeb/Page/Page.h @@ -0,0 +1,91 @@ +/* + * 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/Noncopyable.h> +#include <AK/OwnPtr.h> +#include <AK/RefPtr.h> +#include <LibGUI/Window.h> +#include <LibGfx/Forward.h> +#include <LibGfx/Palette.h> +#include <LibWeb/Forward.h> + +namespace Web { + +class PageClient; + +class Page { + AK_MAKE_NONCOPYABLE(Page); + AK_MAKE_NONMOVABLE(Page); + +public: + explicit Page(PageClient&); + ~Page(); + + PageClient& client() { return m_client; } + const PageClient& client() const { return m_client; } + + Web::Frame& main_frame() { return *m_main_frame; } + const Web::Frame& main_frame() const { return *m_main_frame; } + + void load(const URL&); + + bool handle_mouseup(const Gfx::IntPoint&, unsigned button, unsigned modifiers); + bool handle_mousedown(const Gfx::IntPoint&, unsigned button, unsigned modifiers); + bool handle_mousemove(const Gfx::IntPoint&, unsigned buttons, unsigned modifiers); + + Gfx::Palette palette() const; + +private: + PageClient& m_client; + + RefPtr<Frame> m_main_frame; +}; + +class PageClient { +public: + virtual Gfx::Palette palette() const = 0; + virtual void page_did_set_document_in_main_frame(DOM::Document*) { } + virtual void page_did_change_title(const String&) { } + virtual void page_did_start_loading(const URL&) { } + virtual void page_did_change_selection() { } + virtual void page_did_request_cursor_change(GUI::StandardCursor) { } + virtual void page_did_request_context_menu(const Gfx::IntPoint&) { } + virtual void page_did_request_link_context_menu(const Gfx::IntPoint&, const URL&, [[maybe_unused]] const String& target, [[maybe_unused]] unsigned modifiers) { } + virtual void page_did_click_link(const URL&, [[maybe_unused]] const String& target, [[maybe_unused]] unsigned modifiers) { } + virtual void page_did_middle_click_link(const URL&, [[maybe_unused]] const String& target, [[maybe_unused]] unsigned modifiers) { } + virtual void page_did_enter_tooltip_area(const Gfx::IntPoint&, const String&) { } + virtual void page_did_leave_tooltip_area() { } + virtual void page_did_hover_link(const URL&) { } + virtual void page_did_unhover_link() { } + virtual void page_did_invalidate(const Gfx::IntRect&) { } + virtual void page_did_change_favicon(const Gfx::Bitmap&) { } + virtual void page_did_layout() { } + virtual void page_did_request_scroll_into_view(const Gfx::IntRect&) { } +}; + +} |