This partly reverts commit ad28684b10.
Prior to that change, getBrush() would always end up calling
SetTransform on gradient/image brushes. This is important because, when
drawing text, we combine the current brush transform with the text
transform. If we don't reset the brush transform each time, these
transforms end up accumulating across frames.
initWithWindowScene appears to create a window with no area if the
provided scene is null. As a fallback, creating a window without an
associated scene still returns usable bounds.
The old implementation had a few problems:
- For a target area near but not touching the bottom of the parent area,
and a long menu with an initially-visible item halfway through the
list, the initially-visible item would sometimes be obscured by the
scroller area. The new implementation adjusts the size of the menu to
ensure that there's enough additional room for the scroller areas.
- For a target area at the very top or very bottom of the target area,
the menu would be positioned inconsistently; sometimes it would
overlap with the target area, but other times it would be positioned
with a gap separating the menu and target area. In the new
implementation, if there's not enough room for scrollers to be
positioned above/below the target area, the menu will always be
positioned so that it touches but does not overlap the target area.
- The initially-selected item would normally be
positioned as close as possible to the target area, but this wasn't
always applied consistently for long menus, and the menu would
sometimes only be scrolled enough to make the item visible at the end
of the menu furthest from the target area. In the new implementation,
the initially-visible item will always be positioned on top of the
target area, or adjacent to it, depending on the available space.
This makes it a bit easier to see exactly which PopupMenu state is used
during the calculation, and enforces that no menu state is modified
during the call.
Even if the output stream is the only one receiving callbacks, it's
possible that the input device got disconnected, in which case we'll
still need to recreate both streams.