New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 862424 link

Starred by 1 user

Issue metadata

Status: Assigned
Owner:
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Chrome
Pri: 1
Type: Bug



Sign in to add a comment

Implement Pixel Canvas like snapping logic for ui Layers

Project Member Reported by malaykeshav@chromium.org, Jul 10

Issue description

ui::Layer currently may not align after scaling at fractional scales.
We should implement something similar to Pixel Canvas for ui::Layers where each layer is snapped to its parent layer even after being scaled.
 
Cc: trchen@chromium.org enne@chromium.org
What is different here than what picturelayer does to snap to pixels?
Status: (was: Assigned)
Looking at it again, I think we don't need this. The cc layers already have their bounds in float and are aligned always with other layers (though they may not be snapped to the physical pixel grid). They will not have 1px gaps as views::View did.

Marking this bug as WF unless I am missing something here. @oshima?
Just had an offline discussion with Oshima. The problem here is with the root layer of the platform window. The bounds of the platform window is provided by the hardware (Chrome OS) or the OS (windows, linux & MAC) in pixels. However, the root layer has its size in DIP. This results in some data loss at rounding loss from pixels->DIP. 
This results in bugs like  Issue 843354  on chrome OS or having a 1px black strip at the right and bottom edge in windows fullscreen mode. For chrome OS (and  Issue 843354 ) this is resolved by simply adjusting the ui::compositor size. However we cannot do so for other platform windows.

The other problem that we have is the ui::Layer bounds lying on fractional pixels after scaling. We ensure that the layer origin is on the pixel grid with the use of |subpixel_position_offset_|, but the other corners of the layer may still lie on partial pixels after scaling. This results in blurriness. This was the same issue in ui Views that was resolved with Pixel Canvas. 

I am also aware of |IsSnappedToPixelGridInTarget()|. However I don't know how it snaps to the pixel grid. Does it take the parent ui::Layer bounds into context? If a corner of the ui::Layer was aligned to its parent ui::Layer in DIP, was it aligned after it was scaled and snapped using |IsSnappedToPixelGridInTarget()|? 

The solution proposed is to use the same logic Pixel Canvas used for ui Views. we know the pixel size of the root platform window(Display dimensions on chrome os and window size on other platforms). Similar to |subpixel_position_offset_|, we can have a correction delta for the width and the height of the ui::Layer, such that post scaling the layer bounds matches the desired pixel size. Its immediate child layer will know the parent's pixel size and can compute their own correction delta for their width and height. And so on cascading down.

This however will not work where we want the ui::Layer to intentionally lie on a partial pixel(Shadow?). Or if the layer has some transform applied to it. These are outliers that can be handled with a flag.

I can work on a quick prototype to see if this is feasible and the extent of work needed. But I wanted to get input on this approach or if there is already something to handle situations like these? Does forcing |IsSnappedToPixelGridInTarget()| for all ui::Layers do something similar?
I guess this sounds like a lot more complexity that will make the code harder to understand, more fragile, and harder to change for others in the future. At what point is it worth it to just get the UI working in physical pixels like blink instead of in DIP? I would really rather us spend effort toward that than to adding complex stuff like more ways to snap and flags to control the snapping, at more layers of the stack.
From my understanding, the use of pixels would add more complexity as well. @oshima would be able to elaborate more on this.
Using pixels makes things like multi display, animation, consistently and persistently managing bounds and also UI/UX design much more complex and difficult to handle.
+1 for using pixels for sizing as pixels are ground truth. Calculations can still be performed DIPs where appropriate.

In general the root layer size does not even match the display size because we are using DIPs and we require the scaled bounds of the display to an integer number of DIPs. This requirement is not possible to satisfy without lying about the size of the display in general. We have to add a fraction of a pixel to compensate.
Actually I guess on ash we aren't adding the fractional pixel according to https://bugs.chromium.org/p/chromium/issues/detail?id=843354.
Using pixel on client side isn't as simple as you may think especially in dynamic, multi-density world.
It'd require a lot of work (I'd take more than a year) and can also be very error prone.

* Bounds is no longer meaningful without scale factor. For example, restore bounds 100x100 can mean 200x200 or 150x150 pixels,
and we have many places that stores bounds in memory and on the disk.

* Animation has to be scaled depending on how it's computed.

* Events points/velogicy may needs to be scaled depending on how it's used.

* Most of layout is done in DIP, and converting them into pixel isn't actually that strait forward.
  Say if you have 10dip container and want to layout two children 50% / 50%. Both children will
  be 5px at 1 dsf, but children will have different size at 1.5 dsf because you can't device 15
  into two even pixels. (Pixel canvas does this automatically)

* We can't precompute the size any more.

with all above, most difficult part is the screen coordinates because we can't convert pixels into screen coordinates which is managed in DIP
(This is important to provide consistent view of multiple displays to users).
That means that event has to have extra field for the case when a user dragged something from one display to another.

I'm not saying this is pefect approach. This problem is hard. That's why none of OS has good solution. OSX doesn't allow
fractional scale, android doesn't have true dynamic, multi desnty support. I'm not familiar with Windows, but they had very
weird behavior (they have multipe modes, and behave differently due to legacy code iirc).

That's being said, I still think it's be better if the platform can support this because it simplifies client code a lot.

One potential approach is to implement this in ui/compositor instead (although I haven't looked into details)?
ui/compositor becomes more irrelevant with gpu raster, so i would encourage imagining a world without ui compositor, and try to not make ourselves depend on it in new ways if we can do that in views instead.
Status: Assigned
Fixing bugs with no status.

Sign in to add a comment