diff --git a/pom.xml b/pom.xml
index 2d81c4d..4958be7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
org.marlin
marlin
jar
- 0.9.2-Unsafe
+ 0.9.3-Unsafe
Marlin software rasterizer
https://github.com/bourgesl/marlin-renderer
@@ -40,7 +40,7 @@
UTF-8
-
+
org.apache.maven.plugins
maven-compiler-plugin
@@ -52,7 +52,7 @@
UTF-8
-
+
org.apache.maven.plugins
maven-jar-plugin
@@ -99,7 +99,7 @@
-
+
org.apache.maven.plugins
maven-source-plugin
@@ -133,7 +133,7 @@
-
+
org.apache.maven.plugins
maven-surefire-plugin
diff --git a/src/main/java/org/marlin/pisces/DMarlinRenderingEngine.java b/src/main/java/org/marlin/pisces/DMarlinRenderingEngine.java
index 11f0c86..3024001 100644
--- a/src/main/java/org/marlin/pisces/DMarlinRenderingEngine.java
+++ b/src/main/java/org/marlin/pisces/DMarlinRenderingEngine.java
@@ -30,6 +30,7 @@
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.security.AccessController;
+import java.util.Arrays;
import org.marlin.geom.Path2D;
import static org.marlin.pisces.MarlinUtils.logInfo;
import org.marlin.ReentrantContextProvider;
@@ -334,7 +335,6 @@ void strokeTo(final DRendererContext rdrCtx,
int dashLen = -1;
boolean recycleDashes = false;
- double scale = 1.0d;
double[] dashesD = null;
// Ensure converting dashes to double precision:
@@ -375,7 +375,7 @@ void strokeTo(final DRendererContext rdrCtx,
// a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we
// leave a bit of room for error.
if (nearZero(a*b + c*d) && nearZero(a*a + c*c - (b*b + d*d))) {
- scale = Math.sqrt(a*a + c*c);
+ final double scale = Math.sqrt(a*a + c*c);
if (dashesD != null) {
for (int i = 0; i < dashLen; i++) {
@@ -427,7 +427,7 @@ void strokeTo(final DRendererContext rdrCtx,
pc2d = transformerPC2D.deltaTransformConsumer(pc2d, strokerat);
// stroker will adjust the clip rectangle (width / miter limit):
- pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit, scale,
+ pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit,
(dashesD == null));
// Curve Monotizer:
@@ -839,6 +839,11 @@ public AATileGenerator getAATileGenerator(Shape s,
clipRect[2] = clip.getLoX();
clipRect[3] = clip.getLoX() + clip.getWidth();
+ if (MarlinConst.DO_LOG_CLIP) {
+ MarlinUtils.logInfo("clipRect (clip): "
+ + Arrays.toString(rdrCtx.clipRect));
+ }
+
// Enable clipping:
rdrCtx.doClip = true;
}
diff --git a/src/main/java/org/marlin/pisces/DStroker.java b/src/main/java/org/marlin/pisces/DStroker.java
index a811487..77dc645 100644
--- a/src/main/java/org/marlin/pisces/DStroker.java
+++ b/src/main/java/org/marlin/pisces/DStroker.java
@@ -139,7 +139,6 @@ final class DStroker implements DPathConsumer2D, MarlinConst {
* JOIN_MITER
, JOIN_ROUND
or
* JOIN_BEVEL
.
* @param miterLimit the desired miter limit
- * @param scale scaling factor applied to clip boundaries
* @param subdivideCurves true to indicate to subdivide curves, false if dasher does
* @return this instance
*/
@@ -148,7 +147,6 @@ DStroker init(final DPathConsumer2D pc2d,
final int capStyle,
final int joinStyle,
final double miterLimit,
- final double scale,
final boolean subdivideCurves)
{
this.out = pc2d;
@@ -169,7 +167,6 @@ DStroker init(final DPathConsumer2D pc2d,
if (rdrCtx.doClip) {
// Adjust the clipping rectangle with the stroker margin (miter limit, width)
- double rdrOffX = 0.0d, rdrOffY = 0.0d;
double margin = lineWidth2;
if (capStyle == CAP_SQUARE) {
@@ -178,23 +175,21 @@ DStroker init(final DPathConsumer2D pc2d,
if ((joinStyle == JOIN_MITER) && (margin < limit)) {
margin = limit;
}
- if (scale != 1.0d) {
- margin *= scale;
- rdrOffX = scale * DRenderer.RDR_OFFSET_X;
- rdrOffY = scale * DRenderer.RDR_OFFSET_Y;
- }
- // add a small rounding error:
- margin += 1e-3d;
// bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
// adjust clip rectangle (ymin, ymax, xmin, xmax):
final double[] _clipRect = rdrCtx.clipRect;
- _clipRect[0] -= margin - rdrOffY;
- _clipRect[1] += margin + rdrOffY;
- _clipRect[2] -= margin - rdrOffX;
- _clipRect[3] += margin + rdrOffX;
+ _clipRect[0] -= margin;
+ _clipRect[1] += margin;
+ _clipRect[2] -= margin;
+ _clipRect[3] += margin;
this.clipRect = _clipRect;
+ if (MarlinConst.DO_LOG_CLIP) {
+ MarlinUtils.logInfo("clipRect (stroker): "
+ + Arrays.toString(rdrCtx.clipRect));
+ }
+
// initialize curve splitter here for stroker & dasher:
if (DO_CLIP_SUBDIVIDER) {
subdivide = subdivideCurves;
diff --git a/src/main/java/org/marlin/pisces/DTransformingPathConsumer2D.java b/src/main/java/org/marlin/pisces/DTransformingPathConsumer2D.java
index accac77..5a138c0 100644
--- a/src/main/java/org/marlin/pisces/DTransformingPathConsumer2D.java
+++ b/src/main/java/org/marlin/pisces/DTransformingPathConsumer2D.java
@@ -104,6 +104,10 @@ DPathConsumer2D pathClipper(DPathConsumer2D out) {
DPathConsumer2D deltaTransformConsumer(DPathConsumer2D out,
AffineTransform at)
{
+ if (rdrCtx.doClip) {
+ adjustClipOffset(rdrCtx.clipRect);
+ }
+
if (at == null) {
return out;
}
@@ -133,30 +137,51 @@ DPathConsumer2D deltaTransformConsumer(DPathConsumer2D out,
}
private static void adjustClipOffset(final double[] clipRect) {
- clipRect[0] += Renderer.RDR_OFFSET_Y;
- clipRect[1] += Renderer.RDR_OFFSET_Y;
- clipRect[2] += Renderer.RDR_OFFSET_X;
- clipRect[3] += Renderer.RDR_OFFSET_X;
+ // Adjust the clipping rectangle with the renderer offsets
+ final double rdrOffX = DRenderer.RDR_OFFSET_X;
+ final double rdrOffY = DRenderer.RDR_OFFSET_Y;
+
+ // add a small rounding error:
+ final double margin = 1e-3d;
+
+ clipRect[0] -= margin - rdrOffY;
+ clipRect[1] += margin + rdrOffY;
+ clipRect[2] -= margin - rdrOffX;
+ clipRect[3] += margin + rdrOffX;
}
private static void adjustClipScale(final double[] clipRect,
final double mxx, final double myy)
{
- adjustClipOffset(clipRect);
-
// Adjust the clipping rectangle (iv_DeltaScaleFilter):
clipRect[0] /= myy;
clipRect[1] /= myy;
+
+ if (clipRect[1] < clipRect[0]) {
+ double tmp = clipRect[0];
+ clipRect[0] = clipRect[1];
+ clipRect[1] = tmp;
+ }
+
clipRect[2] /= mxx;
clipRect[3] /= mxx;
+
+ if (clipRect[3] < clipRect[2]) {
+ double tmp = clipRect[2];
+ clipRect[2] = clipRect[3];
+ clipRect[3] = tmp;
+ }
+
+ if (MarlinConst.DO_LOG_CLIP) {
+ MarlinUtils.logInfo("clipRect (ClipScale): "
+ + Arrays.toString(clipRect));
+ }
}
private static void adjustClipInverseDelta(final double[] clipRect,
final double mxx, final double mxy,
final double myx, final double myy)
{
- adjustClipOffset(clipRect);
-
// Adjust the clipping rectangle (iv_DeltaTransformFilter):
final double det = mxx * myy - mxy * myx;
final double imxx = myy / det;
@@ -198,6 +223,11 @@ private static void adjustClipInverseDelta(final double[] clipRect,
clipRect[1] = ymax;
clipRect[2] = xmin;
clipRect[3] = xmax;
+
+ if (MarlinConst.DO_LOG_CLIP) {
+ MarlinUtils.logInfo("clipRect (ClipInverseDelta): "
+ + Arrays.toString(clipRect));
+ }
}
DPathConsumer2D inverseDeltaTransformConsumer(DPathConsumer2D out,
@@ -532,18 +562,12 @@ static final class PathClipFilter implements DPathConsumer2D {
PathClipFilter init(final DPathConsumer2D out) {
this.out = out;
- // Adjust the clipping rectangle with the renderer offsets
- final double rdrOffX = DRenderer.RDR_OFFSET_X;
- final double rdrOffY = DRenderer.RDR_OFFSET_Y;
-
- // add a small rounding error:
- final double margin = 1e-3d;
+ adjustClipOffset(this.clipRect);
- final double[] _clipRect = this.clipRect;
- _clipRect[0] -= margin - rdrOffY;
- _clipRect[1] += margin + rdrOffY;
- _clipRect[2] -= margin - rdrOffX;
- _clipRect[3] += margin + rdrOffX;
+ if (MarlinConst.DO_LOG_CLIP) {
+ MarlinUtils.logInfo("clipRect (PathClipFilter): "
+ + Arrays.toString(clipRect));
+ }
if (MarlinConst.DO_CLIP_SUBDIVIDER) {
// adjust padded clip rectangle:
@@ -890,6 +914,8 @@ static final class CurveClipSplitter {
void init() {
this.init_clipRectPad = true;
+
+ // TODO: adjust LEN_TH by rough scale ?
}
private void initPaddedClip() {
@@ -906,7 +932,7 @@ private void initPaddedClip() {
if (TRACE) {
MarlinUtils.logInfo("clip: X [" + _clipRectPad[2] + " .. " + _clipRectPad[3] +"] "
- + "Y ["+ _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
+ + "Y [" + _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
}
}
@@ -991,7 +1017,7 @@ private boolean subdivideAtIntersections(final int type, final int outCodeOR,
outCodeOR, clipRectPad);
if (TRACE) {
- MarlinUtils.logInfo("nSplits: "+ nSplits);
+ MarlinUtils.logInfo("nSplits: " + nSplits);
MarlinUtils.logInfo("subTs: " + Arrays.toString(Arrays.copyOfRange(subTs, 0, nSplits)));
}
if (nSplits == 0) {
diff --git a/src/main/java/org/marlin/pisces/MarlinConst.java b/src/main/java/org/marlin/pisces/MarlinConst.java
index 8fc7f97..64ec3d3 100644
--- a/src/main/java/org/marlin/pisces/MarlinConst.java
+++ b/src/main/java/org/marlin/pisces/MarlinConst.java
@@ -82,9 +82,12 @@ interface MarlinConst {
static final boolean DO_CLIP_SUBDIVIDER = MarlinProperties.isDoClipSubdivider();
- // flag to enable logs related bounds checks
+ // flag to enable logs related to bounds checks
static final boolean DO_LOG_BOUNDS = ENABLE_LOGS && false;
+ // flag to enable logs related to clip rect
+ static final boolean DO_LOG_CLIP = ENABLE_LOGS && false;
+
// Initial Array sizing (initial context capacity) ~ 450K
// 4096 pixels (width) for initial capacity
diff --git a/src/main/java/org/marlin/pisces/MarlinRenderingEngine.java b/src/main/java/org/marlin/pisces/MarlinRenderingEngine.java
index 858ee4a..ccc5cb5 100644
--- a/src/main/java/org/marlin/pisces/MarlinRenderingEngine.java
+++ b/src/main/java/org/marlin/pisces/MarlinRenderingEngine.java
@@ -30,6 +30,7 @@
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.security.AccessController;
+import java.util.Arrays;
import org.marlin.geom.Path2D;
import static org.marlin.pisces.MarlinUtils.logInfo;
import sun.awt.geom.PathConsumer2D;
@@ -333,7 +334,6 @@ void strokeTo(final RendererContext rdrCtx,
int dashLen = -1;
boolean recycleDashes = false;
- float scale = 1.0f;
if (at != null && !at.isIdentity()) {
final double a = at.getScaleX();
@@ -366,7 +366,7 @@ void strokeTo(final RendererContext rdrCtx,
// a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we
// leave a bit of room for error.
if (nearZero(a*b + c*d) && nearZero(a*a + c*c - (b*b + d*d))) {
- scale = (float) Math.sqrt(a*a + c*c);
+ final float scale = (float) Math.sqrt(a*a + c*c);
if (dashes != null) {
recycleDashes = true;
@@ -421,7 +421,7 @@ void strokeTo(final RendererContext rdrCtx,
pc2d = transformerPC2D.deltaTransformConsumer(pc2d, strokerat);
// stroker will adjust the clip rectangle (width / miter limit):
- pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit, scale,
+ pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit,
(dashes == null));
// Curve Monotizer:
@@ -836,6 +836,11 @@ public AATileGenerator getAATileGenerator(Shape s,
clipRect[2] = clip.getLoX();
clipRect[3] = clip.getLoX() + clip.getWidth();
+ if (MarlinConst.DO_LOG_CLIP) {
+ MarlinUtils.logInfo("clipRect (clip): "
+ + Arrays.toString(rdrCtx.clipRect));
+ }
+
// Enable clipping:
rdrCtx.doClip = true;
}
diff --git a/src/main/java/org/marlin/pisces/Stroker.java b/src/main/java/org/marlin/pisces/Stroker.java
index f56d9b1..0acde45 100644
--- a/src/main/java/org/marlin/pisces/Stroker.java
+++ b/src/main/java/org/marlin/pisces/Stroker.java
@@ -141,7 +141,6 @@ final class Stroker implements PathConsumer2D, MarlinConst {
* JOIN_MITER
, JOIN_ROUND
or
* JOIN_BEVEL
.
* @param miterLimit the desired miter limit
- * @param scale scaling factor applied to clip boundaries
* @param subdivideCurves true to indicate to subdivide curves, false if dasher does
* @return this instance
*/
@@ -150,7 +149,6 @@ Stroker init(final PathConsumer2D pc2d,
final int capStyle,
final int joinStyle,
final float miterLimit,
- final float scale,
final boolean subdivideCurves)
{
this.out = pc2d;
@@ -171,7 +169,6 @@ Stroker init(final PathConsumer2D pc2d,
if (rdrCtx.doClip) {
// Adjust the clipping rectangle with the stroker margin (miter limit, width)
- float rdrOffX = 0.0f, rdrOffY = 0.0f;
float margin = lineWidth2;
if (capStyle == CAP_SQUARE) {
@@ -180,23 +177,21 @@ Stroker init(final PathConsumer2D pc2d,
if ((joinStyle == JOIN_MITER) && (margin < limit)) {
margin = limit;
}
- if (scale != 1.0f) {
- margin *= scale;
- rdrOffX = scale * Renderer.RDR_OFFSET_X;
- rdrOffY = scale * Renderer.RDR_OFFSET_Y;
- }
- // add a small rounding error:
- margin += 1e-3f;
// bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
// adjust clip rectangle (ymin, ymax, xmin, xmax):
final float[] _clipRect = rdrCtx.clipRect;
- _clipRect[0] -= margin - rdrOffY;
- _clipRect[1] += margin + rdrOffY;
- _clipRect[2] -= margin - rdrOffX;
- _clipRect[3] += margin + rdrOffX;
+ _clipRect[0] -= margin;
+ _clipRect[1] += margin;
+ _clipRect[2] -= margin;
+ _clipRect[3] += margin;
this.clipRect = _clipRect;
+ if (MarlinConst.DO_LOG_CLIP) {
+ MarlinUtils.logInfo("clipRect (stroker): "
+ + Arrays.toString(rdrCtx.clipRect));
+ }
+
// initialize curve splitter here for stroker & dasher:
if (DO_CLIP_SUBDIVIDER) {
subdivide = subdivideCurves;
diff --git a/src/main/java/org/marlin/pisces/TransformingPathConsumer2D.java b/src/main/java/org/marlin/pisces/TransformingPathConsumer2D.java
index 1fdf12c..ec6b541 100644
--- a/src/main/java/org/marlin/pisces/TransformingPathConsumer2D.java
+++ b/src/main/java/org/marlin/pisces/TransformingPathConsumer2D.java
@@ -105,6 +105,10 @@ PathConsumer2D pathClipper(PathConsumer2D out) {
PathConsumer2D deltaTransformConsumer(PathConsumer2D out,
AffineTransform at)
{
+ if (rdrCtx.doClip) {
+ adjustClipOffset(rdrCtx.clipRect);
+ }
+
if (at == null) {
return out;
}
@@ -134,30 +138,51 @@ PathConsumer2D deltaTransformConsumer(PathConsumer2D out,
}
private static void adjustClipOffset(final float[] clipRect) {
- clipRect[0] += Renderer.RDR_OFFSET_Y;
- clipRect[1] += Renderer.RDR_OFFSET_Y;
- clipRect[2] += Renderer.RDR_OFFSET_X;
- clipRect[3] += Renderer.RDR_OFFSET_X;
+ // Adjust the clipping rectangle with the renderer offsets
+ final float rdrOffX = Renderer.RDR_OFFSET_X;
+ final float rdrOffY = Renderer.RDR_OFFSET_Y;
+
+ // add a small rounding error:
+ final float margin = 1e-3f;
+
+ clipRect[0] -= margin - rdrOffY;
+ clipRect[1] += margin + rdrOffY;
+ clipRect[2] -= margin - rdrOffX;
+ clipRect[3] += margin + rdrOffX;
}
private static void adjustClipScale(final float[] clipRect,
final float mxx, final float myy)
{
- adjustClipOffset(clipRect);
-
// Adjust the clipping rectangle (iv_DeltaScaleFilter):
clipRect[0] /= myy;
clipRect[1] /= myy;
+
+ if (clipRect[1] < clipRect[0]) {
+ float tmp = clipRect[0];
+ clipRect[0] = clipRect[1];
+ clipRect[1] = tmp;
+ }
+
clipRect[2] /= mxx;
clipRect[3] /= mxx;
+
+ if (clipRect[3] < clipRect[2]) {
+ float tmp = clipRect[2];
+ clipRect[2] = clipRect[3];
+ clipRect[3] = tmp;
+ }
+
+ if (MarlinConst.DO_LOG_CLIP) {
+ MarlinUtils.logInfo("clipRect (ClipScale): "
+ + Arrays.toString(clipRect));
+ }
}
private static void adjustClipInverseDelta(final float[] clipRect,
final float mxx, final float mxy,
final float myx, final float myy)
{
- adjustClipOffset(clipRect);
-
// Adjust the clipping rectangle (iv_DeltaTransformFilter):
final float det = mxx * myy - mxy * myx;
final float imxx = myy / det;
@@ -199,6 +224,11 @@ private static void adjustClipInverseDelta(final float[] clipRect,
clipRect[1] = ymax;
clipRect[2] = xmin;
clipRect[3] = xmax;
+
+ if (MarlinConst.DO_LOG_CLIP) {
+ MarlinUtils.logInfo("clipRect (ClipInverseDelta): "
+ + Arrays.toString(clipRect));
+ }
}
PathConsumer2D inverseDeltaTransformConsumer(PathConsumer2D out,
@@ -533,18 +563,12 @@ static final class PathClipFilter implements PathConsumer2D {
PathClipFilter init(final PathConsumer2D out) {
this.out = out;
- // Adjust the clipping rectangle with the renderer offsets
- final float rdrOffX = Renderer.RDR_OFFSET_X;
- final float rdrOffY = Renderer.RDR_OFFSET_Y;
-
- // add a small rounding error:
- final float margin = 1e-3f;
+ adjustClipOffset(this.clipRect);
- final float[] _clipRect = this.clipRect;
- _clipRect[0] -= margin - rdrOffY;
- _clipRect[1] += margin + rdrOffY;
- _clipRect[2] -= margin - rdrOffX;
- _clipRect[3] += margin + rdrOffX;
+ if (MarlinConst.DO_LOG_CLIP) {
+ MarlinUtils.logInfo("clipRect (PathClipFilter): "
+ + Arrays.toString(clipRect));
+ }
if (MarlinConst.DO_CLIP_SUBDIVIDER) {
// adjust padded clip rectangle:
@@ -891,6 +915,8 @@ static final class CurveClipSplitter {
void init() {
this.init_clipRectPad = true;
+
+ // TODO: adjust LEN_TH by rough scale ?
}
private void initPaddedClip() {
@@ -907,7 +933,7 @@ private void initPaddedClip() {
if (TRACE) {
MarlinUtils.logInfo("clip: X [" + _clipRectPad[2] + " .. " + _clipRectPad[3] +"] "
- + "Y ["+ _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
+ + "Y [" + _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
}
}
@@ -992,7 +1018,7 @@ private boolean subdivideAtIntersections(final int type, final int outCodeOR,
outCodeOR, clipRectPad);
if (TRACE) {
- MarlinUtils.logInfo("nSplits: "+ nSplits);
+ MarlinUtils.logInfo("nSplits: " + nSplits);
MarlinUtils.logInfo("subTs: " + Arrays.toString(Arrays.copyOfRange(subTs, 0, nSplits)));
}
if (nSplits == 0) {