Skip to content

Put the final touches on GDI's underlines#16475

Merged
DHowett merged 5 commits intomainfrom
dev/lhecker/gdi-fine-tuning
Dec 15, 2023
Merged

Put the final touches on GDI's underlines#16475
DHowett merged 5 commits intomainfrom
dev/lhecker/gdi-fine-tuning

Conversation

@lhecker
Copy link
Member

@lhecker lhecker commented Dec 15, 2023

While #16444 left wavy lines in an amazing state already, there were
a few more things that could be done to make GDI look more consistent
with other well known Windows applications.

But before that, a couple unrelated, but helpful changes were made:

  • GdiEngine::UpdateFont was heavily modified to do all calculations
    in floats. All modern CPUs have fast FPUs and even the fairly slow
    lroundf function is so fast (relatively) nowadays that in a cold
    path like this, we can liberally call it to convert back to ints.
    This makes intermediate calculation more accurate and consistent.
  • GdiEngine::PaintBufferGridLines was exception-unsafe due to its
    use of a std::vector with catch clause and this PR fixes that.
    Additionally, the vector was swapped out with a til::small_vector
    to reduce heap allocations. (Arena allocators!)
  • RenderingTests was updated to cover styled underlines

With that in place, these improvements were done:

  • Word's double-underline algorithm was ported over from AtlasEngine.
    It uses a half underline-width (aka thinLineWidth) which will now
    also be used for wavy lines to make them look a bit more filigrane.
  • The Bézier curve for wavy/curly underlines was modified to use
    control points at (0.5,0.5) and (0.5,-0.5) respectively. This results
    in a maxima at y=0.1414 which is much closer to a sine curve with a
    maxima at 1/(2pi) = 0.1592. Previously, the maxima was a lot higher
    (roughly 4x) depending on the aspect ratio of the glyphs.
  • Wavy underlines don't depend on the aspect ratio of glyphs anymore.
    This previously led to several problems depending on the exact font.
    The old renderer would draw exactly 3 periods of the wave into
    each cell which would also ensure continuity between cells.
    Unfortunately, this meant that waves could look inconsistent.
    The new approach always uses the aforementioned sine-like waves.
  • The wavy underline offset was clamped so that it's never outside of
    bounds of a line. This avoids clipping.

Validation Steps Performed

  • Compile RenderingTests and run it
  • Using Consolas, MS Gothic and Cascadia Code while Ctrl+Scrolling
    up and down works as expected without clipping ✅

@lhecker lhecker added Product-Conhost For issues in the Console codebase Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues labels Dec 15, 2023
@lhecker
Copy link
Member Author

lhecker commented Dec 15, 2023

On a 150% display scale monitor...

8, 800% zoom 16, 400% zoom 32, 200% zoom
Consolas image image image
Aptos Mono image image image

I've tested a ton of other fonts as well, too many to list here. Let me know if you find any weird behavior! (Aptos Mono is the one with the consistently weirdest behavior of any font I've seen so far. That's why I listed it above. As you can see there, it specifies a weirdly thin underline...)

@lhecker
Copy link
Member Author

lhecker commented Dec 15, 2023

I've adjusted the wave height to match the double underline height so that it looks consistent. Cascadia Mono 64, 400% zoom:

image

The above images are now technically outdated, but I don't want to redo them to be honest. They still look quite similar.

@DHowett
Copy link
Member

DHowett commented Dec 15, 2023

hehe if you make the font too small you can still see the double and the curly

image

this is not a complaint and you need not fix it

@DHowett
Copy link
Member

DHowett commented Dec 15, 2023

hehe if you make the font too small you can still see the double and the curly

image

this is not a complaint and you need not fix it

actually I am curious as to why underlines disappear at this small size

@DHowett
Copy link
Member

DHowett commented Dec 15, 2023

(atlas does not do this!
image

)

@lhecker
Copy link
Member Author

lhecker commented Dec 15, 2023

Should be fixed in the latest commits.

@DHowett
Copy link
Member

DHowett commented Dec 15, 2023

Re-tested Consolas McTinyfont and it is perfect

@DHowett DHowett changed the title Final touches for GDI's underlines Put the final touches on GDI's underlines Dec 15, 2023
@DHowett DHowett merged commit 99193c9 into main Dec 15, 2023
@DHowett DHowett deleted the dev/lhecker/gdi-fine-tuning branch December 15, 2023 23:02
DHowett pushed a commit that referenced this pull request Dec 15, 2023
While #16444 left wavy lines in an amazing state already, there were
a few more things that could be done to make GDI look more consistent
with other well known Windows applications.

But before that, a couple unrelated, but helpful changes were made:
* `GdiEngine::UpdateFont` was heavily modified to do all calculations
  in floats. All modern CPUs have fast FPUs and even the fairly slow
  `lroundf` function is so fast (relatively) nowadays that in a cold
  path like this, we can liberally call it to convert back to `int`s.
  This makes intermediate calculation more accurate and consistent.
* `GdiEngine::PaintBufferGridLines` was exception-unsafe due to its
  use of a `std::vector` with catch clause and this PR fixes that.
  Additionally, the vector was swapped out with a `til::small_vector`
  to reduce heap allocations. (Arena allocators!)
* RenderingTests was updated to cover styled underlines

With that in place, these improvements were done:
* Word's double-underline algorithm was ported over from `AtlasEngine`.
  It uses a half underline-width (aka `thinLineWidth`) which will now
  also be used for wavy lines to make them look a bit more filigrane.
* The Bézier curve for wavy/curly underlines was modified to use
  control points at (0.5,0.5) and (0.5,-0.5) respectively. This results
  in a maxima at y=0.1414 which is much closer to a sine curve with a
  maxima at 1/(2pi) = 0.1592. Previously, the maxima was a lot higher
  (roughly 4x) depending on the aspect ratio of the glyphs.
* Wavy underlines don't depend on the aspect ratio of glyphs anymore.
  This previously led to several problems depending on the exact font.
  The old renderer would draw exactly 3 periods of the wave into
  each cell which would also ensure continuity between cells.
  Unfortunately, this meant that waves could look inconsistent.
  The new approach always uses the aforementioned sine-like waves.
* The wavy underline offset was clamped so that it's never outside of
  bounds of a line. This avoids clipping.

* Compile RenderingTests and run it
* Using Consolas, MS Gothic and Cascadia Code while Ctrl+Scrolling
  up and down works as expected without clipping ✅

(cherry picked from commit 99193c9)
Service-Card-Id: 91356394
Service-Version: 1.19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues Product-Conhost For issues in the Console codebase

Projects

Development

Successfully merging this pull request may close these issues.

3 participants