LibMarkdown: Implement the image size extension

This implements the image size extension that's quite commonly used:
https://github.com/commonmark/commonmark-spec/wiki/Deployed-Extensions#image-size

This supports specifying...

Both width and height: ![](foo.png =100x200)
Width only: ![](foo.png =100x)
Height only: ![](foo.png =x200)

The size is always in pixels (relative sizing does not seem
to be spec'd anywhere).
This commit is contained in:
MacDue 2022-08-03 00:11:58 +01:00 committed by Andreas Kling
parent fb47a87340
commit 8140b1fa18
Notes: sideshowbarker 2024-07-17 22:01:16 +09:00
2 changed files with 58 additions and 2 deletions

View file

@ -140,6 +140,13 @@ void Text::LinkNode::render_to_html(StringBuilder& builder) const
if (is_image) {
builder.append("<img src=\""sv);
builder.append(escape_html_entities(href));
if (has_image_dimensions()) {
builder.append("\" style=\""sv);
if (image_width.has_value())
builder.appendff("width: {}px;", *image_width);
if (image_height.has_value())
builder.appendff("height: {}px;", *image_height);
}
builder.append("\" alt=\""sv);
text->render_to_html(builder);
builder.append("\" >"sv);
@ -576,11 +583,52 @@ NonnullOwnPtr<Text::Node> Text::parse_link(Vector<Token>::ConstIterator& tokens)
auto separator = *tokens;
VERIFY(separator == "]("sv);
Optional<int> image_width;
Optional<int> image_height;
auto parse_image_dimensions = [&](StringView dimensions) -> bool {
if (!dimensions.starts_with('='))
return false;
ArmedScopeGuard clear_image_dimensions = [&] {
image_width = {};
image_height = {};
};
auto dimension_seperator = dimensions.find('x', 1);
if (!dimension_seperator.has_value())
return false;
auto width_string = dimensions.substring_view(1, *dimension_seperator - 1);
if (!width_string.is_empty()) {
auto width = width_string.to_int();
if (!width.has_value())
return false;
image_width = width;
}
auto height_start = *dimension_seperator + 1;
if (height_start < dimensions.length()) {
auto height_string = dimensions.substring_view(height_start);
auto height = height_string.to_int();
if (!height.has_value())
return false;
image_height = height;
}
clear_image_dimensions.disarm();
return true;
};
StringBuilder address;
for (auto iterator = tokens + 1; !iterator.is_end(); ++iterator) {
// FIXME: What to do if there's multiple dimension tokens?
if (is_image && !address.is_empty() && parse_image_dimensions(iterator->data))
continue;
if (*iterator == ")"sv) {
tokens = iterator;
return make<LinkNode>(is_image, move(link_text), address.build());
return make<LinkNode>(is_image, move(link_text), address.build().trim_whitespace(), image_width, image_height);
}
address.append(iterator->data);

View file

@ -97,14 +97,22 @@ public:
bool is_image;
NonnullOwnPtr<Node> text;
String href;
Optional<int> image_width;
Optional<int> image_height;
LinkNode(bool is_image, NonnullOwnPtr<Node> text, String href)
LinkNode(bool is_image, NonnullOwnPtr<Node> text, String href, Optional<int> image_width, Optional<int> image_height)
: is_image(is_image)
, text(move(text))
, href(move(href))
, image_width(image_width)
, image_height(image_height)
{
}
bool has_image_dimensions() const
{
return image_width.has_value() || image_height.has_value();
}
virtual void render_to_html(StringBuilder& builder) const override;
virtual void render_for_terminal(StringBuilder& builder) const override;
virtual size_t terminal_length() const override;