As you may already know, I am using HaikuWebKit in my IMAP client for Haiku (EmailViewsNeo). It works quite well, but I have noticed that images at any size other than 100% look grainy.
I ran this through Claude, and it came back with a theory and a solution, which I quote below in the hope that someone can validate this somehow can get it fixed.
=========
Scaled images are drawn without bilinear filtering in HaikuWebKit
Symptom
Images shown at any size other than their natural size look grainy in
WebPositive and in other HaikuWebKit-based applications. At 100% zoom
(image drawn 1:1) they are crisp. The same image file, scaled to the same
size in ShowImage, is crisp too — so decoding is fine; the difference is
in how the web view draws a scaled bitmap.
Reproduce: open any page with photos, set the zoom to 100% (crisp), then
to any other zoom, or shrink the window so the layout scales the images
(grainy, nearest-neighbour look).
Cause
GraphicsContextHaiku::drawBitmap
(Source/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp)
requests filtered scaling only for some interpolation qualities:
uint32 flags = 0;
if (options.interpolationQuality() > InterpolationQuality::Low)
flags |= B_FILTER_BITMAP_BILINEAR;
m_view->DrawBitmap(image, BRect(srcRect), BRect(destRect), flags);
But InterpolationQuality (Source/WebCore/platform/graphics/GraphicsTypes.h)
is declared with Default as its first, and therefore smallest, value:
enum class InterpolationQuality : uint8_t {
Default,
DoNotInterpolate,
Low,
Medium,
High
};
Ordinary page images are painted with InterpolationQuality::Default, and
Default > Low is false, so they never get B_FILTER_BITMAP_BILINEAR.
app_server then scales them with nearest-neighbour sampling, which is the
grain seen. Only images that explicitly request Medium or High are
filtered.
Proposed fix
Filter unless interpolation was explicitly disabled. DoNotInterpolate is
what CSS image-rendering: pixelated / crisp-edges maps to, so pixel art
keeps its hard edges:
if (options.interpolationQuality() != InterpolationQuality::DoNotInterpolate)
flags |= B_FILTER_BITMAP_BILINEAR;
One line; nothing else needs to change.
Checked against
Tree cloned from https://codeberg.org/haiku/haikuwebkit.git on 2026-09-18
(default branch, --depth 1).