mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-04 05:20:30 +00:00
pixelflut: Implement alternative flooding strategies
These allow column-wise, traditional scanline, or random pixel flooding. Depending on the use case and amount of contestion, any of the strategies may work best, as tested on 37c3.
This commit is contained in:
parent
fdfd4b5e3d
commit
bdd92e881f
Notes:
sideshowbarker
2024-07-17 20:19:08 +09:00
Author: https://github.com/kleinesfilmroellchen Commit: https://github.com/SerenityOS/serenity/commit/bdd92e881f Pull-request: https://github.com/SerenityOS/serenity/pull/22498
1 changed files with 69 additions and 8 deletions
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <AK/Error.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/QuickSelect.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibCore/Socket.h>
|
||||
|
@ -16,19 +17,42 @@
|
|||
|
||||
constexpr StringView get_command = "SIZE\n"sv;
|
||||
|
||||
// Which strategies to use for flooding the image to the server.
|
||||
enum class FloodStrategy {
|
||||
// Send image row by row, like a CRT scanline.
|
||||
Scanline,
|
||||
// Send random pixels.
|
||||
Random,
|
||||
// Send image column by column.
|
||||
Columns,
|
||||
};
|
||||
|
||||
static Optional<FloodStrategy> parse_strategy(StringView name)
|
||||
{
|
||||
if (name.equals_ignoring_ascii_case("scanline"sv))
|
||||
return FloodStrategy::Scanline;
|
||||
if (name.equals_ignoring_ascii_case("random"sv))
|
||||
return FloodStrategy::Random;
|
||||
if (name.equals_ignoring_ascii_case("columns"sv))
|
||||
return FloodStrategy::Columns;
|
||||
return {};
|
||||
}
|
||||
|
||||
// Client for the Pixelflut protocol
|
||||
// https://github.com/defnull/pixelflut#pixelflut-protocol
|
||||
class Client : public RefCounted<Client> {
|
||||
public:
|
||||
static ErrorOr<NonnullRefPtr<Client>> create(StringView image_path, StringView server, size_t x, size_t y);
|
||||
static ErrorOr<NonnullRefPtr<Client>> create(StringView image_path, StringView server, size_t x, size_t y, FloodStrategy strategy);
|
||||
|
||||
ErrorOr<void> run();
|
||||
|
||||
private:
|
||||
Client(NonnullOwnPtr<Core::BufferedTCPSocket>, NonnullRefPtr<Gfx::Bitmap>, Gfx::IntSize, Gfx::IntPoint);
|
||||
Client(NonnullOwnPtr<Core::BufferedTCPSocket>, NonnullRefPtr<Gfx::Bitmap>, Gfx::IntSize, Gfx::IntPoint, FloodStrategy);
|
||||
|
||||
ErrorOr<void> send_current_pixel();
|
||||
void next_pixel();
|
||||
void next_scanline_pixel();
|
||||
void next_random_pixel();
|
||||
void next_column_pixel();
|
||||
|
||||
NonnullOwnPtr<Core::BufferedTCPSocket> m_socket;
|
||||
|
||||
|
@ -37,9 +61,10 @@ private:
|
|||
Gfx::IntPoint const m_image_offset;
|
||||
|
||||
Gfx::IntPoint m_current_point { 0, 0 };
|
||||
FloodStrategy m_strategy;
|
||||
};
|
||||
|
||||
ErrorOr<NonnullRefPtr<Client>> Client::create(StringView image_path, StringView server, size_t x, size_t y)
|
||||
ErrorOr<NonnullRefPtr<Client>> Client::create(StringView image_path, StringView server, size_t x, size_t y, FloodStrategy strategy)
|
||||
{
|
||||
// Extract hostname and port and connect to server.
|
||||
auto parts = server.split_view(':');
|
||||
|
@ -88,20 +113,27 @@ ErrorOr<NonnullRefPtr<Client>> Client::create(StringView image_path, StringView
|
|||
image = TRY(image->scaled(fitting_scale, fitting_scale));
|
||||
}
|
||||
|
||||
return TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Client(move(socket), move(image), canvas_size, Gfx::IntPoint { x, y })));
|
||||
return TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Client(move(socket), move(image), canvas_size, Gfx::IntPoint { x, y }, strategy)));
|
||||
}
|
||||
|
||||
Client::Client(NonnullOwnPtr<Core::BufferedTCPSocket> socket, NonnullRefPtr<Gfx::Bitmap> image, Gfx::IntSize canvas_size, Gfx::IntPoint image_offset)
|
||||
Client::Client(NonnullOwnPtr<Core::BufferedTCPSocket> socket, NonnullRefPtr<Gfx::Bitmap> image, Gfx::IntSize canvas_size, Gfx::IntPoint image_offset, FloodStrategy strategy)
|
||||
: m_socket(move(socket))
|
||||
, m_image(move(image))
|
||||
, m_canvas_size(canvas_size)
|
||||
, m_image_offset(image_offset)
|
||||
, m_strategy(strategy)
|
||||
{
|
||||
outln("Connected to server, image {}, canvas size {}", m_image, m_canvas_size);
|
||||
}
|
||||
|
||||
ErrorOr<void> Client::run()
|
||||
{
|
||||
Function<void(void)> next_pixel = [this] { this->next_scanline_pixel(); };
|
||||
if (m_strategy == FloodStrategy::Columns)
|
||||
next_pixel = [this] { this->next_column_pixel(); };
|
||||
else if (m_strategy == FloodStrategy::Random)
|
||||
next_pixel = [this] { this->next_random_pixel(); };
|
||||
|
||||
while (true) {
|
||||
TRY(send_current_pixel());
|
||||
next_pixel();
|
||||
|
@ -127,7 +159,7 @@ ErrorOr<void> Client::send_current_pixel()
|
|||
return {};
|
||||
}
|
||||
|
||||
void Client::next_pixel()
|
||||
void Client::next_scanline_pixel()
|
||||
{
|
||||
m_current_point.set_x(m_current_point.x() + 1);
|
||||
if (m_current_point.x() >= m_image->width()) {
|
||||
|
@ -140,6 +172,27 @@ void Client::next_pixel()
|
|||
}
|
||||
}
|
||||
|
||||
void Client::next_column_pixel()
|
||||
{
|
||||
m_current_point.set_y(m_current_point.y() + 1);
|
||||
if (m_current_point.y() >= m_image->height()) {
|
||||
m_current_point.set_y(0);
|
||||
m_current_point.set_x(m_current_point.x() + 1);
|
||||
if (m_current_point.x() >= m_image->width()) {
|
||||
m_current_point.set_x(0);
|
||||
m_current_point.set_y(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::next_random_pixel()
|
||||
{
|
||||
m_current_point = {
|
||||
AK::random_int(0, m_image->width() - 1),
|
||||
AK::random_int(0, m_image->height() - 1),
|
||||
};
|
||||
}
|
||||
|
||||
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
{
|
||||
Core::EventLoop loop;
|
||||
|
@ -148,11 +201,13 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
size_t x;
|
||||
size_t y;
|
||||
StringView server;
|
||||
StringView strategy_string { "scanline"sv };
|
||||
|
||||
Core::ArgsParser args_parser;
|
||||
args_parser.add_option(image_path, "Image to send to server", "image", 'i', "IMAGE");
|
||||
args_parser.add_option(x, "Target x coordinate of the image on the server", "x", 'x', "X");
|
||||
args_parser.add_option(y, "Target y coordinate of the image on the server", "y", 'y', "Y");
|
||||
args_parser.add_option(strategy_string, "Pixel flooding strategy (scanline, random or column; default: scanline)", "strategy", 'm', "STRATEGY");
|
||||
args_parser.add_positional_argument(server, "Pixelflut server (hostname:port)", "server");
|
||||
args_parser.parse(arguments);
|
||||
|
||||
|
@ -161,7 +216,13 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
return 1;
|
||||
}
|
||||
|
||||
auto client = TRY(Client::create(image_path, server, x, y));
|
||||
auto maybe_strategy = parse_strategy(strategy_string);
|
||||
if (!maybe_strategy.has_value()) {
|
||||
warnln("Error: Strategy {} invalid", strategy_string);
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto client = TRY(Client::create(image_path, server, x, y, maybe_strategy.release_value()));
|
||||
|
||||
TRY(client->run());
|
||||
|
||||
|
|
Loading…
Reference in a new issue