Bug 711043 - Factor out operator type checks from the middle of feMorphology loop. r=roc

This commit is contained in:
Cameron McCormack 2013-05-14 08:53:36 +10:00
Родитель f1957ec7e8
Коммит 68aaee6bba
1 изменённых файлов: 58 добавлений и 35 удалений

Просмотреть файл

@ -146,6 +146,57 @@ SVGFEMorphologyElement::GetRXY(int32_t *aRX, int32_t *aRY,
MORPHOLOGY_EPSILON); 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 nsresult
SVGFEMorphologyElement::Filter(nsSVGFilterInstance* instance, SVGFEMorphologyElement::Filter(nsSVGFilterInstance* instance,
const nsTArray<const Image*>& aSources, const nsTArray<const Image*>& aSources,
@ -170,43 +221,15 @@ SVGFEMorphologyElement::Filter(nsSVGFilterInstance* instance,
uint8_t* sourceData = aSources[0]->mImage->Data(); uint8_t* sourceData = aSources[0]->mImage->Data();
uint8_t* targetData = aTarget->mImage->Data(); uint8_t* targetData = aTarget->mImage->Data();
int32_t stride = aTarget->mImage->Stride(); 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. if (mEnumAttributes[OPERATOR].GetAnimValue() == SVG_OPERATOR_ERODE) {
for (int32_t y = rect.y; y < rect.YMost(); y++) { DoMorphology<SVG_OPERATOR_ERODE>(instance, sourceData, targetData, stride,
int32_t startY = std::max(0, y - ry); rect, rx, ry);
// We need to read pixels not just in 'rect', which is limited to } else {
// the dirty part of our filter primitive subregion, but all pixels in DoMorphology<SVG_OPERATOR_DILATE>(instance, sourceData, targetData, stride,
// the given radii from the source surface, so use the surface size here. rect, rx, ry);
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];
}
} }
return NS_OK; return NS_OK;
} }