1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 14:28:12 +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:
Andreas Kling 2019-10-09 21:25:29 +02:00
parent 33043941f9
commit fdbad6284c
16 changed files with 140 additions and 0 deletions

View file

@ -0,0 +1,5 @@
<html>
<body>
<blink>Hello friends!</blink>
</body>
</html>

View file

@ -23,6 +23,7 @@ h1 {
<li><a href="images.html">images</a></li> <li><a href="images.html">images</a></li>
<li><a href="selectors.html">selectors</a></li> <li><a href="selectors.html">selectors</a></li>
<li><a href="link.html">link element</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> <li><a href="http://www.serenityos.org/">www.serenityos.org</a></li>
</ul> </ul>
</body> </body>

View file

@ -97,3 +97,7 @@ hr {
border-color: #888888; border-color: #888888;
border-style: inset; border-style: inset;
} }
blink {
display: inline;
}

View 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();
}

View 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;
};

View file

@ -29,3 +29,10 @@ void Frame::set_size(const Size& size)
return; return;
m_size = size; m_size = size;
} }
void Frame::set_needs_display(const Rect& rect)
{
if (!on_set_needs_display)
return;
on_set_needs_display(rect);
}

View file

@ -1,8 +1,10 @@
#pragma once #pragma once
#include <AK/Function.h>
#include <AK/Noncopyable.h> #include <AK/Noncopyable.h>
#include <AK/RefPtr.h> #include <AK/RefPtr.h>
#include <AK/Weakable.h> #include <AK/Weakable.h>
#include <LibDraw/Rect.h>
#include <LibDraw/Size.h> #include <LibDraw/Size.h>
#include <LibHTML/TreeNode.h> #include <LibHTML/TreeNode.h>
@ -23,6 +25,9 @@ public:
const Size& size() const { return m_size; } const Size& size() const { return m_size; }
void set_size(const Size&); void set_size(const Size&);
void set_needs_display(const Rect&);
Function<void(const Rect&)> on_set_needs_display;
private: private:
Frame(); Frame();

View file

@ -17,6 +17,12 @@ HtmlView::HtmlView(GWidget* parent)
: GScrollableWidget(parent) : GScrollableWidget(parent)
, m_main_frame(Frame::create()) , 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_shape(FrameShape::Container);
set_frame_shadow(FrameShadow::Sunken); set_frame_shadow(FrameShadow::Sunken);
set_frame_thickness(2); set_frame_thickness(2);

View file

@ -194,6 +194,9 @@ void LayoutBlock::compute_height()
void LayoutBlock::render(RenderingContext& context) void LayoutBlock::render(RenderingContext& context)
{ {
if (!is_visible())
return;
LayoutNode::render(context); LayoutNode::render(context);
// FIXME: position this properly // FIXME: position this properly

View file

@ -38,3 +38,15 @@ private:
Vector<LineBox> m_line_boxes; 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;
}
}
}

View file

@ -34,6 +34,9 @@ void LayoutImage::layout()
void LayoutImage::render(RenderingContext& context) void LayoutImage::render(RenderingContext& context)
{ {
if (!is_visible())
return;
if (renders_as_alt_text()) { if (renders_as_alt_text()) {
context.painter().set_font(Font::default_font()); context.painter().set_font(Font::default_font());
StylePainter::paint_frame(context.painter(), rect(), FrameShape::Container, FrameShadow::Sunken, 2); StylePainter::paint_frame(context.painter(), rect(), FrameShape::Container, FrameShadow::Sunken, 2);

View file

@ -1,6 +1,7 @@
#include <LibGUI/GPainter.h> #include <LibGUI/GPainter.h>
#include <LibHTML/DOM/Document.h> #include <LibHTML/DOM/Document.h>
#include <LibHTML/DOM/Element.h> #include <LibHTML/DOM/Element.h>
#include <LibHTML/Frame.h>
#include <LibHTML/Layout/LayoutBlock.h> #include <LibHTML/Layout/LayoutBlock.h>
#include <LibHTML/Layout/LayoutNode.h> #include <LibHTML/Layout/LayoutNode.h>
@ -38,6 +39,9 @@ const LayoutBlock* LayoutNode::containing_block() const
void LayoutNode::render(RenderingContext& context) void LayoutNode::render(RenderingContext& context)
{ {
if (!is_visible())
return;
#ifdef DRAW_BOXES_AROUND_LAYOUT_NODES #ifdef DRAW_BOXES_AROUND_LAYOUT_NODES
context.painter().draw_rect(m_rect, Color::Blue); context.painter().draw_rect(m_rect, Color::Blue);
#endif #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;
});
}

View file

@ -76,6 +76,16 @@ public:
virtual void split_into_lines(LayoutBlock& container); 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: protected:
explicit LayoutNode(const Node*); explicit LayoutNode(const Node*);
@ -88,6 +98,7 @@ private:
Rect m_rect; Rect m_rect;
bool m_inline { false }; bool m_inline { false };
bool m_has_style { false }; bool m_has_style { false };
bool m_visible { true };
}; };
class LayoutNodeWithStyle : public LayoutNode { class LayoutNodeWithStyle : public LayoutNode {
@ -119,3 +130,12 @@ inline const LayoutNodeWithStyle* LayoutNode::parent() const
{ {
return static_cast<const LayoutNodeWithStyle*>(TreeNode<LayoutNode>::parent()); 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;
}

View file

@ -5,6 +5,11 @@
void LineBoxFragment::render(RenderingContext& context) 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()) { if (layout_node().is_text()) {
auto& layout_text = static_cast<const LayoutText&>(layout_node()); auto& layout_text = static_cast<const LayoutText&>(layout_node());
layout_text.render_fragment(context, *this); layout_text.render_fragment(context, *this);

View file

@ -14,6 +14,7 @@ LIBHTML_OBJS = \
DOM/HTMLFontElement.o \ DOM/HTMLFontElement.o \
DOM/HTMLImageElement.o \ DOM/HTMLImageElement.o \
DOM/HTMLLinkElement.o \ DOM/HTMLLinkElement.o \
DOM/HTMLBlinkElement.o \
DOM/Document.o \ DOM/Document.o \
DOM/Text.o \ DOM/Text.o \
DOM/DocumentType.o \ DOM/DocumentType.o \

View file

@ -4,6 +4,7 @@
#include <LibHTML/DOM/DocumentType.h> #include <LibHTML/DOM/DocumentType.h>
#include <LibHTML/DOM/Element.h> #include <LibHTML/DOM/Element.h>
#include <LibHTML/DOM/HTMLAnchorElement.h> #include <LibHTML/DOM/HTMLAnchorElement.h>
#include <LibHTML/DOM/HTMLBlinkElement.h>
#include <LibHTML/DOM/HTMLBodyElement.h> #include <LibHTML/DOM/HTMLBodyElement.h>
#include <LibHTML/DOM/HTMLFontElement.h> #include <LibHTML/DOM/HTMLFontElement.h>
#include <LibHTML/DOM/HTMLHRElement.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)); return adopt(*new HTMLLinkElement(document, tag_name));
if (lowercase_tag_name == "img") if (lowercase_tag_name == "img")
return adopt(*new HTMLImageElement(document, tag_name)); return adopt(*new HTMLImageElement(document, tag_name));
if (lowercase_tag_name == "blink")
return adopt(*new HTMLBlinkElement(document, tag_name));
if (lowercase_tag_name == "h1" if (lowercase_tag_name == "h1"
|| lowercase_tag_name == "h2" || lowercase_tag_name == "h2"
|| lowercase_tag_name == "h3" || lowercase_tag_name == "h3"