Here we go again: Mac vs Win font rendering

Hey guys,
here we go again with the never-ending story of Mac vs Win fonts rendering. I still can’t figure why custom fonts looks so ugly on windows. Here’s an example



As you can see, on Windows the font height and vertical alignment is wrong and looks kinda stretched. The font also looks thinner.

What I’m doing is:

  1. On my LAF, I have:
static Typeface::Ptr getTypefacePlain()
    static Typeface::Ptr typeface = Typeface::createSystemTypefaceFor(BinaryData::PTS55F_ttf, BinaryData::PTS55F_ttfSize);
    return typeface;

static Typeface::Ptr getTypefaceBold()
    static Typeface::Ptr typeface = Typeface::createSystemTypefaceFor(BinaryData::PTS75F_ttf, BinaryData::PTS75F_ttfSize);
    return typeface;
  1. On the Editor I have:
const Font labelFont = Font(laf.getTypefacePlain()).withHeight(12.0).withExtraKerningFactor(0.1f);

I tried with both DirectWrite enabled and disabled. Nothing changes

Any hint would be greatly appreciated.


This may be relevant:

1 Like

Thanks Ben. I found an error on what I were doing (using Height instead of PointHeight) and fixed the clipping of the top part of my labels, but still the fonts render differently.

I read the thread you posted and found another thread by @matt with is works on D2D implementation. I’ll try his fork and see if the font rendering improves. In the meantime, I made some tests with a 4k monitor on my windows machine. With W10 default 150% scaling, the rendered fonts are blurry; totally pixellated with 200% scaling and nice (still thin) with 100% scaling.

Despite the scale value, Ableton Live 11 GUI was always perfect looking. So the problem looks JUCE related.

Is everything pixelated, or just fonts? Have you disabled “Auto-scale plugin window”? You can do this by right-clicking the plugin before adding it.

Edit: it was just the fonts and disabling “Auto-scale plugin window” does the trick. Thanks @reuk
Fonts are still rendered differently and looks thin on windows, but I guess this is related the post Ben linked earlier.

For what it’s worth, I didn’t see a big difference using DirectWrite + the JUCE software renderer. I did see a significant difference using the Direct2D renderer (which always uses DirectWrite).



JUCE (Windows DirectWrite fonts) vs ‘native’ DirectWrite rendering)

The main difference I notice between JUCE software renderer and native is the sub-pixel anti-aliasing (the colored fringes). You can also see that the center bars of the ‘A’ and ‘E’ are snaped to the pixel grid in native Direct-2D, a trick that increases clarity at the expense of distorting the font a little.
Judging by the uneven ‘brightness’ across words, I would also hazard a guess that JUCE is using screen-color-space antialiasing (sRBG) rather than the more accurate linear color-space anti-aliasing.

So the difference is pretty subtle. JUCE is doing a pretty good job, but native renderers are very sophisticated at wringing that last little bit of clarity out of a font.


I tried with both DirectWrite and JUCE_DIRECT2D enabled, but I haven’t seen a huge difference. I haven’t tried your fork yet since I’m still on 6.0.8

If you do try my fork, make sure you select the Direct2D renderer in your window constructor.



Hi Matt,
I tested your Direct2D renderer. It is very nice :+1:.

But I have a problem:
For me it seems like all juce popup menus are not rendered with this renderer.
They do not show any color-space anti-aliasing.

Do you have a hint how I could fix this?
Have I missed something?

The renderer of the popup menu window shown by


is already 1.

In case I add


to the popup menu window the window is shown empty (no menu entries and no borders).


Hi Steffi-

Make sure that HWNDComponentPeer is set up to use Direct2D by default.

Specifically, look in juce_win32_Windowing.cpp, and check that the constructor for HWNDComponentPeer looks like this:

    HWNDComponentPeer (Component& comp, int windowStyleFlags, HWND parent, bool nonRepainting)
        : ComponentPeer (comp, windowStyleFlags),
          dontRepaint (nonRepainting),
          parentToAddTo (parent),
          currentRenderingEngine (direct2DRenderingEngine)
          currentRenderingEngine (softwareRenderingEngine)


Hi Matt,

thank you for looking into this issue.

I found a workaround: The popup menu window needs to be opaque. Then after addToDesktop creates the peer I need to force the rendering engine again with:


Now the popup menus show the same nice color-space anti-aliasing.


1 Like

Hi Matt,

I recognized that setting the popup menu window opague is enough to have the new renderer working.

I wonder if the technique for text rendering could be used to render svg icons in the same way, so that they could have the same nice color-space anti-aliasing.


Quite possibly, but I don’t think I can help there. The JUCE renderers really just perform low-level operations.