* When a glyph is created, check that all its contours have the proper clockwise/counterclockwise orientation. This fixes a nasty display bug with some badly encoded fonts.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
diff --git a/src/FTContour.cpp b/src/FTContour.cpp
index 3f6653f..a998c76 100644
--- a/src/FTContour.cpp
+++ b/src/FTContour.cpp
@@ -120,16 +120,31 @@ FTPoint FTContour::ComputeOutsetPoint(FTPoint A, FTPoint B, FTPoint C)
}
-void FTContour::outsetContour()
+void FTContour::SetParity(int parity)
{
size_t size = PointCount();
FTPoint vOutset;
- for(unsigned int pointIndex = 0; pointIndex < size; ++pointIndex)
+
+ if(((parity & 1) && clockwise) || !(parity & 1) && !clockwise)
{
- int prev = (pointIndex%size + size - 1) % size;
- int cur = pointIndex%size;
- int next = (pointIndex%size + 1) % size;
- /* Build the outset shape with d = 1.0f */
+ // Contour orientation is wrong! We must reverse all points.
+ // FIXME: could it be worth writing FTVector::reverse() for this?
+ for(size_t i = 0; i < size / 2; i++)
+ {
+ FTPoint tmp = pointList[i];
+ pointList[i] = pointList[size - 1 - i];
+ pointList[size - 1 -i] = tmp;
+ }
+
+ clockwise = !clockwise;
+ }
+
+ for(size_t i = 0; i < size; i++)
+ {
+ int prev = (i + size - 1) % size;
+ int cur = i;
+ int next = (i + size + 1) % size;
+
vOutset = ComputeOutsetPoint(Point(prev), Point(cur), Point(next));
AddOutsetPoint(vOutset);
}
@@ -151,7 +166,7 @@ FTContour::FTContour(FT_Vector* contour, char* tags, unsigned int n)
cur = next;
next = FTPoint(contour[(i + 1) % n]);
olddir = dir;
- dir = atan2((next - cur).Y(), (next - cur).Y());
+ dir = atan2((next - cur).Y(), (next - cur).X());
// Compute our path's new direction.
double t = dir - olddir;
@@ -196,9 +211,6 @@ FTContour::FTContour(FT_Vector* contour, char* tags, unsigned int n)
// If final angle is positive (+2PI), it's an anti-clockwise contour,
// otherwise (-2PI) it's clockwise.
clockwise = (angle < 0.0);
-
- // Create (or not) front outset and/or back outset.
- outsetContour();
}
diff --git a/src/FTContour.h b/src/FTContour.h
index 36b16df..d1a3501 100644
--- a/src/FTContour.h
+++ b/src/FTContour.h
@@ -124,10 +124,14 @@ class FTContour
size_t BackPointCount() const { return backPointList.size(); }
/**
- * Create the front/back outset contour
+ * Make sure the glyph has the proper parity and create the front/back
+ * outset contour.
*
- * @param outset The outset distance
+ * @param parity The contour's parity within the glyph.
*/
+ void SetParity(int parity);
+
+ // FIXME: this should probably go away.
void buildFrontOutset(float outset);
void buildBackOutset(float outset);
@@ -170,11 +174,6 @@ class FTContour
inline void evaluateCubicCurve(FTPoint, FTPoint, FTPoint, FTPoint);
/**
- * Create the list point of the outset contour.
- */
- inline void outsetContour();
-
- /**
* Compute the vector norm
*/
inline FTGL_DOUBLE NormVector(const FTPoint &v);
diff --git a/src/FTVectoriser.cpp b/src/FTVectoriser.cpp
index 467a75e..db1d991 100644
--- a/src/FTVectoriser.cpp
+++ b/src/FTVectoriser.cpp
@@ -162,20 +162,76 @@ void FTVectoriser::ProcessContours()
contourList = new FTContour*[ftContourCount];
- for(short contourIndex = 0; contourIndex < ftContourCount; ++contourIndex)
+ for(int i = 0; i < ftContourCount; ++i)
{
FT_Vector* pointList = &outline.points[startIndex];
char* tagList = &outline.tags[startIndex];
- endIndex = outline.contours[contourIndex];
+ endIndex = outline.contours[i];
contourLength = (endIndex - startIndex) + 1;
FTContour* contour = new FTContour(pointList, tagList, contourLength);
- contourList[contourIndex] = contour;
+ contourList[i] = contour;
startIndex = endIndex + 1;
}
+
+ // Compute each contour's parity. FIXME: see if FT_Outline_Get_Orientation
+ // can do it for us.
+ for(int i = 0; i < ftContourCount; i++)
+ {
+ FTContour *c1 = contourList[i];
+
+ // 1. Find the leftmost point.
+ FTPoint leftmost(65536.0, 0.0);
+
+ for(size_t n = 0; n < c1->PointCount(); n++)
+ {
+ FTPoint p = c1->Point(n);
+ if(p.X() < leftmost.X())
+ {
+ leftmost = p;
+ }
+ }
+
+ // 2. Count how many other contours we cross when going further to
+ // the left.
+ int parity = 0;
+
+ for(int j = 0; j < ftContourCount; j++)
+ {
+ if(j == i)
+ {
+ continue;
+ }
+
+ FTContour *c2 = contourList[j];
+
+ for(size_t n = 0; n < c2->PointCount(); n++)
+ {
+ FTPoint p1 = c2->Point(n);
+ FTPoint p2 = c2->Point((n + 1) % c2->PointCount());
+
+ if((p1.Y() < leftmost.Y() && p2.Y() < leftmost.Y())
+ || (p1.Y() >= leftmost.Y() && p2.Y() >= leftmost.Y()))
+ {
+ continue;
+ }
+
+ float K = (p2.Y() - leftmost.Y()) / (p1.Y() - leftmost.Y());
+ float K2 = (p2.X() - p1.X()) / (K - 1.);
+
+ if(leftmost.X() > p1.X() - K2)
+ {
+ parity++;
+ }
+ }
+ }
+
+ // 3. Make sure the glyph has the proper parity.
+ c1->SetParity(parity);
+ }
}