mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 12:35:14 +00:00
LibHTML: Implement the <blink> element
Just in time for Serenity's 1st birthday, here is the <blink> element! This patch adds a bunch of different mechanisms to enable partial repaints of the layout tree (LayoutNode::set_needs_display())) It also adds LayoutNode::is_visible(), which can be toggled to prevent a LayoutNode from rendering anything (it still takes up space though.)
This commit is contained in:
parent
33043941f9
commit
fdbad6284c
Notes:
sideshowbarker
2024-07-19 11:44:38 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/fdbad6284c6
16 changed files with 140 additions and 0 deletions
5
Base/home/anon/www/blink.html
Normal file
5
Base/home/anon/www/blink.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
<html>
|
||||
<body>
|
||||
<blink>Hello friends!</blink>
|
||||
</body>
|
||||
</html>
|
|
@ -23,6 +23,7 @@ h1 {
|
|||
<li><a href="images.html">images</a></li>
|
||||
<li><a href="selectors.html">selectors</a></li>
|
||||
<li><a href="link.html">link element</a></li>
|
||||
<li><a href="blink.html">blink element</a></li>
|
||||
<li><a href="http://www.serenityos.org/">www.serenityos.org</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
|
|
|
@ -97,3 +97,7 @@ hr {
|
|||
border-color: #888888;
|
||||
border-style: inset;
|
||||
}
|
||||
|
||||
blink {
|
||||
display: inline;
|
||||
}
|
||||
|
|
27
Libraries/LibHTML/DOM/HTMLBlinkElement.cpp
Normal file
27
Libraries/LibHTML/DOM/HTMLBlinkElement.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include <LibCore/CTimer.h>
|
||||
#include <LibHTML/CSS/StyleProperties.h>
|
||||
#include <LibHTML/CSS/StyleValue.h>
|
||||
#include <LibHTML/DOM/HTMLBlinkElement.h>
|
||||
#include <LibHTML/Layout/LayoutNode.h>
|
||||
|
||||
HTMLBlinkElement::HTMLBlinkElement(Document& document, const String& tag_name)
|
||||
: HTMLElement(document, tag_name)
|
||||
, m_timer(CTimer::construct())
|
||||
{
|
||||
m_timer->set_interval(500);
|
||||
m_timer->on_timeout = [this] { blink(); };
|
||||
m_timer->start();
|
||||
}
|
||||
|
||||
HTMLBlinkElement::~HTMLBlinkElement()
|
||||
{
|
||||
}
|
||||
|
||||
void HTMLBlinkElement::blink()
|
||||
{
|
||||
if (!layout_node())
|
||||
return;
|
||||
|
||||
layout_node()->set_visible(!layout_node()->is_visible());
|
||||
layout_node()->set_needs_display();
|
||||
}
|
16
Libraries/LibHTML/DOM/HTMLBlinkElement.h
Normal file
16
Libraries/LibHTML/DOM/HTMLBlinkElement.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibHTML/DOM/HTMLElement.h>
|
||||
|
||||
class CTimer;
|
||||
|
||||
class HTMLBlinkElement : public HTMLElement {
|
||||
public:
|
||||
HTMLBlinkElement(Document&, const String& tag_name);
|
||||
virtual ~HTMLBlinkElement() override;
|
||||
|
||||
private:
|
||||
void blink();
|
||||
|
||||
NonnullRefPtr<CTimer> m_timer;
|
||||
};
|
|
@ -29,3 +29,10 @@ void Frame::set_size(const Size& size)
|
|||
return;
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
void Frame::set_needs_display(const Rect& rect)
|
||||
{
|
||||
if (!on_set_needs_display)
|
||||
return;
|
||||
on_set_needs_display(rect);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/Noncopyable.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/Weakable.h>
|
||||
#include <LibDraw/Rect.h>
|
||||
#include <LibDraw/Size.h>
|
||||
#include <LibHTML/TreeNode.h>
|
||||
|
||||
|
@ -23,6 +25,9 @@ public:
|
|||
const Size& size() const { return m_size; }
|
||||
void set_size(const Size&);
|
||||
|
||||
void set_needs_display(const Rect&);
|
||||
Function<void(const Rect&)> on_set_needs_display;
|
||||
|
||||
private:
|
||||
Frame();
|
||||
|
||||
|
|
|
@ -17,6 +17,12 @@ HtmlView::HtmlView(GWidget* parent)
|
|||
: GScrollableWidget(parent)
|
||||
, m_main_frame(Frame::create())
|
||||
{
|
||||
main_frame().on_set_needs_display = [this](auto& content_rect) {
|
||||
Rect adjusted_rect = content_rect;
|
||||
adjusted_rect.set_location(to_widget_position(content_rect.location()));
|
||||
update(adjusted_rect);
|
||||
};
|
||||
|
||||
set_frame_shape(FrameShape::Container);
|
||||
set_frame_shadow(FrameShadow::Sunken);
|
||||
set_frame_thickness(2);
|
||||
|
|
|
@ -194,6 +194,9 @@ void LayoutBlock::compute_height()
|
|||
|
||||
void LayoutBlock::render(RenderingContext& context)
|
||||
{
|
||||
if (!is_visible())
|
||||
return;
|
||||
|
||||
LayoutNode::render(context);
|
||||
|
||||
// FIXME: position this properly
|
||||
|
|
|
@ -38,3 +38,15 @@ private:
|
|||
|
||||
Vector<LineBox> m_line_boxes;
|
||||
};
|
||||
|
||||
template<typename Callback>
|
||||
void LayoutNode::for_each_fragment_of_this(Callback callback)
|
||||
{
|
||||
auto& block = *containing_block();
|
||||
for (auto& line_box : block.line_boxes()) {
|
||||
for (auto& fragment : line_box.fragments()) {
|
||||
if (callback(fragment) == IterationDecision::Break)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ void LayoutImage::layout()
|
|||
|
||||
void LayoutImage::render(RenderingContext& context)
|
||||
{
|
||||
if (!is_visible())
|
||||
return;
|
||||
|
||||
if (renders_as_alt_text()) {
|
||||
context.painter().set_font(Font::default_font());
|
||||
StylePainter::paint_frame(context.painter(), rect(), FrameShape::Container, FrameShadow::Sunken, 2);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <LibGUI/GPainter.h>
|
||||
#include <LibHTML/DOM/Document.h>
|
||||
#include <LibHTML/DOM/Element.h>
|
||||
#include <LibHTML/Frame.h>
|
||||
#include <LibHTML/Layout/LayoutBlock.h>
|
||||
#include <LibHTML/Layout/LayoutNode.h>
|
||||
|
||||
|
@ -38,6 +39,9 @@ const LayoutBlock* LayoutNode::containing_block() const
|
|||
|
||||
void LayoutNode::render(RenderingContext& context)
|
||||
{
|
||||
if (!is_visible())
|
||||
return;
|
||||
|
||||
#ifdef DRAW_BOXES_AROUND_LAYOUT_NODES
|
||||
context.painter().draw_rect(m_rect, Color::Blue);
|
||||
#endif
|
||||
|
@ -127,3 +131,21 @@ void LayoutNode::split_into_lines(LayoutBlock& container)
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
void LayoutNode::set_needs_display()
|
||||
{
|
||||
auto* frame = document().frame();
|
||||
ASSERT(frame);
|
||||
|
||||
if (!is_inline()) {
|
||||
const_cast<Frame*>(frame)->set_needs_display(rect());
|
||||
return;
|
||||
}
|
||||
|
||||
for_each_fragment_of_this([&](auto& fragment) {
|
||||
if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
|
||||
const_cast<Frame*>(frame)->set_needs_display(fragment.rect());
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -76,6 +76,16 @@ public:
|
|||
|
||||
virtual void split_into_lines(LayoutBlock& container);
|
||||
|
||||
bool is_visible() const { return m_visible; }
|
||||
void set_visible(bool visible) { m_visible = visible; }
|
||||
|
||||
void set_needs_display();
|
||||
|
||||
bool is_ancestor_of(const LayoutNode&) const;
|
||||
|
||||
template<typename Callback>
|
||||
void for_each_fragment_of_this(Callback);
|
||||
|
||||
protected:
|
||||
explicit LayoutNode(const Node*);
|
||||
|
||||
|
@ -88,6 +98,7 @@ private:
|
|||
Rect m_rect;
|
||||
bool m_inline { false };
|
||||
bool m_has_style { false };
|
||||
bool m_visible { true };
|
||||
};
|
||||
|
||||
class LayoutNodeWithStyle : public LayoutNode {
|
||||
|
@ -119,3 +130,12 @@ inline const LayoutNodeWithStyle* LayoutNode::parent() const
|
|||
{
|
||||
return static_cast<const LayoutNodeWithStyle*>(TreeNode<LayoutNode>::parent());
|
||||
}
|
||||
|
||||
inline bool LayoutNode::is_ancestor_of(const LayoutNode& other) const
|
||||
{
|
||||
for (auto* ancestor = other.parent(); ancestor; ancestor = ancestor->parent()) {
|
||||
if (ancestor == this)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
|
||||
void LineBoxFragment::render(RenderingContext& context)
|
||||
{
|
||||
for (auto* ancestor = layout_node().parent(); ancestor; ancestor = ancestor->parent()) {
|
||||
if (!ancestor->is_visible())
|
||||
return;
|
||||
}
|
||||
|
||||
if (layout_node().is_text()) {
|
||||
auto& layout_text = static_cast<const LayoutText&>(layout_node());
|
||||
layout_text.render_fragment(context, *this);
|
||||
|
|
|
@ -14,6 +14,7 @@ LIBHTML_OBJS = \
|
|||
DOM/HTMLFontElement.o \
|
||||
DOM/HTMLImageElement.o \
|
||||
DOM/HTMLLinkElement.o \
|
||||
DOM/HTMLBlinkElement.o \
|
||||
DOM/Document.o \
|
||||
DOM/Text.o \
|
||||
DOM/DocumentType.o \
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <LibHTML/DOM/DocumentType.h>
|
||||
#include <LibHTML/DOM/Element.h>
|
||||
#include <LibHTML/DOM/HTMLAnchorElement.h>
|
||||
#include <LibHTML/DOM/HTMLBlinkElement.h>
|
||||
#include <LibHTML/DOM/HTMLBodyElement.h>
|
||||
#include <LibHTML/DOM/HTMLFontElement.h>
|
||||
#include <LibHTML/DOM/HTMLHRElement.h>
|
||||
|
@ -42,6 +43,8 @@ static NonnullRefPtr<Element> create_element(Document& document, const String& t
|
|||
return adopt(*new HTMLLinkElement(document, tag_name));
|
||||
if (lowercase_tag_name == "img")
|
||||
return adopt(*new HTMLImageElement(document, tag_name));
|
||||
if (lowercase_tag_name == "blink")
|
||||
return adopt(*new HTMLBlinkElement(document, tag_name));
|
||||
if (lowercase_tag_name == "h1"
|
||||
|| lowercase_tag_name == "h2"
|
||||
|| lowercase_tag_name == "h3"
|
||||
|
|
Loading…
Add table
Reference in a new issue