[RFC PATCH] mi: reduce missing segments on large ellipse

Olivier Fourdan ofourdan at redhat.com
Thu Apr 16 05:04:20 PDT 2015

When using large values for width/height (> 5000) arcs, the values of
inx and outx in miComputeEllipseSpans() gets so close that the spans
lw and rw get down to 0, meaning that no pixel will be drawn on screen.

lines 566 to 578 in mi/miarc.c from miComputeEllipseSpans()

        span->lx = ICEIL(xorg - outx);
        span->lw = ICEIL(xorg - inx) - span->lx;
        span->rx = ICEIL(xorg + inx);
        span->rw = ICEIL(xorg + outx) - span->rx;

The same issue does not occur with the miZeroArc* routines, but
unfortunately those only work wither with circles or else ellipses of 
size < 800.

I won't pretend I fully understand this code, far from it, but with a
simple test I guess we can try to avoid this condition.

Unfortunately, this is still not perfect, even if there is no more
missing pixels close to the vertical tangent of the ellipse, some
"sawtooth" effects can be observed in place sometimes and there can
still be a few missing pixels close to the horizontal tangents.

Yet this is still an improvement, I guess. 

There is also another ugly issue when using a line width > 1 the border
close the vertical tangent can become insanely large - To reproduce,
try with linewidth=5 in XSetLineAttributes() with the following example.
My patch does not address that... so there is room for improvement.

I was wondering if we could reduce the precision somehow with large
values to avoid these side effects on limits, but, err, I haven't found
yet (and I've already got some headaches with this, so I'm eager to get
some more fresh ideas, thus this RFC patch...)

Following is a simple reproducer to play with.

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/X.h>

int main(int argc, char *argv[])
  Window root_window, win;
  Display* display;
  unsigned long white_pixel, black_pixel;
  int screen_num;
  int j;
  GC gc;
  XEvent e;

  display = XOpenDisplay(NULL);
  if (display == NULL) {
    fprintf(stderr, "Cannot connect to X server %s\n", ":0");
    return -1;
  screen_num = DefaultScreen(display);
  root_window = RootWindow(display, screen_num);
  white_pixel = WhitePixel(display, screen_num);
  black_pixel = BlackPixel(display, screen_num);
  gc = DefaultGC(display, screen_num);
  XSetLineAttributes(display, gc, 1, LineSolid, CapNotLast, JoinMiter);
  win = XCreateSimpleWindow(display, RootWindow(display, screen_num),
                            0, 0, 1024, 1024, 1,
                            black_pixel, white_pixel);
  XSelectInput(display, win, ExposureMask | KeyPressMask);
  XMapWindow(display, win);
  while (1) {
    XNextEvent(display, &e);
    if (e.type == Expose) {
      XSelectInput(display, win, ExposureMask | KeyPressMask);
      for (j = 0; j < 10000; j += 100)
        XDrawArc(display, win, gc,
                 5 + j / 10, j / 2 - (10000 - 1024 / 2),
                 19999, 20000 - j,
                 175 * 64, 10 * 64);

  return 0;

Olivier Fourdan (1):
  mi: reduce missing segments on large arcs

 mi/miarc.c | 10 ++++++++++
 1 file changed, 10 insertions(+)


More information about the xorg-devel mailing list