mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-07 21:59:54 +00:00
LibGfx+LibWeb: Use mipmaps for downscaling images
This changes Gfx::ScalingMode to reflect the three modes of scaling we support using Skia, which makes it a bit easier to reason about the mode to select. New is ::BilinearMipmap, which uses linear interpolation between mipmap levels to produce higher quality downscaled images. The cubic resampling options Mitchell and its sibling CatmullRom both produced weird artifacts or resulted in a worse quality than BilinearMipmap when downscaling. We might not have been using these correctly, but the new ::BilinearMipmap method seems to mirror what Chrome uses for downscaled images.
This commit is contained in:
parent
7544066c0c
commit
3f6cbeb87e
Notes:
github-actions[bot]
2025-11-12 15:00:21 +00:00
Author: https://github.com/gmta
Commit: 3f6cbeb87e
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6792
Reviewed-by: https://github.com/kalenikaliaksandr ✅
23 changed files with 66 additions and 29 deletions
|
|
@ -455,17 +455,19 @@ struct TextDecorationThickness {
|
|||
// FIXME: Find a better place for this helper.
|
||||
inline Gfx::ScalingMode to_gfx_scaling_mode(ImageRendering css_value, Gfx::IntRect source, Gfx::IntRect target)
|
||||
{
|
||||
if (source.size() == target.size())
|
||||
return Gfx::ScalingMode::None;
|
||||
|
||||
switch (css_value) {
|
||||
case ImageRendering::Auto:
|
||||
case ImageRendering::HighQuality:
|
||||
case ImageRendering::Smooth:
|
||||
if (target.width() < source.width() || target.height() < source.height())
|
||||
return Gfx::ScalingMode::BoxSampling;
|
||||
return Gfx::ScalingMode::BilinearBlend;
|
||||
if (target.width() < source.width() && target.height() < source.height())
|
||||
return Gfx::ScalingMode::BilinearMipmap;
|
||||
return Gfx::ScalingMode::Bilinear;
|
||||
case ImageRendering::CrispEdges:
|
||||
return Gfx::ScalingMode::NearestNeighbor;
|
||||
case ImageRendering::Pixelated:
|
||||
return Gfx::ScalingMode::SmoothPixels;
|
||||
return Gfx::ScalingMode::NearestNeighbor;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ WebIDL::ExceptionOr<void> CanvasRenderingContext2D::draw_image_internal(CanvasIm
|
|||
auto scaling_mode = Gfx::ScalingMode::NearestNeighbor;
|
||||
if (drawing_state().image_smoothing_enabled) {
|
||||
// FIXME: Honor drawing_state().image_smoothing_quality
|
||||
scaling_mode = Gfx::ScalingMode::BilinearBlend;
|
||||
scaling_mode = Gfx::ScalingMode::BilinearMipmap;
|
||||
}
|
||||
|
||||
if (auto* painter = this->painter()) {
|
||||
|
|
|
|||
|
|
@ -214,11 +214,11 @@ static ErrorOr<NonnullRefPtr<Gfx::Bitmap>> crop_to_the_source_rectangle_with_for
|
|||
// The "high" value indicates a preference for a high level of image interpolation quality. High-quality image interpolation may be more computationally expensive than lower settings.
|
||||
case Bindings::ResizeQuality::Medium:
|
||||
// The "medium" value indicates a preference for a medium level of image interpolation quality.
|
||||
scaling_passes.append(ScalingPass { .mode = Gfx::ScalingMode::BoxSampling, .width = output_width, .height = output_height });
|
||||
scaling_passes.append(ScalingPass { .mode = Gfx::ScalingMode::BilinearMipmap, .width = output_width, .height = output_height });
|
||||
break;
|
||||
case Bindings::ResizeQuality::Low:
|
||||
// The "low" value indicates a preference for a low level of image interpolation quality. Low-quality image interpolation may be more computationally efficient than higher settings.
|
||||
scaling_passes.append(ScalingPass { .mode = Gfx::ScalingMode::BilinearBlend, .width = output_width, .height = output_height });
|
||||
scaling_passes.append(ScalingPass { .mode = Gfx::ScalingMode::Bilinear, .width = output_width, .height = output_height });
|
||||
break;
|
||||
case Bindings::ResizeQuality::Pixelated: {
|
||||
// The "pixelated" value indicates a preference for scaling the image to preserve the pixelation of the original as much as possible, with minor smoothing as necessary to avoid distorting the image when the target size is not a clean multiple of the original.
|
||||
|
|
@ -237,7 +237,7 @@ static ErrorOr<NonnullRefPtr<Gfx::Bitmap>> crop_to_the_source_rectangle_with_for
|
|||
scaling_passes.append(ScalingPass { .mode = Gfx::ScalingMode::NearestNeighbor, .width = source_width * width_multiple, .height = source_height * height_multiple });
|
||||
|
||||
// then scale it the rest of the way to the target size using bilinear interpolation.
|
||||
scaling_passes.append(ScalingPass { .mode = Gfx::ScalingMode::BilinearBlend, .width = output_width, .height = output_height });
|
||||
scaling_passes.append(ScalingPass { .mode = Gfx::ScalingMode::Bilinear, .width = output_width, .height = output_height });
|
||||
} break;
|
||||
}
|
||||
for (ScalingPass& scaling_pass : scaling_passes) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue