mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-27 01:50:24 +00:00
164 lines
6.3 KiB
C++
164 lines
6.3 KiB
C++
/*
|
|
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include "SlideObject.h"
|
|
#include "Presentation.h"
|
|
#include <AK/JsonObject.h>
|
|
#include <AK/URL.h>
|
|
#include <LibGfx/Font/FontStyleMapping.h>
|
|
#include <LibGfx/Rect.h>
|
|
|
|
static DeprecatedString to_css_length(float design_value, Presentation const& presentation)
|
|
{
|
|
float length_in_vw = design_value / static_cast<float>(presentation.normative_size().width()) * 100.0f;
|
|
return DeprecatedString::formatted("{}vw", length_in_vw);
|
|
}
|
|
|
|
ErrorOr<NonnullRefPtr<SlideObject>> SlideObject::parse_slide_object(JsonObject const& slide_object_json, unsigned slide_index)
|
|
{
|
|
auto frame = slide_object_json.get_u32("frame"sv).value_or(0);
|
|
auto maybe_type = slide_object_json.get_deprecated_string("type"sv);
|
|
if (!maybe_type.has_value())
|
|
return Error::from_string_view("Slide object must have a type"sv);
|
|
|
|
auto type = maybe_type.value();
|
|
RefPtr<SlideObject> object;
|
|
if (type == "text"sv)
|
|
object = TRY(try_make_ref_counted<Text>(Index { slide_index, frame }));
|
|
else if (type == "image"sv)
|
|
object = TRY(try_make_ref_counted<Image>(Index { slide_index, frame }));
|
|
else
|
|
return Error::from_string_view("Unsupported slide object type"sv);
|
|
|
|
slide_object_json.for_each_member([&](auto const& key, auto const& value) {
|
|
object->set_property(key, value);
|
|
});
|
|
|
|
return object.release_nonnull();
|
|
}
|
|
|
|
void SlideObject::set_property(StringView name, JsonValue value)
|
|
{
|
|
if (name == "rect"sv) {
|
|
if (value.is_array() && value.as_array().size() == 4) {
|
|
Gfx::IntRect rect;
|
|
rect.set_x(value.as_array()[0].to_i32());
|
|
rect.set_y(value.as_array()[1].to_i32());
|
|
rect.set_width(value.as_array()[2].to_i32());
|
|
rect.set_height(value.as_array()[3].to_i32());
|
|
m_rect = rect;
|
|
}
|
|
}
|
|
m_properties.set(name, move(value));
|
|
}
|
|
|
|
void GraphicsObject::set_property(StringView name, JsonValue value)
|
|
{
|
|
if (name == "color"sv) {
|
|
if (auto color = Gfx::Color::from_string(value.to_deprecated_string()); color.has_value()) {
|
|
m_color = color.release_value();
|
|
}
|
|
}
|
|
SlideObject::set_property(name, move(value));
|
|
}
|
|
|
|
void Text::set_property(StringView name, JsonValue value)
|
|
{
|
|
if (name == "text"sv) {
|
|
m_text = value.to_deprecated_string();
|
|
} else if (name == "font"sv) {
|
|
m_font_family = value.to_deprecated_string();
|
|
} else if (name == "font-weight"sv) {
|
|
m_font_weight = Gfx::name_to_weight(value.to_deprecated_string());
|
|
} else if (name == "font-size"sv) {
|
|
m_font_size_in_pt = value.to_float();
|
|
} else if (name == "text-alignment"sv) {
|
|
m_text_align = value.to_deprecated_string();
|
|
}
|
|
GraphicsObject::set_property(name, move(value));
|
|
}
|
|
|
|
void Image::set_property(StringView name, JsonValue value)
|
|
{
|
|
if (name == "path"sv) {
|
|
m_src = value.to_deprecated_string();
|
|
} else if (name == "scaling-mode"sv) {
|
|
if (value.to_deprecated_string() == "nearest-neighbor"sv)
|
|
m_image_rendering = "crisp-edges"sv;
|
|
else if (value.to_deprecated_string() == "smooth-pixels"sv)
|
|
m_image_rendering = "pixelated"sv;
|
|
}
|
|
SlideObject::set_property(name, move(value));
|
|
}
|
|
|
|
ErrorOr<HTMLElement> Text::render(Presentation const& presentation) const
|
|
{
|
|
HTMLElement div;
|
|
div.tag_name = "div"sv;
|
|
TRY(div.attributes.try_set("class"sv, DeprecatedString::formatted("frame slide{}-frame{}", m_slide_index, m_frame_index)));
|
|
div.style.set("color"sv, m_color.to_deprecated_string());
|
|
div.style.set("font-family"sv, DeprecatedString::formatted("'{}'", m_font_family));
|
|
div.style.set("font-size"sv, to_css_length(m_font_size_in_pt * 1.33333333f, presentation));
|
|
div.style.set("font-weight"sv, DeprecatedString::number(m_font_weight));
|
|
div.style.set("text-align"sv, m_text_align);
|
|
div.style.set("white-space"sv, "pre-wrap"sv);
|
|
div.style.set("width"sv, to_css_length(m_rect.width(), presentation));
|
|
div.style.set("height"sv, to_css_length(m_rect.height(), presentation));
|
|
div.style.set("position"sv, "absolute"sv);
|
|
div.style.set("left"sv, to_css_length(m_rect.left(), presentation));
|
|
div.style.set("top"sv, to_css_length(m_rect.top(), presentation));
|
|
div.inner_text = m_text;
|
|
return div;
|
|
}
|
|
|
|
ErrorOr<HTMLElement> Image::render(Presentation const& presentation) const
|
|
{
|
|
HTMLElement img;
|
|
img.tag_name = "img"sv;
|
|
img.attributes.set("src"sv, URL::create_with_file_scheme(m_src).to_deprecated_string());
|
|
img.style.set("image-rendering"sv, m_image_rendering);
|
|
if (m_rect.width() > m_rect.height())
|
|
img.style.set("height"sv, "100%"sv);
|
|
else
|
|
img.style.set("width"sv, "100%"sv);
|
|
|
|
HTMLElement image_wrapper;
|
|
image_wrapper.tag_name = "div"sv;
|
|
TRY(image_wrapper.attributes.try_set("class"sv, DeprecatedString::formatted("frame slide{}-frame{}", m_slide_index, m_frame_index)));
|
|
image_wrapper.children.append(move(img));
|
|
image_wrapper.style.set("position"sv, "absolute"sv);
|
|
image_wrapper.style.set("left"sv, to_css_length(m_rect.left(), presentation));
|
|
image_wrapper.style.set("top"sv, to_css_length(m_rect.top(), presentation));
|
|
image_wrapper.style.set("width"sv, to_css_length(m_rect.width(), presentation));
|
|
image_wrapper.style.set("height"sv, to_css_length(m_rect.height(), presentation));
|
|
image_wrapper.style.set("text-align"sv, "center"sv);
|
|
return image_wrapper;
|
|
}
|
|
|
|
ErrorOr<void> HTMLElement::serialize(StringBuilder& builder) const
|
|
{
|
|
TRY(builder.try_appendff("<{}", tag_name));
|
|
for (auto const& [key, value] : attributes) {
|
|
// FIXME: Escape the value string as necessary.
|
|
TRY(builder.try_appendff(" {}='{}'", key, value));
|
|
}
|
|
if (!style.is_empty()) {
|
|
TRY(builder.try_append(" style=\""sv));
|
|
for (auto const& [key, value] : style) {
|
|
// FIXME: Escape the value string as necessary.
|
|
TRY(builder.try_appendff(" {}: {};", key, value));
|
|
}
|
|
TRY(builder.try_append("\""sv));
|
|
}
|
|
TRY(builder.try_append(">"sv));
|
|
if (!inner_text.is_empty())
|
|
TRY(builder.try_append(inner_text));
|
|
for (auto const& child : children) {
|
|
TRY(child.serialize(builder));
|
|
}
|
|
TRY(builder.try_appendff("</{}>", tag_name));
|
|
return {};
|
|
}
|