1    // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
2    package org.xwt;
3    
4    /**
5     *  <p>
6     *  A block of pixels which can be drawn on.
7     *  </p>
8     *
9     *  <p>
10    *  Implementations of the Platform class should return objects
11    *  supporting this interface from the _createPixelBuffer()
12    *  method. These implementations may choose to use off-screen video
13    *  ram for this purpose (for example, a Pixmap on X11).
14    *  </p>
15    *
16    *  <p>
17    *  Many of these functions come in pairs, one that uses ints and one
18    *  that uses floats.  The int functions are intended for situations
19    *  in which the CTM is the identity transform.
20    *  </p>
21    */
22   public abstract class PixelBuffer {
23   
24       /** draw the picture at (dx1, dy1), cropping to (cx1, cy1, cx2, cy2) */
25       protected abstract void drawPicture(Picture source, int dx1, int dy1, int cx1, int cy1, int cx2, int cy2);
26   
27       /** fill a trapezoid whose top and bottom edges are horizontal */
28       public abstract void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int color);
29   
30       /**
31        *  Same as drawPicture, but only uses the alpha channel of the Picture, and is allowed to destructively modify the RGB
32        *  channels of the Picture in the process.  This method may assume that the RGB channels of the image are all zero IFF it
33        *  restores this invariant before returning.
34        */
35       public abstract void drawGlyph(Font.Glyph source, int dx1, int dy1, int cx1, int cy1, int cx2, int cy2, int rgb);
36   
37       // FEATURE: we want floats (inter-pixel spacing) for antialiasing, but this hoses the fastpath line drawing... argh!
38       /** draws a line of width <tt>w</tt>; note that the coordinates here are <i>post-transform</i> */
39       public void drawLine(int x1, int y1, int x2, int y2, int w, int color, boolean capped) {
40   
41   	if (y1 > y2) { int t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; }
42   
43   	if (x1 == x2) {
44               fillTrapezoid(x1 - w / 2, x2 + w / 2, y1 - (capped ? w / 2 : 0),
45                             x1 - w / 2, x2 + w / 2, y2 + (capped ? w / 2 : 0), color);
46               return;
47           }
48   
49           // fastpath for single-pixel width lines
50           if (w == 1) {
51               float slope = (float)(y2 - y1) / (float)(x2 - x1);
52               int last_x = x1;
53               for(int y=y1; y<=y2; y++) {
54                   int new_x = (int)((float)(y - y1) / slope) + x1;
55                   if (slope >= 0) fillTrapezoid(last_x + 1, y != y2 ? new_x + 1 : new_x, y,
56                                                 last_x + 1, y != y2 ? new_x + 1 : new_x, y + 1, color);
57                   else fillTrapezoid(y != y2 ? new_x : new_x + 1, last_x, y,
58                                      y != y2 ? new_x : new_x + 1, last_x, y + 1, color);
59                   last_x = new_x;
60               }
61               return;
62           }
63   
64           // actually half-width
65   	float width = (float)w / 2;
66   	float phi = (float)Math.atan((y2 - y1) / (x2 - x1));
67   	if (phi < 0.0) phi += (float)Math.PI * 2;
68   	float theta = (float)Math.PI / 2 - phi;
69   
70   	// dx and dy are the x and y distance between each endpoint and the corner of the stroke
71   	int dx = (int)(width * Math.cos(theta));
72   	int dy = (int)(width * Math.sin(theta));
73   
74   	// slice is the longest possible length of a horizontal line across the stroke
75   	int slice = (int)(2 * width / Math.cos(theta));
76   
77   	if (capped) {
78   	    x1 -= width * Math.cos(phi);
79   	    x2 += width * Math.cos(phi);
80   	    y1 -= width * Math.sin(phi);
81   	    y2 += width * Math.sin(phi);
82   	}
83   
84   	fillTrapezoid(x1 + dx, x1 + dx, y1 - dy, x1 - dx, x1 - dx + slice, y1 + dy, color);           // top corner
85   	fillTrapezoid(x2 + dx - slice, x2 + dx, y2 - dy, x2 - dx, x2 - dx, y2 + dy, color);           // bottom corner
86   	fillTrapezoid(x1 - dx, x1 - dx + slice, y1 + dy, x2 + dx - slice, x2 + dx, y2 - dy, color);   // middle
87       }
88   
89   }
90