Am Donnerstag, den 02.12.2010, 10:27 -0800 schrieb Alan Coopersmith:
> Nicolai Stange wrote:
> > Alan, will this issue be fixed in the Xnewt?
>
> I have no idea, I don't work on Xnewt directly. I work in the Solaris
> team - Xnewt is part of the Sun Ray product and is managed by their team.
> (We of course talk a lot and work together a lot, but I can't commit fixes
> to their source repos, nor make commitments about them doing so.)
Alan and Julien, you've been very helpful, thank you!
For those Xnewt users who may be concerned by the same issue, I've
attached the work around through libXrender. It works by looking at each
XrenderCreate.*Gradient request's stops at the client side and modifies
them slightly such that there are no two equal ones ever sent to the X
server.
Best regards
Nicolai
--- a/libXrender-0.9.6/src/Picture.c 2009-10-16 23:26:58.000000000 +0200
+++ libXrender-0.9.6/src/Picture.c 2010-12-03 21:00:22.225396000 +0100
@@ -267,6 +267,122 @@
return pid;
}
+/* Sun's XNewt which is based on xorg-server-1.3.0.0 has a bug
+ bug causing X-Clients to crash with a BadValue if two
+ subsequent stops are equal. This is a serious problem with
+ gtk-engines and wxGTK where this situation happens often.
+ This function is a dirty work around that avoids this
+ situation by modifying two subsequent equal the stops
+ slightly. */
+static void cis_rollout_stops(XFixed *stops, int nstops)
+{
+ unsigned int changed = 1;
+ XFixed *equal_stops_start, *equal_stops_end, *enough_space, *s;
+
+ if(nstops <= 2)
+ return;
+
+ while(changed) /* loop that keeps running as long as long as
+ there have been made changes */
+ {
+ changed = 0;
+
+ /*
+ Rollout towards the end
+ */
+ /* At first find a block of equal stops and get its start.
+ It only makes sense to find a block where there are at
+ least three items between the start and the end of all
+ stops.
+ */
+ for(equal_stops_start = stops;
+ (equal_stops_start < stops + nstops - 2
+ && *equal_stops_start != *(equal_stops_start + 1));
+ ++equal_stops_start);
+
+ if(equal_stops_start < stops + nstops - 2) /* Found a
+ possible
+ suitable
+ block's start */
+ {
+ /* Find the end of the block of equal stops, that is
+ get a pointer to the last stop in the block (_not_
+ past it!) */
+ for(equal_stops_end = equal_stops_start + 1;
+ (equal_stops_start < stops + nstops - 1
+ && *equal_stops_end == *(equal_stops_end + 1));
+ ++equal_stops_end);
+
+ if(equal_stops_end < stops + nstops - 1) /* Found a
+ suitable
+ block's end */
+ {
+ /* Now whether we can or cannot just increment the
+ last stop within the block of subsequent equal
+ stops depends on whether there is enough room
+ towards the next.
+ Find the first stop past equal_stops_end that
+ differs from the previous one by at least 2.
+ */
+ for(enough_space = equal_stops_end + 1;
+ (enough_space < stops + nstops
+ && *enough_space - *(enough_space - 1) < 2);
+ ++enough_space);
+ if(enough_space < stops + nstops) /* Found enough
+ space behind
+ the block */
+ {
+ /* Increment all stops between equal_stops_end
+ (remember: points _at_ the last stop of the
+ equal block) and enough_space by one*/
+ for(s = equal_stops_end; s < enough_space; ++s)
+ ++*s;
+
+ changed = 1;
+ }
+ }
+ }
+
+ /*
+ Rollout towards the start
+ */
+ /* Find the first two equal subsequent stops and get a pointer to
+ the second one. When rolling out towards the start, it
+ only makes sense to start the search at stops + 2 */
+ for(equal_stops_start = stops + 2;
+ (equal_stops_start < stops + nstops
+ && *equal_stops_start != *(equal_stops_start - 1));
+ ++equal_stops_start);
+
+ if(equal_stops_start < stops + nstops) /* Found two
+ suitable stops */
+ {
+ /* Now whether we can or cannot just decrement the
+ first stop within the block of subsequent equal stops
+ depends on whether there is enough room towards
+ the previous.
+ Find the last stop before equal_stops_start that
+ differs from the next one by at least 2.
+ */
+ for(enough_space = equal_stops_start - 2;
+ (enough_space + 1 > stops
+ && *(enough_space + 1) - *enough_space < 2);
+ --enough_space);
+
+ if(enough_space + 1 > stops) /* Found enough
+ space before the two
+ subsequent equal stops */
+ {
+ /* Decrement all stops between enough_space + 1
+ equal_stops_start by one*/
+ for(s = enough_space + 1; s < equal_stops_start; ++s)
+ --*s;
+
+ changed = 1;
+ }
+ }
+ }
+}
Picture XRenderCreateLinearGradient(Display *dpy,
const XLinearGradient *gradient,
@@ -291,6 +407,7 @@
req->p2.x = gradient->p2.x;
req->p2.y = gradient->p2.y;
+ cis_rollout_stops((XFixed*)stops, nStops);
req->nStops = nStops;
len = (long) nStops * 3;
SetReqLen (req, len, 6);
@@ -327,6 +444,7 @@
req->inner_radius = gradient->inner.radius;
req->outer_radius = gradient->outer.radius;
+ cis_rollout_stops((XFixed*)stops, nStops);
req->nStops = nStops;
len = (long) nStops * 3;
SetReqLen (req, len, 6);
@@ -360,6 +478,7 @@
req->center.y = gradient->center.y;
req->angle = gradient->angle;
+ cis_rollout_stops((XFixed*)stops, nStops);
req->nStops = nStops;
len = (long) nStops * 3;
SetReqLen (req, len, 6);
_______________________________________________
[email protected]: X.Org support
Archives: http://lists.freedesktop.org/archives/xorg
Info: http://lists.freedesktop.org/mailman/listinfo/xorg
Your subscription address: [email protected]