[4/4] winex11.drv: draw custom dashes [try2]

Evan Stade estade at gmail.com
Mon Jul 30 21:09:25 CDT 2007


Hi,

[try2]
* matched braces style of rest of file
* spread code out to make it more readable
* simplified use of gdi_to_x11_dashes

 dlls/winex11.drv/graphics.c |    3 +
 dlls/winex11.drv/pen.c      |  123 +++++++++++++++++++++++++++++++++++++++++--
 dlls/winex11.drv/x11drv.h   |    1
 3 files changed, 120 insertions(+), 7 deletions(-)

-- 
Evan Stade
-------------- next part --------------
diff --git a/dlls/winex11.drv/graphics.c b/dlls/winex11.drv/graphics.c
index b2e105f..73b7cef 100644
--- a/dlls/winex11.drv/graphics.c
+++ b/dlls/winex11.drv/graphics.c
@@ -245,7 +245,8 @@ BOOL X11DRV_SetupGCForPen( X11DRV_PDEVIC
     wine_tsx11_lock();
     if (physDev->pen.dash_len)
     {
-        XSetDashes( gdi_display, physDev->gc, 0, physDev->pen.dashes, physDev->pen.dash_len );
+        XSetDashes( gdi_display, physDev->gc, physDev->pen.dash_offset,
+            physDev->pen.dashes, physDev->pen.dash_len );
         val.line_style = ((GetBkMode(physDev->hdc) == OPAQUE) && (!physDev->pen.ext))
                          ? LineDoubleDash : LineOnOffDash;
     }
diff --git a/dlls/winex11.drv/pen.c b/dlls/winex11.drv/pen.c
index 96d9043..a1eba17 100644
--- a/dlls/winex11.drv/pen.c
+++ b/dlls/winex11.drv/pen.c
@@ -17,14 +17,105 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
-
 #include "config.h"
 
+#include <limits.h>
 #include "x11drv.h"
 #include "wine/debug.h"
 
+#define MIN(x, y) ((x) > (y) ? (y) : (x))
+
 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
 
+/* X doesn't allow any zero entries. This function removes zero-entries
+ * and combines newly-adjacent entries that originally had the same
+ * parity. Also X represents the dash lengths as characters, so we
+ * can easily overflow.  If we overflow, make the dash length
+ * UCHAR_MAX. Also note that X must start on a dash rather than a space,
+ * which is what the offset business is needed for.
+ *
+ * returns 0 for error, or the pen style for success
+ */
+static DWORD gdi_to_x11_dashes(DWORD* gdi_dashes, int count, char* out,
+    int* outcount, int* outoffset)
+{
+    DWORD dashes[16];
+    int i, j = 0, offset = 0, trailing_zero = 0;
+
+    /* First: find first non-zero entry. */
+    for(i = 0; i < count; i++)
+        if(gdi_dashes[i] != 0)
+            break;
+
+    if(i % 2)
+        offset = 1;
+
+    /* Then: iterate through all entries. */
+    for(; i < count; i++, j++)
+    {
+        if(!gdi_dashes[i])
+        {
+            trailing_zero = 1;
+            break;
+        }
+
+        dashes[j] = MIN(gdi_dashes[i], UCHAR_MAX);
+
+        /* If the next entry is zero, collapse this entry with the next
+         * one (or more) of the same parity. */
+        while((i + 2 < count) && gdi_dashes[i + 1] == 0)
+        {
+            dashes[j] = MIN(UCHAR_MAX, gdi_dashes[i + 2] + dashes[j]);
+            i += 2;
+        }
+    }
+
+    /* j is the number of entries we successfully managed to extract. */
+    if(!(*outcount = j))
+    {
+        ERR("all-zero dash array\n");
+        return 0;
+    }
+
+    if(!offset && trailing_zero)
+    {
+        dashes[0] += dashes[j - 1];
+        offset = dashes[j - 1];
+        j--;
+    }
+
+    /* offset is true if we are starting on a space. We have to copy
+     * everything over shifted one to the left. Also we copy the first
+     * value into the last space-type slot. */
+    if(offset && (j > 1))
+    {
+        for(i = 0; i + 1 < j; i++)
+            out[i] = dashes[i + 1];
+        out[j - 1 - (j % 2)] = MIN(UCHAR_MAX, dashes[0] + dashes[j - 1 - (j % 2)]);
+
+        offset = -dashes[0];
+        for(i = 0; i + 1 < j; i++)
+            offset += out[i];
+    }
+    else
+        for(i = 0; i < j; i++)
+            out[i] = dashes[i];
+
+    *outcount = j;
+    *outoffset = offset;
+
+    if((j == 1) && !(count % 2))
+    {
+        if(offset)
+            return PS_NULL;
+        else
+            return PS_SOLID;
+    }
+
+    return PS_USERSTYLE;
+}
+
+
 /***********************************************************************
  *           SelectPen   (X11DRV.@)
  */
@@ -40,7 +131,10 @@ HPEN X11DRV_SelectPen( X11DRV_PDEVICE *p
     static const char EXTPEN_dashdot[]    = { 3,1,1,1 };
     static const char EXTPEN_dashdotdot[] = { 3,1,1,1,1,1 };
     LOGPEN logpen;
-    int i;
+    DWORD style = 0;
+    int i, numdashes = 0, stretch_dashes = 1;
+
+    physDev->pen.dash_offset = physDev->pen.dash_len = 0;
 
     if (!GetObjectW( hpen, sizeof(logpen), &logpen ))
     {
@@ -54,8 +148,20 @@ HPEN X11DRV_SelectPen( X11DRV_PDEVICE *p
         elp = HeapAlloc( GetProcessHeap(), 0, size );
 
         GetObjectW( hpen, size, elp );
-        /* FIXME: add support for user style pens */
-        logpen.lopnStyle = elp->elpPenStyle;
+
+        /* handling of PS_USERSTYLE | PS_GEOMETRIC */
+        numdashes = MIN(MAX_DASHLEN, elp->elpNumEntries);
+
+        if((elp->elpPenStyle & PS_GEOMETRIC) && numdashes)
+            style = gdi_to_x11_dashes(elp->elpStyleEntry, elp->elpNumEntries,
+                physDev->pen.dashes, &physDev->pen.dash_len,
+                &physDev->pen.dash_offset);
+
+        if(style)
+            logpen.lopnStyle = (elp->elpPenStyle & ~PS_STYLE_MASK) | style;
+        else
+            logpen.lopnStyle = elp->elpPenStyle;
+
         logpen.lopnWidth.x = elp->elpWidth;
         logpen.lopnWidth.y = 0;
         logpen.lopnColor = elp->elpColor;
@@ -106,16 +212,21 @@ HPEN X11DRV_SelectPen( X11DRV_PDEVICE *p
       case PS_ALTERNATE:
             physDev->pen.dash_len = sizeof(PEN_alternate)/sizeof(*PEN_alternate);
             memcpy(physDev->pen.dashes, PEN_alternate, physDev->pen.dash_len);
+            stretch_dashes = 0;
             break;
       case PS_USERSTYLE:
+            if(physDev->pen.ext){
+                stretch_dashes = 0;
+                break;
+            }
         FIXME("PS_USERSTYLE is not supported\n");
         /* fall through */
       default:
         physDev->pen.dash_len = 0;
+        stretch_dashes = 0;
         break;
     }
-    if(physDev->pen.ext && physDev->pen.dash_len &&
-        (logpen.lopnStyle & PS_STYLE_MASK) != PS_ALTERNATE)
+    if(stretch_dashes && physDev->pen.ext && physDev->pen.dash_len)
         for(i = 0; i < physDev->pen.dash_len; i++)
             physDev->pen.dashes[i] *= (physDev->pen.width ? physDev->pen.width : 1);
 
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index a778f64..7301d41 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -80,6 +80,7 @@ typedef struct
     int          width;
     char         dashes[MAX_DASHLEN];
     int          dash_len;
+    int          dash_offset;
     int          type;          /* GEOMETRIC || COSMETIC */
     int          ext;           /* extended pen - 1, otherwise - 0 */
 } X_PHYSPEN;
-- 
1.4.1


More information about the wine-patches mailing list