Bug 711043 - Factor out operator type checks from the middle of feMorphology loop. r=roc a=bajaj
authorCameron McCormack <cam@mcc.id.au>
Tue, 18 Jun 2013 09:22:08 +1000
changeset 110195 0d36e01126b014df0db686da97be463737b83971
parent 110194 468f2568342c0a5d9e9d0a938fa40c7a4122a4a2
child 110196 5ec62d38e16209ba128e417a724c49cf43bacdf4
child 110198 9767fe3a101fbe202bb59cdb450f73ab48a3347e
child 110199 483c883197a8cae4bb1e792fc5ebd7d514615dec
child 110202 481c5ebc386d9f4a3f51315f2fe49caf7e27c809
push id244
push usercmccormack@mozilla.com
push dateMon, 17 Jun 2013 23:26:38 +0000
reviewersroc, bajaj
bugs711043
milestone17.0.6
Bug 711043 - Factor out operator type checks from the middle of feMorphology loop. r=roc a=bajaj
content/svg/content/src/nsSVGFilters.cpp
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -30,16 +30,17 @@
 #include "gfxMatrix.h"
 #include "imgIContainer.h"
 #include "nsNetUtil.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsSVGFilterElement.h"
 #include "nsSVGString.h"
 #include "nsSVGEffects.h"
 #include "gfxUtils.h"
+#include <algorithm>
 
 #if defined(XP_WIN) 
 // Prevent Windows redefining LoadImage
 #undef LoadImage
 #endif
 
 #define NUM_ENTRIES_IN_4x5_MATRIX 20
 
@@ -3796,16 +3797,67 @@ nsSVGFEMorphologyElement::GetRXY(int32_t
                                                   nsSVGNumberPair::eFirst) -
                      MORPHOLOGY_EPSILON);
   *aRY = NSToIntCeil(aInstance.GetPrimitiveNumber(nsSVGUtils::Y,
                                                   &mNumberPairAttributes[RADIUS],
                                                   nsSVGNumberPair::eSecond) -
                      MORPHOLOGY_EPSILON);
 }
 
+template<uint32_t Operator>
+static void
+DoMorphology(nsSVGFilterInstance* instance,
+             uint8_t* sourceData,
+             uint8_t* targetData,
+             int32_t stride,
+             const nsIntRect& rect,
+             int32_t rx,
+             int32_t ry)
+{
+  MOZ_STATIC_ASSERT(Operator == nsSVGFEMorphologyElement::SVG_OPERATOR_ERODE ||
+                    Operator == nsSVGFEMorphologyElement::SVG_OPERATOR_DILATE,
+                    "unexpected morphology operator");
+
+  volatile uint8_t extrema[4];         // RGBA magnitude of extrema
+
+  // Scan the kernel for each pixel to determine max/min RGBA values.
+  for (int32_t y = rect.y; y < rect.YMost(); y++) {
+    int32_t startY = std::max(0, y - ry);
+    // We need to read pixels not just in 'rect', which is limited to
+    // the dirty part of our filter primitive subregion, but all pixels in
+    // the given radii from the source surface, so use the surface size here.
+    int32_t endY = std::min(y + ry, instance->GetSurfaceHeight() - 1);
+    for (int32_t x = rect.x; x < rect.XMost(); x++) {
+      int32_t startX = std::max(0, x - rx);
+      int32_t endX = std::min(x + rx, instance->GetSurfaceWidth() - 1);
+      int32_t targIndex = y * stride + 4 * x;
+
+      for (int32_t i = 0; i < 4; i++) {
+        extrema[i] = sourceData[targIndex + i];
+      }
+      for (int32_t y1 = startY; y1 <= endY; y1++) {
+        for (int32_t x1 = startX; x1 <= endX; x1++) {
+          for (int32_t i = 0; i < 4; i++) {
+            uint8_t pixel = sourceData[y1 * stride + 4 * x1 + i];
+            if (Operator == nsSVGFEMorphologyElement::SVG_OPERATOR_ERODE) {
+              extrema[i] -= (extrema[i] - pixel) & -(extrema[i] > pixel);
+            } else {
+              extrema[i] -= (extrema[i] - pixel) & -(extrema[i] < pixel);
+            }
+          }
+        }
+      }
+      targetData[targIndex  ] = extrema[0];
+      targetData[targIndex+1] = extrema[1];
+      targetData[targIndex+2] = extrema[2];
+      targetData[targIndex+3] = extrema[3];
+    }
+  }
+}
+
 nsresult
 nsSVGFEMorphologyElement::Filter(nsSVGFilterInstance *instance,
                                  const nsTArray<const Image*>& aSources,
                                  const Image* aTarget,
                                  const nsIntRect& rect)
 {
   int32_t rx, ry;
   GetRXY(&rx, &ry, *instance);
@@ -3820,53 +3872,25 @@ nsSVGFEMorphologyElement::Filter(nsSVGFi
 
   // Clamp radii to prevent completely insane values:
   rx = NS_MIN(rx, 100000);
   ry = NS_MIN(ry, 100000);
 
   uint8_t* sourceData = aSources[0]->mImage->Data();
   uint8_t* targetData = aTarget->mImage->Data();
   int32_t stride = aTarget->mImage->Stride();
-  uint8_t extrema[4];         // RGBA magnitude of extrema
-  uint16_t op = mEnumAttributes[OPERATOR].GetAnimValue();
-
-  // Scan the kernel for each pixel to determine max/min RGBA values.
-  for (int32_t y = rect.y; y < rect.YMost(); y++) {
-    int32_t startY = NS_MAX(0, y - ry);
-    // We need to read pixels not just in 'rect', which is limited to
-    // the dirty part of our filter primitive subregion, but all pixels in
-    // the given radii from the source surface, so use the surface size here.
-    int32_t endY = NS_MIN(y + ry, instance->GetSurfaceHeight() - 1);
-    for (int32_t x = rect.x; x < rect.XMost(); x++) {
-      int32_t startX = NS_MAX(0, x - rx);
-      int32_t endX = NS_MIN(x + rx, instance->GetSurfaceWidth() - 1);
-      int32_t targIndex = y * stride + 4 * x;
-
-      for (int32_t i = 0; i < 4; i++) {
-        extrema[i] = sourceData[targIndex + i];
-      }
-      for (int32_t y1 = startY; y1 <= endY; y1++) {
-        for (int32_t x1 = startX; x1 <= endX; x1++) {
-          for (int32_t i = 0; i < 4; i++) {
-            uint8_t pixel = sourceData[y1 * stride + 4 * x1 + i];
-            if ((extrema[i] > pixel &&
-                 op == nsSVGFEMorphologyElement::SVG_OPERATOR_ERODE) ||
-                (extrema[i] < pixel &&
-                 op == nsSVGFEMorphologyElement::SVG_OPERATOR_DILATE)) {
-              extrema[i] = pixel;
-            }
-          }
-        }
-      }
-      targetData[targIndex  ] = extrema[0];
-      targetData[targIndex+1] = extrema[1];
-      targetData[targIndex+2] = extrema[2];
-      targetData[targIndex+3] = extrema[3];
-    }
+
+  if (mEnumAttributes[OPERATOR].GetAnimValue() == SVG_OPERATOR_ERODE) {
+    DoMorphology<SVG_OPERATOR_ERODE>(instance, sourceData, targetData, stride,
+                                     rect, rx, ry);
+  } else {
+    DoMorphology<SVG_OPERATOR_DILATE>(instance, sourceData, targetData, stride,
+                                      rect, rx, ry);
   }
+
   return NS_OK;
 }
 
 bool
 nsSVGFEMorphologyElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                     nsIAtom* aAttribute) const
 {
   return nsSVGFEMorphologyElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||