[4/4] winex11.drv: render custom dash style

Evan Stade estade at gmail.com
Thu Jul 26 19:14:00 CDT 2007


Hi,

The bulk of this patch has to do with converting a gdi-style dash
array to an x11-style dash array (x11 does not allow 0-entries in the
array, and has to start on a dash rather than a space.).

changelog:
*add a member to X_PHYSPEN structure that controls dash offset
*handle PS_USERSTYLE | PS_GEOMETRIC

 dlls/winex11.drv/graphics.c |    3 +
 dlls/winex11.drv/pen.c      |   94 ++++++++++++++++++++++++++++++++++++++++---
 dlls/winex11.drv/x11drv.h   |    1
 3 files changed, 91 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..8343e9a 100644
--- a/dlls/winex11.drv/pen.c
+++ b/dlls/winex11.drv/pen.c
@@ -17,14 +17,74 @@
  * 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.
+ *
+ * If outcount is set to 1 then there are 2 cases:
+ *   1: the line is pretty much just a solid line (no spaces).
+ *      outoffset will be false.
+ *   2: the line is pretty much just a null line (no dashes).
+ *      outoffset will be true.
+ */
+static void gdi_to_x11_dashes(DWORD* gdi_dashes, int count, char* out,
+    int* outcount, int* outoffset)
+{
+    DWORD dashes[16];
+    int i=-1, j=0, offset = 0;
+
+    memset(out, 0, count * sizeof(char));
+    /* First: find first non-zero entry. */
+    while(((i + 1) < count) && (gdi_dashes[++i] == 0));
+    if(i % 2)   offset = 1;
+    /* Then: iterate through all entries. */
+    for(; i < count; i++, j++){
+        if(!gdi_dashes[i]) 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. */
+        for(;(i + 2 < count) && gdi_dashes[i + 1] == 0; i += 2)
+            dashes[j] = MIN(UCHAR_MAX, gdi_dashes[i + 2] + dashes[j]);
+    }
+
+    /* j is the number of entries we successfully managed to extract. */
+    if(!(*outcount = j))
+        ERR("all-zero dash array\n");
+    else if(offset){
+        if(j == 1)
+            out[0] = dashes[0];
+        else{
+            offset = dashes[0];
+
+            for(i = 0; i + 1 < j; i++)
+                out[i] = dashes[i+1];
+
+            out[j - (j > 1) - (j % 2)] = MIN(UCHAR_MAX, offset + dashes[j - (j % 2)]);
+
+            offset *= -1;
+            for(i = 0; i < j; i++)
+                offset += out[i];
+        }
+    }
+    else for(i = 0; i < j; i++) out[i] = dashes[i];
+
+    *outoffset = offset;
+}
+
+
 /***********************************************************************
  *           SelectPen   (X11DRV.@)
  */
@@ -40,7 +100,9 @@ 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;
+    int i, numdashes = 0, stretch_dashes = 1;
+
+    physDev->pen.dash_offset = physDev->pen.dash_len = 0;
 
     if (!GetObjectW( hpen, sizeof(logpen), &logpen ))
     {
@@ -54,8 +116,23 @@ 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 */
+        if((elp->elpPenStyle & PS_GEOMETRIC) && (numdashes = MIN(MAX_DASHLEN, elp->elpNumEntries)))
+            gdi_to_x11_dashes(elp->elpStyleEntry, elp->elpNumEntries, physDev->pen.dashes,
+                &physDev->pen.dash_len, &physDev->pen.dash_offset);
+
+        if(!(numdashes % 2) && (physDev->pen.dash_len == 1)){
+            if(physDev->pen.dash_offset)
+                logpen.lopnStyle = (elp->elpPenStyle & ~PS_STYLE_MASK) | PS_NULL;
+            else
+                logpen.lopnStyle = (elp->elpPenStyle & ~PS_STYLE_MASK) | PS_SOLID;
+
+            physDev->pen.dash_offset = physDev->pen.dash_len = 0;
+        }
+        else
+            logpen.lopnStyle = elp->elpPenStyle;
+
         logpen.lopnWidth.x = elp->elpWidth;
         logpen.lopnWidth.y = 0;
         logpen.lopnColor = elp->elpColor;
@@ -106,16 +183,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