com.adobe.fontengine.font.CScan Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*
* File: CScan.java
*
* ADOBE CONFIDENTIAL
* ___________________
*
* Copyright 2006 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of
* Adobe Systems Incorporated and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe Systems
* Incorporated and its suppliers and may be covered by U.S. and Foreign
* Patents, patents in process, and are protected by trade secret or
* copyright law. Dissemination of this information or reproduction of this
* material is strictly forbidden unless prior written permission is
* obtained from Adobe Systems Incorporated.
*/
/*
* Adobe Patent and/or Adobe Patent Pending invention included within this file:
*
* Adobe patent application tracking # P002,
* entitled "Dropout-free center point fill method for displaying characters"
* inventors: William Paxton and Stephen Schiller
* Issued US Patent 5,200,740 on April 6, 1993.
*
* Adobe patent application tracking # P006,
* entitled "Connected-run dropout-free center point fill method for displaying characters"
* inventors: Micheal Byron and Thomas Malloy
* Issued US Patent 5,233,336 on August 3, 1993.
*
* Adobe patent application tracking # P010C1
* entitled "Method for editing character bit maps at small sizes using connected runs"
* inventors: by Micheal Byron and Thomas Malloy
* Issued US Patent 5,255,357 on October 19, 1993
*/
package com.adobe.fontengine.font;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
/** Scan conversion by center scan.
*/
public final class CScan implements ScanConverter {
private boolean useOffset;
private boolean horizontalProximityFill;
private double[] slopesArray;
private CrossBuilder crossBuilder;
private Map/**/ scanLines;
private int firstScanline;
private int lastScanline;
private Set/**/ crossesAtXMinima;
private Set/**/ crossesAtXMaxima;
private Set/**/ contours;
private static final double [] slopesArrayInit
= {0.0d, -0.0625d, -0.29289d, -0.3660d, -0.434d, -0.5d};
private static int indexOfSlope (double inverseSlope) {
if (inverseSlope < 0.0d) {
inverseSlope = -inverseSlope; }
if (inverseSlope > Math.tan (Math.toRadians (52.5))) {
if (inverseSlope > Math.tan (Math.toRadians (82.5))) {
return 5; }
if (inverseSlope > Math.tan (Math.toRadians (67.5))) {
return 4; }
return 3; }
else if (inverseSlope < Math.tan (Math.toRadians (7.5))) {
return 1; }
return 2;
}
public CScan (boolean useOffset, double idealWidth, boolean horizontalProximityFill) {
this.useOffset = useOffset;
this.horizontalProximityFill = horizontalProximityFill;
this.crossBuilder = new CrossBuilder ();
crossBuilder.setFlatness (1.0d);
this.slopesArray = null;
if (useOffset) {
slopesArray = new double [slopesArrayInit.length];
System.arraycopy (slopesArrayInit, 0, slopesArray, 0, slopesArrayInit.length);
if (idealWidth > 1.0d) {
double g = 2 * idealWidth - 1.0d;
for (int i = 1; i < slopesArray.length; i++) {
slopesArray [i] = Math.max (slopesArray [i] * g, -1.0d); }}}
}
private abstract class Cross {
double x;
double y;
Contour contour;
public String toString () {
return "{" + (Math.round (x * 100) / 100.0d) + ", " + (Math.round (y * 100) / 100.0d) + "}";
}
}
private class IntersectionCross extends Cross implements Comparable {
double xPixel;
int slopeIndex;
public IntersectionCross (double x, double y) {
this.x = x;
this.y = y;
}
public boolean isLeftInRun () {
List/**/ scanLine = getScanline ((int) Math.floor (y));
for (Iterator/**/ it = scanLine.iterator(); it.hasNext(); ) {
IntersectionCross c = (IntersectionCross) it.next ();
if (c == this) {
return true; }
c = (IntersectionCross) it.next ();
if (c == this) {
return false; }}
throw new RuntimeException ("unpaired crosses in run at y=" + y);
}
public IntersectionCross leftInRun () {
List/**/ scanLine = getScanline ((int) Math.floor (y));
IntersectionCross previous = null;
for (Iterator/**/ it = scanLine.iterator(); it.hasNext(); ) {
IntersectionCross c = (IntersectionCross) it.next ();
if (c == this) {
return previous; }
else {
previous = c; }}
return null;
}
public IntersectionCross rightInRun () {
List/**/ scanLine = getScanline ((int) Math.floor (y));
for (Iterator/**/ it = scanLine.iterator(); it.hasNext(); ) {
IntersectionCross c = (IntersectionCross) it.next ();
if (c == this) {
if (it.hasNext ()) {
return (IntersectionCross) it.next (); }
else {
return null; }}}
return null;
}
public int compareTo (Object arg0) {
IntersectionCross e = (IntersectionCross) arg0;
if (e.x < x) {
return +1; }
else if (e.x == x) {
return 0; }
else {
return -1; }
}
}
private class ExtraCross extends Cross {
public ExtraCross (double x, double y) {
this.x = x;
this.y = y;
}
}
private class CrossBuilder extends OutlineConsumer2BaseImpl {
private double THRESHOLD = 127.0;
private double epsilon;
public void setFlatness (double flatness) {
epsilon = Math.max (1.0d/8192, 1.5d * flatness / 4);
}
//--------------------------------------------------------------------------
public void startOutline () {
scanLines = new HashMap ();
firstScanline = Integer.MAX_VALUE;
lastScanline = Integer.MIN_VALUE;
crossesAtXMinima = new HashSet ();
crossesAtXMaxima = new HashSet ();
contours = new HashSet ();
}
public void startContour () {
contour = new Contour ();
vertDir = NO_DIR;
horizDir = NO_DIR;
}
public void line (double x1, double y1, double x2, double y2) {
/* Make sure we never have a point on a midline */
if (Math.abs(y1 - Math.floor (y1) - 0.5d) < 0.00001) {
y1 += y1/1000.0; }
if (Math.abs(y2 - Math.floor (y2) - 0.5d) < 0.00001) {
y2 += y2/1000.0; }
if (horizDir == NO_DIR) {
firstSegmentX1 = x1;
firstSegmentY1 = y1;
firstSegmentX2 = x2;
firstSegmentY2 = y2;
setDirections (x1, y1, x2, y2); }
else {
addInflectionCrossIfNeeded (x1, y1, x2, y2); }
if (y1 < y2) {
double inversedSlope = (x2 - x1) / (y2 - y1);
double yMid = Math.floor (y1 + 0.5) + 0.5;
double xMid = x1 + (yMid - y1) * inversedSlope;
while (yMid <= y2) {
IntersectionCross c = new IntersectionCross (xMid, yMid);
if (useOffset) {
c.slopeIndex = indexOfSlope (inversedSlope); }
addIntersectionCross (c);
yMid += 1.0;
xMid += inversedSlope; }}
else if (y2 < y1) {
double inversedSlope = (x2 - x1) / (y2 - y1);
double yMid = Math.floor (y1 - 0.5) + 0.5; /* round down to a pixel midline */
double xMid = x1 + (yMid - y1) * inversedSlope;
while (y2 <= yMid) {
IntersectionCross c = new IntersectionCross (xMid, yMid);
if (useOffset) {
c.slopeIndex = indexOfSlope (inversedSlope); }
addIntersectionCross (c);
yMid -= 1.0;
xMid -= inversedSlope; }}
}
public void quadraticCurve (double x1, double y1,
double x2, double y2,
double x3, double y3) {
if ( ( (x1 <= x2 && x2 <= x3)
|| (x3 <= x2 && x2 <= x1))
&& (Math.abs (x3 - x1) < THRESHOLD)
&& (Math.abs ((x3 - x1) - 2 * (x2 - x1)) <= epsilon)
&& ( (y1 <= y2 && y2 <= y3)
|| (y3 <= y2 && y2 <= y1))
&& (Math.abs (y3 - y1) < THRESHOLD)
&& (Math.abs ((y3 - y1) - 2 * (y2 - y1)) <= epsilon)) {
line (x1, y1, x3, y3); }
else {
double x12 = (x2 + x1) / 2.0; double y12 = (y2 + y1) / 2.0;
double x23 = (x3 + x2) / 2.0; double y23 = (y3 + y2) / 2.0;
double x1223 = (x12 + x23) / 2.0; double y1223 = (y12 + y23) / 2.0;
quadraticCurve (x1, y1, x12, y12, x1223, y1223);
quadraticCurve (x1223, y1223, x23, y23, x3, y3); }
}
public void cubicCurve (double x1, double y1,
double x2, double y2,
double x3, double y3,
double x4, double y4) {
if ( ( (x1 <= x2 && x2 <= x3 && x3 <= x4)
|| (x4 <= x3 && x3 <= x2 && x2 <= x1))
&& (Math.abs (x4 - x1) < THRESHOLD)
&& (Math.abs ((x4 - x1) - 3 * (x2 - x1)) <= epsilon)
&& (Math.abs ((x4 - x1) - 3 * (x4 - x3)) <= epsilon)
&& ( (y1 <= y2 && y2 <= y3 && y3 <= y4)
|| (y4 <= y3 && y3 <= y2 && y2 <= y1))
&& (Math.abs (y4 - y1) < THRESHOLD)
&& (Math.abs ((y4 - y1) - 3 * (y2 - y1)) <= epsilon)
&& (Math.abs ((y4 - y1) - 3 * (y4 - y3)) <= epsilon)) {
line (x1, y1, x4, y4); }
else {
double x12 = (x2 + x1) / 2.0; double y12 = (y2 + y1) / 2.0;
double x23 = (x3 + x2) / 2.0; double y23 = (y3 + y2) / 2.0;
double x34 = (x4 + x3) / 2.0; double y34 = (y4 + y3) / 2.0;
double x1223 = (x23 + x12) / 2.0; double y1223 = (y23 + y12) / 2.0;
double x2334 = (x34 + x23) / 2.0; double y2334 = (y34 + y23) / 2.0;
double xx = (x1223 + x2334) / 2.0; double yy = (y1223 + y2334) / 2.0;
cubicCurve (x1, y1, x12, y12, x1223, y1223, xx, yy);
cubicCurve (xx, yy, x2334, y2334, x34, y34, x4, y4); }
}
public void endContour () {
addInflectionCrossIfNeeded (firstSegmentX1, firstSegmentY1,
firstSegmentX2, firstSegmentY2);
contours.add (contour);
contour = null;
}
public void endOutline () {
}
//--------------------------------------------------------------------------
final static private int NO_DIR = 0;
final static private int RIGHT_DIR = 1;
final static private int LEFT_DIR = -1;
final static private int VERT_DIR = 2;
final static private int UP_DIR = 1;
final static private int DOWN_DIR = -1;
final static private int HORIZ_DIR = 2;
private int vertDir;
private int horizDir;
private Contour contour;
private double firstSegmentX1;
private double firstSegmentY1;
private double firstSegmentX2;
private double firstSegmentY2;
private void setDirections (double x1, double y1, double x2, double y2) {
if (x1 < x2) {
horizDir = RIGHT_DIR; }
else if (x1 == x2) {
horizDir = VERT_DIR; }
else /* (x1 > x2) */ {
horizDir = LEFT_DIR; }
if (y1 < y2) {
vertDir = UP_DIR; }
else if (y1 == y2) {
vertDir = HORIZ_DIR; }
else /* (y1 > y2) */ {
vertDir = DOWN_DIR; }
}
private void addInflectionCrossIfNeeded (double x1, double y1, double x2, double y2) {
boolean allPoints = false;
Cross c = null;
if (allPoints) {
c = new ExtraCross (x1, y1); }
if (x1 < x2 && horizDir != RIGHT_DIR) {
if (horizDir != NO_DIR) {
if (c == null) {
c = new ExtraCross (x1, y1); }
crossesAtXMinima.add (c); }
horizDir = RIGHT_DIR; }
else if (x1 == x2 && horizDir != VERT_DIR) {
if (horizDir != NO_DIR) {
if (c == null) {
c = new ExtraCross (x1, y1); }
if (horizDir == LEFT_DIR) {
crossesAtXMinima.add (c); }
else {
crossesAtXMaxima.add (c); }}
horizDir = VERT_DIR; }
else if (x1 > x2 && horizDir != LEFT_DIR) {
if (horizDir != NO_DIR) {
if (c == null) {
c = new ExtraCross (x1, y1); }
crossesAtXMaxima.add (c); }
horizDir = LEFT_DIR; }
if (y1 < y2) {
if (vertDir != UP_DIR) {
if (c == null) {
c = new ExtraCross (x1, y1); }
vertDir = UP_DIR; }}
else if (y1 == y2) {
if (vertDir != HORIZ_DIR) {
if (c == null) {
c = new ExtraCross (x1, y1); }
vertDir = HORIZ_DIR; }}
else {
if (vertDir != DOWN_DIR) {
if (c == null) {
c = new ExtraCross (x1, y1); }
vertDir = DOWN_DIR; }}
if (c != null) {
addCrossToCountour (c); }
}
private void addIntersectionCross (IntersectionCross c) {
int y = (int) Math.floor (c.y);
firstScanline = Math.min (firstScanline, y);
lastScanline = Math.max (lastScanline, y);
Integer Y = new Integer (y);
LinkedList/**/ l = (LinkedList/**/) scanLines.get (Y);
if (l == null) {
l = new LinkedList/**/ ();
scanLines.put (Y, l);}
ListIterator it = l.listIterator();
if (!it.hasNext()) {
l.add(0, c); }
else {
boolean added = false;
for (; it.hasNext();){
IntersectionCross cross = (IntersectionCross)it.next();
if (cross.compareTo(c) >= 0) {
if (it.hasPrevious()) {
it.previous();
it.add (c); }
else {
l.add(0, c);
}
added = true;
break; }
}
if (!added)
l.add(c);
}
addCrossToCountour (c);
}
private void addCrossToCountour (Cross c) {
c.contour = contour;
contour.add (c);
}
}
private class Contour {
private static final int FORWARD = 1;
private static final int BACKWARD = -1;
private List/**/ crosses = new ArrayList/**/ ();
public void add (Cross c) {
crosses.add (c);
}
public IntersectionCross intersectionCrossBefore (Cross c1) {
return adjacentIntersectionCross (c1, BACKWARD);
}
public IntersectionCross intersectionCrossAfter (Cross c1) {
return adjacentIntersectionCross (c1, FORWARD);
}
public Cross adjacentCross (Cross c1, int direction) {
int i = crosses.indexOf (c1);
i = (i + direction) % crosses.size();
if (i < 0) { i = i + crosses.size(); }
return (Cross) crosses.get (i);
}
public IntersectionCross adjacentIntersectionCross (Cross c1, int direction) {
Cross c2;
int i = crosses.indexOf (c1);
do {
i = (i + direction) % crosses.size ();
if (i < 0) { i = i + crosses.size (); }
c2 = (Cross) crosses.get (i); }
while (! (c2 instanceof IntersectionCross) && (c2 != c1));
if (c2 instanceof IntersectionCross) {
return (IntersectionCross) c2; }
else {
return null; }
}
public Iterator/**/ iterator () {
return crosses.iterator();
}
public class IntersectionEdgeIterator {
int cursor = 0;
IntersectionCross first;
IntersectionCross second;
public IntersectionEdgeIterator () {
while (cursor < crosses.size () && ! (crosses.get (cursor) instanceof IntersectionCross)) {
cursor++; }
}
public boolean hasNext () {
return cursor < crosses.size ();
}
public void next () {
first = (IntersectionCross) crosses.get (cursor);
int o = (cursor + 1) % crosses.size ();
while (! (crosses.get (o) instanceof IntersectionCross)) {
o = (o + 1) % crosses.size (); }
second = (IntersectionCross) crosses.get (o);
cursor++;
while (cursor < crosses.size () && ! (crosses.get (cursor) instanceof IntersectionCross)) {
cursor++; }
}
public IntersectionCross c1 () {
return first;
}
public IntersectionCross c2 () {
return second;
}
}
public IntersectionEdgeIterator iterateIntersectionEdges () {
return new IntersectionEdgeIterator ();
}
public class EdgeIterator {
int cursor = 0;
int limit;
boolean forceHas;
Cross first;
Cross second;
public EdgeIterator (Cross c1, Cross c2) {
cursor = crosses.indexOf (c1);
limit = crosses.indexOf (c2);
forceHas = false;
}
public EdgeIterator () {
cursor = 0;
limit = 0;
forceHas = true;
}
public boolean hasNext () {
return (forceHas || cursor != limit);
}
public void next () {
forceHas = false;
first = (Cross) crosses.get (cursor);
cursor = (cursor + 1) % crosses.size ();
second = (Cross) crosses.get (cursor);
}
public Cross c1 () {
return first;
}
public Cross c2 () {
return second;
}
}
public EdgeIterator iterateEdges (Cross c1, Cross c2) {
return new EdgeIterator (c1, c2);
}
public EdgeIterator iterateEdges () {
return new EdgeIterator ();
}
}
public void setScanType (int scanType) {
// nothing
}
public OutlineConsumer2 getOutlineConsumer2 () {
return crossBuilder;
}
public void getBitmap (BitmapConsumer bitmapConsumer) {
if (ScalerDebugger.debugOn && outlineDebugger != null) {
paintCrosses (true); }
buildInitialRuns ();
//fillDropouts ();
editWhiteSpace ();
returnBits (bitmapConsumer);
}
private void buildInitialRuns () {
for (int y = firstScanline; y <= lastScanline; y++) {
List/**/ crosses = getScanline (y);
for (Iterator it = crosses.iterator(); it.hasNext (); ) {
double lastX = Double.NEGATIVE_INFINITY;
IntersectionCross c1 = (IntersectionCross) it.next ();
IntersectionCross c2 = (IntersectionCross) it.next ();
if (useOffset) {
double delta1 = slopesArray [c1.slopeIndex];
double delta2 = slopesArray [c2.slopeIndex];
/* we are bringing them closer proportional to the slope of
* the segments...makes it more likely for the stem
* to get thinner or shift right (if they are already thin) in
* correspondence with our narrow stdHW
*/
c1.x -= delta1;
c2.x += delta2;
/* we switched the order...fix that and make stems 1 apart */
if (c1.x >= c2.x) {
c1.x = (c1.x + delta1 + c2.x - delta2) / 2;
c2.x = c1.x + 1; }}
if (c1.x <= lastX) {
c1.x = lastX + lastX/1000.0;
c2.x = c1.x + c1.x/1000.0; }
double leftRun = Math.round (c1.x);
double rightRun = Math.round (c2.x);
if (leftRun != rightRun) { /* Run crosses at least one vertical midline */
c1.xPixel = leftRun;
c2.xPixel = rightRun; }
else if (horizontalProximityFill) { /* Run doesn't cross vertical midline */
c1.xPixel = Math.floor ((c1.x + c2.x) / 2.0);
c2.xPixel = c1.xPixel + 1; }
else {
c1.xPixel = leftRun;
c2.xPixel = rightRun; }
lastX = Math.max (lastX, c2.x); }}
}
private void editWhiteSpace () {
//TODO
}
private void returnBits (BitmapConsumer bitmapConsumer) {
for (int y = firstScanline; y <= lastScanline; y++) {
List/**/ crosses = getScanline (y);
for (Iterator it = crosses.iterator(); it.hasNext (); ) {
IntersectionCross c1 = (IntersectionCross) it.next ();
if (!it.hasNext ()) {
System.err.println ("unpaired cross at y=" + y);
continue; }
IntersectionCross c2 = (IntersectionCross) it.next ();
double left = c1.xPixel;
double right = c2. xPixel;
if (left < right) {
bitmapConsumer.addRun (left, right, y); }}}
}
private void paintCrosses (boolean iCrossesOnly) {
for (Iterator it = contours.iterator(); it.hasNext (); ) {
Contour contour = (Contour) it.next ();
for (Iterator it2 = contour.iterator(); it2.hasNext (); ) {
Cross c = (Cross) it2.next ();
if ((!iCrossesOnly) || (c instanceof IntersectionCross)) {
outlineDebugger.cscanCross (c.x, c.y); }}}
}
//
// private Color[] colors = {Color.RED, Color.GREEN};
//
// public void paintEdges (Graphics2D g2) {
// for (Iterator contoursIterator = contours.iterator (); contoursIterator.hasNext (); ) {
// Contour contour = (Contour) contoursIterator.next ();
// int c = 0;
// for (Contour.EdgeIterator edgeIterator = contour.iterateEdges (); edgeIterator.hasNext (); ) {
// edgeIterator.next ();
// Cross cc1 = edgeIterator.c1 ();
// Cross cc2 = edgeIterator.c2 ();
//
// g2.setColor (colors [c]);
// c = (c + 1) % colors.length;
// g2.draw (new Line2D.Double (cc1.x, cc1.y, cc2.x, cc2.y)); }}
// }
//
// public void paintSnappedOutline (Graphics2D g2) {
// final double width = 0.06;
// final double offset = 0.03 + width / 2.0d ;
//
// g2.setColor (Color.RED);
// g2.setStroke (new BasicStroke ((float) (width)));
//
// for (Iterator contoursIterator = contours.iterator (); contoursIterator.hasNext (); ) {
// Contour contour = (Contour) contoursIterator.next ();
//
// for (Contour.IntersectionEdgeIterator edgeIterator = contour.iterateIntersectionEdges (); edgeIterator.hasNext (); ) {
// edgeIterator.next ();
// IntersectionCross c1 = edgeIterator.c1 ();
// IntersectionCross c2 = edgeIterator.c2 ();
//
// double x1, y1, ymid, x2, y2;
//
// x1 = c1.xPixel;
// y1 = c1.y;
// x2 = c2.xPixel;
// y2 = c2.y;
//
// Cross c3 = c1.contour.adjacentCross(c1, Contour.FORWARD);
// if (c3.y < c1.y) {
// ymid = Math.floor (c1.y);
// ymid += ((x2 > x1) ? -offset : +offset); }
// else {
// ymid = Math.ceil (c1.y);
// ymid += ((x2 < x1) ? +offset : -offset); }
//
// x1 += (c1.isLeftInRun() ? -offset : +offset);
// x2 += (c2.isLeftInRun() ? -offset : +offset);
//
// g2.draw (new Line2D.Double (x1, y1, x1, ymid));
// g2.draw (new Line2D.Double (x1, ymid, x2, ymid));
// g2.draw (new Line2D.Double (x2, ymid, x2, y2)); }}
// }
//
// public void paintDropouts (Graphics2D g2) {
// if (configuration.drawHDropouts) {
// for (int y = firstScanline; y <= lastScanline; y++) {
// SortedSet/**/ crosses = getScanline (y);
// for (Iterator it = crosses.iterator(); it.hasNext (); ) {
// IntersectionCross c1 = (IntersectionCross) it.next ();
// IntersectionCross c2 = (IntersectionCross) it.next ();
// if (c1.xPixel == c2.xPixel) {
// drawDropout (g2, c1.xPixel, c1.y, true); }}}}
//
// if (configuration.drawVDropouts) {
// for (Iterator contoursIterator = contours.iterator (); contoursIterator.hasNext (); ) {
// Contour contour = (Contour) contoursIterator.next ();
//
// for (Contour.IntersectionEdgeIterator it = contour.iterateIntersectionEdges(); it.hasNext(); ) {
// it.next();
// IntersectionCross c1 = it.c1();
// IntersectionCross c2 = it.c2();
//
// double ymid;
// { Cross c3 = c1.contour.adjacentCross(c1, Contour.FORWARD);
// if (c3.y < c1.y) {
// ymid = Math.floor (c1.y); }
// else {
// ymid = Math.ceil (c1.y); }}
//
// if (c1.x > c2.x) {
// IntersectionCross tmp = c1; c1 = c2; c2 = tmp; }
//
// if (c1.isLeftInRun ()) {
// IntersectionCross c = c1;
// while (c != null && c.xPixel < c2.xPixel) {
// IntersectionCross cr = c.rightInRun ();
// if (! c.isLeftInRun ()) {
// dropouts (g2,
// c.xPixel,
// (cr != null) ? Math.min (c2.xPixel, cr.xPixel) : c2.xPixel,
// ymid); }
// c = cr; }}
//
// else if (c2.y != c1.y) {
// IntersectionCross c = c2;
// while (c != null && c1.xPixel < c.xPixel) {
// IntersectionCross cl = c.leftInRun ();
// if (c.isLeftInRun ()) {
// dropouts (g2,
// (cl != null) ? Math.max (c1.xPixel, cl.xPixel) : c1.xPixel,
// c.xPixel,
// ymid); }
// c = cl; }}
//
// else if (ymid > c1.y) { // goes up and right and down on the same line, ink on the outside and above
// IntersectionCross c = leftMostAbove (c1);
//
// if (c == null) {
// dropouts (g2, c1.xPixel, c2.xPixel, ymid); }
//
// else {
// if (c1.xPixel < c.xPixel && c.isLeftInRun ()) {
// dropouts (g2, c1.xPixel, Math.min (c2.xPixel, c.xPixel), ymid); }
//
// while (c != null && c.xPixel < c2.xPixel) {
// IntersectionCross cr = c.rightInRun ();
// if (! c.isLeftInRun ()) {
// dropouts (g2,
// c.xPixel,
// (cr != null) ? Math.min (c2.xPixel, cr.xPixel) : c2.xPixel,
// ymid); }
// c = cr; }}}}}}
//
// if (configuration.drawEDropouts) {
// for (Iterator/**/ it = crossesAtXMinima.iterator (); it.hasNext (); ) {
// Cross c = (Cross) it.next ();
//
// IntersectionCross c1 = c.contour.adjacentIntersectionCross (c, Contour.FORWARD);
// if (! c1.isLeftInRun ()) {
// c1 = c1.leftInRun (); }
// IntersectionCross c2 = c.contour.adjacentIntersectionCross (c, Contour.BACKWARD);
// if (! c2.isLeftInRun ()) {
// c2 = c2.leftInRun (); }
// if (c2.xPixel < c1.xPixel) {
// c1 = c2; }
// dropouts (g2, Math.round (c.x), c1.xPixel, Math.round (c.y)); }
//
//
// for (Iterator/**/ it = crossesAtXMaxima.iterator (); it.hasNext (); ) {
// Cross c = (Cross) it.next ();
//
// IntersectionCross c1 = c.contour.adjacentIntersectionCross (c, Contour.FORWARD);
// if (! c1.isLeftInRun ()) {
// c1 = c1.leftInRun (); }
// IntersectionCross c2 = c.contour.adjacentIntersectionCross (c, Contour.BACKWARD);
// if (! c2.isLeftInRun ()) {
// c2 = c2.leftInRun (); }
// if (c1.rightInRun().xPixel < c2.rightInRun().xPixel) {
// c1 = c2; }
// dropouts (g2, c1.rightInRun().xPixel, Math.round (c.x), Math.round (c.y)); }}
// }
// private IntersectionCross leftMostAbove (IntersectionCross c) {
// SortedSet/**/ scanline = getScanline ((int) (c.y + 1));
//
// for (Iterator it = scanline.iterator (); it.hasNext (); ) {
// IntersectionCross cAbove = (IntersectionCross) it.next ();
// if (c.xPixel <= cAbove.xPixel) {
// return cAbove; }}
//
// return null;
// }
// private void dropouts (Graphics2D g2, double xleft, double xright, double y) {
// for (double x = xleft + 0.5; x < xright; x++) {
// drawDropout (g2, x, y, false); }
// }
//
// private void drawDropout (Graphics2D g2, double x, double y, boolean horizontal) {
// g2.setColor (Color.GREEN);
// final double w = 0.25;
// if (horizontal) {
// g2.fill (new Rectangle2D.Double (x-w, y-w/2.0d, 2*w, w)); }
// else {
// g2.fill (new Rectangle2D.Double (x-w/2.0d, y-w, w, 2*w)); }
// }
private final static List/**/ emptyScanline = new LinkedList ();
private List/**/ getScanline (int y) {
List/**/ scanline = (LinkedList/**/) scanLines.get (new Integer (y));
if (scanline == null) {
scanline = emptyScanline; }
return scanline;
}
//----------------------------------------------------------------------------
private ScalerDebugger outlineDebugger;
public void setDebugger (ScalerDebugger outlineDebugger) {
this.outlineDebugger = outlineDebugger;
}
}