More distance field improvements:
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 24 Mar 2014 18:34:04 +0000 (18:34 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 24 Mar 2014 18:34:04 +0000 (18:34 +0000)
- Make sure we only use the 0,0 subpixel glyph
- Copy image data into outsized buffer to ensure we capture outer edges
- Change edge dump to blend better with original glyph
- Edges are detected across >128 and <128 boundaries, or when
  there are two non-zero <128 pixels next to each other

BUG=skia:
R=robertphillips@google.com

Author: jvanverth@google.com

Review URL: https://codereview.chromium.org/208893003

git-svn-id: http://skia.googlecode.com/svn/trunk@13916 2bbb7eff-a529-9590-31e7-b0007b416f81

src/core/SkDistanceFieldGen.cpp
src/gpu/GrDistanceFieldTextContext.cpp

index f453afe..43e92ba 100755 (executable)
@@ -28,7 +28,8 @@ enum NeighborFlags {
     kNeighborFlagCount        = 8
 };
 
-// We treat an "edge" as a place where we cross from black to non-black, or vice versa.
+// We treat an "edge" as a place where we cross from >=128 to <128, or vice versa, or
+// where we have two non-zero pixels that are <128.
 // '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) {
@@ -38,18 +39,23 @@ static bool found_edge(const unsigned char* imagePtr, int width, int neighborFla
     SkASSERT(kNum8ConnectedNeighbors == kNeighborFlagCount);
 
     // search for an edge
-    bool currVal = (*imagePtr != 0);
+    unsigned char currVal = *imagePtr;
+    unsigned char currCheck = (currVal >> 7);
     for (int i = 0; i < kNum8ConnectedNeighbors; ++i) {
-        bool checkVal;
+        unsigned char neighborVal;
         if ((1 << i) & neighborFlags) {
             const unsigned char* checkPtr = imagePtr + offsets[i];
-            checkVal = (*checkPtr != 0);
+            neighborVal = *checkPtr;
         } else {
-            checkVal = false;
+            neighborVal = 0;
         }
-        SkASSERT(checkVal == 0 || checkVal == 1);
-        SkASSERT(currVal == 0 || currVal == 1);
-        if (checkVal != currVal) {
+        unsigned char neighborCheck = (neighborVal >> 7);
+        SkASSERT(currCheck == 0 || currCheck == 1);
+        SkASSERT(neighborCheck == 0 || neighborCheck == 1);
+        // if sharp transition
+        if (currCheck != neighborCheck ||
+            // or both <128 and >0
+            (!currCheck && !neighborCheck && currVal && neighborVal)) {
             return true;
         }
     }
@@ -349,10 +355,27 @@ bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField,
     unsigned char* edgePtr = (unsigned char*) edgeStorage.get();
     sk_bzero(edgePtr, dataWidth*dataHeight*sizeof(char));
 
+    SkAutoSMalloc<1024> copyStorage((width+2)*(height+2)*sizeof(char));
+    unsigned char* copyPtr = (unsigned char*) copyStorage.get();
+
+    // we copy our source image into a padded copy to ensure we catch edge transitions
+    // around the outside
+    const unsigned char* currImage = image;
+    sk_bzero(copyPtr, (width+2)*sizeof(char));
+    unsigned char* currCopy = copyPtr + width + 2;
+    for (int i = 0; i < height; ++i) {
+        *currCopy++ = 0; 
+        memcpy(currCopy, currImage, width*sizeof(char));
+        currImage += width;
+        currCopy += width;
+        *currCopy++ = 0;
+    }
+    sk_bzero(currCopy, (width+2)*sizeof(char));
+
     // copy glyph into distance field storage
-    init_glyph_data(dataPtr, edgePtr, image,
+    init_glyph_data(dataPtr, edgePtr, copyPtr,
                     dataWidth, dataHeight,
-                    width, height, pad);
+                    width+2, height+2, pad-1);
 
     // create initial distance data, particularly at edges
     init_distances(dataPtr, edgePtr, dataWidth, dataHeight);
@@ -426,10 +449,14 @@ bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField,
     for (int j = 1; j < dataHeight-1; ++j) {
         for (int i = 1; i < dataWidth-1; ++i) {
 #if DUMP_EDGE
-            unsigned char val = sk_float_round2int(255*currData->fAlpha);
+            float alpha = currData->fAlpha;
+            float edge = 0.0f;
             if (*currEdge) {
-                val = 128;
+                edge = 0.25f;
             }
+            // blend with original image
+            float result = alpha + (1.0f-alpha)*edge;
+            unsigned char val = sk_float_round2int(255*result);
             *dfPtr++ = val;
 #else
             float dist;
index 2163e64..1a422c6 100755 (executable)
@@ -372,7 +372,7 @@ void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& s
     SkFixed fy = SkScalarToFixed(y) + SK_FixedHalf;
     SkFixed fixedScale = SkScalarToFixed(sizeRatio);
     while (text < stop) {
-        const SkGlyph& glyph = glyphCacheProc(cache, &text, fx, fy);
+        const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
 
         if (glyph.fWidth) {
             this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),