Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
wine
Manage
Activity
Members
Labels
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Package registry
Container Registry
Model registry
Operate
Terraform modules
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Lorenzo Ferrillo
wine
Commits
e248615a
Commit
e248615a
authored
13 years ago
by
Huw Davies
Committed by
Alexandre Julliard
13 years ago
Browse files
Options
Downloads
Patches
Plain Diff
gdi32: Implement clipping of diagonal lines.
parent
bab85038
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
dlls/gdi32/dibdrv/objects.c
+307
-37
307 additions, 37 deletions
dlls/gdi32/dibdrv/objects.c
dlls/gdi32/tests/dib.c
+23
-1
23 additions, 1 deletion
dlls/gdi32/tests/dib.c
with
330 additions
and
38 deletions
dlls/gdi32/dibdrv/objects.c
+
307
−
37
View file @
e248615a
...
...
@@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include
<stdlib.h>
#include
"gdi_private.h"
#include
"dibdrv.h"
...
...
@@ -106,6 +108,31 @@ static inline BOOL pt_in_rect( const RECT *rect, const POINT *pt )
(
pt
->
y
>=
rect
->
top
)
&&
(
pt
->
y
<
rect
->
bottom
));
}
#define Y_INCREASING_MASK 0x0f
#define X_INCREASING_MASK 0xc3
#define X_MAJOR_MASK 0x99
#define POS_SLOPE_MASK 0x33
static
inline
BOOL
is_xmajor
(
DWORD
octant
)
{
return
octant
&
X_MAJOR_MASK
;
}
static
inline
BOOL
is_pos_slope
(
DWORD
octant
)
{
return
octant
&
POS_SLOPE_MASK
;
}
static
inline
BOOL
is_x_increasing
(
DWORD
octant
)
{
return
octant
&
X_INCREASING_MASK
;
}
static
inline
BOOL
is_y_increasing
(
DWORD
octant
)
{
return
octant
&
Y_INCREASING_MASK
;
}
/**********************************************************************
* get_octant_number
*
...
...
@@ -143,65 +170,276 @@ static void solid_pen_line_callback(INT x, INT y, LPARAM lparam)
return
;
}
static
void
bres_line_with_bias
(
INT
x1
,
INT
y1
,
INT
x2
,
INT
y2
,
void
(
*
callback
)(
INT
,
INT
,
LPARAM
),
LPARAM
lParam
)
#define OUT_LEFT 1
#define OUT_RIGHT 2
#define OUT_TOP 4
#define OUT_BOTTOM 8
static
inline
DWORD
calc_outcode
(
const
POINT
*
pt
,
const
RECT
*
clip
)
{
INT
xadd
=
1
,
yadd
=
1
;
INT
err
,
erradd
;
INT
cnt
;
INT
dx
=
x2
-
x1
;
INT
dy
=
y2
-
y1
;
DWORD
octant
=
get_octant_mask
(
dx
,
dy
);
INT
bias
=
0
;
/* Octants 3, 5, 6 and 8 take a bias */
if
(
octant
&
0xb4
)
bias
=
1
;
if
(
dx
<
0
)
{
dx
=
-
dx
;
xadd
=
-
1
;
}
if
(
dy
<
0
)
DWORD
out
=
0
;
if
(
pt
->
x
<
clip
->
left
)
out
|=
OUT_LEFT
;
else
if
(
pt
->
x
>=
clip
->
right
)
out
|=
OUT_RIGHT
;
if
(
pt
->
y
<
clip
->
top
)
out
|=
OUT_TOP
;
else
if
(
pt
->
y
>=
clip
->
bottom
)
out
|=
OUT_BOTTOM
;
return
out
;
}
typedef
struct
{
unsigned
int
dx
,
dy
;
int
bias
;
DWORD
octant
;
}
bres_params
;
/******************************************************************************
* clip_line
*
* Clips the start and end points to a rectangle.
*
* Note, this treats the end point like the start point. If the
* caller doesn't want it displayed, it should exclude it. If the end
* point is clipped out, then the likelihood is that the new end point
* should be displayed.
*
* Returns 0 if totally excluded, 1 if partially clipped and 2 if unclipped.
*
* This derivation is based on the comments in X.org's xserver/mi/mizerclip.c,
* however the Bresenham error term is defined differently so the equations
* will also differ.
*
* For x major lines we have 2dy >= err + bias > 2dy - 2dx
* 0 >= err + bias - 2dy > -2dx
*
* Note dx, dy, m and n are all +ve.
*
* Moving the start pt from x1 to x1 + m, we need to figure out y1 + n.
* err = 2dy - dx + 2mdy - 2ndx
* 0 >= 2dy - dx + 2mdy - 2ndx + bias - 2dy > -2dx
* 0 >= 2mdy - 2ndx + bias - dx > -2dx
* which of course will give exactly one solution for n,
* so looking at the >= inequality
* n >= (2mdy + bias - dx) / 2dx
* n = ceiling((2mdy + bias - dx) / 2dx)
* = (2mdy + bias + dx - 1) / 2dx (assuming division truncation)
*
* Moving start pt from y1 to y1 + n we need to figure out x1 + m - there may be several
* solutions we pick the one that minimizes m (ie that first unlipped pt). As above:
* 0 >= 2mdy - 2ndx + bias - dx > -2dx
* 2mdy > 2ndx - bias - dx
* m > (2ndx - bias - dx) / 2dy
* m = floor((2ndx - bias - dx) / 2dy) + 1
* m = (2ndx - bias - dx) / 2dy + 1
*
* Moving end pt from x2 to x2 - m, we need to figure out y2 - n
* err = 2dy - dx + 2(dx - m)dy - 2(dy - n)dx
* = 2dy - dx - 2mdy + 2ndx
* 0 >= 2dy - dx - 2mdy + 2ndx + bias - 2dy > -2dx
* 0 >= 2ndx - 2mdy + bias - dx > -2dx
* again exactly one solution.
* 2ndx <= 2mdy - bias + dx
* n = floor((2mdy - bias + dx) / 2dx)
* = (2mdy - bias + dx) / 2dx
*
* Moving end pt from y2 to y2 - n when need x2 - m this time maximizing x2 - m so
* mininizing m to include all of the points at y = y2 - n. As above:
* 0 >= 2ndx - 2mdy + bias - dx > -2dx
* 2mdy >= 2ndx + bias - dx
* m = ceiling((2ndx + bias - dx) / 2dy)
* = (2ndx + bias - dx - 1) / 2dy + 1
*
* For y major lines, symmetry (dx <-> dy and swap the cases over) gives:
*
* Moving start point from y1 to y1 + n find x1 + m
* m = (2ndx + bias + dy - 1) / 2dy
*
* Moving start point from x1 to x1 + m find y1 + n
* n = (2mdy - bias - dy) / 2ndx + 1
*
* Moving end point from y2 to y2 - n find x1 - m
* m = (2ndx - bias + dy) / 2dy
*
* Moving end point from x2 to x2 - m find y2 - n
* n = (2mdy + bias - dy - 1) / 2dx + 1
*/
static
int
clip_line
(
const
POINT
*
start
,
const
POINT
*
end
,
const
RECT
*
clip
,
const
bres_params
*
params
,
POINT
*
pt1
,
POINT
*
pt2
)
{
unsigned
int
n
,
m
;
BOOL
clipped
=
FALSE
;
DWORD
start_oc
,
end_oc
;
const
int
bias
=
params
->
bias
;
const
unsigned
int
dx
=
params
->
dx
;
const
unsigned
int
dy
=
params
->
dy
;
const
unsigned
int
two_dx
=
params
->
dx
*
2
;
const
unsigned
int
two_dy
=
params
->
dy
*
2
;
const
BOOL
xmajor
=
is_xmajor
(
params
->
octant
);
const
BOOL
neg_slope
=
!
is_pos_slope
(
params
->
octant
);
*
pt1
=
*
start
;
*
pt2
=
*
end
;
start_oc
=
calc_outcode
(
start
,
clip
);
end_oc
=
calc_outcode
(
end
,
clip
);
while
(
1
)
{
dy
=
-
dy
;
yadd
=
-
1
;
if
(
start_oc
==
0
&&
end_oc
==
0
)
return
clipped
?
1
:
2
;
/* trivial accept */
if
(
start_oc
&
end_oc
)
return
0
;
/* trivial reject */
clipped
=
TRUE
;
if
(
start_oc
&
OUT_LEFT
)
{
m
=
clip
->
left
-
start
->
x
;
if
(
xmajor
)
n
=
(
m
*
two_dy
+
bias
+
dx
-
1
)
/
two_dx
;
else
n
=
(
m
*
two_dy
-
bias
-
dy
)
/
two_dx
+
1
;
pt1
->
x
=
clip
->
left
;
if
(
neg_slope
)
n
=
-
n
;
pt1
->
y
=
start
->
y
+
n
;
start_oc
=
calc_outcode
(
pt1
,
clip
);
}
else
if
(
start_oc
&
OUT_RIGHT
)
{
m
=
start
->
x
-
clip
->
right
+
1
;
if
(
xmajor
)
n
=
(
m
*
two_dy
+
bias
+
dx
-
1
)
/
two_dx
;
else
n
=
(
m
*
two_dy
-
bias
-
dy
)
/
two_dx
+
1
;
pt1
->
x
=
clip
->
right
-
1
;
if
(
neg_slope
)
n
=
-
n
;
pt1
->
y
=
start
->
y
-
n
;
start_oc
=
calc_outcode
(
pt1
,
clip
);
}
else
if
(
start_oc
&
OUT_TOP
)
{
n
=
clip
->
top
-
start
->
y
;
if
(
xmajor
)
m
=
(
n
*
two_dx
-
bias
-
dx
)
/
two_dy
+
1
;
else
m
=
(
n
*
two_dx
+
bias
+
dy
-
1
)
/
two_dy
;
pt1
->
y
=
clip
->
top
;
if
(
neg_slope
)
m
=
-
m
;
pt1
->
x
=
start
->
x
+
m
;
start_oc
=
calc_outcode
(
pt1
,
clip
);
}
else
if
(
start_oc
&
OUT_BOTTOM
)
{
n
=
start
->
y
-
clip
->
bottom
+
1
;
if
(
xmajor
)
m
=
(
n
*
two_dx
-
bias
-
dx
)
/
two_dy
+
1
;
else
m
=
(
n
*
two_dx
+
bias
+
dy
-
1
)
/
two_dy
;
pt1
->
y
=
clip
->
bottom
-
1
;
if
(
neg_slope
)
m
=
-
m
;
pt1
->
x
=
start
->
x
-
m
;
start_oc
=
calc_outcode
(
pt1
,
clip
);
}
else
if
(
end_oc
&
OUT_LEFT
)
{
m
=
clip
->
left
-
end
->
x
;
if
(
xmajor
)
n
=
(
m
*
two_dy
-
bias
+
dx
)
/
two_dx
;
else
n
=
(
m
*
two_dy
+
bias
-
dy
-
1
)
/
two_dx
+
1
;
pt2
->
x
=
clip
->
left
;
if
(
neg_slope
)
n
=
-
n
;
pt2
->
y
=
end
->
y
+
n
;
end_oc
=
calc_outcode
(
pt2
,
clip
);
}
else
if
(
end_oc
&
OUT_RIGHT
)
{
m
=
end
->
x
-
clip
->
right
+
1
;
if
(
xmajor
)
n
=
(
m
*
two_dy
-
bias
+
dx
)
/
two_dx
;
else
n
=
(
m
*
two_dy
+
bias
-
dy
-
1
)
/
two_dx
+
1
;
pt2
->
x
=
clip
->
right
-
1
;
if
(
neg_slope
)
n
=
-
n
;
pt2
->
y
=
end
->
y
-
n
;
end_oc
=
calc_outcode
(
pt2
,
clip
);
}
else
if
(
end_oc
&
OUT_TOP
)
{
n
=
clip
->
top
-
end
->
y
;
if
(
xmajor
)
m
=
(
n
*
two_dx
+
bias
-
dx
-
1
)
/
two_dy
+
1
;
else
m
=
(
n
*
two_dx
-
bias
+
dy
)
/
two_dy
;
pt2
->
y
=
clip
->
top
;
if
(
neg_slope
)
m
=
-
m
;
pt2
->
x
=
end
->
x
+
m
;
end_oc
=
calc_outcode
(
pt2
,
clip
);
}
else
if
(
end_oc
&
OUT_BOTTOM
)
{
n
=
end
->
y
-
clip
->
bottom
+
1
;
if
(
xmajor
)
m
=
(
n
*
two_dx
+
bias
-
dx
-
1
)
/
two_dy
+
1
;
else
m
=
(
n
*
two_dx
-
bias
+
dy
)
/
two_dy
;
pt2
->
y
=
clip
->
bottom
-
1
;
if
(
neg_slope
)
m
=
-
m
;
pt2
->
x
=
end
->
x
-
m
;
end_oc
=
calc_outcode
(
pt2
,
clip
);
}
}
if
(
dx
>
dy
)
/* line is "more horizontal" */
}
static
void
bres_line_with_bias
(
INT
x1
,
INT
y1
,
INT
x2
,
INT
y2
,
const
bres_params
*
params
,
INT
err
,
BOOL
last_pt
,
void
(
*
callback
)(
INT
,
INT
,
LPARAM
),
LPARAM
lParam
)
{
const
int
xadd
=
is_x_increasing
(
params
->
octant
)
?
1
:
-
1
;
const
int
yadd
=
is_y_increasing
(
params
->
octant
)
?
1
:
-
1
;
INT
erradd
;
if
(
is_xmajor
(
params
->
octant
))
/* line is "more horizontal" */
{
err
=
2
*
dy
-
dx
;
erradd
=
2
*
dy
-
2
*
dx
;
for
(
cnt
=
0
;
cnt
<
dx
;
cnt
++
)
err
add
=
2
*
params
->
dy
-
2
*
params
->
dx
;
while
(
x1
!=
x2
)
{
callback
(
x1
,
y1
,
lParam
);
if
(
err
+
bias
>
0
)
if
(
err
+
params
->
bias
>
0
)
{
y1
+=
yadd
;
err
+=
erradd
;
}
else
err
+=
2
*
dy
;
else
err
+=
2
*
params
->
dy
;
x1
+=
xadd
;
}
if
(
last_pt
)
callback
(
x1
,
y1
,
lParam
);
}
else
/* line is "more vertical" */
{
err
=
2
*
dx
-
dy
;
erradd
=
2
*
dx
-
2
*
dy
;
for
(
cnt
=
0
;
cnt
<
dy
;
cnt
++
)
err
add
=
2
*
params
->
dx
-
2
*
params
->
dy
;
while
(
y1
!=
y2
)
{
callback
(
x1
,
y1
,
lParam
);
if
(
err
+
bias
>
0
)
if
(
err
+
params
->
bias
>
0
)
{
x1
+=
xadd
;
err
+=
erradd
;
}
else
err
+=
2
*
dx
;
else
err
+=
2
*
params
->
dx
;
y1
+=
yadd
;
}
if
(
last_pt
)
callback
(
x1
,
y1
,
lParam
);
}
}
static
BOOL
solid_pen_line
(
dibdrv_physdev
*
pdev
,
POINT
*
start
,
POINT
*
end
)
{
const
WINEREGION
*
clip
=
get_wine_region
(
pdev
->
clip
);
BOOL
ret
=
TRUE
;
if
(
start
->
y
==
end
->
y
)
{
...
...
@@ -264,15 +502,47 @@ static BOOL solid_pen_line(dibdrv_physdev *pdev, POINT *start, POINT *end)
}
else
{
if
(
clip
->
numRects
==
1
&&
pt_in_rect
(
&
clip
->
extents
,
start
)
&&
pt_in_rect
(
&
clip
->
extents
,
end
))
/* FIXME: Optimize by moving Bresenham algorithm to the primitive functions,
or at least cache adjacent points in the callback */
bres_line_with_bias
(
start
->
x
,
start
->
y
,
end
->
x
,
end
->
y
,
solid_pen_line_callback
,
(
LPARAM
)
pdev
);
else
if
(
clip
->
numRects
>=
1
)
ret
=
FALSE
;
bres_params
params
;
INT
dx
=
end
->
x
-
start
->
x
;
INT
dy
=
end
->
y
-
start
->
y
;
INT
i
;
params
.
dx
=
abs
(
dx
);
params
.
dy
=
abs
(
dy
);
params
.
octant
=
get_octant_mask
(
dx
,
dy
);
/* Octants 3, 5, 6 and 8 take a bias */
params
.
bias
=
(
params
.
octant
&
0xb4
)
?
1
:
0
;
for
(
i
=
0
;
i
<
clip
->
numRects
;
i
++
)
{
POINT
clipped_start
,
clipped_end
;
int
clip_status
;
clip_status
=
clip_line
(
start
,
end
,
clip
->
rects
+
i
,
&
params
,
&
clipped_start
,
&
clipped_end
);
if
(
clip_status
)
{
int
m
=
abs
(
clipped_start
.
x
-
start
->
x
);
int
n
=
abs
(
clipped_start
.
y
-
start
->
y
);
int
err
;
BOOL
last_pt
=
FALSE
;
if
(
is_xmajor
(
params
.
octant
))
err
=
2
*
params
.
dy
-
params
.
dx
+
m
*
2
*
params
.
dy
-
n
*
2
*
params
.
dx
;
else
err
=
2
*
params
.
dx
-
params
.
dy
+
n
*
2
*
params
.
dx
-
m
*
2
*
params
.
dy
;
if
(
clip_status
==
1
&&
(
end
->
x
!=
clipped_end
.
x
||
end
->
y
!=
clipped_end
.
y
))
last_pt
=
TRUE
;
bres_line_with_bias
(
clipped_start
.
x
,
clipped_start
.
y
,
clipped_end
.
x
,
clipped_end
.
y
,
&
params
,
err
,
last_pt
,
solid_pen_line_callback
,
(
LPARAM
)
pdev
);
if
(
clip_status
==
2
)
break
;
/* completely unclipped, so we can finish */
}
}
}
release_wine_region
(
pdev
->
clip
);
return
ret
;
return
TRUE
;
}
/***********************************************************************
...
...
This diff is collapsed.
Click to expand it.
dlls/gdi32/tests/dib.c
+
23
−
1
View file @
e248615a
...
...
@@ -82,6 +82,7 @@ static const char *sha1_graphics_a8r8g8b8[] =
"17b2c177bdce5e94433574a928bda5c94a8cdfa5"
,
"fe6cc678fb13a3ead67839481bf22348adc69f52"
,
"d51bd330cec510cdccf5394328bd8e5411901e9e"
,
"df4aebf98d91f11be560dd232123b3ae327303d7"
,
"f2af53dd073a09b1031d0032d28da35c82adc566"
,
NULL
};
...
...
@@ -179,7 +180,7 @@ static const RECT hline_clips[] =
{
10
,
134
,
101
,
134
},
/* r end on l edgecase */
{
10
,
136
,
100
,
136
},
/* r end on l edgecase clipped */
{
199
,
138
,
220
,
138
},
/* l end on r edgecase */
{
200
,
140
,
220
,
20
0
}
/* l end on r edgecase clipped */
{
200
,
140
,
220
,
14
0
}
/* l end on r edgecase clipped */
};
static
const
RECT
vline_clips
[]
=
...
...
@@ -201,6 +202,17 @@ static const RECT vline_clips[] =
{
140
,
200
,
140
,
220
}
/* t end on b edgecase clipped */
};
static
const
RECT
line_clips
[]
=
{
{
90
,
110
,
310
,
120
},
{
90
,
120
,
295
,
130
},
{
90
,
190
,
110
,
240
},
/* totally clipped, moving outcodes */
{
90
,
130
,
100
,
135
},
/* totally clipped, end pt on l edge */
{
90
,
132
,
101
,
137
},
/* end pt just inside l edge */
{
200
,
140
,
210
,
141
},
/* totally clipped, start pt on r edge */
{
199
,
142
,
210
,
143
}
/* start pt just inside r edge */
};
static
const
RECT
patblt_clips
[]
=
{
{
120
,
120
,
140
,
126
},
/* unclipped */
...
...
@@ -252,6 +264,7 @@ static void draw_graphics(HDC hdc, BITMAPINFO *bmi, BYTE *bits, const char ***sh
compare_hash
(
bmi
,
bits
,
sha1
,
"h and v solid lines"
);
memset
(
bits
,
0xcc
,
dib_size
);
/* diagonal lines */
SetROP2
(
hdc
,
R2_COPYPEN
);
for
(
i
=
0
;
i
<
16
;
i
++
)
{
...
...
@@ -320,6 +333,15 @@ static void draw_graphics(HDC hdc, BITMAPINFO *bmi, BYTE *bits, const char ***sh
compare_hash
(
bmi
,
bits
,
sha1
,
"clipped solid vlines"
);
memset
(
bits
,
0xcc
,
dib_size
);
for
(
i
=
0
;
i
<
sizeof
(
line_clips
)
/
sizeof
(
line_clips
[
0
]);
i
++
)
{
MoveToEx
(
hdc
,
line_clips
[
i
].
left
,
line_clips
[
i
].
top
,
NULL
);
LineTo
(
hdc
,
line_clips
[
i
].
right
,
line_clips
[
i
].
bottom
);
}
compare_hash
(
bmi
,
bits
,
sha1
,
"clipped solid diagonal lines"
);
memset
(
bits
,
0xcc
,
dib_size
);
/* clipped PatBlt */
for
(
i
=
0
;
i
<
sizeof
(
patblt_clips
)
/
sizeof
(
patblt_clips
[
0
]);
i
++
)
{
PatBlt
(
hdc
,
patblt_clips
[
i
].
left
,
patblt_clips
[
i
].
top
,
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment