Index: src/core/SkDistanceFieldGen.cpp |
diff --git a/src/core/SkDistanceFieldGen.cpp b/src/core/SkDistanceFieldGen.cpp |
index cd469a4d953077828fbaf394cd30d000c9557002..fa36bf7dd68bc8f1cce3e92aa3f9fac3cd0610e3 100755 |
--- a/src/core/SkDistanceFieldGen.cpp |
+++ b/src/core/SkDistanceFieldGen.cpp |
@@ -14,16 +14,43 @@ struct DFData { |
SkPoint fDistVector; // distance vector to nearest (so far) edge texel |
}; |
+enum NeighborFlags { |
+ kLeft_NeighborFlag = 0x01, |
+ kRight_NeighborFlag = 0x02, |
+ kTopLeft_NeighborFlag = 0x04, |
+ kTop_NeighborFlag = 0x08, |
+ kTopRight_NeighborFlag = 0x10, |
+ kBottomLeft_NeighborFlag = 0x20, |
+ kBottom_NeighborFlag = 0x40, |
+ kBottomRight_NeighborFlag = 0x80, |
+ kAll_NeighborFlags = 0xff, |
+ |
+ kNeighborFlagCount = 8 |
+}; |
+ |
// We treat an "edge" as a place where we cross from a texel >= 128 to a texel < 128, |
// or vice versa. This means we just need to check if the MSBs are different. |
-static bool found_edge(const unsigned char* imagePtr, int width) { |
+// 'neighborFlags' is used to limit the directions in which we test to avoid indexing |
+// outside of the image |
+static bool found_edge(const unsigned char* imagePtr, int width, int neighborFlags) { |
+ // the order of these should match the neighbor flags above |
+ const int kNum8ConnectedNeighbors = 8; |
const int offsets[8] = {-1, 1, -width-1, -width, -width+1, width-1, width, width+1 }; |
+ SkASSERT(kNum8ConnectedNeighbors == kNeighborFlagCount); |
// search for an edge |
- int checkVal = *imagePtr >> 7; |
- for (int i = 0; i < 8; ++i) { |
- const unsigned char* checkPtr = imagePtr + offsets[i]; |
- if (checkVal ^ (*checkPtr >> 7)) { |
+ unsigned char currVal = *imagePtr >> 7; |
+ for (int i = 0; i < kNum8ConnectedNeighbors; ++i) { |
+ unsigned char checkVal; |
+ if ((1 << i) & neighborFlags) { |
+ const unsigned char* checkPtr = imagePtr + offsets[i]; |
+ checkVal = *checkPtr >> 7; |
+ } else { |
+ checkVal = 0; |
+ } |
+ SkASSERT(checkVal == 0 || checkVal == 1); |
+ SkASSERT(currVal == 0 || currVal == 1); |
+ if (checkVal != currVal) { |
return true; |
} |
} |
@@ -46,8 +73,20 @@ static void init_glyph_data(DFData* data, unsigned char* edges, const unsigned c |
} else { |
data->fAlpha = (*image)*0.00392156862f; // 1/255 |
} |
- if (i > 0 && i < imageWidth-1 && j > 0 && j < imageHeight-1 && |
- found_edge(image, imageWidth)) { |
+ int checkMask = kAll_NeighborFlags; |
+ if (i == 0) { |
+ checkMask &= ~(kLeft_NeighborFlag|kTopLeft_NeighborFlag|kBottomLeft_NeighborFlag); |
+ } |
+ if (i == imageWidth-1) { |
+ checkMask &= ~(kRight_NeighborFlag|kTopRight_NeighborFlag|kBottomRight_NeighborFlag); |
+ } |
+ if (j == 0) { |
+ checkMask &= ~(kTopLeft_NeighborFlag|kTop_NeighborFlag|kTopRight_NeighborFlag); |
+ } |
+ if (j == imageHeight-1) { |
+ checkMask &= ~(kBottomLeft_NeighborFlag|kBottom_NeighborFlag|kBottomRight_NeighborFlag); |
+ } |
+ if (found_edge(image, imageWidth, checkMask)) { |
*edges = 255; // using 255 makes for convenient debug rendering |
} |
++data; |
@@ -268,6 +307,10 @@ static void B2(DFData* curr, int width) { |
} |
} |
+// enable this to output edge data rather than the distance field |
+#define DUMP_EDGE 0 |
+ |
+#if !DUMP_EDGE |
static unsigned char pack_distance_field_val(float dist, float distanceMagnitude) { |
if (dist <= -distanceMagnitude) { |
return 255; |
@@ -277,6 +320,7 @@ static unsigned char pack_distance_field_val(float dist, float distanceMagnitude |
return (unsigned char)((distanceMagnitude-dist)*128.0f/distanceMagnitude); |
} |
} |
+#endif |
// assumes an 8-bit image and distance field |
bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField, |
@@ -382,14 +426,21 @@ bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField, |
unsigned char *dfPtr = distanceField; |
for (int j = 1; j < dataHeight-1; ++j) { |
for (int i = 1; i < dataWidth-1; ++i) { |
+#if DUMP_EDGE |
+ unsigned char val = (currData->fAlpha >= 0.5f) ? 255 : 0; |
+ if (*currEdge) { |
+ val = 128; |
+ } |
+ *dfPtr++ = val; |
+#else |
float dist; |
if (currData->fAlpha > 0.5f) { |
dist = -SkScalarSqrt(currData->fDistSq); |
} else { |
dist = SkScalarSqrt(currData->fDistSq); |
} |
- |
*dfPtr++ = pack_distance_field_val(dist, (float)distanceMagnitude); |
+#endif |
++currData; |
++currEdge; |
} |