/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. *
*/
void checkValue(BitmapScopedWriteAccess& pAccess, int x, int y, Color aExpected, int& nNumberOfQuirks, int& nNumberOfErrors, bool bQuirkMode, int nColorDeltaThresh = 0)
{ constbool bColorize = false;
Color aColor = pAccess->GetPixel(y, x); int nColorDelta = deltaColor(aColor, aExpected);
if (nColorDelta <= nColorDeltaThresh)
{ if (bColorize)
pAccess->SetPixel(y, x, COL_LIGHTGREEN);
} elseif (bQuirkMode)
{
nNumberOfQuirks++; if (bColorize)
pAccess->SetPixel(y, x, COL_YELLOW);
} else
{
nNumberOfErrors++; if (bColorize)
pAccess->SetPixel(y, x, COL_LIGHTRED);
}
}
void checkValue(BitmapScopedWriteAccess& pAccess, const Point& point, Color aExpected, int& nNumberOfQuirks, int& nNumberOfErrors, bool bQuirkMode, int nColorDeltaThresh = 0)
{
checkValue(pAccess, point.getX(), point.getY(), aExpected, nNumberOfQuirks, nNumberOfErrors, bQuirkMode, nColorDeltaThresh);
}
void checkValue(BitmapScopedWriteAccess& pAccess, int x, int y, Color aExpected, int& nNumberOfQuirks, int& nNumberOfErrors, int nColorDeltaThresh, int nColorDeltaThreshQuirk = 0)
{ constbool bColorize = false;
Color aColor = pAccess->GetPixel(y, x); int nColorDelta = deltaColor(aColor, aExpected);
nColorDeltaThreshQuirk = std::max( nColorDeltaThresh, nColorDeltaThreshQuirk);
if (nColorDelta <= nColorDeltaThresh)
{ if (bColorize)
pAccess->SetPixel(y, x, COL_LIGHTGREEN);
} elseif (nColorDelta <= nColorDeltaThreshQuirk)
{
nNumberOfQuirks++; if (bColorize)
pAccess->SetPixel(y, x, COL_YELLOW);
} else
{
nNumberOfErrors++; if (bColorize)
pAccess->SetPixel(y, x, COL_LIGHTRED);
}
}
char returnDominantColor(Color aColor)
{ int aRed = aColor.GetRed(); int aGreen = aColor.GetGreen(); int aBlue = aColor.GetBlue(); if (aRed > aGreen && aRed > aBlue) return'R';
if (aGreen > aRed && aGreen > aBlue) return'G';
if(aBlue > aRed && aBlue > aGreen) return'B';
return'X'; //No Dominant Color.
}
void checkValueAA(BitmapScopedWriteAccess& pAccess, int x, int y, Color aExpected, int& nNumberOfQuirks, int& nNumberOfErrors, int nColorDeltaThresh = 64)
{ constbool bColorize = false;
Color aColor = pAccess->GetPixel(y, x); bool aColorResult = returnDominantColor(aExpected) == returnDominantColor(aColor); int nColorDelta = deltaColor(aColor, aExpected);
if (nColorDelta <= nColorDeltaThresh && aColorResult)
{ if (bColorize)
pAccess->SetPixel(y, x, COL_LIGHTGREEN);
} elseif (aColorResult)
{
nNumberOfQuirks++; if (bColorize)
pAccess->SetPixel(y, x, COL_YELLOW);
} else
{
nNumberOfErrors++; if (bColorize)
pAccess->SetPixel(y, x, COL_LIGHTRED);
}
}
// Return all colors in the rectangle and their count.
std::map<Color, int> collectColors(Bitmap& bitmap, const tools::Rectangle& rectangle)
{
std::map<Color, int> colors;
BitmapScopedWriteAccess pAccess(bitmap); for (tools::Long y = rectangle.Top(); y < rectangle.Bottom(); ++y) for (tools::Long x = rectangle.Left(); x < rectangle.Right(); ++x)
++colors[pAccess->GetPixel(y, x)]; // operator[] initializes to 0 (default ctor) if creating return colors;
}
bool checkConvexHullProperty(Bitmap& bitmap, Color constLineColor, int nWidthOffset, int nHeightOffset)
{
BitmapScopedWriteAccess pAccess(bitmap);
tools::Long thresholdWidth = pAccess->Width() - nWidthOffset;
tools::Long thresholdHeight = pAccess->Height() - nHeightOffset; for (tools::Long y = 0; y < pAccess->Height(); ++y)
{ for (tools::Long x = 0; x < pAccess->Width(); ++x)
{ /* If the shape exceeds the threshold limit of height or width or both, this would indicate that the bezier curve is not within its convex polygon and hence is faulty.
*/ if (pAccess->GetPixel(y, x) == constLineColor
&& (thresholdHeight < y || thresholdWidth < x))
{ returnfalse;
}
}
} returntrue;
}
TestResult checkRect(Bitmap& rBitmap, int aLayerNumber, Color aExpectedColor)
{
BitmapScopedWriteAccess pAccess(rBitmap);
tools::Long nHeight = pAccess->Height();
tools::Long nWidth = pAccess->Width();
if (nNumberOfQuirks > 0)
aResult = TestResult::PassedWithQuirks; if (nNumberOfErrors > 0)
aResult = TestResult::Failed; return aResult;
}
} // end anonymous namespace
const Color OutputDeviceTestCommon::constBackgroundColor(COL_LIGHTGRAY); const Color OutputDeviceTestCommon::constLineColor(COL_LIGHTBLUE); const Color OutputDeviceTestCommon::constFillColor(COL_BLUE);
TestResult OutputDeviceTestCommon::checkFilled(Bitmap& rBitmap, tools::Rectangle aRectangle, Color aExpectedColor)
{
BitmapScopedWriteAccess pAccess(rBitmap);
TestResult aResult = TestResult::Passed; int nNumberOfQuirks = 0; int nNumberOfErrors = 0;
for (tools::Long y = aRectangle.Top(); y < aRectangle.Top() + aRectangle.GetHeight(); y++)
{ for (tools::Long x = aRectangle.Left(); x < aRectangle.Left() + aRectangle.GetWidth(); x++)
{
checkValue(pAccess, x, y, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false);
}
}
if (nNumberOfQuirks > 0)
aResult = TestResult::PassedWithQuirks;
if (nNumberOfErrors > 0)
aResult = TestResult::Failed;
return aResult;
}
TestResult OutputDeviceTestCommon::checkRectangles(Bitmap& aBitmap, std::vector<Color>& aExpectedColors)
{
TestResult aReturnValue = TestResult::Passed; for (size_t i = 0; i < aExpectedColors.size(); i++)
{
TestResult eResult = checkRect(aBitmap, i, aExpectedColors[i]);
for (tools::Long x = 0; x < pAccess->Width(); x++)
{ for (tools::Long y = 0; y < pAccess->Height(); y++)
{ if (SetPixels[{ x, y }])
{ if (aEnableAA)
{ // coverity[swapped_arguments : FALSE] - this is in the correct order
checkValueAA(pAccess, y, x, constLineColor, nNumberOfQuirks, nNumberOfErrors);
} else
checkValue(pAccess, y, x, constLineColor, nNumberOfQuirks, nNumberOfErrors, true);
} else
{ if (!aEnableAA)
checkValue(pAccess, y, x, constBackgroundColor, nNumberOfQuirks, nNumberOfErrors, true);
}
}
}
if (nNumberOfQuirks > 0)
aResult = TestResult::PassedWithQuirks; if (nNumberOfErrors > 0)
aResult = TestResult::Failed; return aResult;
}
TestResult OutputDeviceTestCommon::checkBezier(Bitmap& rBitmap)
{
std::vector<Color> aExpected
{
constBackgroundColor, constBackgroundColor
}; // Check the bezier doesn't go over to the margins first // TODO extend the check with more exact assert return checkRectangles(rBitmap, aExpected);
}
for (tools::Long x = 0; x < pAccess->Width(); x++)
{ for (tools::Long y = 0; y < pAccess->Height(); ++y)
{ // coverity[swapped_arguments : FALSE] - this is in the correct order if (SetPixels[{ y, x }])
{ if (aEnableAA)
checkValueAA(pAccess, x, y, constLineColor, nNumberOfQuirks, nNumberOfErrors); else
checkValue(pAccess, x, y, constLineColor, nNumberOfQuirks, nNumberOfErrors, true);
} else
{ if (!aEnableAA)
checkValue(pAccess, x, y, constBackgroundColor, nNumberOfQuirks,
nNumberOfErrors, true);
}
}
}
if (nNumberOfQuirks > 0)
aResult = TestResult::PassedWithQuirks; if (nNumberOfErrors > 0)
aResult = TestResult::Failed; return aResult;
}
for (tools::Long x = 0; x < pAccess->Width(); x++)
{ for (tools::Long y = 0; y < pAccess->Height(); ++y)
{ // coverity[swapped_arguments : FALSE] - this is in the correct order if (SetPixels[{ y, x }])
{
checkValue(pAccess, x, y, constLineColor, nNumberOfQuirks, nNumberOfErrors, true);
} else
{
checkValue(pAccess, x, y, constBackgroundColor, nNumberOfQuirks, nNumberOfErrors, true);
}
}
}
for (tools::Long x = 0; x < pAccess->Width(); x++)
{ for (tools::Long y = 0; y < pAccess->Height(); ++y)
{ // coverity[swapped_arguments : FALSE] - this is in the correct order if (SetPixels[{ y, x }])
{
checkValue(pAccess, x, y, constLineColor, nNumberOfQuirks, nNumberOfErrors, true);
} else
{
checkValue(pAccess, x, y, constBackgroundColor, nNumberOfQuirks, nNumberOfErrors, true);
}
}
} if (nNumberOfQuirks > 0)
aResult = TestResult::PassedWithQuirks; if (nNumberOfErrors > 0 || !checkConvexHullProperty(rBitmap, constLineColor, 2, 5))
aResult = TestResult::Failed; return aResult;
}
for (tools::Long x = 0; x < pAccess->Width(); x++)
{ for (tools::Long y = 0; y < pAccess->Height(); ++y)
{ if (SetPixels[{ x, y }])
{
checkValue(pAccess, y, x, constFillColor, nNumberOfQuirks, nNumberOfErrors, true);
} else
{
checkValue(pAccess, y, x, constBackgroundColor, nNumberOfQuirks, nNumberOfErrors, true);
}
}
}
if (nNumberOfQuirks > 0)
aResult = TestResult::PassedWithQuirks; if (nNumberOfErrors > 0)
aResult = TestResult::Failed; return aResult;
}
TestResult OutputDeviceTestCommon::checkIntersectingRecs(Bitmap& rBitmap, int aLayerNumber,
Color aExpected)
{
BitmapScopedWriteAccess pAccess(rBitmap);
TestResult aResult = TestResult::Passed; int nNumberOfQuirks = 0; int nNumberOfErrors = 0;
for (int x = 4; x <= 19; ++x)
{
checkValue(pAccess, x, aLayerNumber, aExpected, nNumberOfQuirks, nNumberOfErrors, true);
}
if (nNumberOfQuirks > 0)
aResult = TestResult::PassedWithQuirks; if (nNumberOfErrors > 0)
aResult = TestResult::Failed; return aResult;
}
TestResult OutputDeviceTestCommon::checkEvenOddRuleInIntersectingRecs(Bitmap& rBitmap)
{ /* The even-odd rule would be tested via the below pattern as layers both of the constFillColor & constBackgroundColor appears in an even-odd fashion.
*/
std::vector<Color> aExpectedColors
= { constBackgroundColor, constBackgroundColor, constLineColor, constFillColor,
constFillColor, constLineColor, constBackgroundColor, constBackgroundColor,
constLineColor, constFillColor, constFillColor, constLineColor,
constBackgroundColor, constBackgroundColor, constLineColor, constFillColor,
constFillColor, constLineColor, constBackgroundColor, constBackgroundColor,
constLineColor, constFillColor, constLineColor };
TestResult aReturnValue = TestResult::Passed; for (size_t i = 0; i < aExpectedColors.size(); i++)
{
TestResult eResult = checkIntersectingRecs(rBitmap, i, aExpectedColors[i]);
if (nNumberOfQuirks > 0)
aResult = TestResult::PassedWithQuirks; if (nNumberOfErrors > 0)
aResult = TestResult::Failed; return aResult;
}
// Check 'count' pixels from (x,y) in (addX,addY) direction, the color values must not decrease. staticbool checkGradient(BitmapScopedWriteAccess& pAccess, int x, int y, int count, int addX, int addY)
{ constbool bColorize = false;
Color maxColor = COL_BLACK; for( int i = 0; i < count; ++i )
{
Color color = pAccess->GetPixel(y, x); if( color.GetRed() < maxColor.GetRed() || color.GetGreen() < maxColor.GetGreen() || color.GetBlue() < maxColor.GetBlue())
{ if (bColorize)
pAccess->SetPixel(y, x, COL_RED); returnfalse;
}
maxColor = color; if (bColorize)
pAccess->SetPixel(y, x, COL_LIGHTGREEN);
x += addX;
y += addY;
} returntrue;
}
TestResult OutputDeviceTestCommon::checkLinearGradient(Bitmap& bitmap)
{
BitmapScopedWriteAccess pAccess(bitmap);
TestResult aResult = TestResult::Passed; int nNumberOfQuirks = 0; int nNumberOfErrors = 0;
// The lowest line is missing in the default VCL implementation => quirk.
checkValue(pAccess, 1, 10, COL_WHITE, nNumberOfQuirks, nNumberOfErrors, true, 255 / 10);
checkValue(pAccess, 10, 10, COL_BLACK, nNumberOfQuirks, nNumberOfErrors, true, 255 / 10); for(int y = 1; y < 10; ++y)
{
checkValue(pAccess, 1, y, COL_WHITE, nNumberOfQuirks, nNumberOfErrors, 255 / 10);
checkValue(pAccess, 10, y, COL_BLACK, nNumberOfQuirks, nNumberOfErrors, 255 / 10);
} for(int y = 1; y < 10; ++y) if( !checkGradient( pAccess, 10, y, 10, -1, 0 )) return TestResult::Failed; if (nNumberOfQuirks > 0)
checkResult(TestResult::PassedWithQuirks, aResult); if (nNumberOfErrors > 0)
checkResult(TestResult::Failed, aResult); return aResult;
}
TestResult OutputDeviceTestCommon::checkLinearGradientAngled(Bitmap& bitmap)
{
BitmapScopedWriteAccess pAccess(bitmap);
TestResult aResult = TestResult::Passed; int nNumberOfQuirks = 0; int nNumberOfErrors = 0;
// The top-left pixel is not white but gray in the default VCL implementation => quirk.
checkValue(pAccess, 1, 1, COL_WHITE, nNumberOfQuirks, nNumberOfErrors, 50);
checkValue(pAccess, 10, 10, COL_BLACK, nNumberOfQuirks, nNumberOfErrors, 0, 255 / 10); // Bottom-right. // Main diagonal. if( !checkGradient( pAccess, 10, 10, 10, -1, -1 )) return TestResult::Failed; if (nNumberOfQuirks > 0)
checkResult(TestResult::PassedWithQuirks, aResult); if (nNumberOfErrors > 0)
checkResult(TestResult::Failed, aResult); return TestResult::Passed;
}
TestResult OutputDeviceTestCommon::checkLinearGradientBorder(Bitmap& bitmap)
{
TestResult aResult = TestResult::Passed; // Top half is border.
checkResult(checkFilled(bitmap, tools::Rectangle(Point(1, 1), Size(10, 5)), COL_WHITE), aResult);
BitmapScopedWriteAccess pAccess(bitmap); int nNumberOfQuirks = 0; int nNumberOfErrors = 0; for(int x = 1; x <= 10; ++x)
{
checkValue(pAccess, x, 10, COL_BLACK, nNumberOfQuirks, nNumberOfErrors, 255 / 10, 255 / 5); if( !checkGradient( pAccess, x, 10, 5, 0, -1 )) return TestResult::Failed;
} if (nNumberOfQuirks > 0)
checkResult(TestResult::PassedWithQuirks, aResult); if (nNumberOfErrors > 0)
checkResult(TestResult::Failed, aResult); return aResult;
}
TestResult OutputDeviceTestCommon::checkLinearGradientIntensity(Bitmap& bitmap)
{
BitmapScopedWriteAccess pAccess(bitmap);
TestResult aResult = TestResult::Passed; int nNumberOfQuirks = 0; int nNumberOfErrors = 0;
for(int x = 1; x <= 10; ++x)
{ // The gradient starts at half intensity, i.e. white's 255's are halved.
checkValue(pAccess, x, 1, Color(128,128,128), nNumberOfQuirks, nNumberOfErrors, false, 10);
checkValue(pAccess, x, 10, COL_BLACK, nNumberOfQuirks, nNumberOfErrors, 255 / 10); if( !checkGradient( pAccess, x, 10, 10, 0, -1 )) return TestResult::Failed;
} if (nNumberOfQuirks > 0)
checkResult(TestResult::PassedWithQuirks, aResult); if (nNumberOfErrors > 0)
checkResult(TestResult::Failed, aResult); return aResult;
}
TestResult OutputDeviceTestCommon::checkLinearGradientSteps(Bitmap& bitmap)
{ // Reuse the basic linear gradient check.
TestResult aResult = checkLinearGradient(bitmap); // Only 4 steps in the gradient, there should be only 4 colors. if( collectColors( bitmap, tools::Rectangle( Point( 1, 1 ), Size( 10, 10 ))).size() != 4 ) return TestResult::Failed; return aResult;
}
TestResult OutputDeviceTestCommon::checkAxialGradient(Bitmap& bitmap)
{
BitmapScopedWriteAccess pAccess(bitmap);
TestResult aResult = TestResult::Passed; int nNumberOfQuirks = 0; int nNumberOfErrors = 0;
for(int y = 1; y <= 11; ++y)
{ // Middle horizontal line is white, gradients to the sides.
checkValue(pAccess, 6, y, COL_WHITE, nNumberOfQuirks, nNumberOfErrors, 255 / 10, 255 / 5);
checkValue(pAccess, 1, y, COL_BLACK, nNumberOfQuirks, nNumberOfErrors, 255 / 10, 255 / 5);
checkValue(pAccess, 11, y, COL_BLACK, nNumberOfQuirks, nNumberOfErrors, 255 / 10, 255 / 5); if( !checkGradient( pAccess, 1, y, 6, 1, 0 )) return TestResult::Failed; if( !checkGradient( pAccess, 11, y, 6, -1, 0 )) return TestResult::Failed;
} if (nNumberOfQuirks > 0)
checkResult(TestResult::PassedWithQuirks, aResult); if (nNumberOfErrors > 0)
checkResult(TestResult::Failed, aResult); return aResult;
}
TestResult OutputDeviceTestCommon::checkRadialGradient(Bitmap& bitmap)
{
BitmapScopedWriteAccess pAccess(bitmap);
TestResult aResult = TestResult::Passed; int nNumberOfQuirks = 0; int nNumberOfErrors = 0; // The default VCL implementation is off-center in the direction to the top-left. // This means not all corners will be pure white => quirks.
checkValue(pAccess, 1, 1, COL_WHITE, nNumberOfQuirks, nNumberOfErrors, 255 / 10, 255 / 2);
checkValue(pAccess, 1, 10, COL_WHITE, nNumberOfQuirks, nNumberOfErrors, 255 / 10, 255 / 5);
checkValue(pAccess, 10, 1, COL_WHITE, nNumberOfQuirks, nNumberOfErrors, 255 / 10, 255 / 5);
checkValue(pAccess, 10, 10, COL_WHITE, nNumberOfQuirks, nNumberOfErrors, 255 / 10, 255 / 5); // And not all centers will be pure black => quirks.
checkValue(pAccess, 5, 5, COL_BLACK, nNumberOfQuirks, nNumberOfErrors, 255 / 10, 255 / 5);
checkValue(pAccess, 5, 6, COL_BLACK, nNumberOfQuirks, nNumberOfErrors, 255 / 10, 255 / 3);
checkValue(pAccess, 6, 5, COL_BLACK, nNumberOfQuirks, nNumberOfErrors, 255 / 10, 255 / 3);
checkValue(pAccess, 6, 6, COL_BLACK, nNumberOfQuirks, nNumberOfErrors, 255 / 10, 255 / 2); // Check diagonals, from the offset center. if(!checkGradient(pAccess, 5, 5, 5, -1, -1)) return TestResult::Failed; if(!checkGradient(pAccess, 5, 5, 6, 1, 1)) return TestResult::Failed; if(!checkGradient(pAccess, 5, 5, 5, 1, -1)) return TestResult::Failed; if(!checkGradient(pAccess, 5, 5, 5, -1, 1)) return TestResult::Failed; if (nNumberOfQuirks > 0)
checkResult(TestResult::PassedWithQuirks, aResult); if (nNumberOfErrors > 0)
checkResult(TestResult::Failed, aResult); return aResult;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.