GithubHelp home page GithubHelp logo

Comments (12)

pjcherriman avatar pjcherriman commented on July 22, 2024

I had seen a similar linegap issue on a TV using dash.js for playback

IMG_20240116_110504

It seems the issues is the TV (like many TVs) uses a devicePixelRatio of 1.5

from imscjs.

poolec avatar poolec commented on July 22, 2024

This problem, at least as far as the line gap is concerned, appears to be specific to the case where window.devicePixelRatio is greater than 1 (i.e. where the graphics are rendered at a higher resolution than the co-ordinate system). This is fairly common on TVs and mobiles and indeed in desktop browsers where high resolution displays are used.

Having investigated this further, I believe the problem arises because the implementation of fillLineGap pads each line to an integer vertical co-ordinate in the CSS pixel co-ordinate space. When the device is using a higher resolution for rendering, this does not necessarily align with a device pixel boundary. If that happens, then when the browser draws the background boxes and the positions are not integer positions, gaps can arise e.g. due to independent rounding of positions and sizes in the rendering process. (Overlaps may also occur but would not be apparent with the opaque backgrounds that we use).

I believe there is a fairly straightforward fix to this by rounding to device pixel boundaries. e.g. instead of applying Math.round in the applyFillLineGap function, use a function such as this:

function roundToDevicePixel(position) {
        return Math.round(position * window.devicePixelRatio)/window.devicePixelRatio;
}

from imscjs.

nigelmegitt avatar nigelmegitt commented on July 22, 2024

Worth checking against this test in particular:

This test uses background colours with around 50% opacity, so if there are overlapping background boxes then they look like darker lines at the overlap locations. If this fix doesn't break that test, I expect that it's probably fine. Obviously should pass all the other tests too.

from imscjs.

poolec avatar poolec commented on July 22, 2024

I tried that test. At 1.0 devicePixelRatio it works fine. At other devicePixelRatios, the generated PNG always comes out the same size so is not representative of the browser display. With or without my proposed fix, the generated image shows gaps.

The generated HTML shows no overlaps when viewed on the same browser at the same devicePixelRatio. I do still see a gap in one devicePixelRatio, even with the proposed fix, so will dig into that one a bit further.

from imscjs.

poolec avatar poolec commented on July 22, 2024

I've now done some more detailed investigation using this test.
What I see in Chrome can be summarised as follows:

  • When window.devicePixelRatio is 1.0, getBoundingClientRect returns values that are precise multiples of 1/64 pixel
  • When devicePixelRatio is 1.0, calculated padding values are precise multiples of 1/64 pixel and once padded, the resulting span has an integer vertical size
  • When devicePixelRatio is 1.25, getBoundingClientRect returns values that are close to multiples of 0.2 pixels but +/- something of the order of 0.00001
  • When devicePixelRatio is 1.25, calculated padding values are close to multiples of 0.2 pixels but +/- something of the order of 0.00001
  • When the bottom padding value is even a tiny bit less than the nearest multiple of 0.2 pixels, the background is rendered with a gap. If the bottom padding is a tiny bit more than a multiple of 0.2 pixels, there is no gap. For example: 2.799999237061 gives a cap. 2.8 does not.
  • When a gap is visible, the new span height returned by getBoundingClientRect after padding has been applied is ~1/64 pixels smaller than expected

The 1/64 figure I am seeing correlates with the fixed point representation with 6 fractional bits that appears to be used within Blink (and came originally from WebKit). It appears that some calculations within the Chrome browser are rounding down to the nearest 1/64th of a pixel in cases where rounding to nearest might appear more appropriate.

I also observe that whilst 1.25 (the devicePixelRatio I tested) can be precisely represented in floating point, 1/1.25 (0.8), and multiples of it, cannot. Thus I wonder whether some loss of precision in the layout calculations is contributing to the problem.

Based on these new observations, I have just tested a different workaround in which I add 0.0001 to each calculated bottom padding value in the implementation of applyFillLineGap so as to prevent the calculated padding values ever ending up slightly less than the 'expected' value.

Initial results suggest that the problem then does not arise (nor is there any overlap) but more tests would be needed to confirm.

This is, of course, not a very satisfactory fix for imscJS.

from imscjs.

nigelmegitt avatar nigelmegitt commented on July 22, 2024

@JibberJim did some work on this before to make it work with devicePixelRatio != 1 on the BBC fork. I did a diff between the BBC fork and the main repo and could not see any significant differences that would explain why it might work in one context but not in another.

from imscjs.

poolec avatar poolec commented on July 22, 2024

Having now investigated this issue further, it's clear that different browsers are showing different rounding behaviours when rendering subtitles on displays where devicePixelRatio is not 1.0. This causes gaps between lines at certain vertical positions. In some cases, there are even gaps between adjacent spans.

I do not believe there are any concrete requirements for the user agent covering rounding behaviour in such cases. As such it can't confidently be argued that it is a user agent problem. In my mind, it therefore falls to imscJS to do its best to avoid these gaps being visible to the end user across the range of browsers in use. (Separately, there may be a case for making the specs more precise.)

To my mind, the best solution would be to introduce a small (~1 pixel) overlap in the text backgrounds in the case where (i) fillLineGap is enabled, (ii) the background colours of adjacent lines are both opaque and (iii) devicePixelRatio is not 1.0. This would not prevent gaps in cases where semi-transparent backgrounds are used but in that case, there is a risk of creating visible overlaps instead which would probably look just as bad. It would address the problem fully for the opaque background case. It could be achieved by an additional 1 pixel of bottom padding and -1 pixel of bottom margin.

A similar approach could be taken between adjacent spans to eliminate vertical lines appearing between words.

It's possible that an overlap of less than 1 pixel may address the problems observed. Maybe 0.5 pixel or 1/devicePixelRatio or 0.5/devicePixelRatio might be sufficient. However, I'm not sure it is worth trying to find the absolute minimum that would solve the problems seen today since (i) future devices might be affected in different ways and (ii) the visible difference would be negligible.

This approach would not result in any text characters being clipped in the same way they would if, for example, line spacing were artificially reduced.

I plan to prototype this properly when I have time, but in the mean time, I'd welcome any comments or suggestions for improvement.

from imscjs.

palemieux avatar palemieux commented on July 22, 2024

Thanks for all the sleuthing!

From an imscJS main branch perspective, I feel that the energy spent chasing UA shortcomings could be better spent either

  • relentlessly bugging UA folks to support missing CSS features so that imscJS and others do not have to implement fragile workarounds; or
  • fixing the shortcomings directly in the UA code.

For example, inline-sizing would make implementing fillLineGap less fragile.

[ed.: I do think imscJS needs workarounds for critical features, but there is diminishing returns in addressing all idiosyncrasies.]

from imscjs.

poolec avatar poolec commented on July 22, 2024

I understand the sentiment. However, the problem with that approach is that it really doesn't address the TV market. TVs invariably have browsers that are some way behind the cutting edge of desktop browsers (typically 2 years or more), very rarely receive updates and are infrequently replaced by their users.

As a content provider wishing to ensure our viewers get a great experience with subtitles on their TVs, we have to work with what is out there, much as we might wish it to be better. Since the majority of TV viewing is on a TV, and we're seeing the problems described here on many of them, I think it is entirely appropriate that imscJS acknowledge that reality and do what's reasonably possible to address it in the interest of subtitle users, provided that the fix doesn't break something else.

I don't want to waste time on a fix for this if you would reject it on principle. However, I think it could be written in a fairly self contained way and be made configurable. Would that be acceptable?

from imscjs.

palemieux avatar palemieux commented on July 22, 2024

@poolec Can you share the compatibility requirements for those TV browsers? In particular, what is the lowest ECMA Script version support? The idea is to figure out a strategy for legacy support, esp. in light of the ongoing work on imscJS 2.0.

from imscjs.

poolec avatar poolec commented on July 22, 2024

Sure. They're supporting either HbbTV 2.0.3 or, for very recent models, HbbTV 2.0.4.
HbbTV 2.0.3 references the CTA WAVE Web Media API Snapshot 2018
HbbTV 2.0.4 references the CTA WAVE Web Media API Snapshot 2021
In terms of ECMAScript, they reference ECMAScript 6 and ECMAScript 2021 respectively, albeit with some exceptions.

from imscjs.

nigelmegitt avatar nigelmegitt commented on July 22, 2024

Hypothesis: when devicePixelRatio is not 1 the UA is incorrectly calculating the bottom or right edges of areas, because, in general:

round(origin * devicePixelRatio) + round(extent * devicePixelRatio) != round((origin + extent) * devicePixelRatio)

In other words, the theory is that the UA is using the wrong algorithm to calculate the edges in scaled views.

I put together a codepen to discover how frequently this might arise, at https://codepen.io/nigelmegitt/full/pomKoww - if this theory is correct, there are a lot of opportunities to generate 1px gaps or overlaps when devicePixelRatio is not 1.

Just to emphasise, it's a hypothesis only at this point.

from imscjs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.