Evince does a bad job of displaying some DVI files, such as ones containing cubed roots. Gnome bug 494736 documents the problem. So I decided that I should just fix this bug, because how hard could it be?

After playing with TeX to create some sample files, it became obvious that the cubed root character was getting covered over. The characters were not being placed with a transparent background, they we being placed with a white background. To confirm this, I placed the characters transparently and lo and behold the cube root character was being covered up.

dvi_cairo_draw_glyph in backend/dvi/cairo-device.c does all of the drawing. This is the relevant change to confirm the problem.

cairo_translate (cairo_device->cr, x, y);
cairo_pattern_t* pattern = cairo_pattern_create_rgba(1.0, 1.0, 1.0, .5 /* 50% transparency */);
cairo_set_source_surface (cairo_device->cr,
					  (cairo_surface_t *) glyph->data,
					  0, 0);
cairo_mask (cairo_device->cr, pattern);
/* cairo_paint (cairo_device->cr); */

This is a simple TeX file that causes the problem.

$ \root 3 \of x $
\end

And this is how the TeX above looks like as a DVI file in Evince with the changes above. Notice how the 3 is lighter than the root symbol, this is because the root symbol is being placed on top of it and it's white background is on top of the 3.
picture of cubed root with the change to confirm the problem
Diagnosis complete, time to fix.

The glyph->data above is a bitmap image of the glyph to place. Some debugging shows that it is stored as a CAIRO_FORMAT_RGB24, a format with no transparency information. Now to find where the bitmap is being created and store it as CAIRO_FORMAT_ARGB32 a format with 8 bits for each of red, green, blue and alpha/transparency.

mdvi_cairo_device_render creates an image surface with CAIRO_FORMAT_RGB24, lets change this to ARGB32. This still doesn't fix things, perhaps transparency is never being set when loading the glyphs in the first place. The bitmaps are loaded from font files in backend/dvi/mdvi-lib/pk.c get_packed. METAFONT uses a compressed format for it's font files called Packed File Font Format. I found the following reference on PK files Packed Font File Format. The upshot is that each character is encoded as a sequence of black or white pixels. Something like 3 pixels of black followed by 10 pixels of white, followed by 6 pixels of black might draw one row of the character. backend/dvi/mdvi-lib/bitmap.c bitmap_set_row is called to draw a sequence of these black or white bits.

/*
 * to use this function you should first make sure that
 * there is room for `count' bits in the scanline
 *
 * A general-purpose (but not very efficient) function to paint `n' pixels
 * on a bitmap, starting at position (x, y) would be:
 *
 *    bitmap_paint_bits(__bm_unit_ptr(bitmap, x, y), x % BITMAP_BITS, n)
 *
 */
void	bitmap_paint_bits(BmUnit *ptr, int n, int count)
{
	/* paint the head */
	if(n + count > BITMAP_BITS) {
		*ptr |= SEGMENT(BITMAP_BITS - n, n);
		count -= BITMAP_BITS - n;
		ptr++;
	} else {
		*ptr |= SEGMENT(count, n);
		return;
	}
	/* paint the middle */
	for(; count >= BITMAP_BITS; count -= BITMAP_BITS)
		*ptr++ = bit_masks[BITMAP_BITS];
	/* paint the tail */
	if(count > 0)
		*ptr |= SEGMENT(count, 0);
}
/*
 * same as paint_bits but clears pixels instead of painting them. Written
 * as a separate function for efficiency reasons.
 */
void bitmap_clear_bits(BmUnit *ptr, int n, int count)
{
	if(n + count > BITMAP_BITS) {
		*ptr &= ~SEGMENT(BITMAP_BITS - n, n);
		count -= BITMAP_BITS;
		ptr++;
	} else {
		*ptr &= ~SEGMENT(count, n);
		return;
	}
	for(; count >= BITMAP_BITS; count -= BITMAP_BITS)
		*ptr++ = 0;
	if(count > 0)
		*ptr &= ~SEGMENT(count, 0);
}
/* the general function to paint rows. Still used by the PK reader, but that
 * will change soon (The GF reader already uses bitmap_paint_bits()).
 */
void bitmap_set_row(BITMAP *bm, int row, int col, int count, int state)
{
	BmUnit	*ptr;
	ptr = __bm_unit_ptr(bm, col, row);
	if(state)
		bitmap_paint_bits(ptr, col & (BITMAP_BITS-1), count);
	else
		bitmap_clear_bits(ptr, col & (BITMAP_BITS-1), count);
}

The code above reads in where the ink goes, it doesn't specify the color of the ink, that happens later. backend/dvi/mdvi-lib/bitmap.c mdvi_shrink_glyph_grey appears to do the work of converting a bitmap into an image of the proper size. This function calls backend/dvi/cairo_device.c dvi_cairo_put_pixel to draw each pixel of the image to be placed. A quick fix is to intercept pixels colored non-transparent white, and make them fully transparent. The complete patch against evince 2.30.3 from Ubuntu 10.04 is below.

---
 backend/dvi/cairo-device.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/backend/dvi/cairo-device.c b/backend/dvi/cairo-device.c
index 9a8ca0e..42ebc64 100644
--- a/backend/dvi/cairo-device.c
+++ b/backend/dvi/cairo-device.c
@@ -233,7 +233,7 @@ dvi_cairo_create_image (void *device_data,
 			Uint  height,
 			Uint  bpp)
 {
-	return cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
+	return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
 }
 static void
@@ -254,6 +254,14 @@ dvi_cairo_put_pixel (void *image, int x, int y, Ulong color)
 	rowstride = cairo_image_surface_get_stride (surface);
 	p = (guint32*) (cairo_image_surface_get_data (surface) + y * rowstride + x * 4);
+        /* Assume that a white pixel with no transparency
+           (color=0xFFFFFFFF) is meant to be transparent
+           (color=0x00??????). Fixes gnome bug 494736 where cubed
+           roots are not displayed
+         */
+        if ( color == 0xFFFFFFFF ) {
+          color = 0;
+        }
 	*p = color;
 }
@@ -334,7 +342,7 @@ mdvi_cairo_device_render (DviContext* dvi)
 	memset (pixels, 0xff, page_height * rowstride);
 	surface = cairo_image_surface_create_for_data (pixels,
-						       CAIRO_FORMAT_RGB24,
+						       CAIRO_FORMAT_ARGB32,
 						       page_width, page_height,
 						       rowstride);
 	cairo_surface_set_user_data (surface, &key,
--

A properly drawn cubed root

Is this an acceptable solution? I imagine that most DVI documents are black text on white "paper". Also, Evince does not appear to support colored DVI documents so in that sense no functionality is lost. I think that most users will benefit from being able to view all of the document's glyphs as intended.