gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: NSView patch


From: Nicola Pero
Subject: Re: NSView patch
Date: Mon, 23 Feb 2009 17:37:39 +0100


I would say that the algorithm followed by GUI must be incorrect in the case
of overlapping siblings - while a normal floating
point mismatch in computing areas that need drawing could result in some
areas being redrawn unnecessarily, I fail to
see how it could cause a major part of a view to be drawn *above* the views
above it, as in the screenshot ... unless there
is an error in the drawing logic.  But possibly making it correct for
overlapping siblings might make it too expensive
in the normal case of nested views ? (that's what the Apple documentation
suggests)


because of the floating point mismatch, whole views are not set as not
needing display after drawing

I completely agree with this. I had a look and you are completely right. :-)

You can't even see the problem by using NSStringFromRect(), because
it prints coordinates using %g, which does not print enough significant
digits (shall we fix that ?). ;-)

But if you hack NSStringFromRect() to use %f, you can see that the coordinate conversions in the GUI introduces floating point errors ... at least in the case of
DBModeler (couldn't find another example).

In my experiment, the conversion error occurred for a view with frame --

 x=281.721222, y=148.529358, width=150.000000, height=70.000000

when the frame was converted into the view's own coordinate system, it became

 x=0.000000, y=0.000000, width=149.99969, height=70.000000

So, the GUI started trying to redraw the entire view; it took the view's frame, and converted it into the view's coordinate system to get the area to redraw.

Because of the rounding error, the area to redraw ended up being smaller,
by 0.00031 pixels, than the bounds.  So the area was redrawn, but the
view was still not marked as fully redrawn because of the area redrawn
was smaller than the bounds. :-(

Now this is definitely a performance issue since the view will keep getting
redrawn due to the rounding error; but it shouldn't generate any invalid
display. ;-)

I'm not sure how you fix this; I'm not too keen on forcing different floating point values to be considered equal ;-) ... either the coordinate conversion
should be improved, or some more robust logic could be used ... trying
to reduce the number of conversions and the effect of rounding errors. Maybe we could always redraw an area that is slightly larger than the frame ? Or
we could use the bounds instead of taking the frame and converting ?


unfortunately for our unsuspecting view, subviews which were at some
odd coordinate were left as needing display,  when their super views
noticed that they were still marked as needing display and redisplayed
only those. (in case a view calls -setNeedsDisplay: on something while
in drawRect:)

Yes. This is where there seems to be an error in the logic in the current code - ie, support for overlapping sibling views is missing. If a view is redrawn, all views
that above it must always be redrawn too. ;-)

So, if view A is still marked as needing redisplay, and view B is on top
of it, both A and B must be redrawn, even if B is not marked as needing
redisplay. The current code in the GUI doesn't do that; it iterates over the
subviews, and redraws the ones marked for redisplay, but doesn't redraw
any other one, without considering that if we support overlapping sibling views, it also needs to redraw all the other views that are on top of the ones being
redrawn. ;-)

In the standard situation where there are no overlapping views, adding support for overlapping sibling views in that way would mean a lot of pointless redrawing though - because if view A is redrawn, then all views following it in the list of subviews would be redrawn even if they are not actually overlapping A. In other words, any time anything changes in a window, everything needs to be redrawn. :-(

Presumably the code could try to only redraw views that are over (according to the list of views) *and* that overlap the ones that needed to be redrawn. I'm not sure how to do that computation efficiently though ... I suppose for
every view that is redrawn, you also iterate over all the views above it
looking for ones that overlap, and redraw these as well. That sounds potentially
expensive (N^2) if there are a lot of subviews ... :-(

Thanks




reply via email to

[Prev in Thread] Current Thread [Next in Thread]