Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
90b4e7d3
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
90b4e7d3
编写于
8月 23, 2010
作者:
L
lana
浏览文件
操作
浏览文件
下载
差异文件
Merge
上级
2c7696d6
32315d6e
变更
7
显示空白变更内容
内联
并排
Showing
7 changed file
with
799 addition
and
1390 deletion
+799
-1390
src/share/classes/sun/java2d/pisces/Dasher.java
src/share/classes/sun/java2d/pisces/Dasher.java
+83
-116
src/share/classes/sun/java2d/pisces/LineSink.java
src/share/classes/sun/java2d/pisces/LineSink.java
+10
-10
src/share/classes/sun/java2d/pisces/PiscesMath.java
src/share/classes/sun/java2d/pisces/PiscesMath.java
+0
-155
src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java
...hare/classes/sun/java2d/pisces/PiscesRenderingEngine.java
+167
-62
src/share/classes/sun/java2d/pisces/Renderer.java
src/share/classes/sun/java2d/pisces/Renderer.java
+382
-717
src/share/classes/sun/java2d/pisces/Stroker.java
src/share/classes/sun/java2d/pisces/Stroker.java
+157
-246
src/share/classes/sun/java2d/pisces/Transform4.java
src/share/classes/sun/java2d/pisces/Transform4.java
+0
-84
未找到文件。
src/share/classes/sun/java2d/pisces/Dasher.java
浏览文件 @
90b4e7d3
...
@@ -36,117 +36,71 @@ package sun.java2d.pisces;
...
@@ -36,117 +36,71 @@ package sun.java2d.pisces;
* semantics are unclear.
* semantics are unclear.
*
*
*/
*/
public
class
Dasher
extends
LineSink
{
public
class
Dasher
implements
LineSink
{
private
final
LineSink
output
;
private
final
float
[]
dash
;
private
final
float
startPhase
;
private
final
boolean
startDashOn
;
private
final
int
startIdx
;
LineSink
output
;
private
final
float
m00
,
m10
,
m01
,
m11
;
int
[]
dash
;
private
final
float
det
;
int
startPhase
;
boolean
startDashOn
;
int
startIdx
;
int
idx
;
private
boolean
firstDashOn
;
boolean
dashOn
;
private
boolean
starting
;
int
phase
;
int
sx
,
sy
;
private
int
idx
;
int
x0
,
y0
;
private
boolean
dashOn
;
private
float
phase
;
int
m00
,
m01
;
private
float
sx
,
sy
;
int
m10
,
m11
;
private
float
x0
,
y0
;
private
float
sx1
,
sy1
;
Transform4
transform
;
boolean
symmetric
;
long
ldet
;
boolean
firstDashOn
;
boolean
starting
;
int
sx1
,
sy1
;
/**
* Empty constructor. <code>setOutput</code> and
* <code>setParameters</code> must be called prior to calling any
* other methods.
*/
public
Dasher
()
{}
/**
/**
* Constructs a <code>Dasher</code>.
* Constructs a <code>Dasher</code>.
*
*
* @param output an output <code>LineSink</code>.
* @param output an output <code>LineSink</code>.
* @param dash an array of <code>int</code>s containing the dash
* @param dash an array of <code>int</code>s containing the dash pattern
* pattern in S15.16 format.
* @param phase an <code>int</code> containing the dash phase
* @param phase an <code>int</code> containing the dash phase in
* S15.16 format.
* @param transform a <code>Transform4</code> object indicating
* @param transform a <code>Transform4</code> object indicating
* the transform that has been previously applied to all incoming
* the transform that has been previously applied to all incoming
* coordinates. This is required in order to compute dash lengths
* coordinates. This is required in order to compute dash lengths
* properly.
* properly.
*/
*/
public
Dasher
(
LineSink
output
,
public
Dasher
(
LineSink
output
,
int
[]
dash
,
int
phase
,
float
[]
dash
,
float
phase
,
Transform4
transform
)
{
float
a00
,
float
a01
,
float
a10
,
float
a11
)
{
setOutput
(
output
);
setParameters
(
dash
,
phase
,
transform
);
}
/**
* Sets the output <code>LineSink</code> of this
* <code>Dasher</code>.
*
* @param output an output <code>LineSink</code>.
*/
public
void
setOutput
(
LineSink
output
)
{
this
.
output
=
output
;
}
/**
* Sets the parameters of this <code>Dasher</code>.
*
* @param dash an array of <code>int</code>s containing the dash
* pattern in S15.16 format.
* @param phase an <code>int</code> containing the dash phase in
* S15.16 format.
* @param transform a <code>Transform4</code> object indicating
* the transform that has been previously applied to all incoming
* coordinates. This is required in order to compute dash lengths
* properly.
*/
public
void
setParameters
(
int
[]
dash
,
int
phase
,
Transform4
transform
)
{
if
(
phase
<
0
)
{
if
(
phase
<
0
)
{
throw
new
IllegalArgumentException
(
"phase < 0 !"
);
throw
new
IllegalArgumentException
(
"phase < 0 !"
);
}
}
this
.
output
=
output
;
// Normalize so 0 <= phase < dash[0]
// Normalize so 0 <= phase < dash[0]
int
idx
=
0
;
int
idx
=
0
;
dashOn
=
true
;
dashOn
=
true
;
in
t
d
;
floa
t
d
;
while
(
phase
>=
(
d
=
dash
[
idx
]))
{
while
(
phase
>=
(
d
=
dash
[
idx
]))
{
phase
-=
d
;
phase
-=
d
;
idx
=
(
idx
+
1
)
%
dash
.
length
;
idx
=
(
idx
+
1
)
%
dash
.
length
;
dashOn
=
!
dashOn
;
dashOn
=
!
dashOn
;
}
}
this
.
dash
=
new
int
[
dash
.
length
];
this
.
dash
=
dash
;
for
(
int
i
=
0
;
i
<
dash
.
length
;
i
++)
{
this
.
dash
[
i
]
=
dash
[
i
];
}
this
.
startPhase
=
this
.
phase
=
phase
;
this
.
startPhase
=
this
.
phase
=
phase
;
this
.
startDashOn
=
dashOn
;
this
.
startDashOn
=
dashOn
;
this
.
startIdx
=
idx
;
this
.
startIdx
=
idx
;
this
.
transform
=
transform
;
m00
=
a00
;
m01
=
a01
;
this
.
m00
=
transform
.
m00
;
m10
=
a10
;
this
.
m01
=
transform
.
m01
;
m11
=
a11
;
this
.
m10
=
transform
.
m10
;
det
=
m00
*
m11
-
m01
*
m10
;
this
.
m11
=
transform
.
m11
;
this
.
ldet
=
((
long
)
m00
*
m11
-
(
long
)
m01
*
m10
)
>>
16
;
this
.
symmetric
=
(
m00
==
m11
&&
m10
==
-
m01
);
}
}
public
void
moveTo
(
int
x0
,
in
t
y0
)
{
public
void
moveTo
(
float
x0
,
floa
t
y0
)
{
output
.
moveTo
(
x0
,
y0
);
output
.
moveTo
(
x0
,
y0
);
this
.
idx
=
startIdx
;
this
.
idx
=
startIdx
;
this
.
dashOn
=
this
.
startDashOn
;
this
.
dashOn
=
this
.
startDashOn
;
...
@@ -160,7 +114,7 @@ public class Dasher extends LineSink {
...
@@ -160,7 +114,7 @@ public class Dasher extends LineSink {
output
.
lineJoin
();
output
.
lineJoin
();
}
}
private
void
goTo
(
int
x1
,
in
t
y1
)
{
private
void
goTo
(
float
x1
,
floa
t
y1
)
{
if
(
dashOn
)
{
if
(
dashOn
)
{
if
(
starting
)
{
if
(
starting
)
{
this
.
sx1
=
x1
;
this
.
sx1
=
x1
;
...
@@ -180,52 +134,64 @@ public class Dasher extends LineSink {
...
@@ -180,52 +134,64 @@ public class Dasher extends LineSink {
this
.
y0
=
y1
;
this
.
y0
=
y1
;
}
}
public
void
lineTo
(
int
x1
,
int
y1
)
{
public
void
lineTo
(
float
x1
,
float
y1
)
{
while
(
true
)
{
// The widened line is squished to a 0 width one, so no drawing is done
int
d
=
dash
[
idx
]
-
phase
;
if
(
det
==
0
)
{
int
lx
=
x1
-
x0
;
goTo
(
x1
,
y1
);
int
ly
=
y1
-
y0
;
return
;
}
float
dx
=
x1
-
x0
;
float
dy
=
y1
-
y0
;
// Compute segment length in the untransformed
// Compute segment length in the untransformed
// coordinate system
// coordinate system
// IMPL NOTE - use fixed point
int
l
;
float
la
=
(
dy
*
m00
-
dx
*
m10
)/
det
;
if
(
symmetric
)
{
float
lb
=
(
dy
*
m01
-
dx
*
m11
)/
det
;
l
=
(
int
)((
PiscesMath
.
hypot
(
lx
,
ly
)*
65536L
)/
ldet
);
float
origLen
=
(
float
)
Math
.
hypot
(
la
,
lb
);
}
else
{
long
la
=
((
long
)
ly
*
m00
-
(
long
)
lx
*
m10
)/
ldet
;
if
(
origLen
==
0
)
{
long
lb
=
((
long
)
ly
*
m01
-
(
long
)
lx
*
m11
)/
ldet
;
// Let the output LineSink deal with cases where dx, dy are 0.
l
=
(
int
)
PiscesMath
.
hypot
(
la
,
lb
);
goTo
(
x1
,
y1
);
return
;
}
}
if
(
l
<
d
)
{
// The scaling factors needed to get the dx and dy of the
// transformed dash segments.
float
cx
=
dx
/
origLen
;
float
cy
=
dy
/
origLen
;
while
(
true
)
{
float
leftInThisDashSegment
=
dash
[
idx
]
-
phase
;
if
(
origLen
<
leftInThisDashSegment
)
{
goTo
(
x1
,
y1
);
goTo
(
x1
,
y1
);
// Advance phase within current dash segment
// Advance phase within current dash segment
phase
+=
l
;
phase
+=
origLen
;
return
;
}
else
if
(
origLen
==
leftInThisDashSegment
)
{
goTo
(
x1
,
y1
);
phase
=
0
f
;
idx
=
(
idx
+
1
)
%
dash
.
length
;
dashOn
=
!
dashOn
;
return
;
return
;
}
}
long
t
;
float
dashx
,
dashy
;
int
xsplit
,
ysplit
;
float
dashdx
=
dash
[
idx
]
*
cx
;
// // For zero length dashses, SE appears to move 1/8 unit
float
dashdy
=
dash
[
idx
]
*
cy
;
// // in device space
if
(
phase
==
0
)
{
// if (d == 0) {
dashx
=
x0
+
dashdx
;
// double dlx = lx/65536.0;
dashy
=
y0
+
dashdy
;
// double dly = ly/65536.0;
}
else
{
// len = PiscesMath.hypot(dlx, dly);
float
p
=
(
leftInThisDashSegment
)
/
dash
[
idx
];
// double dt = 1.0/(8*len);
dashx
=
x0
+
p
*
dashdx
;
// double dxsplit = (x0/65536.0) + dt*dlx;
dashy
=
y0
+
p
*
dashdy
;
// double dysplit = (y0/65536.0) + dt*dly;
}
// xsplit = (int)(dxsplit*65536.0);
// ysplit = (int)(dysplit*65536.0);
// } else {
t
=
((
long
)
d
<<
16
)/
l
;
xsplit
=
x0
+
(
int
)(
t
*(
x1
-
x0
)
>>
16
);
ysplit
=
y0
+
(
int
)(
t
*(
y1
-
y0
)
>>
16
);
// }
goTo
(
xsplit
,
ysplit
);
goTo
(
dashx
,
dashy
);
origLen
-=
(
dash
[
idx
]
-
phase
);
// Advance to next dash segment
// Advance to next dash segment
idx
=
(
idx
+
1
)
%
dash
.
length
;
idx
=
(
idx
+
1
)
%
dash
.
length
;
dashOn
=
!
dashOn
;
dashOn
=
!
dashOn
;
...
@@ -233,6 +199,7 @@ public class Dasher extends LineSink {
...
@@ -233,6 +199,7 @@ public class Dasher extends LineSink {
}
}
}
}
public
void
close
()
{
public
void
close
()
{
lineTo
(
sx
,
sy
);
lineTo
(
sx
,
sy
);
if
(
firstDashOn
)
{
if
(
firstDashOn
)
{
...
...
src/share/classes/sun/java2d/pisces/LineSink.java
浏览文件 @
90b4e7d3
...
@@ -39,16 +39,16 @@ package sun.java2d.pisces;
...
@@ -39,16 +39,16 @@ package sun.java2d.pisces;
* <code>LineSink</code> interface.
* <code>LineSink</code> interface.
*
*
*/
*/
public
abstract
class
LineSink
{
public
interface
LineSink
{
/**
/**
* Moves the current drawing position to the point <code>(x0,
* Moves the current drawing position to the point <code>(x0,
* y0)</code>.
* y0)</code>.
*
*
* @param x0 the X coordinate
in S15.16 format
* @param x0 the X coordinate
* @param y0 the Y coordinate
in S15.16 format
* @param y0 the Y coordinate
*/
*/
public
abstract
void
moveTo
(
int
x0
,
in
t
y0
);
public
void
moveTo
(
float
x0
,
floa
t
y0
);
/**
/**
* Provides a hint that the current segment should be joined to
* Provides a hint that the current segment should be joined to
...
@@ -65,29 +65,29 @@ public abstract class LineSink {
...
@@ -65,29 +65,29 @@ public abstract class LineSink {
* <p> Other <code>LineSink</code> classes should simply pass this
* <p> Other <code>LineSink</code> classes should simply pass this
* hint to their output sink as needed.
* hint to their output sink as needed.
*/
*/
public
abstract
void
lineJoin
();
public
void
lineJoin
();
/**
/**
* Draws a line from the current drawing position to the point
* Draws a line from the current drawing position to the point
* <code>(x1, y1)</code> and sets the current drawing position to
* <code>(x1, y1)</code> and sets the current drawing position to
* <code>(x1, y1)</code>.
* <code>(x1, y1)</code>.
*
*
* @param x1 the X coordinate
in S15.16 format
* @param x1 the X coordinate
* @param y1 the Y coordinate
in S15.16 format
* @param y1 the Y coordinate
*/
*/
public
abstract
void
lineTo
(
int
x1
,
in
t
y1
);
public
void
lineTo
(
float
x1
,
floa
t
y1
);
/**
/**
* Closes the current path by drawing a line from the current
* Closes the current path by drawing a line from the current
* drawing position to the point specified by the moset recent
* drawing position to the point specified by the moset recent
* <code>moveTo</code> command.
* <code>moveTo</code> command.
*/
*/
public
abstract
void
close
();
public
void
close
();
/**
/**
* Ends the current path. It may be necessary to end a path in
* Ends the current path. It may be necessary to end a path in
* order to allow end caps to be drawn.
* order to allow end caps to be drawn.
*/
*/
public
abstract
void
end
();
public
void
end
();
}
}
src/share/classes/sun/java2d/pisces/PiscesMath.java
已删除
100644 → 0
浏览文件 @
2c7696d6
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
sun.java2d.pisces
;
public
class
PiscesMath
{
private
PiscesMath
()
{}
private
static
final
int
SINTAB_LG_ENTRIES
=
10
;
private
static
final
int
SINTAB_ENTRIES
=
1
<<
SINTAB_LG_ENTRIES
;
private
static
int
[]
sintab
;
public
static
final
int
PI
=
(
int
)(
Math
.
PI
*
65536.0
);
public
static
final
int
TWO_PI
=
(
int
)(
2.0
*
Math
.
PI
*
65536.0
);
public
static
final
int
PI_OVER_TWO
=
(
int
)((
Math
.
PI
/
2.0
)*
65536.0
);
public
static
final
int
SQRT_TWO
=
(
int
)(
Math
.
sqrt
(
2.0
)*
65536.0
);
static
{
sintab
=
new
int
[
SINTAB_ENTRIES
+
1
];
for
(
int
i
=
0
;
i
<
SINTAB_ENTRIES
+
1
;
i
++)
{
double
theta
=
i
*(
Math
.
PI
/
2.0
)/
SINTAB_ENTRIES
;
sintab
[
i
]
=
(
int
)(
Math
.
sin
(
theta
)*
65536.0
);
}
}
public
static
int
sin
(
int
theta
)
{
int
sign
=
1
;
if
(
theta
<
0
)
{
theta
=
-
theta
;
sign
=
-
1
;
}
// 0 <= theta
while
(
theta
>=
TWO_PI
)
{
theta
-=
TWO_PI
;
}
// 0 <= theta < 2*PI
if
(
theta
>=
PI
)
{
theta
=
TWO_PI
-
theta
;
sign
=
-
sign
;
}
// 0 <= theta < PI
if
(
theta
>
PI_OVER_TWO
)
{
theta
=
PI
-
theta
;
}
// 0 <= theta <= PI/2
int
itheta
=
(
int
)((
long
)
theta
*
SINTAB_ENTRIES
/(
PI_OVER_TWO
));
return
sign
*
sintab
[
itheta
];
}
public
static
int
cos
(
int
theta
)
{
return
sin
(
PI_OVER_TWO
-
theta
);
}
// public static double sqrt(double x) {
// double dsqrt = Math.sqrt(x);
// int ix = (int)(x*65536.0);
// Int Isqrt = Isqrt(Ix);
// Long Lx = (Long)(X*65536.0);
// Long Lsqrt = Lsqrt(Lx);
// System.Out.Println();
// System.Out.Println("X = " + X);
// System.Out.Println("Dsqrt = " + Dsqrt);
// System.Out.Println("Ix = " + Ix);
// System.Out.Println("Isqrt = " + Isqrt/65536.0);
// System.Out.Println("Lx = " + Lx);
// System.Out.Println("Lsqrt = " + Lsqrt/65536.0);
// Return Dsqrt;
// }
// From Ken Turkowski, _Fixed-Point Square Root_, In Graphics Gems V
public
static
int
isqrt
(
int
x
)
{
int
fracbits
=
16
;
int
root
=
0
;
int
remHi
=
0
;
int
remLo
=
x
;
int
count
=
15
+
fracbits
/
2
;
do
{
remHi
=
(
remHi
<<
2
)
|
(
remLo
>>>
30
);
// N.B. - unsigned shift R
remLo
<<=
2
;
root
<<=
1
;
int
testdiv
=
(
root
<<
1
)
+
1
;
if
(
remHi
>=
testdiv
)
{
remHi
-=
testdiv
;
root
++;
}
}
while
(
count
--
!=
0
);
return
root
;
}
public
static
long
lsqrt
(
long
x
)
{
int
fracbits
=
16
;
long
root
=
0
;
long
remHi
=
0
;
long
remLo
=
x
;
int
count
=
31
+
fracbits
/
2
;
do
{
remHi
=
(
remHi
<<
2
)
|
(
remLo
>>>
62
);
// N.B. - unsigned shift R
remLo
<<=
2
;
root
<<=
1
;
long
testDiv
=
(
root
<<
1
)
+
1
;
if
(
remHi
>=
testDiv
)
{
remHi
-=
testDiv
;
root
++;
}
}
while
(
count
--
!=
0
);
return
root
;
}
public
static
double
hypot
(
double
x
,
double
y
)
{
// new RuntimeException().printStackTrace();
return
Math
.
sqrt
(
x
*
x
+
y
*
y
);
}
public
static
int
hypot
(
int
x
,
int
y
)
{
return
(
int
)((
lsqrt
((
long
)
x
*
x
+
(
long
)
y
*
y
)
+
128
)
>>
8
);
}
public
static
long
hypot
(
long
x
,
long
y
)
{
return
(
lsqrt
(
x
*
x
+
y
*
y
)
+
128
)
>>
8
;
}
}
src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java
浏览文件 @
90b4e7d3
...
@@ -27,6 +27,7 @@ package sun.java2d.pisces;
...
@@ -27,6 +27,7 @@ package sun.java2d.pisces;
import
java.awt.Shape
;
import
java.awt.Shape
;
import
java.awt.BasicStroke
;
import
java.awt.BasicStroke
;
import
java.awt.geom.FlatteningPathIterator
;
import
java.awt.geom.Path2D
;
import
java.awt.geom.Path2D
;
import
java.awt.geom.AffineTransform
;
import
java.awt.geom.AffineTransform
;
import
java.awt.geom.PathIterator
;
import
java.awt.geom.PathIterator
;
...
@@ -37,23 +38,9 @@ import sun.java2d.pipe.RenderingEngine;
...
@@ -37,23 +38,9 @@ import sun.java2d.pipe.RenderingEngine;
import
sun.java2d.pipe.AATileGenerator
;
import
sun.java2d.pipe.AATileGenerator
;
public
class
PiscesRenderingEngine
extends
RenderingEngine
{
public
class
PiscesRenderingEngine
extends
RenderingEngine
{
public
static
Transform4
IdentT4
=
new
Transform4
();
public
static
double
defaultFlat
=
0.1
;
public
static
double
defaultFlat
=
0.1
;
static
int
FloatToS15_16
(
float
flt
)
{
private
static
enum
NormMode
{
OFF
,
ON_NO_AA
,
ON_WITH_AA
}
flt
=
flt
*
65536
f
+
0.5f
;
if
(
flt
<=
-(
65536
f
*
65536
f
))
{
return
Integer
.
MIN_VALUE
;
}
else
if
(
flt
>=
(
65536
f
*
65536
f
))
{
return
Integer
.
MAX_VALUE
;
}
else
{
return
(
int
)
Math
.
floor
(
flt
);
}
}
static
float
S15_16ToFloat
(
int
fix
)
{
return
(
fix
/
65536
f
);
}
/**
/**
* Create a widened path as specified by the parameters.
* Create a widened path as specified by the parameters.
...
@@ -85,18 +72,19 @@ public class PiscesRenderingEngine extends RenderingEngine {
...
@@ -85,18 +72,19 @@ public class PiscesRenderingEngine extends RenderingEngine {
strokeTo
(
src
,
strokeTo
(
src
,
null
,
null
,
width
,
width
,
NormMode
.
OFF
,
caps
,
caps
,
join
,
join
,
miterlimit
,
miterlimit
,
dashes
,
dashes
,
dashphase
,
dashphase
,
new
LineSink
()
{
new
LineSink
()
{
public
void
moveTo
(
int
x0
,
in
t
y0
)
{
public
void
moveTo
(
float
x0
,
floa
t
y0
)
{
p2d
.
moveTo
(
S15_16ToFloat
(
x0
),
S15_16ToFloat
(
y0
)
);
p2d
.
moveTo
(
x0
,
y0
);
}
}
public
void
lineJoin
()
{}
public
void
lineJoin
()
{}
public
void
lineTo
(
int
x1
,
in
t
y1
)
{
public
void
lineTo
(
float
x1
,
floa
t
y1
)
{
p2d
.
lineTo
(
S15_16ToFloat
(
x1
),
S15_16ToFloat
(
y1
)
);
p2d
.
lineTo
(
x1
,
y1
);
}
}
public
void
close
()
{
public
void
close
()
{
p2d
.
closePath
();
p2d
.
closePath
();
...
@@ -142,14 +130,17 @@ public class PiscesRenderingEngine extends RenderingEngine {
...
@@ -142,14 +130,17 @@ public class PiscesRenderingEngine extends RenderingEngine {
boolean
antialias
,
boolean
antialias
,
final
PathConsumer2D
consumer
)
final
PathConsumer2D
consumer
)
{
{
strokeTo
(
src
,
at
,
bs
,
thin
,
normalize
,
antialias
,
NormMode
norm
=
(
normalize
)
?
((
antialias
)
?
NormMode
.
ON_WITH_AA
:
NormMode
.
ON_NO_AA
)
:
NormMode
.
OFF
;
strokeTo
(
src
,
at
,
bs
,
thin
,
norm
,
antialias
,
new
LineSink
()
{
new
LineSink
()
{
public
void
moveTo
(
int
x0
,
in
t
y0
)
{
public
void
moveTo
(
float
x0
,
floa
t
y0
)
{
consumer
.
moveTo
(
S15_16ToFloat
(
x0
),
S15_16ToFloat
(
y0
)
);
consumer
.
moveTo
(
x0
,
y0
);
}
}
public
void
lineJoin
()
{}
public
void
lineJoin
()
{}
public
void
lineTo
(
int
x1
,
in
t
y1
)
{
public
void
lineTo
(
float
x1
,
floa
t
y1
)
{
consumer
.
lineTo
(
S15_16ToFloat
(
x1
),
S15_16ToFloat
(
y1
)
);
consumer
.
lineTo
(
x1
,
y1
);
}
}
public
void
close
()
{
public
void
close
()
{
consumer
.
closePath
();
consumer
.
closePath
();
...
@@ -164,7 +155,7 @@ public class PiscesRenderingEngine extends RenderingEngine {
...
@@ -164,7 +155,7 @@ public class PiscesRenderingEngine extends RenderingEngine {
AffineTransform
at
,
AffineTransform
at
,
BasicStroke
bs
,
BasicStroke
bs
,
boolean
thin
,
boolean
thin
,
boolean
normalize
,
NormMode
normalize
,
boolean
antialias
,
boolean
antialias
,
LineSink
lsink
)
LineSink
lsink
)
{
{
...
@@ -181,6 +172,7 @@ public class PiscesRenderingEngine extends RenderingEngine {
...
@@ -181,6 +172,7 @@ public class PiscesRenderingEngine extends RenderingEngine {
strokeTo
(
src
,
strokeTo
(
src
,
at
,
at
,
lw
,
lw
,
normalize
,
bs
.
getEndCap
(),
bs
.
getEndCap
(),
bs
.
getLineJoin
(),
bs
.
getLineJoin
(),
bs
.
getMiterLimit
(),
bs
.
getMiterLimit
(),
...
@@ -258,6 +250,7 @@ public class PiscesRenderingEngine extends RenderingEngine {
...
@@ -258,6 +250,7 @@ public class PiscesRenderingEngine extends RenderingEngine {
void
strokeTo
(
Shape
src
,
void
strokeTo
(
Shape
src
,
AffineTransform
at
,
AffineTransform
at
,
float
width
,
float
width
,
NormMode
normalize
,
int
caps
,
int
caps
,
int
join
,
int
join
,
float
miterlimit
,
float
miterlimit
,
...
@@ -265,36 +258,139 @@ public class PiscesRenderingEngine extends RenderingEngine {
...
@@ -265,36 +258,139 @@ public class PiscesRenderingEngine extends RenderingEngine {
float
dashphase
,
float
dashphase
,
LineSink
lsink
)
LineSink
lsink
)
{
{
Transform4
t4
;
float
a00
=
1
f
,
a01
=
0
f
,
a10
=
0
f
,
a11
=
1
f
;
if
(
at
!=
null
&&
!
at
.
isIdentity
())
{
if
(
at
==
null
||
at
.
isIdentity
())
{
a00
=
(
float
)
at
.
getScaleX
();
t4
=
IdentT4
;
a01
=
(
float
)
at
.
getShearX
();
a10
=
(
float
)
at
.
getShearY
();
a11
=
(
float
)
at
.
getScaleY
();
}
lsink
=
new
Stroker
(
lsink
,
width
,
caps
,
join
,
miterlimit
,
a00
,
a01
,
a10
,
a11
);
if
(
dashes
!=
null
)
{
lsink
=
new
Dasher
(
lsink
,
dashes
,
dashphase
,
a00
,
a01
,
a10
,
a11
);
}
PathIterator
pi
;
if
(
normalize
!=
NormMode
.
OFF
)
{
pi
=
new
FlatteningPathIterator
(
new
NormalizingPathIterator
(
src
.
getPathIterator
(
at
),
normalize
),
defaultFlat
);
}
else
{
}
else
{
t4
=
new
Transform4
(
FloatToS15_16
((
float
)
at
.
getScaleX
()),
pi
=
src
.
getPathIterator
(
at
,
defaultFlat
);
FloatToS15_16
((
float
)
at
.
getShearX
()),
}
FloatToS15_16
((
float
)
at
.
getShearY
()),
pathTo
(
pi
,
lsink
);
FloatToS15_16
((
float
)
at
.
getScaleY
()));
}
}
lsink
=
new
Stroker
(
lsink
,
private
static
class
NormalizingPathIterator
implements
PathIterator
{
FloatToS15_16
(
width
),
caps
,
private
final
PathIterator
src
;
join
,
FloatToS15_16
(
miterlimit
),
// the adjustment applied to the current position.
t4
);
private
float
curx_adjust
,
cury_adjust
;
if
(
dashes
!=
null
)
{
// the adjustment applied to the last moveTo position.
int
fdashes
[]
=
new
int
[
dashes
.
length
];
private
float
movx_adjust
,
movy_adjust
;
for
(
int
i
=
0
;
i
<
dashes
.
length
;
i
++)
{
fdashes
[
i
]
=
FloatToS15_16
(
dashes
[
i
]);
// constants used in normalization computations
private
final
float
lval
,
rval
;
NormalizingPathIterator
(
PathIterator
src
,
NormMode
mode
)
{
this
.
src
=
src
;
switch
(
mode
)
{
case
ON_NO_AA:
// round to nearest (0.25, 0.25) pixel
lval
=
rval
=
0.25f
;
break
;
case
ON_WITH_AA:
// round to nearest pixel center
lval
=
0
f
;
rval
=
0.5f
;
break
;
case
OFF:
throw
new
InternalError
(
"A NormalizingPathIterator should "
+
"not be created if no normalization is being done"
);
default
:
throw
new
InternalError
(
"Unrecognized normalization mode"
);
}
}
lsink
=
new
Dasher
(
lsink
,
fdashes
,
FloatToS15_16
(
dashphase
),
t4
);
}
}
PathIterator
pi
=
src
.
getPathIterator
(
at
,
defaultFlat
);
public
int
currentSegment
(
float
[]
coords
)
{
pathTo
(
pi
,
lsink
);
int
type
=
src
.
currentSegment
(
coords
);
int
lastCoord
;
switch
(
type
)
{
case
PathIterator
.
SEG_CUBICTO
:
lastCoord
=
4
;
break
;
case
PathIterator
.
SEG_QUADTO
:
lastCoord
=
2
;
break
;
case
PathIterator
.
SEG_LINETO
:
case
PathIterator
.
SEG_MOVETO
:
lastCoord
=
0
;
break
;
case
PathIterator
.
SEG_CLOSE
:
// we don't want to deal with this case later. We just exit now
curx_adjust
=
movx_adjust
;
cury_adjust
=
movy_adjust
;
return
type
;
default
:
throw
new
InternalError
(
"Unrecognized curve type"
);
}
// normalize endpoint
float
x_adjust
=
(
float
)
Math
.
floor
(
coords
[
lastCoord
]
+
lval
)
+
rval
-
coords
[
lastCoord
];
float
y_adjust
=
(
float
)
Math
.
floor
(
coords
[
lastCoord
+
1
]
+
lval
)
+
rval
-
coords
[
lastCoord
+
1
];
coords
[
lastCoord
]
+=
x_adjust
;
coords
[
lastCoord
+
1
]
+=
y_adjust
;
// now that the end points are done, normalize the control points
switch
(
type
)
{
case
PathIterator
.
SEG_CUBICTO
:
coords
[
0
]
+=
curx_adjust
;
coords
[
1
]
+=
cury_adjust
;
coords
[
2
]
+=
x_adjust
;
coords
[
3
]
+=
y_adjust
;
break
;
case
PathIterator
.
SEG_QUADTO
:
coords
[
0
]
+=
(
curx_adjust
+
x_adjust
)
/
2
;
coords
[
1
]
+=
(
cury_adjust
+
y_adjust
)
/
2
;
break
;
case
PathIterator
.
SEG_LINETO
:
break
;
case
PathIterator
.
SEG_MOVETO
:
movx_adjust
=
x_adjust
;
movy_adjust
=
y_adjust
;
break
;
case
PathIterator
.
SEG_CLOSE
:
throw
new
InternalError
(
"This should be handled earlier."
);
}
curx_adjust
=
x_adjust
;
cury_adjust
=
y_adjust
;
return
type
;
}
public
int
currentSegment
(
double
[]
coords
)
{
float
[]
tmp
=
new
float
[
6
];
int
type
=
this
.
currentSegment
(
tmp
);
for
(
int
i
=
0
;
i
<
6
;
i
++)
{
coords
[
i
]
=
(
float
)
tmp
[
i
];
}
return
type
;
}
public
int
getWindingRule
()
{
return
src
.
getWindingRule
();
}
public
boolean
isDone
()
{
return
src
.
isDone
();
}
public
void
next
()
{
src
.
next
();
}
}
}
void
pathTo
(
PathIterator
pi
,
LineSink
lsink
)
{
void
pathTo
(
PathIterator
pi
,
LineSink
lsink
)
{
...
@@ -302,13 +398,11 @@ public class PiscesRenderingEngine extends RenderingEngine {
...
@@ -302,13 +398,11 @@ public class PiscesRenderingEngine extends RenderingEngine {
while
(!
pi
.
isDone
())
{
while
(!
pi
.
isDone
())
{
switch
(
pi
.
currentSegment
(
coords
))
{
switch
(
pi
.
currentSegment
(
coords
))
{
case
PathIterator
.
SEG_MOVETO
:
case
PathIterator
.
SEG_MOVETO
:
lsink
.
moveTo
(
FloatToS15_16
(
coords
[
0
]),
lsink
.
moveTo
(
coords
[
0
],
coords
[
1
]);
FloatToS15_16
(
coords
[
1
]));
break
;
break
;
case
PathIterator
.
SEG_LINETO
:
case
PathIterator
.
SEG_LINETO
:
lsink
.
lineJoin
();
lsink
.
lineJoin
();
lsink
.
lineTo
(
FloatToS15_16
(
coords
[
0
]),
lsink
.
lineTo
(
coords
[
0
],
coords
[
1
]);
FloatToS15_16
(
coords
[
1
]));
break
;
break
;
case
PathIterator
.
SEG_CLOSE
:
case
PathIterator
.
SEG_CLOSE
:
lsink
.
lineJoin
();
lsink
.
lineJoin
();
...
@@ -378,18 +472,28 @@ public class PiscesRenderingEngine extends RenderingEngine {
...
@@ -378,18 +472,28 @@ public class PiscesRenderingEngine extends RenderingEngine {
int
bbox
[])
int
bbox
[])
{
{
PiscesCache
pc
=
PiscesCache
.
createInstance
();
PiscesCache
pc
=
PiscesCache
.
createInstance
();
Renderer
r
=
new
Renderer
();
Renderer
r
;
r
.
setCache
(
pc
);
NormMode
norm
=
(
normalize
)
?
NormMode
.
ON_WITH_AA
:
NormMode
.
OFF
;
r
.
setAntialiasing
(
3
,
3
);
r
.
beginRendering
(
clip
.
getLoX
(),
clip
.
getLoY
(),
clip
.
getWidth
(),
clip
.
getHeight
());
if
(
bs
==
null
)
{
if
(
bs
==
null
)
{
PathIterator
pi
=
s
.
getPathIterator
(
at
,
defaultFlat
);
PathIterator
pi
;
r
.
setWindingRule
(
pi
.
getWindingRule
());
if
(
normalize
)
{
pi
=
new
FlatteningPathIterator
(
new
NormalizingPathIterator
(
s
.
getPathIterator
(
at
),
norm
),
defaultFlat
);
}
else
{
pi
=
s
.
getPathIterator
(
at
,
defaultFlat
);
}
r
=
new
Renderer
(
3
,
3
,
clip
.
getLoX
(),
clip
.
getLoY
(),
clip
.
getWidth
(),
clip
.
getHeight
(),
pi
.
getWindingRule
(),
pc
);
pathTo
(
pi
,
r
);
pathTo
(
pi
,
r
);
}
else
{
}
else
{
r
.
setWindingRule
(
PathIterator
.
WIND_NON_ZERO
);
r
=
new
Renderer
(
3
,
3
,
strokeTo
(
s
,
at
,
bs
,
thin
,
normalize
,
true
,
r
);
clip
.
getLoX
(),
clip
.
getLoY
(),
clip
.
getWidth
(),
clip
.
getHeight
(),
PathIterator
.
WIND_NON_ZERO
,
pc
);
strokeTo
(
s
,
at
,
bs
,
thin
,
norm
,
true
,
r
);
}
}
r
.
endRendering
();
r
.
endRendering
();
PiscesTileGenerator
ptg
=
new
PiscesTileGenerator
(
pc
,
r
.
MAX_AA_ALPHA
);
PiscesTileGenerator
ptg
=
new
PiscesTileGenerator
(
pc
,
r
.
MAX_AA_ALPHA
);
...
@@ -420,3 +524,4 @@ public class PiscesRenderingEngine extends RenderingEngine {
...
@@ -420,3 +524,4 @@ public class PiscesRenderingEngine extends RenderingEngine {
}
}
}
}
}
}
src/share/classes/sun/java2d/pisces/Renderer.java
浏览文件 @
90b4e7d3
...
@@ -25,629 +25,478 @@
...
@@ -25,629 +25,478 @@
package
sun.java2d.pisces
;
package
sun.java2d.pisces
;
public
class
Renderer
extends
LineSink
{
import
java.util.Arrays
;
public
static
final
int
WIND_EVEN_ODD
=
0
;
public
static
final
int
WIND_NON_ZERO
=
1
;
// Initial edge list size
// IMPL_NOTE - restore size after growth
public
static
final
int
INITIAL_EDGES
=
1000
;
// Recommended maximum scratchpad sizes. The arrays will grow
// larger if needed, but when finished() is called they will be released
// if they have grown larger than these sizes.
public
static
final
int
DEFAULT_INDICES_SIZE
=
8192
;
public
static
final
int
DEFAULT_CROSSINGS_SIZE
=
32
*
1024
;
// Antialiasing
private
int
SUBPIXEL_LG_POSITIONS_X
;
private
int
SUBPIXEL_LG_POSITIONS_Y
;
private
int
SUBPIXEL_MASK_X
;
private
int
SUBPIXEL_MASK_Y
;
private
int
SUBPIXEL_POSITIONS_X
;
private
int
SUBPIXEL_POSITIONS_Y
;
int
MAX_AA_ALPHA
;
private
int
MAX_AA_ALPHA_DENOM
;
private
int
HALF_MAX_AA_ALPHA_DENOM
;
private
int
XSHIFT
;
private
int
YSHIFT
;
private
int
YSTEP
;
private
int
HYSTEP
;
private
int
YMASK
;
private
static
final
int
MIN_QUAD_OPT_WIDTH
=
100
<<
16
;
// Cache to store RLE-encoded coverage mask of the current primitive
public
class
Renderer
implements
LineSink
{
PiscesCache
cache
;
// Bounds of the drawing region, at S15.16 precsion
private
int
boundsMinX
,
boundsMinY
,
boundsMaxX
,
boundsMaxY
;
// Bounds of the current primitive, at subsample precision
private
int
rasterMinX
,
rasterMaxX
,
rasterMinY
,
rasterMaxY
;
// Pixel bounding box for current primitive
///////////////////////////////////////////////////////////////////////////////
private
int
bboxX0
,
bboxY0
,
bboxX1
,
bboxY1
;
// Scan line iterator and edge crossing data.
//////////////////////////////////////////////////////////////////////////////
// Current winding rule
private
int
windingRule
;
// Current drawing position, i.e., final point of last segment
private
int
[]
crossings
;
private
int
x0
,
y0
;
// Position of most recent 'moveTo' command
private
int
sx0
,
sy0
;
// Buffer to be filled with one row's worth of alpha values
// This is an array of indices into the edge array. It is initialized to
private
byte
[]
rowAA
;
// needs to be short if 16x16 subsampling
// [i * SIZEOF_STRUCT_EDGE for i in range(0, edgesSize/SIZEOF_STRUCT_EDGE)]
// (where range(i, j) is i,i+1,...,j-1 -- just like in python).
// The reason for keeping this is because we need the edges array sorted
// by y0, but we don't want to move all that data around, so instead we
// sort the indices into the edge array, and use edgeIndices to access
// the edges array. This is meant to simulate a pointer array (hence the name)
private
int
[]
edgePtrs
;
//
Track the number of vertical extrema of the incoming edge list
//
crossing bounds. The bounds are not necessarily tight (the scan line
//
in order to determine the maximum number of crossings of a
//
at minY, for example, might have no crossings). The x bounds will
//
scanline
//
be accumulated as crossings are computed.
private
int
firstOrientation
;
private
int
minY
,
maxY
;
private
int
lastOrientation
;
private
int
minX
,
maxX
;
private
int
flips
;
private
int
nextY
;
// Parameters for emitRow
// indices into the edge pointer list. They indicate the "active" sublist in
private
int
alphaWidth
;
// the edge list (the portion of the list that contains all the edges that
// cross the next scan line).
private
int
lo
,
hi
;
public
Renderer
()
{
private
static
final
int
INIT_CROSSINGS_SIZE
=
50
;
private
void
ScanLineItInitialize
()
{
crossings
=
new
int
[
INIT_CROSSINGS_SIZE
];
edgePtrs
=
new
int
[
edgesSize
/
SIZEOF_STRUCT_EDGE
];
for
(
int
i
=
0
;
i
<
edgePtrs
.
length
;
i
++)
{
edgePtrs
[
i
]
=
i
*
SIZEOF_STRUCT_EDGE
;
}
}
public
void
setAntialiasing
(
int
subpixelLgPositionsX
,
qsort
(
0
,
edgePtrs
.
length
-
1
);
int
subpixelLgPositionsY
)
{
this
.
SUBPIXEL_LG_POSITIONS_X
=
subpixelLgPositionsX
;
this
.
SUBPIXEL_LG_POSITIONS_Y
=
subpixelLgPositionsY
;
this
.
SUBPIXEL_MASK_X
=
// We don't care if we clip some of the line off with ceil, since
(
1
<<
(
SUBPIXEL_LG_POSITIONS_X
))
-
1
;
// no scan line crossings will be eliminated (in fact, the ceil is
this
.
SUBPIXEL_MASK_Y
=
// the y of the first scan line crossing).
(
1
<<
(
SUBPIXEL_LG_POSITIONS_Y
))
-
1
;
nextY
=
minY
=
Math
.
max
(
boundsMinY
,
(
int
)
Math
.
ceil
(
edgeMinY
));
this
.
SUBPIXEL_POSITIONS_X
=
maxY
=
Math
.
min
(
boundsMaxY
,
(
int
)
Math
.
ceil
(
edgeMaxY
));
1
<<
(
SUBPIXEL_LG_POSITIONS_X
);
this
.
SUBPIXEL_POSITIONS_Y
=
1
<<
(
SUBPIXEL_LG_POSITIONS_Y
);
this
.
MAX_AA_ALPHA
=
(
SUBPIXEL_POSITIONS_X
*
SUBPIXEL_POSITIONS_Y
);
this
.
MAX_AA_ALPHA_DENOM
=
255
*
MAX_AA_ALPHA
;
this
.
HALF_MAX_AA_ALPHA_DENOM
=
MAX_AA_ALPHA_DENOM
/
2
;
this
.
XSHIFT
=
16
-
SUBPIXEL_LG_POSITIONS_X
;
this
.
YSHIFT
=
16
-
SUBPIXEL_LG_POSITIONS_Y
;
this
.
YSTEP
=
1
<<
YSHIFT
;
this
.
HYSTEP
=
1
<<
(
YSHIFT
-
1
);
this
.
YMASK
=
~(
YSTEP
-
1
);
}
public
int
getSubpixelLgPositionsX
()
{
for
(
lo
=
0
;
lo
<
edgePtrs
.
length
&&
edges
[
edgePtrs
[
lo
]+
Y1
]
<=
nextY
;
lo
++)
return
SUBPIXEL_LG_POSITIONS_X
;
;
for
(
hi
=
lo
;
hi
<
edgePtrs
.
length
&&
edges
[
edgePtrs
[
hi
]+
CURY
]
<=
nextY
;
hi
++)
;
// the active list is *edgePtrs[lo] (inclusive) *edgePtrs[hi] (exclusive)
for
(
int
i
=
lo
;
i
<
hi
;
i
++)
{
setCurY
(
edgePtrs
[
i
],
nextY
);
}
}
public
int
getSubpixelLgPositionsY
()
{
// We accumulate X in the iterator because accumulating it in addEdge
return
SUBPIXEL_LG_POSITIONS_Y
;
// like we do with Y does not do much good: if there's an edge
// (0,0)->(1000,10000), and if y gets clipped to 1000, then the x
// bound should be 100, but the accumulator from addEdge would say 1000,
// so we'd still have to accumulate the X bounds as we add crossings.
minX
=
boundsMinX
;
maxX
=
boundsMaxX
;
}
}
p
ublic
void
setWindingRule
(
int
windingRule
)
{
p
rivate
int
ScanLineItCurrentY
(
)
{
this
.
windingRule
=
windingRule
;
return
nextY
-
1
;
}
}
public
int
getWindingRule
()
{
private
int
ScanLineItGoToNextYAndComputeCrossings
()
{
return
windingRule
;
// we go through the active list and remove the ones that don't cross
// the nextY scanline.
int
crossingIdx
=
0
;
for
(
int
i
=
lo
;
i
<
hi
;
i
++)
{
if
(
edges
[
edgePtrs
[
i
]+
Y1
]
<=
nextY
)
{
edgePtrs
[
i
]
=
edgePtrs
[
lo
++];
}
}
public
void
beginRendering
(
int
boundsX
,
int
boundsY
,
int
boundsWidth
,
int
boundsHeight
)
{
lastOrientation
=
0
;
flips
=
0
;
resetEdges
();
this
.
boundsMinX
=
boundsX
<<
16
;
this
.
boundsMinY
=
boundsY
<<
16
;
this
.
boundsMaxX
=
(
boundsX
+
boundsWidth
)
<<
16
;
this
.
boundsMaxY
=
(
boundsY
+
boundsHeight
)
<<
16
;
this
.
bboxX0
=
boundsX
;
this
.
bboxY0
=
boundsY
;
this
.
bboxX1
=
boundsX
+
boundsWidth
;
this
.
bboxY1
=
boundsY
+
boundsHeight
;
}
}
if
(
hi
-
lo
>
crossings
.
length
)
{
public
void
moveTo
(
int
x0
,
int
y0
)
{
int
newSize
=
Math
.
max
(
hi
-
lo
,
crossings
.
length
*
2
);
// System.out.println("Renderer: moveTo " + x0/65536.0 + " " + y0/65536.0);
crossings
=
Arrays
.
copyOf
(
crossings
,
newSize
);
close
();
this
.
sx0
=
this
.
x0
=
x0
;
this
.
sy0
=
this
.
y0
=
y0
;
this
.
lastOrientation
=
0
;
}
}
// Now every edge between lo and hi crosses nextY. Compute it's
public
void
lineJoin
()
{
// crossing and put it in the crossings array.
// System.out.println("Renderer: lineJoin");
for
(
int
i
=
lo
;
i
<
hi
;
i
++)
{
// do nothing
addCrossing
(
nextY
,
getCurCrossing
(
edgePtrs
[
i
]),
(
int
)
edges
[
edgePtrs
[
i
]+
OR
],
crossingIdx
);
gotoNextY
(
edgePtrs
[
i
]);
crossingIdx
++;
}
}
public
void
lineTo
(
int
x1
,
int
y1
)
{
nextY
++;
// System.out.println("Renderer: lineTo " + x1/65536.0 + " " + y1/65536.0);
// Expand active list to include new edges.
for
(;
hi
<
edgePtrs
.
length
&&
edges
[
edgePtrs
[
hi
]+
CURY
]
<=
nextY
;
hi
++)
{
// Ignore horizontal lines
setCurY
(
edgePtrs
[
hi
],
nextY
);
// Next line will count flip
if
(
y0
==
y1
)
{
this
.
x0
=
x1
;
return
;
}
}
int
orientation
=
(
y0
<
y1
)
?
1
:
-
1
;
Arrays
.
sort
(
crossings
,
0
,
crossingIdx
);
if
(
lastOrientation
==
0
)
{
return
crossingIdx
;
firstOrientation
=
orientation
;
}
else
if
(
orientation
!=
lastOrientation
)
{
++
flips
;
}
}
lastOrientation
=
orientation
;
// Bias Y by 1 ULP so endpoints never lie on a scanline
private
boolean
ScanLineItHasNext
()
{
addEdge
(
x0
,
y0
|
0x1
,
x1
,
y1
|
0x1
);
return
nextY
<
maxY
;
this
.
x0
=
x1
;
this
.
y0
=
y1
;
}
}
public
void
close
()
{
private
void
addCrossing
(
int
y
,
int
x
,
int
or
,
int
idx
)
{
// System.out.println("Renderer: close");
if
(
x
<
minX
)
{
minX
=
x
;
int
orientation
=
lastOrientation
;
if
(
y0
!=
sy0
)
{
orientation
=
(
y0
<
sy0
)
?
1
:
-
1
;
}
if
(
orientation
!=
firstOrientation
)
{
++
flips
;
}
}
lineTo
(
sx0
,
sy0
);
if
(
x
>
maxX
)
{
maxX
=
x
;
}
}
x
<<=
1
;
public
void
end
()
{
crossings
[
idx
]
=
((
or
==
1
)
?
(
x
|
0x1
)
:
x
);
close
();
// System.out.println("Renderer: end");
// do nothing
}
// Scan convert a single edge
private
void
computeCrossingsForEdge
(
int
index
,
int
boundsMinY
,
int
boundsMaxY
)
{
int
iy0
=
edges
[
index
+
1
];
int
iy1
=
edges
[
index
+
3
];
// Clip to valid Y range
int
clipy0
=
(
iy0
>
boundsMinY
)
?
iy0
:
boundsMinY
;
int
clipy1
=
(
iy1
<
boundsMaxY
)
?
iy1
:
boundsMaxY
;
int
minY
=
((
clipy0
+
HYSTEP
)
&
YMASK
)
+
HYSTEP
;
int
maxY
=
((
clipy1
-
HYSTEP
)
&
YMASK
)
+
HYSTEP
;
// IMPL_NOTE - If line falls outside the valid X range, could
// draw a vertical line instead
// Exit if no scanlines are crossed
if
(
minY
>
maxY
)
{
return
;
}
}
// Scan convert line using a DDA approach
int
ix0
=
edges
[
index
];
// quicksort implementation for sorting the edge indices ("pointers")
int
ix1
=
edges
[
index
+
2
];
// by increasing y0. first, last are indices into the "pointer" array
long
dx
=
((
long
)
ix1
)
-
ix0
;
// It sorts the pointer array from first (inclusive) to last (inclusive)
long
dy
=
((
long
)
iy1
)
-
iy0
;
private
void
qsort
(
int
first
,
int
last
)
{
if
(
last
>
first
)
{
// Compute first crossing point at y = minY
int
p
=
partition
(
first
,
last
);
int
orientation
=
edges
[
index
+
4
];
if
(
first
<
p
-
1
)
{
int
y
=
minY
;
qsort
(
first
,
p
-
1
);
long
lx
=
(((
long
)
y
)
-
iy0
)*
dx
/
dy
+
ix0
;
addCrossing
(
y
>>
YSHIFT
,
(
int
)(
lx
>>
XSHIFT
),
orientation
);
// Advance y to next scanline, exit if past endpoint
y
+=
YSTEP
;
if
(
y
>
maxY
)
{
return
;
}
}
if
(
p
<
last
)
{
// Compute xstep only if additional scanlines are crossed
qsort
(
p
,
last
);
// For each scanline, add xstep to lx and YSTEP to y and
// emit the new crossing
long
xstep
=
((
long
)
YSTEP
*
dx
)/
dy
;
for
(;
y
<=
maxY
;
y
+=
YSTEP
)
{
lx
+=
xstep
;
addCrossing
(
y
>>
YSHIFT
,
(
int
)(
lx
>>
XSHIFT
),
orientation
);
}
}
}
}
private
void
computeBounds
()
{
rasterMinX
=
crossingMinX
&
~
SUBPIXEL_MASK_X
;
rasterMaxX
=
crossingMaxX
|
SUBPIXEL_MASK_X
;
rasterMinY
=
crossingMinY
&
~
SUBPIXEL_MASK_Y
;
rasterMaxY
=
crossingMaxY
|
SUBPIXEL_MASK_Y
;
// If nothing was drawn, we have:
// minX = Integer.MAX_VALUE and maxX = Integer.MIN_VALUE
// so nothing to render
if
(
rasterMinX
>
rasterMaxX
||
rasterMinY
>
rasterMaxY
)
{
rasterMinX
=
0
;
rasterMaxX
=
-
1
;
rasterMinY
=
0
;
rasterMaxY
=
-
1
;
return
;
}
}
if
(
rasterMinX
<
boundsMinX
>>
XSHIFT
)
{
// i, j are indices into edgePtrs.
rasterMinX
=
boundsMinX
>>
XSHIFT
;
private
int
partition
(
int
i
,
int
j
)
{
}
int
pivotVal
=
edgePtrs
[
i
];
if
(
rasterMinY
<
boundsMinY
>>
YSHIFT
)
{
while
(
i
<=
j
)
{
rasterMinY
=
boundsMinY
>>
YSHIFT
;
// edges[edgePtrs[i]+1] is equivalent to (*(edgePtrs[i])).y0 in C
while
(
edges
[
edgePtrs
[
i
]+
CURY
]
<
edges
[
pivotVal
+
CURY
])
{
i
++;
}
while
(
edges
[
edgePtrs
[
j
]+
CURY
]
>
edges
[
pivotVal
+
CURY
])
{
j
--;
}
if
(
i
<=
j
)
{
int
tmp
=
edgePtrs
[
i
];
edgePtrs
[
i
]
=
edgePtrs
[
j
];
edgePtrs
[
j
]
=
tmp
;
i
++;
j
--;
}
}
if
(
rasterMaxX
>
boundsMaxX
>>
XSHIFT
)
{
rasterMaxX
=
boundsMaxX
>>
XSHIFT
;
}
}
if
(
rasterMaxY
>
boundsMaxY
>>
YSHIFT
)
{
return
i
;
rasterMaxY
=
boundsMaxY
>>
YSHIFT
;
}
//============================================================================
//////////////////////////////////////////////////////////////////////////////
// EDGE LIST
//////////////////////////////////////////////////////////////////////////////
private
static
final
int
INIT_NUM_EDGES
=
1000
;
private
static
final
int
SIZEOF_STRUCT_EDGE
=
5
;
// The following array is a poor man's struct array:
// it simulates a struct array by having
// edges[SIZEOF_STRUCT_EDGE * i + j] be the jth field in the ith element
// of an array of edge structs.
private
float
[]
edges
;
private
int
edgesSize
;
// size of the edge list.
private
static
final
int
Y1
=
0
;
private
static
final
int
SLOPE
=
1
;
private
static
final
int
OR
=
2
;
// the orientation. This can be -1 or 1.
// -1 means up, 1 means down.
private
static
final
int
CURY
=
3
;
// j = 5 corresponds to the "current Y".
// Each edge keeps track of the last scanline
// crossing it computed, and this is the y coord of
// that scanline.
private
static
final
int
CURX
=
4
;
//the x coord of the current crossing.
// Note that while the array is declared as a float[] not all of it's
// elements should be floats. currentY and Orientation should be ints (or int and
// byte respectively), but they all need to be the same type. This isn't
// really a problem because floats can represent exactly all 23 bit integers,
// which should be more than enough.
// Note, also, that we only need x1 for slope computation, so we don't need
// to store it. x0, y0 don't need to be stored either. They can be put into
// curx, cury, and it's ok if they're lost when curx and cury are changed.
// We take this undeniably ugly and error prone approach (instead of simply
// making an Edge class) for performance reasons. Also, it would probably be nicer
// to have one array for each field, but that would defeat the purpose because
// it would make poor use of the processor cache, since we tend to access
// all the fields for one edge at a time.
private
float
edgeMinY
;
private
float
edgeMaxY
;
private
void
addEdge
(
float
x0
,
float
y0
,
float
x1
,
float
y1
)
{
float
or
=
(
y0
<
y1
)
?
1
f
:
-
1
f
;
// orientation: 1 = UP; -1 = DOWN
if
(
or
==
-
1
)
{
float
tmp
=
y0
;
y0
=
y1
;
y1
=
tmp
;
tmp
=
x0
;
x0
=
x1
;
x1
=
tmp
;
}
}
// skip edges that don't cross a scanline
if
(
Math
.
ceil
(
y0
)
>=
Math
.
ceil
(
y1
))
{
return
;
}
}
private
int
clamp
(
int
x
,
int
min
,
int
max
)
{
int
newSize
=
edgesSize
+
SIZEOF_STRUCT_EDGE
;
if
(
x
<
min
)
{
if
(
edges
.
length
<
newSize
)
{
return
min
;
edges
=
Arrays
.
copyOf
(
edges
,
newSize
*
2
);
}
else
if
(
x
>
max
)
{
return
max
;
}
return
x
;
}
}
edges
[
edgesSize
+
CURX
]
=
x0
;
edges
[
edgesSize
+
CURY
]
=
y0
;
edges
[
edgesSize
+
Y1
]
=
y1
;
edges
[
edgesSize
+
SLOPE
]
=
(
x1
-
x0
)
/
(
y1
-
y0
);
edges
[
edgesSize
+
OR
]
=
or
;
// the crossing values can't be initialized meaningfully yet. This
// will have to wait until setCurY is called
edgesSize
+=
SIZEOF_STRUCT_EDGE
;
private
void
_endRendering
()
{
// Accumulate edgeMinY and edgeMaxY
if
(
flips
==
0
)
{
if
(
y0
<
edgeMinY
)
{
edgeMinY
=
y0
;
}
bboxX0
=
bboxY0
=
0
;
if
(
y1
>
edgeMaxY
)
{
edgeMaxY
=
y1
;
}
bboxX1
=
bboxY1
=
-
1
;
return
;
}
}
// Special case for filling a single rect with a flat, opaque color
// As far as the following methods care, this edges extends to infinity.
// REMIND: This special case was not originally written to fill a
// They can compute the x intersect of any horizontal line.
// cache object and called directly to a Blit - it needs some code
// precondition: idx is the index to the start of the desired edge.
// to fill the cache instead to be useful for this usage...
// So, if the ith edge is wanted, idx should be SIZEOF_STRUCT_EDGE * i
if
(
false
/* Does not work with cache (yet?) */
&&
private
void
setCurY
(
int
idx
,
int
y
)
{
edgeIdx
==
10
&&
// compute the x crossing of edge at idx and horizontal line y
edges
[
0
]
==
edges
[
2
]
&&
// currentXCrossing = (y - y0)*slope + x0
edges
[
1
]
==
edges
[
6
]
&&
edges
[
idx
+
CURX
]
=
(
y
-
edges
[
idx
+
CURY
])
*
edges
[
idx
+
SLOPE
]
+
edges
[
idx
+
CURX
];
edges
[
3
]
==
edges
[
8
]
&&
edges
[
idx
+
CURY
]
=
(
float
)
y
;
edges
[
5
]
==
edges
[
7
]
&&
Math
.
abs
(
edges
[
0
]
-
edges
[
5
])
>
MIN_QUAD_OPT_WIDTH
)
{
int
x0
=
edges
[
0
]
>>
XSHIFT
;
int
y0
=
edges
[
1
]
>>
YSHIFT
;
int
x1
=
edges
[
5
]
>>
XSHIFT
;
int
y1
=
edges
[
3
]
>>
YSHIFT
;
if
(
x0
>
x1
)
{
int
tmp
=
x0
;
x0
=
x1
;
x1
=
tmp
;
}
}
if
(
y0
>
y1
)
{
int
tmp
=
y0
;
private
void
gotoNextY
(
int
idx
)
{
y0
=
y1
;
edges
[
idx
+
CURY
]
+=
1
f
;
// i.e. curY += 1
y1
=
tmp
;
edges
[
idx
+
CURX
]
+=
edges
[
idx
+
SLOPE
];
// i.e. curXCrossing += slope
}
}
int
bMinX
=
this
.
boundsMinX
>>
XSHIFT
;
private
int
getCurCrossing
(
int
idx
)
{
int
bMinY
=
this
.
boundsMinY
>>
YSHIFT
;
return
(
int
)
edges
[
idx
+
CURX
];
int
bMaxX
=
this
.
boundsMaxX
>>
XSHIFT
;
}
int
bMaxY
=
this
.
boundsMaxY
>>
YSHIFT
;
//====================================================================================
// Clip to image bounds in supersampled coordinates
x0
=
clamp
(
x0
,
bMinX
,
bMaxX
);
x1
=
clamp
(
x1
,
bMinX
,
bMaxX
);
y0
=
clamp
(
y0
,
bMinY
,
bMaxY
);
y1
=
clamp
(
y1
,
bMinY
,
bMaxY
);
/*
* REMIND: Need to fill the cache here instead...
Blit.fillRectSrcOver(this,
imageData, imageType,
imageOffset,
imageScanlineStride, imagePixelStride,
width, height,
x0, y0, x1, y1,
cred, cgreen, cblue);
*/
bboxX0
=
x0
>>
SUBPIXEL_LG_POSITIONS_X
;
public
static
final
int
WIND_EVEN_ODD
=
0
;
bboxY0
=
y0
>>
SUBPIXEL_LG_POSITIONS_Y
;
public
static
final
int
WIND_NON_ZERO
=
1
;
bboxX1
=
(
x1
+
SUBPIXEL_POSITIONS_X
-
1
)
>>
SUBPIXEL_LG_POSITIONS_X
;
bboxY1
=
(
y1
+
SUBPIXEL_POSITIONS_Y
-
1
)
>>
SUBPIXEL_LG_POSITIONS_Y
;
return
;
// Antialiasing
}
final
private
int
SUBPIXEL_LG_POSITIONS_X
;
final
private
int
SUBPIXEL_LG_POSITIONS_Y
;
final
private
int
SUBPIXEL_POSITIONS_X
;
final
private
int
SUBPIXEL_POSITIONS_Y
;
final
private
int
SUBPIXEL_MASK_X
;
final
private
int
SUBPIXEL_MASK_Y
;
final
int
MAX_AA_ALPHA
;
int
minY
=
(
edgeMinY
>
boundsMinY
)
?
edgeMinY
:
boundsMinY
;
// Cache to store RLE-encoded coverage mask of the current primitive
int
maxY
=
(
edgeMaxY
<
boundsMaxY
)
?
edgeMaxY
:
boundsMaxY
;
final
PiscesCache
cache
;
// Check for empty intersection of primitive with the drawing area
// Bounds of the drawing region, at subpixel precision.
if
(
minY
>
maxY
)
{
final
private
int
boundsMinX
,
boundsMinY
,
boundsMaxX
,
boundsMaxY
;
bboxX0
=
bboxY0
=
0
;
bboxX1
=
bboxY1
=
-
1
;
return
;
}
// Compute Y extent in subpixel coordinates
// Pixel bounding box for current primitive
int
iminY
=
(
minY
>>
YSHIFT
)
&
~
SUBPIXEL_MASK_Y
;
private
int
pix_bboxX0
,
pix_bboxY0
,
pix_bboxX1
,
pix_bboxY1
;
int
imaxY
=
(
maxY
>>
YSHIFT
)
|
SUBPIXEL_MASK_Y
;
int
yextent
=
(
imaxY
-
iminY
)
+
1
;
// Maximum number of crossings
// Current winding rule
int
size
=
flips
*
yextent
;
final
private
int
windingRule
;
int
bmax
=
(
boundsMaxY
>>
YSHIFT
)
-
1
;
// Current drawing position, i.e., final point of last segment
if
(
imaxY
>
bmax
)
{
private
float
x0
,
y0
;
imaxY
=
bmax
;
}
// Initialize X bounds, will be refined for each strip
// Position of most recent 'moveTo' command
bboxX0
=
Integer
.
MAX_VALUE
;
private
float
pix_sx0
,
pix_sy0
;
bboxX1
=
Integer
.
MIN_VALUE
;
// Set Y bounds
public
Renderer
(
int
subpixelLgPositionsX
,
int
subpixelLgPositionsY
,
bboxY0
=
iminY
>>
SUBPIXEL_LG_POSITIONS_Y
;
int
pix_boundsX
,
int
pix_boundsY
,
bboxY1
=
(
imaxY
+
SUBPIXEL_POSITIONS_Y
-
1
)
>>
SUBPIXEL_LG_POSITIONS_Y
;
int
pix_boundsWidth
,
int
pix_boundsHeight
,
int
windingRule
,
PiscesCache
cache
)
{
this
.
SUBPIXEL_LG_POSITIONS_X
=
subpixelLgPositionsX
;
this
.
SUBPIXEL_LG_POSITIONS_Y
=
subpixelLgPositionsY
;
this
.
SUBPIXEL_MASK_X
=
(
1
<<
(
SUBPIXEL_LG_POSITIONS_X
))
-
1
;
this
.
SUBPIXEL_MASK_Y
=
(
1
<<
(
SUBPIXEL_LG_POSITIONS_Y
))
-
1
;
this
.
SUBPIXEL_POSITIONS_X
=
1
<<
(
SUBPIXEL_LG_POSITIONS_X
);
this
.
SUBPIXEL_POSITIONS_Y
=
1
<<
(
SUBPIXEL_LG_POSITIONS_Y
);
this
.
MAX_AA_ALPHA
=
(
SUBPIXEL_POSITIONS_X
*
SUBPIXEL_POSITIONS_Y
);
// Compute number of rows that can be processing using
this
.
edges
=
new
float
[
SIZEOF_STRUCT_EDGE
*
INIT_NUM_EDGES
];
// a crossings table no larger than DEFAULT_CROSSINGS_SIZE.
edgeMinY
=
Float
.
POSITIVE_INFINITY
;
// However, we must process at least one row, so we grow the table
edgeMaxY
=
Float
.
NEGATIVE_INFINITY
;
// temporarily if needed. This would require an object with a
edgesSize
=
0
;
// huge number of flips.
int
rows
=
DEFAULT_CROSSINGS_SIZE
/(
flips
*
SUBPIXEL_POSITIONS_Y
);
rows
=
Math
.
min
(
rows
,
yextent
);
rows
=
Math
.
max
(
rows
,
1
);
for
(
int
i
=
iminY
;
i
<=
imaxY
;
i
+=
rows
*
SUBPIXEL_POSITIONS_Y
)
{
// Compute index of last scanline to be processed in this pass
int
last
=
Math
.
min
(
i
+
rows
*
SUBPIXEL_POSITIONS_Y
-
1
,
imaxY
);
setCrossingsExtents
(
i
,
last
,
flips
);
int
bminY
=
i
<<
YSHIFT
;
this
.
windingRule
=
windingRule
;
int
bmaxY
=
(
last
<<
YSHIFT
)
|
~
YMASK
;
this
.
cache
=
cache
;
// Process edges from the edge list
this
.
boundsMinX
=
pix_boundsX
*
SUBPIXEL_POSITIONS_X
;
int
maxIdx
=
edgeIdx
;
this
.
boundsMinY
=
pix_boundsY
*
SUBPIXEL_POSITIONS_Y
;
for
(
int
index
=
0
;
index
<
maxIdx
;
index
+=
5
)
{
this
.
boundsMaxX
=
(
pix_boundsX
+
pix_boundsWidth
)
*
SUBPIXEL_POSITIONS_X
;
// Test y1 < min:
this
.
boundsMaxY
=
(
pix_boundsY
+
pix_boundsHeight
)
*
SUBPIXEL_POSITIONS_Y
;
//
// If edge lies entirely above current strip,
// discard it
if
(
edges
[
index
+
3
]
<
bminY
)
{
// Overwrite the edge with the last edge
edgeIdx
-=
5
;
int
fidx
=
edgeIdx
;
int
tidx
=
index
;
edges
[
tidx
++]
=
edges
[
fidx
++];
edges
[
tidx
++]
=
edges
[
fidx
++];
edges
[
tidx
++]
=
edges
[
fidx
++];
edges
[
tidx
++]
=
edges
[
fidx
++];
edges
[
tidx
]
=
edges
[
fidx
];
maxIdx
-=
5
;
this
.
pix_bboxX0
=
pix_boundsX
;
index
-=
5
;
this
.
pix_bboxY0
=
pix_boundsY
;
continue
;
this
.
pix_bboxX1
=
pix_boundsX
+
pix_boundsWidth
;
this
.
pix_bboxY1
=
pix_boundsY
+
pix_boundsHeight
;
}
}
// Test y0 > max:
private
float
tosubpixx
(
float
pix_x
)
{
//
return
pix_x
*
SUBPIXEL_POSITIONS_X
;
// If edge lies entirely below current strip,
// skip it for now
if
(
edges
[
index
+
1
]
>
bmaxY
)
{
continue
;
}
}
private
float
tosubpixy
(
float
pix_y
)
{
computeCrossingsForEdge
(
index
,
bminY
,
bmaxY
)
;
return
pix_y
*
SUBPIXEL_POSITIONS_Y
;
}
}
computeBounds
();
public
void
moveTo
(
float
pix_x0
,
float
pix_y0
)
{
if
(
rasterMaxX
<
rasterMinX
)
{
close
();
continue
;
this
.
pix_sx0
=
pix_x0
;
this
.
pix_sy0
=
pix_y0
;
this
.
y0
=
tosubpixy
(
pix_y0
);
this
.
x0
=
tosubpixx
(
pix_x0
);
}
}
bboxX0
=
Math
.
min
(
bboxX0
,
public
void
lineJoin
()
{
/* do nothing */
}
rasterMinX
>>
SUBPIXEL_LG_POSITIONS_X
);
bboxX1
=
Math
.
max
(
bboxX1
,
(
rasterMaxX
+
SUBPIXEL_POSITIONS_X
-
1
)
>>
SUBPIXEL_LG_POSITIONS_X
);
renderStrip
();
}
// Free up any unusually large scratchpad memory used by the
public
void
lineTo
(
float
pix_x1
,
float
pix_y1
)
{
// preceding primitive
float
x1
=
tosubpixx
(
pix_x1
);
crossingListFinished
();
float
y1
=
tosubpixy
(
pix_y1
);
}
public
void
endRendering
()
{
// Ignore horizontal lines
// Set up the cache to accumulate the bounding box
if
(
y0
==
y1
)
{
if
(
cache
!=
null
)
{
this
.
x0
=
x1
;
cache
.
bboxX0
=
Integer
.
MAX_VALUE
;
return
;
cache
.
bboxY0
=
Integer
.
MAX_VALUE
;
cache
.
bboxX1
=
Integer
.
MIN_VALUE
;
cache
.
bboxY1
=
Integer
.
MIN_VALUE
;
}
}
_endRendering
();
addEdge
(
x0
,
y0
,
x1
,
y1
);
}
public
void
getBoundingBox
(
int
[]
bbox
)
{
this
.
x0
=
x1
;
bbox
[
0
]
=
bboxX0
;
this
.
y0
=
y1
;
bbox
[
1
]
=
bboxY0
;
bbox
[
2
]
=
bboxX1
-
bboxX0
;
bbox
[
3
]
=
bboxY1
-
bboxY0
;
}
}
p
rivate
void
renderStrip
()
{
p
ublic
void
close
()
{
//
Grow rowAA according to the raster width
//
lineTo expects its input in pixel coordinates.
int
width
=
(
rasterMaxX
-
rasterMinX
+
1
)
>>
SUBPIXEL_LG_POSITIONS_X
;
lineTo
(
pix_sx0
,
pix_sy0
)
;
alphaWidth
=
width
;
}
// Allocate one extra entry in rowAA to avoid a conditional in
public
void
end
()
{
// the rendering loop
close
();
int
bufLen
=
width
+
1
;
if
(
this
.
rowAA
==
null
||
this
.
rowAA
.
length
<
bufLen
)
{
this
.
rowAA
=
new
byte
[
bufLen
];
}
}
private
void
_endRendering
()
{
// Mask to determine the relevant bit of the crossing sum
// Mask to determine the relevant bit of the crossing sum
// 0x1 if EVEN_ODD, all bits if NON_ZERO
// 0x1 if EVEN_ODD, all bits if NON_ZERO
int
mask
=
(
windingRule
==
WIND_EVEN_ODD
)
?
0x1
:
~
0x0
;
int
mask
=
(
windingRule
==
WIND_EVEN_ODD
)
?
0x1
:
~
0x0
;
int
y
=
0
;
// add 1 to better deal with the last pixel in a pixel row.
int
prevY
=
rasterMinY
-
1
;
int
width
=
((
boundsMaxX
-
boundsMinX
)
>>
SUBPIXEL_LG_POSITIONS_X
)
+
1
;
byte
[]
alpha
=
new
byte
[
width
+
1
];
int
minX
=
Integer
.
MAX_VALUE
;
int
maxX
=
Integer
.
MIN_VALUE
;
iterateCrossings
();
// Now we iterate through the scanlines. We must tell emitRow the coord
while
(
hasMoreCrossingRows
())
{
// of the first non-transparent pixel, so we must keep accumulators for
y
=
crossingY
;
// the first and last pixels of the section of the current pixel row
// that we will emit.
// We also need to accumulate pix_bbox*, but the iterator does it
// for us. We will just get the values from it once this loop is done
int
pix_maxX
=
Integer
.
MIN_VALUE
;
int
pix_minX
=
Integer
.
MAX_VALUE
;
// Emit any skipped rows
int
y
=
boundsMinY
;
// needs to be declared here so we emit the last row properly.
for
(
int
j
=
prevY
+
1
;
j
<
y
;
j
++)
{
ScanLineItInitialize
();
if
(((
j
&
SUBPIXEL_MASK_Y
)
==
SUBPIXEL_MASK_Y
)
||
for
(
;
ScanLineItHasNext
();
)
{
(
j
==
rasterMaxY
))
{
int
numCrossings
=
ScanLineItGoToNextYAndComputeCrossings
();
emitRow
(
j
>>
SUBPIXEL_LG_POSITIONS_Y
,
0
,
-
1
);
y
=
ScanLineItCurrentY
();
}
}
prevY
=
y
;
if
(
crossingRowIndex
<
crossingRowCount
)
{
if
(
numCrossings
>
0
)
{
int
lx
=
crossings
[
crossingRowOffset
+
crossingRowIndex
];
int
lowx
=
crossings
[
0
]
>>
1
;
lx
>>=
1
;
int
highx
=
crossings
[
numCrossings
-
1
]
>>
1
;
int
hx
=
crossings
[
crossingRowOffset
+
crossingRowCount
-
1
];
int
x0
=
Math
.
max
(
lowx
,
boundsMinX
);
hx
>>=
1
;
int
x1
=
Math
.
min
(
highx
,
boundsMaxX
);
int
x0
=
lx
>
rasterMinX
?
lx
:
rasterMinX
;
int
x1
=
hx
<
rasterMaxX
?
hx
:
rasterMaxX
;
x0
-=
rasterMinX
;
x1
-=
rasterMinX
;
minX
=
Math
.
min
(
minX
,
x0
>>
SUBPIXEL_LG_POSITIONS_X
);
pix_minX
=
Math
.
min
(
pix_
minX
,
x0
>>
SUBPIXEL_LG_POSITIONS_X
);
maxX
=
Math
.
max
(
maxX
,
x1
>>
SUBPIXEL_LG_POSITIONS_X
);
pix_maxX
=
Math
.
max
(
pix_
maxX
,
x1
>>
SUBPIXEL_LG_POSITIONS_X
);
}
}
int
sum
=
0
;
int
sum
=
0
;
int
prev
=
rasterMinX
;
int
prev
=
boundsMinX
;
while
(
crossingRowIndex
<
crossingRowCount
)
{
for
(
int
i
=
0
;
i
<
numCrossings
;
i
++)
{
int
crxo
=
crossings
[
crossingRowOffset
+
crossingRowIndex
];
int
curxo
=
crossings
[
i
];
crossingRowIndex
++;
int
curx
=
curxo
>>
1
;
int
crorientation
=
((
curxo
&
0x1
)
==
0x1
)
?
1
:
-
1
;
if
((
sum
&
mask
)
!=
0
)
{
int
x0
=
Math
.
max
(
prev
,
boundsMinX
);
int
x1
=
Math
.
min
(
curx
,
boundsMaxX
);
if
(
x0
<
x1
)
{
x0
-=
boundsMinX
;
// turn x0, x1 from coords to indeces
x1
-=
boundsMinX
;
// in the alpha array.
int
crx
=
crxo
>>
1
;
int
pix_x
=
x0
>>
SUBPIXEL_LG_POSITIONS_X
;
int
crorientation
=
((
crxo
&
0x1
)
==
0x1
)
?
1
:
-
1
;
int
pix_xmaxm1
=
(
x1
-
1
)
>>
SUBPIXEL_LG_POSITIONS_X
;
if
((
sum
&
mask
)
!=
0
)
{
if
(
pix_x
==
pix_xmaxm1
)
{
// Clip to active X range, if x1 < x0 loop will
// have no effect
int
x0
=
prev
>
rasterMinX
?
prev
:
rasterMinX
;
int
x1
=
crx
<
rasterMaxX
?
crx
:
rasterMaxX
;
// Empty spans
if
(
x1
>
x0
)
{
x0
-=
rasterMinX
;
x1
-=
rasterMinX
;
// Accumulate alpha, equivalent to:
// for (int x = x0; x < x1; x++) {
// ++rowAA[x >> SUBPIXEL_LG_POSITIONS_X];
// }
//
// In the middle of the span, we can update a full
// pixel at a time (i.e., SUBPIXEL_POSITIONS_X
// subpixels)
int
x
=
x0
>>
SUBPIXEL_LG_POSITIONS_X
;
int
xmaxm1
=
(
x1
-
1
)
>>
SUBPIXEL_LG_POSITIONS_X
;
if
(
x
==
xmaxm1
)
{
// Start and end in same pixel
// Start and end in same pixel
rowAA
[
x
]
+=
x1
-
x0
;
alpha
[
pix_x
]
+=
(
x1
-
x0
);
alpha
[
pix_x
+
1
]
-=
(
x1
-
x0
);
}
else
{
}
else
{
// Start and end in different pixels
int
pix_xmax
=
x1
>>
SUBPIXEL_LG_POSITIONS_X
;
rowAA
[
x
++]
+=
SUBPIXEL_POSITIONS_X
-
alpha
[
pix_x
]
+=
SUBPIXEL_POSITIONS_X
-
(
x0
&
SUBPIXEL_MASK_X
);
(
x0
&
SUBPIXEL_MASK_X
);
alpha
[
pix_x
+
1
]
+=
(
x0
&
SUBPIXEL_MASK_X
);
int
xmax
=
x1
>>
SUBPIXEL_LG_POSITIONS_X
;
alpha
[
pix_xmax
]
-=
SUBPIXEL_POSITIONS_X
-
(
x1
&
SUBPIXEL_MASK_X
);
while
(
x
<
xmax
)
{
alpha
[
pix_xmax
+
1
]
-=
(
x1
&
SUBPIXEL_MASK_X
);
rowAA
[
x
++]
+=
SUBPIXEL_POSITIONS_X
;
}
// Note - at this point it is possible that
// x == width, which implies that
// x1 & SUBPIXEL_MASK_X == 0. We allocate
// one extra entry in rowAA so this
// assignment will be harmless. The alternative
// is an extra conditional here, or some other
// scheme to deal with the last pixel better.
rowAA
[
x
]
+=
x1
&
SUBPIXEL_MASK_X
;
}
}
}
}
}
}
sum
+=
crorientation
;
sum
+=
crorientation
;
prev
=
crx
;
prev
=
c
u
rx
;
}
}
// Every SUBPIXEL_POSITIONS rows, output an antialiased row
if
((
y
&
SUBPIXEL_MASK_Y
)
==
SUBPIXEL_MASK_Y
)
{
if
(((
y
&
SUBPIXEL_MASK_Y
)
==
SUBPIXEL_MASK_Y
)
||
emitRow
(
alpha
,
y
>>
SUBPIXEL_LG_POSITIONS_Y
,
pix_minX
,
pix_maxX
);
(
y
==
rasterMaxY
))
{
pix_minX
=
Integer
.
MAX_VALUE
;
emitRow
(
y
>>
SUBPIXEL_LG_POSITIONS_Y
,
minX
,
maxX
);
pix_maxX
=
Integer
.
MIN_VALUE
;
minX
=
Integer
.
MAX_VALUE
;
maxX
=
Integer
.
MIN_VALUE
;
}
}
}
}
// Emit final row
// Emit final row
for
(
int
j
=
prevY
+
1
;
j
<=
rasterMaxY
;
j
++)
{
if
(
pix_maxX
>=
pix_minX
)
{
if
(((
j
&
SUBPIXEL_MASK_Y
)
==
SUBPIXEL_MASK_Y
)
||
emitRow
(
alpha
,
y
>>
SUBPIXEL_LG_POSITIONS_Y
,
pix_minX
,
pix_maxX
);
(
j
==
rasterMaxY
))
{
emitRow
(
j
>>
SUBPIXEL_LG_POSITIONS_Y
,
minX
,
maxX
);
minX
=
Integer
.
MAX_VALUE
;
maxX
=
Integer
.
MIN_VALUE
;
}
}
}
pix_bboxX0
=
minX
>>
SUBPIXEL_LG_POSITIONS_X
;
pix_bboxX1
=
maxX
>>
SUBPIXEL_LG_POSITIONS_X
;
pix_bboxY0
=
minY
>>
SUBPIXEL_LG_POSITIONS_Y
;
pix_bboxY1
=
maxY
>>
SUBPIXEL_LG_POSITIONS_Y
;
}
}
private
void
clearAlpha
(
byte
[]
alpha
,
int
width
,
int
minX
,
int
maxX
)
{
if
(
maxX
>=
minX
)
{
int
w
=
maxX
-
minX
+
1
;
if
(
w
+
minX
>
width
)
{
w
=
width
-
minX
;
}
int
aidx
=
minX
;
public
void
endRendering
()
{
for
(
int
i
=
0
;
i
<
w
;
i
++,
aidx
++)
{
// Set up the cache to accumulate the bounding box
alpha
[
aidx
]
=
(
byte
)
0
;
if
(
cache
!=
null
)
{
cache
.
bboxX0
=
Integer
.
MAX_VALUE
;
cache
.
bboxY0
=
Integer
.
MAX_VALUE
;
cache
.
bboxX1
=
Integer
.
MIN_VALUE
;
cache
.
bboxY1
=
Integer
.
MIN_VALUE
;
}
}
_endRendering
();
}
}
public
void
getBoundingBox
(
int
[]
pix_bbox
)
{
pix_bbox
[
0
]
=
pix_bboxX0
;
pix_bbox
[
1
]
=
pix_bboxY0
;
pix_bbox
[
2
]
=
pix_bboxX1
-
pix_bboxX0
;
pix_bbox
[
3
]
=
pix_bboxY1
-
pix_bboxY0
;
}
}
private
void
emitRow
(
int
y
,
int
minX
,
int
maxX
)
{
private
void
emitRow
(
byte
[]
alphaRow
,
int
pix_y
,
int
pix_from
,
int
pix_to
)
{
// Copy rowAA data into the cache if one is present
// Copy rowAA data into the cache if one is present
if
(
cache
!=
null
)
{
if
(
cache
!=
null
)
{
if
(
maxX
>=
minX
)
{
if
(
pix_to
>=
pix_from
)
{
int
x0
=
minX
+
(
rasterMinX
>>
SUBPIXEL_LG_POSITIONS_X
);
cache
.
startRow
(
pix_y
,
pix_from
,
pix_to
);
int
x1
=
maxX
+
(
rasterMinX
>>
SUBPIXEL_LG_POSITIONS_X
);
cache
.
startRow
(
y
,
x0
,
x1
);
// Perform run-length encoding and store results in the cache
int
srcIdx
=
minX
;
int
from
=
pix_from
-
(
boundsMinX
>>
SUBPIXEL_LG_POSITIONS_X
);
int
to
=
pix_to
-
(
boundsMinX
>>
SUBPIXEL_LG_POSITIONS_X
);
// Perform run-length encoding
// and store results in the cache
byte
startVal
=
rowAA
[
srcIdx
++];
int
runLen
=
1
;
int
runLen
=
1
;
while
(
srcIdx
<=
maxX
)
{
byte
startVal
=
alphaRow
[
from
];
byte
nextVal
=
rowAA
[
srcIdx
++];
for
(
int
i
=
from
+
1
;
i
<=
to
;
i
++)
{
byte
nextVal
=
(
byte
)(
startVal
+
alphaRow
[
i
]);
if
(
nextVal
==
startVal
&&
runLen
<
255
)
{
if
(
nextVal
==
startVal
&&
runLen
<
255
)
{
++
runLen
;
runLen
++
;
}
else
{
}
else
{
cache
.
addRLERun
(
startVal
,
runLen
);
cache
.
addRLERun
(
startVal
,
runLen
);
runLen
=
1
;
runLen
=
1
;
startVal
=
nextVal
;
startVal
=
nextVal
;
}
}
...
@@ -656,190 +505,6 @@ public class Renderer extends LineSink {
...
@@ -656,190 +505,6 @@ public class Renderer extends LineSink {
cache
.
addRLERun
((
byte
)
0
,
0
);
cache
.
addRLERun
((
byte
)
0
,
0
);
}
}
}
}
java
.
util
.
Arrays
.
fill
(
alphaRow
,
(
byte
)
0
);
clearAlpha
(
rowAA
,
alphaWidth
,
minX
,
maxX
);
}
public
void
setCache
(
PiscesCache
cache
)
{
this
.
cache
=
cache
;
}
// Edge list data
private
int
[]
edges
=
new
int
[
5
*
INITIAL_EDGES
];
private
int
edgeIdx
=
0
;
private
int
edgeMinY
=
Integer
.
MAX_VALUE
;
private
int
edgeMaxY
=
Integer
.
MIN_VALUE
;
private
void
addEdge
(
int
x0
,
int
y0
,
int
x1
,
int
y1
)
{
int
newLen
=
edgeIdx
+
5
;
if
(
edges
.
length
<
newLen
)
{
int
[]
tmp
=
new
int
[
Math
.
max
(
11
*
edges
.
length
/
10
,
newLen
)];
System
.
arraycopy
(
edges
,
0
,
tmp
,
0
,
edgeIdx
);
this
.
edges
=
tmp
;
}
int
orientation
=
1
;
if
(
y0
>
y1
)
{
int
tmp
=
y0
;
y0
=
y1
;
y1
=
tmp
;
orientation
=
-
1
;
}
// Skip edges that don't cross a subsampled scanline
int
eminY
=
((
y0
+
HYSTEP
)
&
YMASK
);
int
emaxY
=
((
y1
-
HYSTEP
)
&
YMASK
);
if
(
eminY
>
emaxY
)
{
return
;
}
if
(
orientation
==
-
1
)
{
int
tmp
=
x0
;
x0
=
x1
;
x1
=
tmp
;
}
edges
[
edgeIdx
++]
=
x0
;
edges
[
edgeIdx
++]
=
y0
;
edges
[
edgeIdx
++]
=
x1
;
edges
[
edgeIdx
++]
=
y1
;
edges
[
edgeIdx
++]
=
orientation
;
// Update Y bounds of primitive
if
(
y0
<
edgeMinY
)
{
edgeMinY
=
y0
;
}
if
(
y1
>
edgeMaxY
)
{
edgeMaxY
=
y1
;
}
}
private
void
resetEdges
()
{
this
.
edgeIdx
=
0
;
this
.
edgeMinY
=
Integer
.
MAX_VALUE
;
this
.
edgeMaxY
=
Integer
.
MIN_VALUE
;
}
// Crossing list data
private
int
[]
crossingIndices
;
private
int
[]
crossings
;
private
int
crossingMinY
;
private
int
crossingMaxY
;
private
int
crossingMinX
=
Integer
.
MAX_VALUE
;
private
int
crossingMaxX
=
Integer
.
MIN_VALUE
;
private
int
crossingMaxXEntries
;
private
int
numCrossings
=
0
;
private
boolean
crossingsSorted
=
false
;
private
int
crossingY
;
private
int
crossingRowCount
;
private
int
crossingRowOffset
;
private
int
crossingRowIndex
;
private
void
setCrossingsExtents
(
int
minY
,
int
maxY
,
int
maxXEntries
)
{
int
yextent
=
maxY
-
minY
+
1
;
// Grow indices array as needed
if
(
crossingIndices
==
null
||
crossingIndices
.
length
<
yextent
)
{
this
.
crossingIndices
=
new
int
[
Math
.
max
(
yextent
,
DEFAULT_INDICES_SIZE
)];
}
// Grow crossings array as needed
if
(
crossings
==
null
||
crossings
.
length
<
yextent
*
maxXEntries
)
{
this
.
crossings
=
new
int
[
Math
.
max
(
yextent
*
maxXEntries
,
DEFAULT_CROSSINGS_SIZE
)];
}
this
.
crossingMinY
=
minY
;
this
.
crossingMaxY
=
maxY
;
this
.
crossingMaxXEntries
=
maxXEntries
;
resetCrossings
();
}
private
void
resetCrossings
()
{
int
yextent
=
crossingMaxY
-
crossingMinY
+
1
;
int
start
=
0
;
for
(
int
i
=
0
;
i
<
yextent
;
i
++)
{
crossingIndices
[
i
]
=
start
;
start
+=
crossingMaxXEntries
;
}
crossingMinX
=
Integer
.
MAX_VALUE
;
crossingMaxX
=
Integer
.
MIN_VALUE
;
numCrossings
=
0
;
crossingsSorted
=
false
;
}
// Free sorting arrays if larger than maximum size
private
void
crossingListFinished
()
{
if
(
crossings
!=
null
&&
crossings
.
length
>
DEFAULT_CROSSINGS_SIZE
)
{
crossings
=
new
int
[
DEFAULT_CROSSINGS_SIZE
];
}
if
(
crossingIndices
!=
null
&&
crossingIndices
.
length
>
DEFAULT_INDICES_SIZE
)
{
crossingIndices
=
new
int
[
DEFAULT_INDICES_SIZE
];
}
}
private
void
sortCrossings
(
int
[]
x
,
int
off
,
int
len
)
{
for
(
int
i
=
off
+
1
;
i
<
off
+
len
;
i
++)
{
int
j
=
i
;
int
xj
=
x
[
j
];
int
xjm1
;
while
(
j
>
off
&&
(
xjm1
=
x
[
j
-
1
])
>
xj
)
{
x
[
j
]
=
xjm1
;
x
[
j
-
1
]
=
xj
;
j
--;
}
}
}
private
void
sortCrossings
()
{
int
start
=
0
;
for
(
int
i
=
0
;
i
<=
crossingMaxY
-
crossingMinY
;
i
++)
{
sortCrossings
(
crossings
,
start
,
crossingIndices
[
i
]
-
start
);
start
+=
crossingMaxXEntries
;
}
}
private
void
addCrossing
(
int
y
,
int
x
,
int
orientation
)
{
if
(
x
<
crossingMinX
)
{
crossingMinX
=
x
;
}
if
(
x
>
crossingMaxX
)
{
crossingMaxX
=
x
;
}
int
index
=
crossingIndices
[
y
-
crossingMinY
]++;
x
<<=
1
;
crossings
[
index
]
=
(
orientation
==
1
)
?
(
x
|
0x1
)
:
x
;
++
numCrossings
;
}
private
void
iterateCrossings
()
{
if
(!
crossingsSorted
)
{
sortCrossings
();
crossingsSorted
=
true
;
}
crossingY
=
crossingMinY
-
1
;
crossingRowOffset
=
-
crossingMaxXEntries
;
}
private
boolean
hasMoreCrossingRows
()
{
if
(++
crossingY
<=
crossingMaxY
)
{
crossingRowOffset
+=
crossingMaxXEntries
;
int
y
=
crossingY
-
crossingMinY
;
crossingRowCount
=
crossingIndices
[
y
]
-
y
*
crossingMaxXEntries
;
crossingRowIndex
=
0
;
return
true
;
}
else
{
return
false
;
}
}
}
}
}
src/share/classes/sun/java2d/pisces/Stroker.java
浏览文件 @
90b4e7d3
...
@@ -25,7 +25,7 @@
...
@@ -25,7 +25,7 @@
package
sun.java2d.pisces
;
package
sun.java2d.pisces
;
public
class
Stroker
extend
s
LineSink
{
public
class
Stroker
implement
s
LineSink
{
private
static
final
int
MOVE_TO
=
0
;
private
static
final
int
MOVE_TO
=
0
;
private
static
final
int
LINE_TO
=
1
;
private
static
final
int
LINE_TO
=
1
;
...
@@ -61,19 +61,15 @@ public class Stroker extends LineSink {
...
@@ -61,19 +61,15 @@ public class Stroker extends LineSink {
*/
*/
public
static
final
int
CAP_SQUARE
=
2
;
public
static
final
int
CAP_SQUARE
=
2
;
LineSink
output
;
private
final
LineSink
output
;
int
lineWidth
;
private
final
int
capStyle
;
int
capStyle
;
private
final
int
joinStyle
;
int
joinStyle
;
int
miterLimit
;
Transform4
transform
;
private
final
float
m00
,
m01
,
m10
,
m11
,
det
;
int
m00
,
m01
;
int
m10
,
m11
;
in
t
lineWidth2
;
private
final
floa
t
lineWidth2
;
long
scaledLineWidth2
;
private
final
float
scaledLineWidth2
;
// For any pen offset (pen_dx, pen_dy) that does not depend on
// For any pen offset (pen_dx, pen_dy) that does not depend on
// the line orientation, the pen should be transformed so that:
// the line orientation, the pen should be transformed so that:
...
@@ -88,143 +84,86 @@ public class Stroker extends LineSink {
...
@@ -88,143 +84,86 @@ public class Stroker extends LineSink {
//
//
// pen_dx'(r, theta) = r*(m00*cos(theta) + m01*sin(theta))
// pen_dx'(r, theta) = r*(m00*cos(theta) + m01*sin(theta))
// pen_dy'(r, theta) = r*(m10*cos(theta) + m11*sin(theta))
// pen_dy'(r, theta) = r*(m10*cos(theta) + m11*sin(theta))
int
numPenSegments
;
private
int
numPenSegments
;
int
[]
pen_dx
;
private
final
float
[]
pen_dx
;
int
[]
pen_dy
;
private
final
float
[]
pen_dy
;
boolean
[]
penIncluded
;
private
boolean
[]
penIncluded
;
int
[]
join
;
private
final
float
[]
join
;
int
[]
offset
=
new
int
[
2
];
private
final
float
[]
offset
=
new
float
[
2
];
int
[]
reverse
=
new
int
[
100
];
private
float
[]
reverse
=
new
float
[
100
];
int
[]
miter
=
new
int
[
2
];
private
final
float
[]
miter
=
new
float
[
2
];
long
miterLimitSq
;
private
final
float
miterLimitSq
;
int
prev
;
private
int
prev
;
int
rindex
;
private
int
rindex
;
boolean
started
;
private
boolean
started
;
boolean
lineToOrigin
;
private
boolean
lineToOrigin
;
boolean
joinToOrigin
;
private
boolean
joinToOrigin
;
int
sx0
,
sy0
,
sx1
,
sy1
,
x0
,
y0
,
x1
,
y1
;
private
float
sx0
,
sy0
,
sx1
,
sy1
,
x0
,
y0
,
px0
,
py0
;
int
mx0
,
my0
,
mx1
,
my1
,
omx
,
omy
;
private
float
mx0
,
my0
,
omx
,
omy
;
int
lx0
,
ly0
,
lx1
,
ly1
,
lx0p
,
ly0p
,
px0
,
py0
;
private
float
m00_2_m01_2
;
double
m00_2_m01_2
;
private
float
m10_2_m11_2
;
double
m10_2_m11_2
;
private
float
m00_m10_m01_m11
;
double
m00_m10_m01_m11
;
/**
* Empty constructor. <code>setOutput</code> and
* <code>setParameters</code> must be called prior to calling any
* other methods.
*/
public
Stroker
()
{}
/**
/**
* Constructs a <code>Stroker</code>.
* Constructs a <code>Stroker</code>.
*
*
* @param output an output <code>LineSink</code>.
* @param output an output <code>LineSink</code>.
* @param lineWidth the desired line width in pixels, in S15.16
* @param lineWidth the desired line width in pixels
* format.
* @param capStyle the desired end cap style, one of
* @param capStyle the desired end cap style, one of
* <code>CAP_BUTT</code>, <code>CAP_ROUND</code> or
* <code>CAP_BUTT</code>, <code>CAP_ROUND</code> or
* <code>CAP_SQUARE</code>.
* <code>CAP_SQUARE</code>.
* @param joinStyle the desired line join style, one of
* @param joinStyle the desired line join style, one of
* <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or
* <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or
* <code>JOIN_BEVEL</code>.
* <code>JOIN_BEVEL</code>.
* @param miterLimit the desired miter limit
, in S15.16 format.
* @param miterLimit the desired miter limit
* @param transform a <code>Transform4</code> object indicating
* @param transform a <code>Transform4</code> object indicating
* the transform that has been previously applied to all incoming
* the transform that has been previously applied to all incoming
* coordinates. This is required in order to produce consistently
* coordinates. This is required in order to produce consistently
* shaped end caps and joins.
* shaped end caps and joins.
*/
*/
public
Stroker
(
LineSink
output
,
public
Stroker
(
LineSink
output
,
in
t
lineWidth
,
floa
t
lineWidth
,
int
capStyle
,
int
capStyle
,
int
joinStyle
,
int
joinStyle
,
int
miterLimit
,
float
miterLimit
,
Transform4
transform
)
{
float
m00
,
float
m01
,
float
m10
,
float
m11
)
{
setOutput
(
output
);
setParameters
(
lineWidth
,
capStyle
,
joinStyle
,
miterLimit
,
transform
);
}
/**
* Sets the output <code>LineSink</code> of this
* <code>Stroker</code>.
*
* @param output an output <code>LineSink</code>.
*/
public
void
setOutput
(
LineSink
output
)
{
this
.
output
=
output
;
this
.
output
=
output
;
}
/**
this
.
lineWidth2
=
lineWidth
/
2
;
* Sets the parameters of this <code>Stroker</code>.
this
.
scaledLineWidth2
=
m00
*
lineWidth2
;
* @param lineWidth the desired line width in pixels, in S15.16
* format.
* @param capStyle the desired end cap style, one of
* <code>CAP_BUTT</code>, <code>CAP_ROUND</code> or
* <code>CAP_SQUARE</code>.
* @param joinStyle the desired line join style, one of
* <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or
* <code>JOIN_BEVEL</code>.
* @param miterLimit the desired miter limit, in S15.16 format.
* @param transform a <code>Transform4</code> object indicating
* the transform that has been previously applied to all incoming
* coordinates. This is required in order to produce consistently
* shaped end caps and joins.
*/
public
void
setParameters
(
int
lineWidth
,
int
capStyle
,
int
joinStyle
,
int
miterLimit
,
Transform4
transform
)
{
this
.
lineWidth
=
lineWidth
;
this
.
lineWidth2
=
lineWidth
>>
1
;
this
.
scaledLineWidth2
=
((
long
)
transform
.
m00
*
lineWidth2
)
>>
16
;
this
.
capStyle
=
capStyle
;
this
.
capStyle
=
capStyle
;
this
.
joinStyle
=
joinStyle
;
this
.
joinStyle
=
joinStyle
;
this
.
miterLimit
=
miterLimit
;
this
.
transform
=
transform
;
m00_2_m01_2
=
m00
*
m00
+
m01
*
m01
;
this
.
m00
=
transform
.
m00
;
m10_2_m11_2
=
m10
*
m10
+
m11
*
m11
;
this
.
m01
=
transform
.
m01
;
m00_m10_m01_m11
=
m00
*
m10
+
m01
*
m11
;
this
.
m10
=
transform
.
m10
;
this
.
m11
=
transform
.
m11
;
this
.
m00_2_m01_2
=
(
double
)
m00
*
m00
+
(
double
)
m01
*
m01
;
this
.
m00
=
m00
;
this
.
m10_2_m11_2
=
(
double
)
m10
*
m10
+
(
double
)
m11
*
m11
;
this
.
m01
=
m01
;
this
.
m00_m10_m01_m11
=
(
double
)
m00
*
m10
+
(
double
)
m01
*
m11
;
this
.
m10
=
m10
;
this
.
m11
=
m11
;
det
=
m00
*
m11
-
m01
*
m10
;
double
dm00
=
m00
/
65536.0
;
float
limit
=
miterLimit
*
lineWidth2
*
det
;
double
dm01
=
m01
/
65536.0
;
this
.
miterLimitSq
=
limit
*
limit
;
double
dm10
=
m10
/
65536.0
;
double
dm11
=
m11
/
65536.0
;
double
determinant
=
dm00
*
dm11
-
dm01
*
dm10
;
if
(
joinStyle
==
JOIN_MITER
)
{
this
.
numPenSegments
=
(
int
)(
3.14159f
*
lineWidth
);
double
limit
=
this
.
pen_dx
=
new
float
[
numPenSegments
];
(
miterLimit
/
65536.0
)*(
lineWidth2
/
65536.0
)*
determinant
;
this
.
pen_dy
=
new
float
[
numPenSegments
];
double
limitSq
=
limit
*
limit
;
this
.
miterLimitSq
=
(
long
)(
limitSq
*
65536.0
*
65536.0
);
}
this
.
numPenSegments
=
(
int
)(
3.14159f
*
lineWidth
/
65536.0f
);
if
(
pen_dx
==
null
||
pen_dx
.
length
<
numPenSegments
)
{
this
.
pen_dx
=
new
int
[
numPenSegments
];
this
.
pen_dy
=
new
int
[
numPenSegments
];
this
.
penIncluded
=
new
boolean
[
numPenSegments
];
this
.
penIncluded
=
new
boolean
[
numPenSegments
];
this
.
join
=
new
int
[
2
*
numPenSegments
];
this
.
join
=
new
float
[
2
*
numPenSegments
];
}
for
(
int
i
=
0
;
i
<
numPenSegments
;
i
++)
{
for
(
int
i
=
0
;
i
<
numPenSegments
;
i
++)
{
double
r
=
lineWidth
/
2.0
;
double
theta
=
(
i
*
2.0
*
Math
.
PI
)/
numPenSegments
;
double
theta
=
(
double
)
i
*
2.0
*
Math
.
PI
/
numPenSegments
;
double
cos
=
Math
.
cos
(
theta
);
double
cos
=
Math
.
cos
(
theta
);
double
sin
=
Math
.
sin
(
theta
);
double
sin
=
Math
.
sin
(
theta
);
pen_dx
[
i
]
=
(
int
)(
r
*(
dm00
*
cos
+
d
m01
*
sin
));
pen_dx
[
i
]
=
(
float
)(
lineWidth2
*
(
m00
*
cos
+
m01
*
sin
));
pen_dy
[
i
]
=
(
int
)(
r
*(
dm10
*
cos
+
d
m11
*
sin
));
pen_dy
[
i
]
=
(
float
)(
lineWidth2
*
(
m10
*
cos
+
m11
*
sin
));
}
}
prev
=
CLOSE
;
prev
=
CLOSE
;
...
@@ -233,32 +172,31 @@ public class Stroker extends LineSink {
...
@@ -233,32 +172,31 @@ public class Stroker extends LineSink {
lineToOrigin
=
false
;
lineToOrigin
=
false
;
}
}
private
void
computeOffset
(
int
x0
,
int
y0
,
int
x1
,
int
y1
,
int
[]
m
)
{
private
void
computeOffset
(
float
x0
,
float
y0
,
long
lx
=
(
long
)
x1
-
(
long
)
x0
;
float
x1
,
float
y1
,
float
[]
m
)
{
long
ly
=
(
long
)
y1
-
(
long
)
y0
;
float
lx
=
x1
-
x0
;
float
ly
=
y1
-
y0
;
in
t
dx
,
dy
;
floa
t
dx
,
dy
;
if
(
m00
>
0
&&
m00
==
m11
&&
m01
==
0
&
m10
==
0
)
{
if
(
m00
>
0
&&
m00
==
m11
&&
m01
==
0
&
m10
==
0
)
{
long
ilen
=
Pisces
Math
.
hypot
(
lx
,
ly
);
float
ilen
=
(
float
)
Math
.
hypot
(
lx
,
ly
);
if
(
ilen
==
0
)
{
if
(
ilen
==
0
)
{
dx
=
dy
=
0
;
dx
=
dy
=
0
;
}
else
{
}
else
{
dx
=
(
int
)(
(
ly
*
scaledLineWidth2
)/
ilen
)
;
dx
=
(
ly
*
scaledLineWidth2
)/
ilen
;
dy
=
(
int
)(-(
lx
*
scaledLineWidth2
)/
ilen
)
;
dy
=
-(
lx
*
scaledLineWidth2
)/
ilen
;
}
}
}
else
{
}
else
{
double
dlx
=
x1
-
x0
;
double
dly
=
y1
-
y0
;
double
det
=
(
double
)
m00
*
m11
-
(
double
)
m01
*
m10
;
int
sdet
=
(
det
>
0
)
?
1
:
-
1
;
int
sdet
=
(
det
>
0
)
?
1
:
-
1
;
double
a
=
dly
*
m00
-
dlx
*
m10
;
float
a
=
ly
*
m00
-
lx
*
m10
;
double
b
=
dly
*
m01
-
dlx
*
m11
;
float
b
=
ly
*
m01
-
lx
*
m11
;
double
dh
=
PiscesMath
.
hypot
(
a
,
b
);
float
dh
=
(
float
)
Math
.
hypot
(
a
,
b
);
double
div
=
sdet
*
lineWidth2
/(
65536.0
*
dh
);
float
div
=
sdet
*
lineWidth2
/
dh
;
double
ddx
=
dly
*
m00_2_m01_2
-
dlx
*
m00_m10_m01_m11
;
double
ddy
=
dly
*
m00_m10_m01_m11
-
dlx
*
m10_2_m11_2
;
float
ddx
=
ly
*
m00_2_m01_2
-
lx
*
m00_m10_m01_m11
;
dx
=
(
int
)(
ddx
*
div
);
float
ddy
=
ly
*
m00_m10_m01_m11
-
lx
*
m10_2_m11_2
;
dy
=
(
int
)(
ddy
*
div
);
dx
=
ddx
*
div
;
dy
=
ddy
*
div
;
}
}
m
[
0
]
=
dx
;
m
[
0
]
=
dx
;
...
@@ -267,58 +205,43 @@ public class Stroker extends LineSink {
...
@@ -267,58 +205,43 @@ public class Stroker extends LineSink {
private
void
ensureCapacity
(
int
newrindex
)
{
private
void
ensureCapacity
(
int
newrindex
)
{
if
(
reverse
.
length
<
newrindex
)
{
if
(
reverse
.
length
<
newrindex
)
{
int
[]
tmp
=
new
int
[
Math
.
max
(
newrindex
,
6
*
reverse
.
length
/
5
)];
reverse
=
java
.
util
.
Arrays
.
copyOf
(
reverse
,
6
*
reverse
.
length
/
5
);
System
.
arraycopy
(
reverse
,
0
,
tmp
,
0
,
rindex
);
this
.
reverse
=
tmp
;
}
}
}
}
private
boolean
isCCW
(
int
x0
,
int
y0
,
private
boolean
isCCW
(
float
x0
,
float
y0
,
int
x1
,
int
y1
,
float
x1
,
float
y1
,
int
x2
,
int
y2
)
{
float
x2
,
float
y2
)
{
int
dx0
=
x1
-
x0
;
return
(
x1
-
x0
)
*
(
y2
-
y1
)
<
(
y1
-
y0
)
*
(
x2
-
x1
);
int
dy0
=
y1
-
y0
;
int
dx1
=
x2
-
x1
;
int
dy1
=
y2
-
y1
;
return
(
long
)
dx0
*
dy1
<
(
long
)
dy0
*
dx1
;
}
}
private
boolean
side
(
int
x
,
int
y
,
int
x0
,
int
y0
,
int
x1
,
int
y1
)
{
private
boolean
side
(
float
x
,
float
y
,
long
lx
=
x
;
float
x0
,
float
y0
,
long
ly
=
y
;
float
x1
,
float
y1
)
{
long
lx0
=
x0
;
return
(
y0
-
y1
)*
x
+
(
x1
-
x0
)*
y
+
(
x0
*
y1
-
x1
*
y0
)
>
0
;
long
ly0
=
y0
;
long
lx1
=
x1
;
long
ly1
=
y1
;
return
(
ly0
-
ly1
)*
lx
+
(
lx1
-
lx0
)*
ly
+
(
lx0
*
ly1
-
lx1
*
ly0
)
>
0
;
}
}
private
int
computeRoundJoin
(
int
cx
,
in
t
cy
,
private
int
computeRoundJoin
(
float
cx
,
floa
t
cy
,
int
xa
,
in
t
ya
,
float
xa
,
floa
t
ya
,
int
xb
,
in
t
yb
,
float
xb
,
floa
t
yb
,
int
side
,
int
side
,
boolean
flip
,
boolean
flip
,
in
t
[]
join
)
{
floa
t
[]
join
)
{
in
t
px
,
py
;
floa
t
px
,
py
;
int
ncoords
=
0
;
int
ncoords
=
0
;
boolean
centerSide
;
boolean
centerSide
;
if
(
side
==
0
)
{
if
(
side
==
0
)
{
centerSide
=
side
(
cx
,
cy
,
xa
,
ya
,
xb
,
yb
);
centerSide
=
side
(
cx
,
cy
,
xa
,
ya
,
xb
,
yb
);
}
else
{
}
else
{
centerSide
=
(
side
==
1
)
?
true
:
false
;
centerSide
=
(
side
==
1
);
}
}
for
(
int
i
=
0
;
i
<
numPenSegments
;
i
++)
{
for
(
int
i
=
0
;
i
<
numPenSegments
;
i
++)
{
px
=
cx
+
pen_dx
[
i
];
px
=
cx
+
pen_dx
[
i
];
py
=
cy
+
pen_dy
[
i
];
py
=
cy
+
pen_dy
[
i
];
boolean
penSide
=
side
(
px
,
py
,
xa
,
ya
,
xb
,
yb
);
boolean
penSide
=
side
(
px
,
py
,
xa
,
ya
,
xb
,
yb
);
if
(
penSide
!=
centerSide
)
{
penIncluded
[
i
]
=
(
penSide
!=
centerSide
);
penIncluded
[
i
]
=
true
;
}
else
{
penIncluded
[
i
]
=
false
;
}
}
}
int
start
=
-
1
,
end
=
-
1
;
int
start
=
-
1
,
end
=
-
1
;
...
@@ -338,10 +261,10 @@ public class Stroker extends LineSink {
...
@@ -338,10 +261,10 @@ public class Stroker extends LineSink {
}
}
if
(
start
!=
-
1
&&
end
!=
-
1
)
{
if
(
start
!=
-
1
&&
end
!=
-
1
)
{
long
dxa
=
cx
+
pen_dx
[
start
]
-
xa
;
float
dxa
=
cx
+
pen_dx
[
start
]
-
xa
;
long
dya
=
cy
+
pen_dy
[
start
]
-
ya
;
float
dya
=
cy
+
pen_dy
[
start
]
-
ya
;
long
dxb
=
cx
+
pen_dx
[
start
]
-
xb
;
float
dxb
=
cx
+
pen_dx
[
start
]
-
xb
;
long
dyb
=
cy
+
pen_dy
[
start
]
-
yb
;
float
dyb
=
cy
+
pen_dy
[
start
]
-
yb
;
boolean
rev
=
(
dxa
*
dxa
+
dya
*
dya
>
dxb
*
dxb
+
dyb
*
dyb
);
boolean
rev
=
(
dxa
*
dxa
+
dya
*
dya
>
dxb
*
dxb
+
dyb
*
dyb
);
int
i
=
rev
?
end
:
start
;
int
i
=
rev
?
end
:
start
;
...
@@ -362,22 +285,25 @@ public class Stroker extends LineSink {
...
@@ -362,22 +285,25 @@ public class Stroker extends LineSink {
return
ncoords
/
2
;
return
ncoords
/
2
;
}
}
private
static
final
long
ROUND_JOIN_THRESHOLD
=
1000L
;
// pisces used to use fixed point arithmetic with 16 decimal digits. I
private
static
final
long
ROUND_JOIN_INTERNAL_THRESHOLD
=
1000000000L
;
// didn't want to change the values of the constants below when I converted
// it to floating point, so that's why the divisions by 2^16 are there.
private
static
final
float
ROUND_JOIN_THRESHOLD
=
1000
/
65536
f
;
private
static
final
float
ROUND_JOIN_INTERNAL_THRESHOLD
=
1000000000
/
65536
f
;
private
void
drawRoundJoin
(
int
x
,
in
t
y
,
private
void
drawRoundJoin
(
float
x
,
floa
t
y
,
int
omx
,
int
omy
,
int
mx
,
in
t
my
,
float
omx
,
float
omy
,
float
mx
,
floa
t
my
,
int
side
,
int
side
,
boolean
flip
,
boolean
flip
,
boolean
rev
,
boolean
rev
,
long
threshold
)
{
float
threshold
)
{
if
((
omx
==
0
&&
omy
==
0
)
||
(
mx
==
0
&&
my
==
0
))
{
if
((
omx
==
0
&&
omy
==
0
)
||
(
mx
==
0
&&
my
==
0
))
{
return
;
return
;
}
}
long
domx
=
(
long
)
omx
-
mx
;
float
domx
=
omx
-
mx
;
long
domy
=
(
long
)
omy
-
my
;
float
domy
=
omy
-
my
;
long
len
=
domx
*
domx
+
domy
*
domy
;
float
len
=
domx
*
domx
+
domy
*
domy
;
if
(
len
<
threshold
)
{
if
(
len
<
threshold
)
{
return
;
return
;
}
}
...
@@ -389,10 +315,10 @@ public class Stroker extends LineSink {
...
@@ -389,10 +315,10 @@ public class Stroker extends LineSink {
my
=
-
my
;
my
=
-
my
;
}
}
in
t
bx0
=
x
+
omx
;
floa
t
bx0
=
x
+
omx
;
in
t
by0
=
y
+
omy
;
floa
t
by0
=
y
+
omy
;
in
t
bx1
=
x
+
mx
;
floa
t
bx1
=
x
+
mx
;
in
t
by1
=
y
+
my
;
floa
t
by1
=
y
+
my
;
int
npoints
=
computeRoundJoin
(
x
,
y
,
int
npoints
=
computeRoundJoin
(
x
,
y
,
bx0
,
by0
,
bx1
,
by1
,
side
,
flip
,
bx0
,
by0
,
bx1
,
by1
,
side
,
flip
,
...
@@ -404,40 +330,30 @@ public class Stroker extends LineSink {
...
@@ -404,40 +330,30 @@ public class Stroker extends LineSink {
// Return the intersection point of the lines (ix0, iy0) -> (ix1, iy1)
// Return the intersection point of the lines (ix0, iy0) -> (ix1, iy1)
// and (ix0p, iy0p) -> (ix1p, iy1p) in m[0] and m[1]
// and (ix0p, iy0p) -> (ix1p, iy1p) in m[0] and m[1]
private
void
computeMiter
(
int
ix0
,
int
iy0
,
int
ix1
,
int
iy1
,
private
void
computeMiter
(
float
x0
,
float
y0
,
float
x1
,
float
y1
,
int
ix0p
,
int
iy0p
,
int
ix1p
,
int
iy1p
,
float
x0p
,
float
y0p
,
float
x1p
,
float
y1p
,
int
[]
m
)
{
float
[]
m
)
{
long
x0
=
ix0
;
float
x10
=
x1
-
x0
;
long
y0
=
iy0
;
float
y10
=
y1
-
y0
;
long
x1
=
ix1
;
float
x10p
=
x1p
-
x0p
;
long
y1
=
iy1
;
float
y10p
=
y1p
-
y0p
;
long
x0p
=
ix0p
;
float
den
=
x10
*
y10p
-
x10p
*
y10
;
long
y0p
=
iy0p
;
long
x1p
=
ix1p
;
long
y1p
=
iy1p
;
long
x10
=
x1
-
x0
;
long
y10
=
y1
-
y0
;
long
x10p
=
x1p
-
x0p
;
long
y10p
=
y1p
-
y0p
;
long
den
=
(
x10
*
y10p
-
x10p
*
y10
)
>>
16
;
if
(
den
==
0
)
{
if
(
den
==
0
)
{
m
[
0
]
=
i
x0
;
m
[
0
]
=
x0
;
m
[
1
]
=
i
y0
;
m
[
1
]
=
y0
;
return
;
return
;
}
}
long
t
=
(
x1p
*(
y0
-
y0p
)
-
x0
*
y10p
+
x0p
*(
y1p
-
y0
))
>>
16
;
float
t
=
x1p
*(
y0
-
y0p
)
-
x0
*
y10p
+
x0p
*(
y1p
-
y0
)
;
m
[
0
]
=
(
int
)(
x0
+
(
t
*
x10
)/
den
)
;
m
[
0
]
=
x0
+
(
t
*
x10
)/
den
;
m
[
1
]
=
(
int
)(
y0
+
(
t
*
y10
)/
den
)
;
m
[
1
]
=
y0
+
(
t
*
y10
)/
den
;
}
}
private
void
drawMiter
(
int
px0
,
in
t
py0
,
private
void
drawMiter
(
float
px0
,
floa
t
py0
,
int
x0
,
in
t
y0
,
float
x0
,
floa
t
y0
,
int
x1
,
in
t
y1
,
float
x1
,
floa
t
y1
,
int
omx
,
int
omy
,
int
mx
,
in
t
my
,
float
omx
,
float
omy
,
float
mx
,
floa
t
my
,
boolean
rev
)
{
boolean
rev
)
{
if
(
mx
==
omx
&&
my
==
omy
)
{
if
(
mx
==
omx
&&
my
==
omy
)
{
return
;
return
;
...
@@ -461,11 +377,11 @@ public class Stroker extends LineSink {
...
@@ -461,11 +377,11 @@ public class Stroker extends LineSink {
miter
);
miter
);
// Compute miter length in untransformed coordinates
// Compute miter length in untransformed coordinates
long
dx
=
(
long
)
miter
[
0
]
-
x0
;
float
dx
=
miter
[
0
]
-
x0
;
long
dy
=
(
long
)
miter
[
1
]
-
y0
;
float
dy
=
miter
[
1
]
-
y0
;
long
a
=
(
dy
*
m00
-
dx
*
m10
)
>>
16
;
float
a
=
dy
*
m00
-
dx
*
m10
;
long
b
=
(
dy
*
m01
-
dx
*
m11
)
>>
16
;
float
b
=
dy
*
m01
-
dx
*
m11
;
long
lenSq
=
a
*
a
+
b
*
b
;
float
lenSq
=
a
*
a
+
b
*
b
;
if
(
lenSq
<
miterLimitSq
)
{
if
(
lenSq
<
miterLimitSq
)
{
emitLineTo
(
miter
[
0
],
miter
[
1
],
rev
);
emitLineTo
(
miter
[
0
],
miter
[
1
],
rev
);
...
@@ -473,7 +389,7 @@ public class Stroker extends LineSink {
...
@@ -473,7 +389,7 @@ public class Stroker extends LineSink {
}
}
public
void
moveTo
(
int
x0
,
in
t
y0
)
{
public
void
moveTo
(
float
x0
,
floa
t
y0
)
{
// System.out.println("Stroker.moveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
// System.out.println("Stroker.moveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
if
(
lineToOrigin
)
{
if
(
lineToOrigin
)
{
...
@@ -501,7 +417,7 @@ public class Stroker extends LineSink {
...
@@ -501,7 +417,7 @@ public class Stroker extends LineSink {
this
.
joinSegment
=
true
;
this
.
joinSegment
=
true
;
}
}
public
void
lineTo
(
int
x1
,
in
t
y1
)
{
public
void
lineTo
(
float
x1
,
floa
t
y1
)
{
// System.out.println("Stroker.lineTo(" + x1/65536.0 + ", " + y1/65536.0 + ")");
// System.out.println("Stroker.lineTo(" + x1/65536.0 + ", " + y1/65536.0 + ")");
if
(
lineToOrigin
)
{
if
(
lineToOrigin
)
{
...
@@ -526,10 +442,10 @@ public class Stroker extends LineSink {
...
@@ -526,10 +442,10 @@ public class Stroker extends LineSink {
joinSegment
=
false
;
joinSegment
=
false
;
}
}
private
void
lineToImpl
(
int
x1
,
in
t
y1
,
boolean
joinSegment
)
{
private
void
lineToImpl
(
float
x1
,
floa
t
y1
,
boolean
joinSegment
)
{
computeOffset
(
x0
,
y0
,
x1
,
y1
,
offset
);
computeOffset
(
x0
,
y0
,
x1
,
y1
,
offset
);
in
t
mx
=
offset
[
0
];
floa
t
mx
=
offset
[
0
];
in
t
my
=
offset
[
1
];
floa
t
my
=
offset
[
1
];
if
(!
started
)
{
if
(!
started
)
{
emitMoveTo
(
x0
+
mx
,
y0
+
my
);
emitMoveTo
(
x0
+
mx
,
y0
+
my
);
...
@@ -567,10 +483,6 @@ public class Stroker extends LineSink {
...
@@ -567,10 +483,6 @@ public class Stroker extends LineSink {
emitLineTo
(
x0
-
mx
,
y0
-
my
,
true
);
emitLineTo
(
x0
-
mx
,
y0
-
my
,
true
);
emitLineTo
(
x1
-
mx
,
y1
-
my
,
true
);
emitLineTo
(
x1
-
mx
,
y1
-
my
,
true
);
lx0
=
x1
+
mx
;
ly0
=
y1
+
my
;
lx0p
=
x1
-
mx
;
ly0p
=
y1
-
my
;
lx1
=
x1
;
ly1
=
y1
;
this
.
omx
=
mx
;
this
.
omx
=
mx
;
this
.
omy
=
my
;
this
.
omy
=
my
;
this
.
px0
=
x0
;
this
.
px0
=
x0
;
...
@@ -594,8 +506,8 @@ public class Stroker extends LineSink {
...
@@ -594,8 +506,8 @@ public class Stroker extends LineSink {
}
}
computeOffset
(
x0
,
y0
,
sx0
,
sy0
,
offset
);
computeOffset
(
x0
,
y0
,
sx0
,
sy0
,
offset
);
in
t
mx
=
offset
[
0
];
floa
t
mx
=
offset
[
0
];
in
t
my
=
offset
[
1
];
floa
t
my
=
offset
[
1
];
// Draw penultimate join
// Draw penultimate join
boolean
ccw
=
isCCW
(
px0
,
py0
,
x0
,
y0
,
sx0
,
sy0
);
boolean
ccw
=
isCCW
(
px0
,
py0
,
x0
,
y0
,
sx0
,
sy0
);
...
@@ -678,12 +590,10 @@ public class Stroker extends LineSink {
...
@@ -678,12 +590,10 @@ public class Stroker extends LineSink {
this
.
prev
=
MOVE_TO
;
this
.
prev
=
MOVE_TO
;
}
}
long
lineLength
(
long
ldx
,
long
ldy
)
{
double
userSpaceLineLength
(
double
dx
,
double
dy
)
{
long
ldet
=
((
long
)
m00
*
m11
-
(
long
)
m01
*
m10
)
>>
16
;
double
a
=
(
dy
*
m00
-
dx
*
m10
)/
det
;
long
la
=
((
long
)
ldy
*
m00
-
(
long
)
ldx
*
m10
)/
ldet
;
double
b
=
(
dy
*
m01
-
dx
*
m11
)/
det
;
long
lb
=
((
long
)
ldy
*
m01
-
(
long
)
ldx
*
m11
)/
ldet
;
return
Math
.
hypot
(
a
,
b
);
long
llen
=
(
int
)
PiscesMath
.
hypot
(
la
,
lb
);
return
llen
;
}
}
private
void
finish
()
{
private
void
finish
()
{
...
@@ -692,13 +602,13 @@ public class Stroker extends LineSink {
...
@@ -692,13 +602,13 @@ public class Stroker extends LineSink {
omx
,
omy
,
-
omx
,
-
omy
,
1
,
false
,
false
,
omx
,
omy
,
-
omx
,
-
omy
,
1
,
false
,
false
,
ROUND_JOIN_THRESHOLD
);
ROUND_JOIN_THRESHOLD
);
}
else
if
(
capStyle
==
CAP_SQUARE
)
{
}
else
if
(
capStyle
==
CAP_SQUARE
)
{
long
ldx
=
(
long
)(
px0
-
x0
)
;
float
dx
=
px0
-
x0
;
long
ldy
=
(
long
)(
py0
-
y0
)
;
float
dy
=
py0
-
y0
;
long
llen
=
lineLength
(
ldx
,
l
dy
);
float
len
=
(
float
)
userSpaceLineLength
(
dx
,
dy
);
long
s
=
(
long
)
lineWidth2
*
65536
/
l
len
;
float
s
=
lineWidth2
/
len
;
int
capx
=
x0
-
(
int
)(
ldx
*
s
>>
16
)
;
float
capx
=
x0
-
dx
*
s
;
int
capy
=
y0
-
(
int
)(
ldy
*
s
>>
16
)
;
float
capy
=
y0
-
dy
*
s
;
emitLineTo
(
capx
+
omx
,
capy
+
omy
);
emitLineTo
(
capx
+
omx
,
capy
+
omy
);
emitLineTo
(
capx
-
omx
,
capy
-
omy
);
emitLineTo
(
capx
-
omx
,
capy
-
omy
);
...
@@ -714,13 +624,13 @@ public class Stroker extends LineSink {
...
@@ -714,13 +624,13 @@ public class Stroker extends LineSink {
-
mx0
,
-
my0
,
mx0
,
my0
,
1
,
false
,
false
,
-
mx0
,
-
my0
,
mx0
,
my0
,
1
,
false
,
false
,
ROUND_JOIN_THRESHOLD
);
ROUND_JOIN_THRESHOLD
);
}
else
if
(
capStyle
==
CAP_SQUARE
)
{
}
else
if
(
capStyle
==
CAP_SQUARE
)
{
long
ldx
=
(
long
)(
sx1
-
sx0
)
;
float
dx
=
sx1
-
sx0
;
long
ldy
=
(
long
)(
sy1
-
sy0
)
;
float
dy
=
sy1
-
sy0
;
long
llen
=
lineLength
(
ldx
,
l
dy
);
float
len
=
(
float
)
userSpaceLineLength
(
dx
,
dy
);
long
s
=
(
long
)
lineWidth2
*
65536
/
l
len
;
float
s
=
lineWidth2
/
len
;
int
capx
=
sx0
-
(
int
)(
ldx
*
s
>>
16
)
;
float
capx
=
sx0
-
dx
*
s
;
int
capy
=
sy0
-
(
int
)(
ldy
*
s
>>
16
)
;
float
capy
=
sy0
-
dy
*
s
;
emitLineTo
(
capx
-
mx0
,
capy
-
my0
);
emitLineTo
(
capx
-
mx0
,
capy
-
my0
);
emitLineTo
(
capx
+
mx0
,
capy
+
my0
);
emitLineTo
(
capx
+
mx0
,
capy
+
my0
);
...
@@ -730,17 +640,17 @@ public class Stroker extends LineSink {
...
@@ -730,17 +640,17 @@ public class Stroker extends LineSink {
this
.
joinSegment
=
false
;
this
.
joinSegment
=
false
;
}
}
private
void
emitMoveTo
(
int
x0
,
in
t
y0
)
{
private
void
emitMoveTo
(
float
x0
,
floa
t
y0
)
{
// System.out.println("Stroker.emitMoveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
// System.out.println("Stroker.emitMoveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
output
.
moveTo
(
x0
,
y0
);
output
.
moveTo
(
x0
,
y0
);
}
}
private
void
emitLineTo
(
int
x1
,
in
t
y1
)
{
private
void
emitLineTo
(
float
x1
,
floa
t
y1
)
{
// System.out.println("Stroker.emitLineTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
// System.out.println("Stroker.emitLineTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
output
.
lineTo
(
x1
,
y1
);
output
.
lineTo
(
x1
,
y1
);
}
}
private
void
emitLineTo
(
int
x1
,
in
t
y1
,
boolean
rev
)
{
private
void
emitLineTo
(
float
x1
,
floa
t
y1
,
boolean
rev
)
{
if
(
rev
)
{
if
(
rev
)
{
ensureCapacity
(
rindex
+
2
);
ensureCapacity
(
rindex
+
2
);
reverse
[
rindex
++]
=
x1
;
reverse
[
rindex
++]
=
x1
;
...
@@ -755,3 +665,4 @@ public class Stroker extends LineSink {
...
@@ -755,3 +665,4 @@ public class Stroker extends LineSink {
output
.
close
();
output
.
close
();
}
}
}
}
src/share/classes/sun/java2d/pisces/Transform4.java
已删除
100644 → 0
浏览文件 @
2c7696d6
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
sun.java2d.pisces
;
public
class
Transform4
{
public
int
m00
,
m01
,
m10
,
m11
;
// double det; // det*65536
public
Transform4
()
{
this
(
1
<<
16
,
0
,
0
,
1
<<
16
);
}
public
Transform4
(
int
m00
,
int
m01
,
int
m10
,
int
m11
)
{
this
.
m00
=
m00
;
this
.
m01
=
m01
;
this
.
m10
=
m10
;
this
.
m11
=
m11
;
// this.det = (double)m00*m11 - (double)m01*m10;
}
// public Transform4 createInverse() {
// double dm00 = m00/65536.0;
// double dm01 = m01/65536.0;
// double dm10 = m10/65536.0;
// double dm11 = m11/65536.0;
// double invdet = 65536.0/(dm00*dm11 - dm01*dm10);
// int im00 = (int)( dm11*invdet);
// int im01 = (int)(-dm01*invdet);
// int im10 = (int)(-dm10*invdet);
// int im11 = (int)( dm00*invdet);
// return new Transform4(im00, im01, im10, im11);
// }
// public void transform(int[] point) {
// }
// /**
// * Returns the length of the line segment obtained by inverse
// * transforming the points <code>(x0, y0)</code> and <code>(x1,
// * y1)</code>.
// */
// public int getTransformedLength(int x0, int x1, int y0, int y1) {
// int lx = x1 - x0;
// int ly = y1 - y0;
// double a = (double)m00*ly - (double)m10*lx;
// double b = (double)m01*ly - (double)m11*lx;
// double len = PiscesMath.sqrt((a*a + b*b)/(det*det));
// return (int)(len*65536.0);
// }
// public int getType() {
// }
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录