#1469 [GTK] Rounding issue in font ascent and descent can truncate lines vertically

Bug
open
nobody
patch (5) GTK (8)
5
2013-05-01
2013-04-29
No

The font ascent and descent is currently rounded down, which results in vertically truncated lines if the values aren't integers. To fix this, round the values up.

This doesn't change anything on screen, probably because the screen resolution is set up on pixels, but this fixes drawing on e.g. a scaled print surface.

On a technical point of view, I'm not sure why simply making SurfaceImple::Ascent() and SurfaceImpl::Descent() properly internally work on XYPOSITIONs (which IIUC are floats) doesn't fix the issue, but I guess that some code uses their return values as integers or something.

1 Attachments

Related

Bugs: #1536

Discussion

  • Colomban Wendling

    side-by-side view of the difference on a surface scaled up by a factor of 1/3.

     
  • Neil Hodgson

    Neil Hodgson - 2013-04-30

    Printers normally have more pixels per character than screens so truncation should be les noticeable. The actual values may be interesting.

    Using ceil has the potential to display fewer lines on screen which annoys people so I'd like to be sure this change never does that. Screen display is much more important than printing.

    Ascent and Descent are truncated to integers in FontRealised::Realise in ViewStyle.cxx.

     
    • Colomban Wendling

      Printers normally have more pixels per character than screens so truncation should be les noticeable. The actual values may be interesting.

      Apparently the GtkPrintContext always has a resolution of 72 when printing. I don't have direct printers, but that's the case both for "print to file" and a remote printer supposedly printing at 300dpi. My wild guess here is that GTK simply sends PS data to the printer telling it to draw it at 300dpi or something.

      The actual values I gathered:

      • Monospace 8:
        • Pango context resolution from screen (depends on the screen DPI): 96
        • Pango context resolution from GtkPrintOperation: 72
        • Pango context font ascent/descent from screen: 10.0/3.0
        • Pango context font ascent/descent from print: 7.421875/1.890625
        • Scintilla font ascent/descent from screen: 10.0/3.0
        • Scintilla font ascent/descent from print: 10.0/2.666016
      • Monospace 10:
        • Pango context resolution from screen (depends on the screen DPI): 96
        • Pango context resolution from GtkPrintOperation: 72
        • Pango context font ascent/descent from screen: 12.0/3.0
        • Pango context font ascent/descent from print: 9.281250/2.359375
        • Scintilla font ascent/descent from screen: 12.0/3.0
        • Scintilla font ascent/descent from print: 12.0/2.666016
      • Monospace 12:
        • Pango context resolution from screen (depends on the screen DPI): 96
        • Pango context resolution from GtkPrintOperation: 72
        • Pango context font ascent/descent from screen: 15.0/4.0
        • Pango context font ascent/descent from print: 11.140625/2.828125
        • Scintilla font ascent/descent from screen: 15.0/4.0
        • Scintilla font ascent/descent from print: 15.0/4.0
      • Monospace 16:
        • Pango context resolution from screen (depends on the screen DPI): 96
        • Pango context resolution from GtkPrintOperation: 72
        • Pango context font ascent/descent from screen: 20.0/5.0
        • Pango context font ascent/descent from print: 14.859375/3.781250
        • Scintilla font ascent/descent from screen: 20.0/5.0
        • Scintilla font ascent/descent from print: 20.0/5.333008

      Changing the screen DPI changes the values, but apparently the screen ones always stay round.

      Note that for printing I scale the target surface to adapt to the print resolution: since Scintilla creates its own Pango context, and the resolution is part of that context, I need to scale the Scintilla drawings by print_ctx.resolution/widget_ctx.resolution for them to match the expected resolution:

      scale = print_ctx.resolution / widget_ctx.resolution
      fr.hdcTarget.save()
      fr.hdcTarget.scale(scale, scale)
      scintilla_send_message(sci, SCI_FORMATRANGE, TRUE, &fr)
      fr.hdcTarget.restore()
      

      The factor is 0.75 for 96dpi screen and 72dpi print.

      Using ceil has the potential to display fewer lines on screen which annoys people so I'd like to be sure this change never does that. Screen display is much more important than printing.

      Yes, not losing screen space is important, but I think that not truncating the lines is at least equally as important (in my sample you could see that not only the "g" was truncated, but also the underscores weren't visible at all). And if the screen ascent and descent weren't round already, the lines would also be truncated here.

      I agree that using ceil() like this can theoretically report one pixel too much, if ceil(descent)+ceil(ascent) is greater than ceil(descent+ascent). However, the only way to fix this would be to use floating point values to store ascent and descent everywhere. And to lose even less space, supporting non-round line heights.

       
      Last edit: Colomban Wendling 2013-05-01
      • Colomban Wendling

        Oops, I pasted the wrong Pango print context font ascent and descent for font size 12. It's fixed now.

        BTW I'm not quite sure why it's not exact, but given we scale them by the appropriate factor both Pango print context and Scintilla size are roughly equal:

        • 7.421875+1.890625 ≈ (10+2.666016)*(72/96), so 9.3125 ≈ 9.499512
        • 9.281250+2.359375 ≈ (12+2.666016)*(72/96), so 11.640625 ≈ 10.999512
        • 11.140625+2.828125 ≈ (15+4)*(72/96), so 13.96875 ≈ 14.25
        • 14.859375+3.781250 ≈ (20+5.333008)*(72/96), so 18.640625 ≈ 18.999756
         
      • Neil Hodgson

        Neil Hodgson - 2013-05-01

        The ascent and descent reported by Pango (and all other drawing APIs) is an approximation that does not always cover the extreme ink of all characters and accents. For example the first 'Å' doesn't show the complete ring here, despite the reported ascent being integral:
        Ascender cut off

        There's a trade-off between allowing for extreme characters and accents and fitting more text for the common task of ASCII screen display. Omitting the top 0.2 pixels will often only drop some barely visible grey. Its a judgement call that has gone different ways on different platforms: on OS X, which often reports fractional ascents and descents, rounding is used.

         
        • Colomban Wendling

          The ascent and descent reported by Pango (and all other drawing APIs) is an approximation that does not always cover the extreme ink of all characters and accents. For example the first 'Å' doesn't show the complete ring here, despite the reported ascent being integral:

          Yes, ascent and descent gives the logical line height, so won't include any ink that overflows it.

          There's a trade-off between allowing for extreme characters and accents and fitting more text for the common task of ASCII screen display.

          I wasn't speaking about ink overflows here, only about ascent and descent. If we crop ascent and descent, which themselves may not include all the ink, what part of the characters are we left with? I mean, cropping ascent and descent might crop perfectly common ASCII characters, just like "g" and "_" in my example; not only special cases like Å that could overflow the logical line height.

          What do you propose? Would you prefer some rounding, maybe like floor(descent + 0.8) or something? Or supporting fractional line heights?

           
  • Neil Hodgson

    Neil Hodgson - 2013-05-01

    Its worth trying some different settings to see what happens. Your measurements show some .99s (for the combined height) which are classic rounding errors. Its also common for rounding errors to go the other way and calling ceil then makes a big change.

    Fractional line heights are problematic for displaying code. '-' and '=' are often composed of single pixel lines and having a line pitch of x.5 makes these appear as alternating grey blobs and distinct images. Thought I had an image of this but I can't find it.

     
    • Colomban Wendling

      Its worth trying some different settings to see what happens.

      What do you suggest? I can run whatever appropriate tests on a few Linux machines, maybe even a Windows one.

      BTW, I ran the exact same code on another machine, with GTK 2.20 -- the previous tests were made with GTK 3.4. The results are really similar:

      • Monospace 8:
        • Pango context resolution from screen (depends on the screen DPI): 85.103516
        • Pango context resolution from GtkPrintOperation: 72
        • Pango context font ascent/descent from screen: 9.0/3.0
        • Pango context font ascent/descent from print: 7.421875/1.890625
        • Scintilla font ascent/descent from screen: 9.0/3.0
        • Scintilla font ascent/descent from print: 9.0/2.363281
      • Monospace 10:
        • Pango context resolution from screen (depends on the screen DPI): 85.103516
        • Pango context resolution from GtkPrintOperation: 72
        • Pango context font ascent/descent from screen: 11.0/3.0
        • Pango context font ascent/descent from print: 9.281250/2.359375
        • Scintilla font ascent/descent from screen: 11.0/3.0
        • Scintilla font ascent/descent from print: 11.0/3.545898
      • Monospace 12:
        • Pango context resolution from screen (depends on the screen DPI): 85.103516
        • Pango context resolution from GtkPrintOperation: 72
        • Pango context font ascent/descent from screen: 14.0/4.0
        • Pango context font ascent/descent from print: 11.140625/2.828125
        • Scintilla font ascent/descent from screen: 14.0/4.0
        • Scintilla font ascent/descent from print: 14.0/3.545898
      • Monospace 16:
        • Pango context resolution from screen (depends on the screen DPI): 85.103516
        • Pango context resolution from GtkPrintOperation: 72
        • Pango context font ascent/descent from screen: 18.0/5.0
        • Pango context font ascent/descent from print: 14.859375/3.781250
        • Scintilla font ascent/descent from screen: 18.0/5.0
        • Scintilla font ascent/descent from print: 18.0/4.727539

      Again, Pango print context line height vs. Scintilla line height scaled by print_resolution/widget_resolution:

      • 9.3125 vs 9.613659
      • 11.640625 vs 12.306244
      • 13.96875 vs 14.844329
      • 18.640625 vs 19.228145

      Your measurements show some .99s (for the combined height) which are classic rounding errors.

      Indeed, but note that these were manual additions of the number above, so with only 6 fractional digits. But yeah, this could perhaps be a problem, but it probably could be solved easily by giving room for error, like floor(val + 0.9) or something.

      Fractional line heights are problematic for displaying code. '-' and '=' are often composed of single pixel lines and having a line pitch of x.5 makes these appear as alternating grey blobs and distinct images.

      It's only a problem if hitting sub-pixels of the rendering device. On a screen it is a problem, but on a printer it's just fine. And I'd argue that apparently Pango gives meaningful ascent and descent for the device: the screen values seems always full pixels, but the printer values are more arbitrary (probably more exact for the font/resolution).

      Though, I indeed don't know for sure if Pango gives me round pixel values for screen because it knows it should or if it's some kinda luck -- although I'm pretty confident it knows it and it's nothing like luck. And of course, I have no idea what other platform would give.

       
      • Neil Hodgson

        Neil Hodgson - 2013-05-04

        See if various rounding calculations like roundf() or floor(v+0.9) produce OK results. And try with proportional fonts since monospaced fonts are more likely to want to tile well both horizontally and vertically.

        I wouldn't want to assume that integral ascent and descent are always the case for the screen due to the diversity of Linux distributions. Most distributions ship with very conservative FreeType configurations (partly because of the patent issue) and there is some variance between distributions: Fedora and Ubuntu have different text appearances.

        Various patch sets improve font rendering and are more likely to result in fractional pixel positioning: Infinality, for example, makes a big difference to Fedora.
        http://www.infinality.net/blog/infinality-freetype-patches/
        Its difficult enough to provoke horizontal fractional positions under Pango - kerned pairs like "Te" (in a proportional font) are a simple way.

         

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks