Hi all,
(
Note that this is the 4th time attempting to submit this post and get by the dreaded:
"Please note: your content was added successfully, but a moderator needs to approve it before it can be posted"
)
I am trying to understand the behavior of copiesOnScroll in a typical NSScrollView/NSClipView/NSView setup. I’ll refer to the NSView or documentView as MyCustomView throughout, and just note that this is a large view that can take substantial time to draw (I am actually doing this in a sample app to better understand all the various issues at play here). Note also that I am currently working on the “non-layer backed case” and not opting in to responsive scrolling. Let’s say the view is 10,000 x 800 units. Assume also that this scroll view takes up the entire window, and we are simply viewing the beginning portion of MyCustomView in a window that is 1,500 x 800 (so we are viewing the rect (l: 0, t:0, r:1500, b:800)). Now let’s scroll everything to the left by 500 so that we are now viewing (l:500, t:0, r:2000, b:800). During such a scroll, I would expect, with copiesOnScroll set to YES, that the dirty rect we get in MyCustomView’s drawRect method would be (l: 1500, t:0, r:2000, b:800) but instead we get the entire visible area: (l:500: t:0, r:2000, b:800).
According to Apple docu on copiesOnScroll:
When the value of this property is YES, the clip view copies its existing rendered image while scrolling (only drawing exposed portions of its document view); when it is NO, the view forces its contents to be redrawn each time.
For what it’s worth, this was the behavior we saw with scrolling when our app (the real app, not this sample one) used to be a Carbon based app, the update region would only consist of the newly exposed parts of the visible region.
In order to understand this behavior a little more, I substituted MyScrollView/MyClipView subclasses for the NSScrollView/NSClipView part of the setup. Overriding a few routines and just calling super to get a feel for whose was calling various update routines (like setNeedsDisplay or setNeedsDisplayInRect:) I found the following:
When clicking in the scroll bar to start scrolling to the right, I get the following calls to MyClipView::setNeedsDisplayInRect:(NSRect)invalidRect:
invalidRect, NSRect (origin = (x = 0, y = 0), size = (width = 0, height = 0))
invalidRect, NSRect (origin = (x = 0, y = 0), size = (width = 0, height = 0))
And then:
invalidRect, NSRect (origin = (x = 180.5, y = 0), size = (width = 460, height = 363))
This is the entire visibleRect being invalidated as a result of the translateOriginToPoint call apparently as seen in the stack (but not copying here because I am trying to figure out what is not allowing this post to be posted).
And then:
invalidRect, NSRect (origin = (x = 460, y = 0), size = (width = 180.5, height = 363))
This looks like the correct newly “revealed” section to draw. And here is the stack (but not copying here because I am trying to figure out what is not allowing this post to be posted)
And then 3 more of these:
invalidRect, NSRect (origin = (x = 0, y = 0), size = (width = 0, height = 0))
invalidRect, NSRect (origin = (x = 0, y = 0), size = (width = 0, height = 0))
invalidRect, NSRect (origin = (x = 0, y = 0), size = (width = 0, height = 0))
And eventually the MyCustomView drawRect is called with the dirtyRect:
dirtyRect, NSRect (origin = (x = 180.5, y = 0), size = (width = 460, height = 363))
instead of the desired:
dirtyRect, NSRect (origin = (x = 460, y = 0), size = (width = 180.5, height = 363))
So any idea why copiesOnScroll doesn’t send an appropriately smaller dirtyRect (or a list of smaller rects via getRectsBeingDrawn)? This extra drawing is causing significant performance issues in the real app.
Thanks,
Chris