[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