Bug 711043 - Factor out operator type checks from the middle of feMorphology loop. r=roc,a=bajaj
authorCameron McCormack <cam@mcc.id.au>
Tue, 14 May 2013 08:53:36 +1000
changeset 137777 cd634aafced67b3bc807d09bc9cea63e6e9dc74c
parent 137776 d172de3a217393ea94751f9300464d92458e0135
child 137778 366114b624352a75a6e5d00220e5db134b8819d9
push id2560
push userrocallahan@mozilla.com
push dateTue, 11 Jun 2013 21:54:33 +0000
treeherdermozilla-beta@cd634aafced6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, bajaj
bugs711043
milestone22.0
Bug 711043 - Factor out operator type checks from the middle of feMorphology loop. r=roc,a=bajaj
content/svg/content/src/SVGFEMorphologyElement.cpp
--- a/content/svg/content/src/SVGFEMorphologyElement.cpp
+++ b/content/svg/content/src/SVGFEMorphologyElement.cpp
@@ -141,16 +141,67 @@ SVGFEMorphologyElement::GetRXY(int32_t *
                                                   nsSVGNumberPair::eFirst) -
                      MORPHOLOGY_EPSILON);
   *aRY = NSToIntCeil(aInstance.GetPrimitiveNumber(SVGContentUtils::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 == SVG_OPERATOR_ERODE ||
+                    Operator == 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 == 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
 SVGFEMorphologyElement::Filter(nsSVGFilterInstance* instance,
                                const nsTArray<const Image*>& aSources,
                                const Image* aTarget,
                                const nsIntRect& rect)
 {
   int32_t rx, ry;
   GetRXY(&rx, &ry, *instance);
@@ -165,53 +216,25 @@ SVGFEMorphologyElement::Filter(nsSVGFilt
 
   // Clamp radii to prevent completely insane values:
   rx = std::min(rx, 100000);
   ry = std::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 = 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 ((extrema[i] > pixel &&
-                 op == SVG_OPERATOR_ERODE) ||
-                (extrema[i] < pixel &&
-                 op == 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
 SVGFEMorphologyElement::AttributeAffectsRendering(int32_t aNameSpaceID,
                                                   nsIAtom* aAttribute) const
 {
   return SVGFEMorphologyElementBase::AttributeAffectsRendering(aNameSpaceID, aAttribute) ||