Repository: LadybirdBrowser/ladybird
File: Libraries/LibWeb/HTML/HTMLLinkElement.cpp (C++)

Code before:
}

bool HTMLLinkElement::is_implicitly_potentially_render_blocking() const
{
    // A link element of this type is implicitly potentially render-blocking if the element was created by its node document's parser.
    return &document() == m_parser_document;
}

void HTMLLinkElement::resource_did_load_favicon()
{
    VERIFY(m_relationship & (Relationship::Icon));
    if (!resource()->has_encoded_data()) {
        dbgln_if(SPAM_DEBUG, "Favicon downloaded, no encoded data");
        return;
    }

    dbgln_if(SPAM_DEBUG, "Favicon downloaded, {} bytes from {}", resource()->encoded_data().size(), resource()->url());

    document().check_favicon_after_loading_link_resource();
}

static NonnullRefPtr<Core::Promise<Web::Platform::DecodedImage>> decode_favicon(ReadonlyBytes favicon_data, URL::URL const& favicon_url, GC::Ref<DOM::Document> document)
{
    auto on_failed_decode = [favicon_url]([[maybe_unused]] Error& error) {
        dbgln_if(IMAGE_DECODER_DEBUG, "Failed to decode favicon {}: {}", favicon_url, error);
    };

    auto on_successful_decode = [document = GC::Root(document)](Web::Platform::DecodedImage& decoded_image) -> ErrorOr<void> {
        auto favicon_bitmap = decoded_image.frames[0].bitmap;
        dbgln_if(IMAGE_DECODER_DEBUG, "Decoded favicon, {}", favicon_bitmap->size());

        auto navigable = document->navigable();
        if (navigable && navigable->is_traversable())
            navigable->traversable_navigable()->page().client().page_did_change_favicon(*favicon_bitmap);

        return {};
    };

    auto promise = Platform::ImageCodecPlugin::the().decode_image(favicon_data, move(on_successful_decode), move(on_failed_decode));

    return promise;
}

bool HTMLLinkElement::load_favicon_and_use_if_window_is_active()
{
    if (!has_loaded_icon())
        return false;

    // FIXME: Refactor the caller(s) to handle the async nature of image loading
    auto promise = decode_favicon(resource()->encoded_data(), *resource()->url(), document());
    auto result = promise->await();

Review comment (suggestion):
It might be infeasible to do but shouldn’t you check for `image/svg+xml` mime type instead of file extension?
https://www.w3.org/TR/SVG11/mimereg.html

Code after:
{
    m_parser_document = document->make_weak_ptr<DOM::Document>();
}

bool HTMLLinkElement::is_implicitly_potentially_render_blocking() const
{
    // A link element of this type is implicitly potentially render-blocking if the element was created by its node document's parser.
    return &document() == m_parser_document;
}

void HTMLLinkElement::resource_did_load_favicon()
{
    VERIFY(m_relationship & (Relationship::Icon));
    if (!resource()->has_encoded_data()) {
        dbgln_if(SPAM_DEBUG, "Favicon downloaded, no encoded data");
        return;
    }

    dbgln_if(SPAM_DEBUG, "Favicon downloaded, {} bytes from {}", resource()->encoded_data().size(), resource()->url());

    document().check_favicon_after_loading_link_resource();
}

static NonnullRefPtr<Core::Promise<bool>> decode_favicon(ReadonlyBytes favicon_data, URL::URL const& favicon_url, GC::Ref<DOM::Document> document)
{
    if (favicon_url.basename().ends_with(".svg"sv)) {
        auto result = SVG::SVGDecodedImageData::create(document->realm(), document->page(), favicon_url, favicon_data);
        auto promise = Core::Promise<bool>::construct();
        if (result.is_error()) {
            promise->reject(Error::from_string_view("Failed to decode SVG favicon"sv));
            return promise;
        }

        // FIXME: Calculate size based on device pixel ratio
        Gfx::IntSize size { 32, 32 };
        auto immutable_bitmap = result.release_value()->bitmap(0, size);
        auto bitmap = immutable_bitmap->bitmap();
        if (!bitmap) {
            promise->reject(Error::from_string_view("Failed to get bitmap from SVG favicon"sv));
            return promise;
        }
        auto navigable = document->navigable();
        if (navigable && navigable->is_traversable())
            navigable->traversable_navigable()->page().client().page_did_change_favicon(*bitmap);
        promise->resolve(true);
        return promise;
    }

    auto on_failed_decode = [favicon_url]([[maybe_unused]] Error& error) {
        dbgln_if(IMAGE_DECODER_DEBUG, "Failed to decode favicon {}: {}", favicon_url, error);
    };