switch (format)
	{
		default:
			return "all(equal(" + lhs + ", " + rhs + "))";
		case VK_FORMAT_R8_USCALED:
		case VK_FORMAT_R8_UINT:
		case VK_FORMAT_R8_SINT:
		case VK_FORMAT_R16_UINT:
		case VK_FORMAT_R16_SINT:
		case VK_FORMAT_R32_UINT:
		case VK_FORMAT_R32_SINT:
		case VK_FORMAT_R64_UINT:
		case VK_FORMAT_R64_SINT:
			return "(" + lhs + " == " + rhs + ")";
		case VK_FORMAT_R16_SFLOAT:
			if (isMinMax)
				return "(" + lhs + " == " + rhs + ")";
			else
				return "(abs(" + lhs + " - " + rhs + ") < " + formatName + "(gl_SubgroupSize==128 ? 0.2: 0.1))";
		case VK_FORMAT_R32_SFLOAT:
		case VK_FORMAT_R64_SFLOAT:
			if (isMinMax)
				return "(" + lhs + " == " + rhs + ")";
			else
				return "(abs(" + lhs + " - " + rhs + ") < (gl_SubgroupSize==128 ? 0.00002:0.00001))";
		case VK_FORMAT_R16G16_SFLOAT:
		case VK_FORMAT_R16G16B16_SFLOAT:
		case VK_FORMAT_R16G16B16A16_SFLOAT:
			if (isMinMax)
				return "all(equal(" + lhs + ", " + rhs + "))";
			else
				return "all(lessThan(abs(" + lhs + " - " + rhs + "), " + formatName + "(gl_SubgroupSize==128 ? 0.2: 0.1)))";
		case VK_FORMAT_R32G32_SFLOAT:
		case VK_FORMAT_R32G32B32_SFLOAT:
		case VK_FORMAT_R32G32B32A32_SFLOAT:
		case VK_FORMAT_R64G64_SFLOAT:
		case VK_FORMAT_R64G64B64_SFLOAT:
		case VK_FORMAT_R64G64B64A64_SFLOAT:
			if (isMinMax)
				return "all(equal(" + lhs + ", " + rhs + "))";
			else
				return "all(lessThan(abs(" + lhs + " - " + rhs + "), " + formatName + "(gl_SubgroupSize==128 ? 0.00002: 0.00001)))";
	}
}

/*------------------------------------------------------------------------
 * Vulkan Conformance Tests
 * ------------------------
 *
 *
 *
 */ /*!
 * \file
 * \brief Subgroups Tests
 */ /*--------------------------------------------------------------------*/

#include "vktSubgroupsScanHelpers.hpp"
#include "vktSubgroupsTestsUtils.hpp"

#include <string>
#include <vector>

using namespace tcu;
using namespace std;
using namespace vk;
using namespace vkt;

string getScanOpName (string prefix, string suffix, Operator op, ScanType scanType)
{
	string n;
	switch (scanType)
	{
		case SCAN_REDUCE:		n = "";				break;
		case SCAN_INCLUSIVE:	n = "Inclusive";	break;
		case SCAN_EXCLUSIVE:	n = "Exclusive";	break;
	}
	switch (op)
	{
		case OPERATOR_ADD:	n += "Add";	break;
		case OPERATOR_MUL:	n += "Mul";	break;
		case OPERATOR_MIN:	n += "Min";	break;
		case OPERATOR_MAX:	n += "Max";	break;
		case OPERATOR_AND:	n += "And";	break;
		case OPERATOR_OR:	n += "Or";	break;
		case OPERATOR_XOR:	n += "Xor";	break;
	}
	return prefix + n + suffix;
}

string getOpOperation (Operator op, VkFormat format, string lhs, string rhs)
{
	switch (op)
	{
		default:
			DE_FATAL("Unsupported op type");
			return "";
		case OPERATOR_ADD:
			return lhs + " + " + rhs;
		case OPERATOR_MUL:
			return lhs + " * " + rhs;
		case OPERATOR_MIN:
			switch (format)
			{
				default:
					return "min(" + lhs + ", " + rhs + ")";
				case VK_FORMAT_R16_SFLOAT:
				case VK_FORMAT_R32_SFLOAT:
				case VK_FORMAT_R64_SFLOAT:
					return "(isnan(" + lhs + ") ? " + rhs + " : (isnan(" + rhs + ") ? " + lhs + " : min(" + lhs + ", " + rhs + ")))";
				case VK_FORMAT_R16G16_SFLOAT:
				case VK_FORMAT_R16G16B16_SFLOAT:
				case VK_FORMAT_R16G16B16A16_SFLOAT:
				case VK_FORMAT_R32G32_SFLOAT:
				case VK_FORMAT_R32G32B32_SFLOAT:
				case VK_FORMAT_R32G32B32A32_SFLOAT:
				case VK_FORMAT_R64G64_SFLOAT:
				case VK_FORMAT_R64G64B64_SFLOAT:
				case VK_FORMAT_R64G64B64A64_SFLOAT:
					return "mix(mix(min(" + lhs + ", " + rhs + "), " + lhs + ", isnan(" + rhs + ")), " + rhs + ", isnan(" + lhs + "))";
			}
		case OPERATOR_MAX:
			switch (format)
			{
				default:
					return "max(" + lhs + ", " + rhs + ")";
				case VK_FORMAT_R16_SFLOAT:
				case VK_FORMAT_R32_SFLOAT:
				case VK_FORMAT_R64_SFLOAT:
					return "(isnan(" + lhs + ") ? " + rhs + " : (isnan(" + rhs + ") ? " + lhs + " : max(" + lhs + ", " + rhs + ")))";
				case VK_FORMAT_R16G16_SFLOAT:
				case VK_FORMAT_R16G16B16_SFLOAT:
				case VK_FORMAT_R16G16B16A16_SFLOAT:
				case VK_FORMAT_R32G32_SFLOAT:
				case VK_FORMAT_R32G32B32_SFLOAT:
				case VK_FORMAT_R32G32B32A32_SFLOAT:
				case VK_FORMAT_R64G64_SFLOAT:
				case VK_FORMAT_R64G64B64_SFLOAT:
				case VK_FORMAT_R64G64B64A64_SFLOAT:
					return "mix(mix(max(" + lhs + ", " + rhs + "), " + lhs + ", isnan(" + rhs + ")), " + rhs + ", isnan(" + lhs + "))";
			}
		case OPERATOR_AND:
			switch (format)
			{
				default:
					return lhs + " & " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " && " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y, " + lhs + ".z && " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y, " + lhs + ".z && " + rhs + ".z, " + lhs + ".w && " + rhs + ".w)";
			}
		case OPERATOR_OR:
			switch (format)
			{
				default:
					return lhs + " | " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " || " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y, " + lhs + ".z || " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y, " + lhs + ".z || " + rhs + ".z, " + lhs + ".w || " + rhs + ".w)";
			}
		case OPERATOR_XOR:
			switch (format)
			{
				default:
					return lhs + " ^ " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " ^^ " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y, " + lhs + ".z ^^ " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y, " + lhs + ".z ^^ " + rhs + ".z, " + lhs + ".w ^^ " + rhs + ".w)";
			}
	}
}

string getIdentity (Operator op, VkFormat format)
{
	const bool isFloat		= subgroups::isFormatFloat(format);
	const bool isInt		= subgroups::isFormatSigned(format);
	const bool isUnsigned	= subgroups::isFormatUnsigned(format);

	switch (op)
	{
		default:
			DE_FATAL("Unsupported op type");
			return "";
		case OPERATOR_ADD:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
		case OPERATOR_MUL:
			return subgroups::getFormatNameForGLSL(format) + "(1)";
		case OPERATOR_MIN:
			if (isFloat)
			{
				return subgroups::getFormatNameForGLSL(format) + "(intBitsToFloat(0x7f800000))";
			}
			else if (isInt)
			{
				switch (format)
				{
					default:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fffffff)";
					case VK_FORMAT_R8_SINT:
					case VK_FORMAT_R8G8_SINT:
					case VK_FORMAT_R8G8B8_SINT:
					case VK_FORMAT_R8G8B8A8_SINT:
					case VK_FORMAT_R8_UINT:
					case VK_FORMAT_R8G8_UINT:
					case VK_FORMAT_R8G8B8_UINT:
					case VK_FORMAT_R8G8B8A8_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7f)";
					case VK_FORMAT_R16_SINT:
					case VK_FORMAT_R16G16_SINT:
					case VK_FORMAT_R16G16B16_SINT:
					case VK_FORMAT_R16G16B16A16_SINT:
					case VK_FORMAT_R16_UINT:
					case VK_FORMAT_R16G16_UINT:
					case VK_FORMAT_R16G16B16_UINT:
					case VK_FORMAT_R16G16B16A16_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fff)";
					case VK_FORMAT_R64_SINT:
					case VK_FORMAT_R64G64_SINT:
					case VK_FORMAT_R64G64B64_SINT:
					case VK_FORMAT_R64G64B64A64_SINT:
					case VK_FORMAT_R64_UINT:
					case VK_FORMAT_R64G64_UINT:
					case VK_FORMAT_R64G64B64_UINT:
					case VK_FORMAT_R64G64B64A64_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fffffffffffffffUL)";
				}
			}
			else if (isUnsigned)
			{
				return subgroups::getFormatNameForGLSL(format) + "(-1)";
			}
			else
			{
				DE_FATAL("Unhandled case");
				return "";
			}
		case OPERATOR_MAX:
			if (isFloat)
			{
				return subgroups::getFormatNameForGLSL(format) + "(intBitsToFloat(0xff800000))";
			}
			else if (isInt)
			{
				switch (format)
				{
					default:
						return subgroups::getFormatNameForGLSL(format) + "(0x80000000)";
					case VK_FORMAT_R8_SINT:
					case VK_FORMAT_R8G8_SINT:
					case VK_FORMAT_R8G8B8_SINT:
					case VK_FORMAT_R8G8B8A8_SINT:
					case VK_FORMAT_R8_UINT:
					case VK_FORMAT_R8G8_UINT:
					case VK_FORMAT_R8G8B8_UINT:
					case VK_FORMAT_R8G8B8A8_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x80)";
					case VK_FORMAT_R16_SINT:
					case VK_FORMAT_R16G16_SINT:
					case VK_FORMAT_R16G16B16_SINT:
					case VK_FORMAT_R16G16B16A16_SINT:
					case VK_FORMAT_R16_UINT:
					case VK_FORMAT_R16G16_UINT:
					case VK_FORMAT_R16G16B16_UINT:
					case VK_FORMAT_R16G16B16A16_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x8000)";
					case VK_FORMAT_R64_SINT:
					case VK_FORMAT_R64G64_SINT:
					case VK_FORMAT_R64G64B64_SINT:
					case VK_FORMAT_R64G64B64A64_SINT:
					case VK_FORMAT_R64_UINT:
					case VK_FORMAT_R64G64_UINT:
					case VK_FORMAT_R64G64B64_UINT:
					case VK_FORMAT_R64G64B64A64_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x8000000000000000UL)";
				}
			}
			else if (isUnsigned)
			{
				return subgroups::getFormatNameForGLSL(format) + "(0)";
			}
			else
			{
				DE_FATAL("Unhandled case");
				return "";
			}
		case OPERATOR_AND:
			return subgroups::getFormatNameForGLSL(format) + "(~0)";
		case OPERATOR_OR:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
		case OPERATOR_XOR:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
	}
}

string getCompare (Operator op, VkFormat format, string lhs, string rhs)
{
	const string	formatName	= subgroups::getFormatNameForGLSL(format);
	const bool		isMinMax	= (op == OPERATOR_MIN || op == OPERATOR_MAX);


/*------------------------------------------------------------------------
 * Vulkan Conformance Tests
 * ------------------------
 *
 *
 *
 */ /*!
 * \file
 * \brief Subgroups Tests
 */ /*--------------------------------------------------------------------*/

#include "vktSubgroupsScanHelpers.hpp"
#include "vktSubgroupsTestsUtils.hpp"

#include <string>
#include <vector>

using namespace tcu;
using namespace std;
using namespace vk;
using namespace vkt;

string getScanOpName (string prefix, string suffix, Operator op, ScanType scanType)
{
	string n;
	switch (scanType)
	{
		case SCAN_REDUCE:		n = "";				break;
		case SCAN_INCLUSIVE:	n = "Inclusive";	break;
		case SCAN_EXCLUSIVE:	n = "Exclusive";	break;
	}
	switch (op)
	{
		case OPERATOR_ADD:	n += "Add";	break;
		case OPERATOR_MUL:	n += "Mul";	break;
		case OPERATOR_MIN:	n += "Min";	break;
		case OPERATOR_MAX:	n += "Max";	break;
		case OPERATOR_AND:	n += "And";	break;
		case OPERATOR_OR:	n += "Or";	break;
		case OPERATOR_XOR:	n += "Xor";	break;
	}
	return prefix + n + suffix;
}

string getOpOperation (Operator op, VkFormat format, string lhs, string rhs)
{
	switch (op)
	{
		default:
			DE_FATAL("Unsupported op type");
			return "";
		case OPERATOR_ADD:
			return lhs + " + " + rhs;
		case OPERATOR_MUL:
			return lhs + " * " + rhs;
		case OPERATOR_MIN:
			switch (format)
			{
				default:
					return "min(" + lhs + ", " + rhs + ")";
				case VK_FORMAT_R16_SFLOAT:
				case VK_FORMAT_R32_SFLOAT:
				case VK_FORMAT_R64_SFLOAT:
					return "(isnan(" + lhs + ") ? " + rhs + " : (isnan(" + rhs + ") ? " + lhs + " : min(" + lhs + ", " + rhs + ")))";
				case VK_FORMAT_R16G16_SFLOAT:
				case VK_FORMAT_R16G16B16_SFLOAT:
				case VK_FORMAT_R16G16B16A16_SFLOAT:
				case VK_FORMAT_R32G32_SFLOAT:
				case VK_FORMAT_R32G32B32_SFLOAT:
				case VK_FORMAT_R32G32B32A32_SFLOAT:
				case VK_FORMAT_R64G64_SFLOAT:
				case VK_FORMAT_R64G64B64_SFLOAT:
				case VK_FORMAT_R64G64B64A64_SFLOAT:
					return "mix(mix(min(" + lhs + ", " + rhs + "), " + lhs + ", isnan(" + rhs + ")), " + rhs + ", isnan(" + lhs + "))";
			}
		case OPERATOR_MAX:
			switch (format)
			{
				default:
					return "max(" + lhs + ", " + rhs + ")";
				case VK_FORMAT_R16_SFLOAT:
				case VK_FORMAT_R32_SFLOAT:
				case VK_FORMAT_R64_SFLOAT:
					return "(isnan(" + lhs + ") ? " + rhs + " : (isnan(" + rhs + ") ? " + lhs + " : max(" + lhs + ", " + rhs + ")))";
				case VK_FORMAT_R16G16_SFLOAT:
				case VK_FORMAT_R16G16B16_SFLOAT:
				case VK_FORMAT_R16G16B16A16_SFLOAT:
				case VK_FORMAT_R32G32_SFLOAT:
				case VK_FORMAT_R32G32B32_SFLOAT:
				case VK_FORMAT_R32G32B32A32_SFLOAT:
				case VK_FORMAT_R64G64_SFLOAT:
				case VK_FORMAT_R64G64B64_SFLOAT:
				case VK_FORMAT_R64G64B64A64_SFLOAT:
					return "mix(mix(max(" + lhs + ", " + rhs + "), " + lhs + ", isnan(" + rhs + ")), " + rhs + ", isnan(" + lhs + "))";
			}
		case OPERATOR_AND:
			switch (format)
			{
				default:
					return lhs + " & " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " && " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y, " + lhs + ".z && " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y, " + lhs + ".z && " + rhs + ".z, " + lhs + ".w && " + rhs + ".w)";
			}
		case OPERATOR_OR:
			switch (format)
			{
				default:
					return lhs + " | " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " || " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y, " + lhs + ".z || " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y, " + lhs + ".z || " + rhs + ".z, " + lhs + ".w || " + rhs + ".w)";
			}
		case OPERATOR_XOR:
			switch (format)
			{
				default:
					return lhs + " ^ " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " ^^ " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y, " + lhs + ".z ^^ " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y, " + lhs + ".z ^^ " + rhs + ".z, " + lhs + ".w ^^ " + rhs + ".w)";
			}
	}
}

string getIdentity (Operator op, VkFormat format)
{
	const bool isFloat		= subgroups::isFormatFloat(format);
	const bool isInt		= subgroups::isFormatSigned(format);
	const bool isUnsigned	= subgroups::isFormatUnsigned(format);

	switch (op)
	{
		default:
			DE_FATAL("Unsupported op type");
			return "";
		case OPERATOR_ADD:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
		case OPERATOR_MUL:
			return subgroups::getFormatNameForGLSL(format) + "(1)";
		case OPERATOR_MIN:
			if (isFloat)
			{
				return subgroups::getFormatNameForGLSL(format) + "(intBitsToFloat(0x7f800000))";
			}
			else if (isInt)
			{
				switch (format)
				{
					default:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fffffff)";
					case VK_FORMAT_R8_SINT:
					case VK_FORMAT_R8G8_SINT:
					case VK_FORMAT_R8G8B8_SINT:
					case VK_FORMAT_R8G8B8A8_SINT:
					case VK_FORMAT_R8_UINT:
					case VK_FORMAT_R8G8_UINT:
					case VK_FORMAT_R8G8B8_UINT:
					case VK_FORMAT_R8G8B8A8_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7f)";
					case VK_FORMAT_R16_SINT:
					case VK_FORMAT_R16G16_SINT:
					case VK_FORMAT_R16G16B16_SINT:
					case VK_FORMAT_R16G16B16A16_SINT:
					case VK_FORMAT_R16_UINT:
					case VK_FORMAT_R16G16_UINT:
					case VK_FORMAT_R16G16B16_UINT:
					case VK_FORMAT_R16G16B16A16_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fff)";
					case VK_FORMAT_R64_SINT:
					case VK_FORMAT_R64G64_SINT:
					case VK_FORMAT_R64G64B64_SINT:
					case VK_FORMAT_R64G64B64A64_SINT:
					case VK_FORMAT_R64_UINT:
					case VK_FORMAT_R64G64_UINT:
					case VK_FORMAT_R64G64B64_UINT:
					case VK_FORMAT_R64G64B64A64_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fffffffffffffffUL)";
				}
			}
			else if (isUnsigned)
			{
				return subgroups::getFormatNameForGLSL(format) + "(-1)";
			}
			else
			{
				DE_FATAL("Unhandled case");
				return "";
			}
		case OPERATOR_MAX:
			if (isFloat)
			{
				return subgroups::getFormatNameForGLSL(format) + "(intBitsToFloat(0xff800000))";
			}
			else if (isInt)
			{
				switch (format)
				{
					default:
						return subgroups::getFormatNameForGLSL(format) + "(0x80000000)";
					case VK_FORMAT_R8_SINT:
					case VK_FORMAT_R8G8_SINT:
					case VK_FORMAT_R8G8B8_SINT:
					case VK_FORMAT_R8G8B8A8_SINT:
					case VK_FORMAT_R8_UINT:
					case VK_FORMAT_R8G8_UINT:
					case VK_FORMAT_R8G8B8_UINT:
					case VK_FORMAT_R8G8B8A8_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x80)";
					case VK_FORMAT_R16_SINT:
					case VK_FORMAT_R16G16_SINT:
					case VK_FORMAT_R16G16B16_SINT:
					case VK_FORMAT_R16G16B16A16_SINT:
					case VK_FORMAT_R16_UINT:
					case VK_FORMAT_R16G16_UINT:
					case VK_FORMAT_R16G16B16_UINT:
					case VK_FORMAT_R16G16B16A16_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x8000)";
					case VK_FORMAT_R64_SINT:
					case VK_FORMAT_R64G64_SINT:
					case VK_FORMAT_R64G64B64_SINT:
					case VK_FORMAT_R64G64B64A64_SINT:
					case VK_FORMAT_R64_UINT:
					case VK_FORMAT_R64G64_UINT:
					case VK_FORMAT_R64G64B64_UINT:
					case VK_FORMAT_R64G64B64A64_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x8000000000000000UL)";
				}
			}
			else if (isUnsigned)
			{
				return subgroups::getFormatNameForGLSL(format) + "(0)";
			}
			else
			{
				DE_FATAL("Unhandled case");
				return "";
			}
		case OPERATOR_AND:
			return subgroups::getFormatNameForGLSL(format) + "(~0)";
		case OPERATOR_OR:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
		case OPERATOR_XOR:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
	}
}

string getCompare (Operator op, VkFormat format, string lhs, string rhs)
{
	const string	formatName	= sub

	const bool		isMinMax	= (op == OPERATOR_MIN || op == OPERATOR_MAX);

	switch (format)
	{
		default:
			return "all(equal(" + lhs + ", " + rhs + "))";
		case VK_FORMAT_R8_USCALED:
		case VK_FORMAT_R8_UINT:
		case VK_FORMAT_R8_SINT:
		case VK_FORMAT_R16_UINT:
		case VK_FORMAT_R16_SINT:
		case VK_FORMAT_R32_UINT:
		case VK_FORMAT_R32_SINT:
		case VK_FORMAT_R64_UINT:
		case VK_FORMAT_R64_SINT:
			return "(" + lhs + " == " + rhs + ")";
		case VK_FORMAT_R16_SFLOAT:
			if (isMinMax)
				return "(" + lhs + " == " + rhs + ")";
			else
				return "(abs(" + lhs + " - " + rhs + ") < " + formatName + "(gl_SubgroupSize==128 ? 0.2: 0.1))";
		case VK_FORMAT_R32_SFLOAT:
		case VK_FORMAT_R64_SFLOAT:
			if (isMinMax)
				return "(" + lhs + " == " + rhs + ")";
			else
				return "(abs(" + lhs + " - " + rhs + ") < (gl_SubgroupSize==128 ? 0.00002:0.00001))";
		case VK_FORMAT_R16G16_SFLOAT:
		case VK_FORMAT_R16G16B16_SFLOAT:
		case VK_FORMAT_R16G16B16A16_SFLOAT:
			if (isMinMax)
				return "all(equal(" + lhs + ", " + rhs + "))";
			else
				return "all(lessThan(abs(" + lhs + " - " + rhs + "), " + formatName + "(gl_SubgroupSize==128 ? 0.2: 0.1)))";
		case VK_FORMAT_R32G32_SFLOAT:
		case VK_FORMAT_R32G32B32_SFLOAT:
		case VK_FORMAT_R32G32B32A32_SFLOAT:
		case VK_FORMAT_R64G64_SFLOAT:
		case VK_FORMAT_R64G64B64_SFLOAT:
		case VK_FORMAT_R64G64B64A64_SFLOAT:
			if (isMinMax)
				return "all(equal(" + lhs + ", " + rhs + "))";
			else
				return "all(lessThan(abs(" + lhs + " - " + rhs + "), " + formatName + "(gl_SubgroupSize==128 ? 0.00002: 0.00001)))";
	}
}


if (isMinMax)
				return "all(equal(" + lhs + ", " + rhs + "))";
			else
				return "all(lessThan(abs(" + lhs + " - " + rhs + "), " + formatName + "(gl_SubgroupSize==128 ? 0.00002: 0.00001)))";

/*------------------------------------------------------------------------
 * Vulkan Conformance Tests
 * ------------------------
 *
 *
 *
 */ /*!
 * \file
 * \brief Subgroups Tests
 */ /*--------------------------------------------------------------------*/

#include "vktSubgroupsScanHelpers.hpp"
#include "vktSubgroupsTestsUtils.hpp"

#include <string>
#include <vector>

using namespace tcu;
using namespace std;
using namespace vk;
using namespace vkt;

string getScanOpName (string prefix, string suffix, Operator op, ScanType scanType)
{
	string n;
	switch (scanType)
	{
		case SCAN_REDUCE:		n = "";				break;
		case SCAN_INCLUSIVE:	n = "Inclusive";	break;
		case SCAN_EXCLUSIVE:	n = "Exclusive";	break;
	}
	switch (op)
	{
		case OPERATOR_ADD:	n += "Add";	break;
		case OPERATOR_MUL:	n += "Mul";	break;
		case OPERATOR_MIN:	n += "Min";	break;
		case OPERATOR_MAX:	n += "Max";	break;
		case OPERATOR_AND:	n += "And";	break;
		case OPERATOR_OR:	n += "Or";	break;
		case OPERATOR_XOR:	n += "Xor";	break;
	}
	return prefix + n + suffix;
}

string getOpOperation (Operator op, VkFormat format, string lhs, string rhs)
{
	switch (op)
	{
		default:
			DE_FATAL("Unsupported op type");
			return "";
		case OPERATOR_ADD:
			return lhs + " + " + rhs;
		case OPERATOR_MUL:
			return lhs + " * " + rhs;
		case OPERATOR_MIN:
			switch (format)
			{
				default:
					return "min(" + lhs + ", " + rhs + ")";
				case VK_FORMAT_R16_SFLOAT:
				case VK_FORMAT_R32_SFLOAT:
				case VK_FORMAT_R64_SFLOAT:
					return "(isnan(" + lhs + ") ? " + rhs + " : (isnan(" + rhs + ") ? " + lhs + " : min(" + lhs + ", " + rhs + ")))";
				case VK_FORMAT_R16G16_SFLOAT:
				case VK_FORMAT_R16G16B16_SFLOAT:
				case VK_FORMAT_R16G16B16A16_SFLOAT:
				case VK_FORMAT_R32G32_SFLOAT:
				case VK_FORMAT_R32G32B32_SFLOAT:
				case VK_FORMAT_R32G32B32A32_SFLOAT:
				case VK_FORMAT_R64G64_SFLOAT:
				case VK_FORMAT_R64G64B64_SFLOAT:
				case VK_FORMAT_R64G64B64A64_SFLOAT:
					return "mix(mix(min(" + lhs + ", " + rhs + "), " + lhs + ", isnan(" + rhs + ")), " + rhs + ", isnan(" + lhs + "))";
			}
		case OPERATOR_MAX:
			switch (format)
			{
				default:
					return "max(" + lhs + ", " + rhs + ")";
				case VK_FORMAT_R16_SFLOAT:
				case VK_FORMAT_R32_SFLOAT:
				case VK_FORMAT_R64_SFLOAT:
					return "(isnan(" + lhs + ") ? " + rhs + " : (isnan(" + rhs + ") ? " + lhs + " : max(" + lhs + ", " + rhs + ")))";
				case VK_FORMAT_R16G16_SFLOAT:
				case VK_FORMAT_R16G16B16_SFLOAT:
				case VK_FORMAT_R16G16B16A16_SFLOAT:
				case VK_FORMAT_R32G32_SFLOAT:
				case VK_FORMAT_R32G32B32_SFLOAT:
				case VK_FORMAT_R32G32B32A32_SFLOAT:
				case VK_FORMAT_R64G64_SFLOAT:
				case VK_FORMAT_R64G64B64_SFLOAT:
				case VK_FORMAT_R64G64B64A64_SFLOAT:
					return "mix(mix(max(" + lhs + ", " + rhs + "), " + lhs + ", isnan(" + rhs + ")), " + rhs + ", isnan(" + lhs + "))";
			}
		case OPERATOR_AND:
			switch (format)
			{
				default:
					return lhs + " & " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " && " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y, " + lhs + ".z && " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y, " + lhs + ".z && " + rhs + ".z, " + lhs + ".w && " + rhs + ".w)";
			}
		case OPERATOR_OR:
			switch (format)
			{
				default:
					return lhs + " | " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " || " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y, " + lhs + ".z || " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y, " + lhs + ".z || " + rhs + ".z, " + lhs + ".w || " + rhs + ".w)";
			}
		case OPERATOR_XOR:
			switch (format)
			{
				default:
					return lhs + " ^ " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " ^^ " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y, " + lhs + ".z ^^ " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y, " + lhs + ".z ^^ " + rhs + ".z, " + lhs + ".w ^^ " + rhs + ".w)";
			}
	}
}

string getIdentity (Operator op, VkFormat format)
{
	const bool isFloat		= subgroups::isFormatFloat(format);
	const bool isInt		= subgroups::isFormatSigned(format);
	const bool isUnsigned	= subgroups::isFormatUnsigned(format);

	switch (op)
	{
		default:
			DE_FATAL("Unsupported op type");
			return "";
		case OPERATOR_ADD:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
		case OPERATOR_MUL:
			return subgroups::getFormatNameForGLSL(format) + "(1)";
		case OPERATOR_MIN:
			if (isFloat)
			{
				return subgroups::getFormatNameForGLSL(format) + "(intBitsToFloat(0x7f800000))";
			}
			else if (isInt)
			{
				switch (format)
				{
					default:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fffffff)";
					case VK_FORMAT_R8_SINT:
					case VK_FORMAT_R8G8_SINT:
					case VK_FORMAT_R8G8B8_SINT:
					case VK_FORMAT_R8G8B8A8_SINT:
					case VK_FORMAT_R8_UINT:
					case VK_FORMAT_R8G8_UINT:
					case VK_FORMAT_R8G8B8_UINT:
					case VK_FORMAT_R8G8B8A8_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7f)";
					case VK_FORMAT_R16_SINT:
					case VK_FORMAT_R16G16_SINT:
					case VK_FORMAT_R16G16B16_SINT:
					case VK_FORMAT_R16G16B16A16_SINT:
					case VK_FORMAT_R16_UINT:
					case VK_FORMAT_R16G16_UINT:
					case VK_FORMAT_R16G16B16_UINT:
					case VK_FORMAT_R16G16B16A16_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fff)";
					case VK_FORMAT_R64_SINT:
					case VK_FORMAT_R64G64_SINT:
					case VK_FORMAT_R64G64B64_SINT:
					case VK_FORMAT_R64G64B64A64_SINT:
					case VK_FORMAT_R64_UINT:
					case VK_FORMAT_R64G64_UINT:
					case VK_FORMAT_R64G64B64_UINT:
					case VK_FORMAT_R64G64B64A64_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fffffffffffffffUL)";
				}
			}
			else if (isUnsigned)
			{
				return subgroups::getFormatNameForGLSL(format) + "(-1)";
			}
			else
			{
				DE_FATAL("Unhandled case");
				return "";
			}
		case OPERATOR_MAX:
			if (isFloat)
			{
				return subgroups::getFormatNameForGLSL(format) + "(intBitsToFloat(0xff800000))";
			}
			else if (isInt)
			{
				switch (format)
				{
					default:
						return subgroups::getFormatNameForGLSL(format) + "(0x80000000)";
					case VK_FORMAT_R8_SINT:
					case VK_FORMAT_R8G8_SINT:
					case VK_FORMAT_R8G8B8_SINT:
					case VK_FORMAT_R8G8B8A8_SINT:
					case VK_FORMAT_R8_UINT:
					case VK_FORMAT_R8G8_UINT:
					case VK_FORMAT_R8G8B8_UINT:
					case VK_FORMAT_R8G8B8A8_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x80)";
					case VK_FORMAT_R16_SINT:
					case VK_FORMAT_R16G16_SINT:
					case VK_FORMAT_R16G16B16_SINT:
					case VK_FORMAT_R16G16B16A16_SINT:
					case VK_FORMAT_R16_UINT:
					case VK_FORMAT_R16G16_UINT:
					case VK_FORMAT_R16G16B16_UINT:
					case VK_FORMAT_R16G16B16A16_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x8000)";
					case VK_FORMAT_R64_SINT:
					case VK_FORMAT_R64G64_SINT:
					case VK_FORMAT_R64G64B64_SINT:
					case VK_FORMAT_R64G64B64A64_SINT:
					case VK_FORMAT_R64_UINT:
					case VK_FORMAT_R64G64_UINT:
					case VK_FORMAT_R64G64B64_UINT:
					case VK_FORMAT_R64G64B64A64_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x8000000000000000UL)";
				}
			}
			else if (isUnsigned)
			{
				return subgroups::getFormatNameForGLSL(format) + "(0)";
			}
			else
			{
				DE_FATAL("Unhandled case");
				return "";
			}
		case OPERATOR_AND:
			return subgroups::getFormatNameForGLSL(format) + "(~0)";
		case OPERATOR_OR:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
		case OPERATOR_XOR:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
	}
}

string getCompare (Operator op, VkFormat format, string lhs, string rhs)
{
	const string	formatName	= subgroups::getFormatNameForGLSL(format);
	const bool		isMinMax	= (op == OPERATOR_MIN || op == OPERATOR_MAX);

	switch (format)
	{
		default:
			return "all(equal(" + lhs + ", " + rhs + "))";
		case VK_FORMAT_R8_USCALED:
		case VK_FORMAT_R8_UINT:
		case VK_FORMAT_R8_SINT:
		case VK_FORMAT_R16_UINT:
		case VK_FORMAT_R16_SINT:
		case VK_FORMAT_R32_UINT:
		case VK_FORMAT_R32_SINT:
		case VK_FORMAT_R64_UINT:
		case VK_FORMAT_R64_SINT:
			return "(" + lhs + " == " + rhs + ")";
		case VK_FORMAT_R16_SFLOAT:
			if (isMinMax)
				return "(" + lhs + " == " + rhs + ")";
			else
				return "(abs(" + lhs + " - " + rhs + ") < " + formatName + "(gl_SubgroupSize==128 ? 0.2: 0.1))";
		case VK_FORMAT_R32_SFLOAT:
		case VK_FORMAT_R64_SFLOAT:
			if (isMinMax)
				return "(" + lhs + " == " + rhs + ")";
			else
				return "(abs(" + lhs + " - " + rhs + ") < (gl_SubgroupSize==128 ? 0.00002:0.00001))";
		case VK_FORMAT_R16G16_SFLOAT:
		case VK_FORMAT_R16G16B16_SFLOAT:
		case VK_FORMAT_R16G16B16A16_SFLOAT:
			if (isMinMax)
				return "all(equal(" + lhs + ", " + rhs + "))";
			else
				return "all(lessThan(abs(" + lhs + " - " + rhs + "), " + formatName + "(gl_SubgroupSize==128 ? 0.2: 0.1)))";
		case VK_FORMAT_R32G32_SFLOAT:
		case VK_FORMAT_R32G32B32_SFLOAT:
		case VK_FORMAT_R32G32B32A32_SFLOAT:
		case VK_FORMAT_R64G64_SFLOAT:
		case VK_FORMAT_R64G64B64_SFLOAT:
		case VK_FORMAT_R64G64B64A64_SFLOAT:


switch (op)
	{
		case OPERATOR_ADD:	n += "Add";	break;
		case OPERATOR_MUL:	n += "Mul";	break;
		case OPERATOR_MIN:	n += "Min";	break;
		case OPERATOR_MAX:	n += "Max";	break;
		case OPERATOR_AND:	n += "And";	break;
		case OPERATOR_OR:	n += "Or";	break;
		case OPERATOR_XOR:	n += "Xor";	break;
	}

/*------------------------------------------------------------------------
 * Vulkan Conformance Tests
 * ------------------------
 *
 *
 *
 */ /*!
 * \file
 * \brief Subgroups Tests
 */ /*--------------------------------------------------------------------*/

#include "vktSubgroupsScanHelpers.hpp"
#include "vktSubgroupsTestsUtils.hpp"

#include <string>
#include <vector>

using namespace tcu;
using namespace std;
using namespace vk;
using namespace vkt;

string getScanOpName (string prefix, string suffix, Operator op, ScanType scanType)
{
	string n;
	switch (scanType)
	{
		case SCAN_REDUCE:		n = "";				break;
		case SCAN_INCLUSIVE:	n = "Inclusive";	break;
		case SCAN_EXCLUSIVE:	n = "Exclusive";	break;
	}

	return prefix + n + suffix;
}

string getOpOperation (Operator op, VkFormat format, string lhs, string rhs)
{
	switch (op)
	{
		default:
			DE_FATAL("Unsupported op type");
			return "";
		case OPERATOR_ADD:
			return lhs + " + " + rhs;
		case OPERATOR_MUL:
			return lhs + " * " + rhs;
		case OPERATOR_MIN:
			switch (format)
			{
				default:
					return "min(" + lhs + ", " + rhs + ")";
				case VK_FORMAT_R16_SFLOAT:
				case VK_FORMAT_R32_SFLOAT:
				case VK_FORMAT_R64_SFLOAT:
					return "(isnan(" + lhs + ") ? " + rhs + " : (isnan(" + rhs + ") ? " + lhs + " : min(" + lhs + ", " + rhs + ")))";
				case VK_FORMAT_R16G16_SFLOAT:
				case VK_FORMAT_R16G16B16_SFLOAT:
				case VK_FORMAT_R16G16B16A16_SFLOAT:
				case VK_FORMAT_R32G32_SFLOAT:
				case VK_FORMAT_R32G32B32_SFLOAT:
				case VK_FORMAT_R32G32B32A32_SFLOAT:
				case VK_FORMAT_R64G64_SFLOAT:
				case VK_FORMAT_R64G64B64_SFLOAT:
				case VK_FORMAT_R64G64B64A64_SFLOAT:
					return "mix(mix(min(" + lhs + ", " + rhs + "), " + lhs + ", isnan(" + rhs + ")), " + rhs + ", isnan(" + lhs + "))";
			}
		case OPERATOR_MAX:
			switch (format)
			{
				default:
					return "max(" + lhs + ", " + rhs + ")";
				case VK_FORMAT_R16_SFLOAT:
				case VK_FORMAT_R32_SFLOAT:
				case VK_FORMAT_R64_SFLOAT:
					return "(isnan(" + lhs + ") ? " + rhs + " : (isnan(" + rhs + ") ? " + lhs + " : max(" + lhs + ", " + rhs + ")))";
				case VK_FORMAT_R16G16_SFLOAT:
				case VK_FORMAT_R16G16B16_SFLOAT:
				case VK_FORMAT_R16G16B16A16_SFLOAT:
				case VK_FORMAT_R32G32_SFLOAT:
				case VK_FORMAT_R32G32B32_SFLOAT:
				case VK_FORMAT_R32G32B32A32_SFLOAT:
				case VK_FORMAT_R64G64_SFLOAT:
				case VK_FORMAT_R64G64B64_SFLOAT:
				case VK_FORMAT_R64G64B64A64_SFLOAT:
					return "mix(mix(max(" + lhs + ", " + rhs + "), " + lhs + ", isnan(" + rhs + ")), " + rhs + ", isnan(" + lhs + "))";
			}
		case OPERATOR_AND:
			switch (format)
			{
				default:
					return lhs + " & " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " && " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y, " + lhs + ".z && " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y, " + lhs + ".z && " + rhs + ".z, " + lhs + ".w && " + rhs + ".w)";
			}
		case OPERATOR_OR:
			switch (format)
			{
				default:
					return lhs + " | " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " || " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y, " + lhs + ".z || " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y, " + lhs + ".z || " + rhs + ".z, " + lhs + ".w || " + rhs + ".w)";
			}
		case OPERATOR_XOR:
			switch (format)
			{
				default:
					return lhs + " ^ " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " ^^ " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y, " + lhs + ".z ^^ " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y, " + lhs + ".z ^^ " + rhs + ".z, " + lhs + ".w ^^ " + rhs + ".w)";
			}
	}
}

string getIdentity (Operator op, VkFormat format)
{
	const bool isFloat		= subgroups::isFormatFloat(format);
	const bool isInt		= subgroups::isFormatSigned(format);
	const bool isUnsigned	= subgroups::isFormatUnsigned(format);

	switch (op)
	{
		default:
			DE_FATAL("Unsupported op type");
			return "";
		case OPERATOR_ADD:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
		case OPERATOR_MUL:
			return subgroups::getFormatNameForGLSL(format) + "(1)";
		case OPERATOR_MIN:
			if (isFloat)
			{
				return subgroups::getFormatNameForGLSL(format) + "(intBitsToFloat(0x7f800000))";
			}
			else if (isInt)
			{
				switch (format)
				{
					default:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fffffff)";
					case VK_FORMAT_R8_SINT:
					case VK_FORMAT_R8G8_SINT:
					case VK_FORMAT_R8G8B8_SINT:
					case VK_FORMAT_R8G8B8A8_SINT:
					case VK_FORMAT_R8_UINT:
					case VK_FORMAT_R8G8_UINT:
					case VK_FORMAT_R8G8B8_UINT:
					case VK_FORMAT_R8G8B8A8_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7f)";
					case VK_FORMAT_R16_SINT:
					case VK_FORMAT_R16G16_SINT:
					case VK_FORMAT_R16G16B16_SINT:
					case VK_FORMAT_R16G16B16A16_SINT:
					case VK_FORMAT_R16_UINT:
					case VK_FORMAT_R16G16_UINT:
					case VK_FORMAT_R16G16B16_UINT:
					case VK_FORMAT_R16G16B16A16_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fff)";
					case VK_FORMAT_R64_SINT:
					case VK_FORMAT_R64G64_SINT:
					case VK_FORMAT_R64G64B64_SINT:
					case VK_FORMAT_R64G64B64A64_SINT:
					case VK_FORMAT_R64_UINT:
					case VK_FORMAT_R64G64_UINT:
					case VK_FORMAT_R64G64B64_UINT:
					case VK_FORMAT_R64G64B64A64_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fffffffffffffffUL)";
				}
			}
			else if (isUnsigned)
			{
				return subgroups::getFormatNameForGLSL(format) + "(-1)";
			}
			else
			{
				DE_FATAL("Unhandled case");
				return "";
			}
		case OPERATOR_MAX:
			if (isFloat)
			{
				return subgroups::getFormatNameForGLSL(format) + "(intBitsToFloat(0xff800000))";
			}
			else if (isInt)
			{
				switch (format)
				{
					default:
						return subgroups::getFormatNameForGLSL(format) + "(0x80000000)";
					case VK_FORMAT_R8_SINT:
					case VK_FORMAT_R8G8_SINT:
					case VK_FORMAT_R8G8B8_SINT:
					case VK_FORMAT_R8G8B8A8_SINT:
					case VK_FORMAT_R8_UINT:
					case VK_FORMAT_R8G8_UINT:
					case VK_FORMAT_R8G8B8_UINT:
					case VK_FORMAT_R8G8B8A8_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x80)";
					case VK_FORMAT_R16_SINT:
					case VK_FORMAT_R16G16_SINT:
					case VK_FORMAT_R16G16B16_SINT:
					case VK_FORMAT_R16G16B16A16_SINT:
					case VK_FORMAT_R16_UINT:
					case VK_FORMAT_R16G16_UINT:
					case VK_FORMAT_R16G16B16_UINT:
					case VK_FORMAT_R16G16B16A16_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x8000)";
					case VK_FORMAT_R64_SINT:
					case VK_FORMAT_R64G64_SINT:
					case VK_FORMAT_R64G64B64_SINT:
					case VK_FORMAT_R64G64B64A64_SINT:
					case VK_FORMAT_R64_UINT:
					case VK_FORMAT_R64G64_UINT:
					case VK_FORMAT_R64G64B64_UINT:
					case VK_FORMAT_R64G64B64A64_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x8000000000000000UL)";
				}
			}
			else if (isUnsigned)
			{
				return subgroups::getFormatNameForGLSL(format) + "(0)";
			}
			else
			{
				DE_FATAL("Unhandled case");
				return "";
			}
		case OPERATOR_AND:
			return subgroups::getFormatNameForGLSL(format) + "(~0)";
		case OPERATOR_OR:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
		case OPERATOR_XOR:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
	}
}

string getCompare (Operator op, VkFormat format, string lhs, string rhs)
{
	const string	formatName	= subgroups::getFormatNameForGLSL(format);
	const bool		isMinMax	= (op == OPERATOR_MIN || op == OPERATOR_MAX);

	switch (format)
	{
		default:
			return "all(equal(" + lhs + ", " + rhs + "))";
		case VK_FORMAT_R8_USCALED:
		case VK_FORMAT_R8_UINT:
		case VK_FORMAT_R8_SINT:
		case VK_FORMAT_R16_UINT:
		case VK_FORMAT_R16_SINT:
		case VK_FORMAT_R32_UINT:
		case VK_FORMAT_R32_SINT:
		case VK_FORMAT_R64_UINT:
		case VK_FORMAT_R64_SINT:
			return "(" + lhs + " == " + rhs + ")";
		case VK_FORMAT_R16_SFLOAT:
			if (isMinMax)
				return "(" + lhs + " == " + rhs + ")";
			else
				return "(abs(" + lhs + " - " + rhs + ") < " + formatName + "(gl_SubgroupSize==128 ? 0.2: 0.1))";
		case VK_FORMAT_R32_SFLOAT:
		case VK_FORMAT_R64_SFLOAT:
			if (isMinMax)
				return "(" + lhs + " == " + rhs + ")";
			else
				return "(abs(" + lhs + " - " + rhs + ") < (gl_SubgroupSize==128 ? 0.00002:0.00001))";
		case VK_FORMAT_R16G16_SFLOAT:
		case VK_FORMAT_R16G16B16_SFLOAT:
		case VK_FORMAT_R16G16B16A16_SFLOAT:
			if (isMinMax)
				return "all(equal(" + lhs + ", " + rhs + "))";
			else
				return "all(lessThan(abs(" + lhs + " - " + rhs + "), " + formatName + "(gl_SubgroupSize==128 ? 0.2: 0.1)))";
		case VK_FORMAT_R32G32_SFLOAT:
		case VK_FORMAT_R32G32B32_SFLOAT:
		case VK_FORMAT_R32G32B32A32_SFLOAT:
		case VK_FORMAT_R64G64_SFLOAT:
		case VK_FORMAT_R64G64B64_SFLOAT:
		case VK_FORMAT_R64G64B64A64_SFLOAT:
			if (isMinMax)
				return "all(equal(" + lhs + ", " + rhs + "))";
			else
				return "all(lessThan(abs(" + lhs + " - " + rhs + "), " + formatName + "(gl_SubgroupSize==128 ? 0.00002: 0.00001)))";
	}
}


/*------------------------------------------------------------------------
 * Vulkan Conformance Tests
 * ------------------------
 *
 *
 *
 */ /*!
 * \file
 * \brief Subgroups Tests
 */ /*--------------------------------------------------------------------*/

#include "vktSubgroupsScanHelpers.hpp"
#include "vktSubgroupsTestsUtils.hpp"

#include <string>
#include <vector>

using namespace tcu;
using namespace std;
using namespace vk;
using namespace vkt;

string getScanOpName (string prefix, string suffix, Operator op, ScanType scanType)
{
	string n;
	switch (scanType)
	{
		case SCAN_REDUCE:		n = "";				break;
		case SCAN_INCLUSIVE:	n = "Inclusive";	break;
		case SCAN_EXCLUSIVE:	n = "Exclusive";	break;
	}
	switch (op)
	{
		case OPERATOR_ADD:	n += "Add";	break;
		case OPERATOR_MUL:	n += "Mul";	break;
		case OPERATOR_MIN:	n += "Min";	break;
		case OPERATOR_MAX:	n += "Max";	break;
		case OPERATOR_AND:	n += "And";	break;
		case OPERATOR_OR:	n += "Or";	break;
		case OPERATOR_XOR:	n += "Xor";	break;
	}
	return prefix + n + suffix;
}

string getOpOperation (Operator op, VkFormat format, string lhs, string rhs)
{
	switch (op)
	{
		default:
			DE_FATAL("Unsupported op type");
			return "";
		case OPERATOR_ADD:
			return lhs + " + " + rhs;
		case OPERATOR_MUL:
			return lhs + " * " + rhs;
		case OPERATOR_MIN:
			switch (format)
			{
				default:
					return "min(" + lhs + ", " + rhs + ")";
				case VK_FORMAT_R16_SFLOAT:
				case VK_FORMAT_R32_SFLOAT:
				case VK_FORMAT_R64_SFLOAT:
					return "(isnan(" + lhs + ") ? " + rhs + " : (isnan(" + rhs + ") ? " + lhs + " : min(" + lhs + ", " + rhs + ")))";
				case VK_FORMAT_R16G16_SFLOAT:
				case VK_FORMAT_R16G16B16_SFLOAT:
				case VK_FORMAT_R16G16B16A16_SFLOAT:
				case VK_FORMAT_R32G32_SFLOAT:
				case VK_FORMAT_R32G32B32_SFLOAT:
				case VK_FORMAT_R32G32B32A32_SFLOAT:
				case VK_FORMAT_R64G64_SFLOAT:
				case VK_FORMAT_R64G64B64_SFLOAT:
				case VK_FORMAT_R64G64B64A64_SFLOAT:
					return "mix(mix(min(" + lhs + ", " + rhs + "), " + lhs + ", isnan(" + rhs + ")), " + rhs + ", isnan(" + lhs + "))";
			}
		case OPERATOR_MAX:
			switch (format)
			{
				default:
					return "max(" + lhs + ", " + rhs + ")";
				case VK_FORMAT_R16_SFLOAT:
				case VK_FORMAT_R32_SFLOAT:
				case VK_FORMAT_R64_SFLOAT:
					return "(isnan(" + lhs + ") ? " + rhs + " : (isnan(" + rhs + ") ? " + lhs + " : max(" + lhs + ", " + rhs + ")))";
				case VK_FORMAT_R16G16_SFLOAT:
				case VK_FORMAT_R16G16B16_SFLOAT:
				case VK_FORMAT_R16G16B16A16_SFLOAT:
				case VK_FORMAT_R32G32_SFLOAT:
				case VK_FORMAT_R32G32B32_SFLOAT:
				case VK_FORMAT_R32G32B32A32_SFLOAT:
				case VK_FORMAT_R64G64_SFLOAT:
				case VK_FORMAT_R64G64B64_SFLOAT:
				case VK_FORMAT_R64G64B64A64_SFLOAT:
					return "mix(mix(max(" + lhs + ", " + rhs + "), " + lhs + ", isnan(" + rhs + ")), " + rhs + ", isnan(" + lhs + "))";
			}
		case OPERATOR_AND:
			switch (format)
			{
				default:
					return lhs + " & " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " && " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y, " + lhs + ".z && " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x && " + rhs + ".x, " + lhs + ".y && " + rhs + ".y, " + lhs + ".z && " + rhs + ".z, " + lhs + ".w && " + rhs + ".w)";
			}
		case OPERATOR_OR:
			switch (format)
			{
				default:
					return lhs + " | " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " || " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y, " + lhs + ".z || " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x || " + rhs + ".x, " + lhs + ".y || " + rhs + ".y, " + lhs + ".z || " + rhs + ".z, " + lhs + ".w || " + rhs + ".w)";
			}
		case OPERATOR_XOR:
			switch (format)
			{
				default:
					return lhs + " ^ " + rhs;
				case VK_FORMAT_R8_USCALED:
					return lhs + " ^^ " + rhs;
				case VK_FORMAT_R8G8_USCALED:
					return "bvec2(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y)";
				case VK_FORMAT_R8G8B8_USCALED:
					return "bvec3(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y, " + lhs + ".z ^^ " + rhs + ".z)";
				case VK_FORMAT_R8G8B8A8_USCALED:
					return "bvec4(" + lhs + ".x ^^ " + rhs + ".x, " + lhs + ".y ^^ " + rhs + ".y, " + lhs + ".z ^^ " + rhs + ".z, " + lhs + ".w ^^ " + rhs + ".w)";
			}
	}
}

string getIdentity (Operator op, VkFormat format)
{
	const bool isFloat		= subgroups::isFormatFloat(format);
	const bool isInt		= subgroups::isFormatSigned(format);
	const bool isUnsigned	= subgroups::isFormatUnsigned(format);

	switch (op)
	{
		default:
			DE_FATAL("Unsupported op type");
			return "";
		case OPERATOR_ADD:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
		case OPERATOR_MUL:
			return subgroups::getFormatNameForGLSL(format) + "(1)";
		case OPERATOR_MIN:
			if (isFloat)
			{
				return subgroups::getFormatNameForGLSL(format) + "(intBitsToFloat(0x7f800000))";
			}
			else if (isInt)
			{
				switch (format)
				{
					default:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fffffff)";
					case VK_FORMAT_R8_SINT:
					case VK_FORMAT_R8G8_SINT:
					case VK_FORMAT_R8G8B8_SINT:
					case VK_FORMAT_R8G8B8A8_SINT:
					case VK_FORMAT_R8_UINT:
					case VK_FORMAT_R8G8_UINT:
					case VK_FORMAT_R8G8B8_UINT:
					case VK_FORMAT_R8G8B8A8_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7f)";
					case VK_FORMAT_R16_SINT:
					case VK_FORMAT_R16G16_SINT:
					case VK_FORMAT_R16G16B16_SINT:
					case VK_FORMAT_R1

6G16B16A16_SINT:
					case VK_FORMAT_R16_UINT:
					case VK_FORMAT_R16G16_UINT:
					case VK_FORMAT_R16G16B16_UINT:
					case VK_FORMAT_R16G16B16A16_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fff)";
					case VK_FORMAT_R64_SINT:
					case VK_FORMAT_R64G64_SINT:
					case VK_FORMAT_R64G64B64_SINT:
					case VK_FORMAT_R64G64B64A64_SINT:
					case VK_FORMAT_R64_UINT:
					case VK_FORMAT_R64G64_UINT:
					case VK_FORMAT_R64G64B64_UINT:
					case VK_FORMAT_R64G64B64A64_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x7fffffffffffffffUL)";
				}
			}
			else if (isUnsigned)
			{
				return subgroups::getFormatNameForGLSL(format) + "(-1)";
			}
			else
			{
				DE_FATAL("Unhandled case");
				return "";
			}
		case OPERATOR_MAX:
			if (isFloat)
			{
				return subgroups::getFormatNameForGLSL(format) + "(intBitsToFloat(0xff800000))";
			}
			else if (isInt)
			{
				switch (format)
				{
					default:
						return subgroups::getFormatNameForGLSL(format) + "(0x80000000)";
					case VK_FORMAT_R8_SINT:
					case VK_FORMAT_R8G8_SINT:
					case VK_FORMAT_R8G8B8_SINT:
					case VK_FORMAT_R8G8B8A8_SINT:
					case VK_FORMAT_R8_UINT:
					case VK_FORMAT_R8G8_UINT:
					case VK_FORMAT_R8G8B8_UINT:
					case VK_FORMAT_R8G8B8A8_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x80)";
					case VK_FORMAT_R16_SINT:
					case VK_FORMAT_R16G16_SINT:
					case VK_FORMAT_R16G16B16_SINT:
					case VK_FORMAT_R16G16B16A16_SINT:
					case VK_FORMAT_R16_UINT:
					case VK_FORMAT_R16G16_UINT:
					case VK_FORMAT_R16G16B16_UINT:
					case VK_FORMAT_R16G16B16A16_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x8000)";
					case VK_FORMAT_R64_SINT:
					case VK_FORMAT_R64G64_SINT:
					case VK_FORMAT_R64G64B64_SINT:
					case VK_FORMAT_R64G64B64A64_SINT:
					case VK_FORMAT_R64_UINT:
					case VK_FORMAT_R64G64_UINT:
					case VK_FORMAT_R64G64B64_UINT:
					case VK_FORMAT_R64G64B64A64_UINT:
						return subgroups::getFormatNameForGLSL(format) + "(0x8000000000000000UL)";
				}
			}
			else if (isUnsigned)
			{
				return subgroups::getFormatNameForGLSL(format) + "(0)";
			}
			else
			{
				DE_FATAL("Unhandled case");
				return "";
			}
		case OPERATOR_AND:
			return subgroups::getFormatNameForGLSL(format) + "(~0)";
		case OPERATOR_OR:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
		case OPERATOR_XOR:
			return subgroups::getFormatNameForGLSL(format) + "(0)";
	}
}

string getCompare (Operator op, VkFormat format, string lhs, string rhs)
{
	const string	formatName	= subgroups::getFormatNameForGLSL(format);
	const bool		isMinMax	= (op == OPERATOR_MIN || op == OPERATOR_MAX);

	switch (format)
	{
		default:
			return "all(equal(" + lhs + ", " + rhs + "))";
		case VK_FORMAT_R8_USCALED:
		case VK_FORMAT_R8_UINT:
		case VK_FORMAT_R8_SINT:
		case VK_FORMAT_R16_UINT:
		case VK_FORMAT_R16_SINT:
		case VK_FORMAT_R32_UINT:
		case VK_FORMAT_R32_SINT:
		case VK_FORMAT_R64_UINT:
		case VK_FORMAT_R64_SINT:
			return "(" + lhs + " == " + rhs + ")";
		case VK_FORMAT_R16_SFLOAT:
			if (isMinMax)
				return "(" + lhs + " == " + rhs + ")";
			else
				return "(abs(" + lhs + " - " + rhs + ") < " + formatName + "(gl_SubgroupSize==128 ? 0.2: 0.1))";
		case VK_FORMAT_R32_SFLOAT:
		case VK_FORMAT_R64_SFLOAT:
			if (isMinMax)
				return "(" + lhs + " == " + rhs + ")";
			else
				return "(abs(" + lhs + " - " + rhs + ") < (gl_SubgroupSize==128 ? 0.00002:0.00001))";
		case VK_FORMAT_R16G16_SFLOAT:
		case VK_FORMAT_R16G16B16_SFLOAT:
		case VK_FORMAT_R16G16B16A16_SFLOAT:
			if (isMinMax)
				return "all(equal(" + lhs + ", " + rhs + "))";
			else
				return "all(lessThan(abs(" + lhs + " - " + rhs + "), " + formatName + "(gl_SubgroupSize==128 ? 0.2: 0.1)))";
		case VK_FORMAT_R32G32_SFLOAT:
		case VK_FORMAT_R32G32B32_SFLOAT:
		case VK_FORMAT_R32G32B32A32_SFLOAT:
		case VK_FORMAT_R64G64_SFLOAT:
		case VK_FORMAT_R64G64B64_SFLOAT:
		case VK_FORMAT_R64G64B64A64_SFLOAT:
			if (isMinMax)
				return "all(equal(" + lhs + ", " + rhs + "))";
			else
				return "all(lessThan(abs(" + lhs + " - " + rhs + "), " + formatName + "(gl_SubgroupSize==128 ? 0.00002: 0.00001)))";
	}
}


/*
 *
 */

#include "config.h"
#include "TextEncoding.h"

#include "PlatformString.h"
#include "TextCodec.h"
#include "TextEncodingRegistry.h"
#if USE(ICU_UNICODE)
#include <unicode/unorm.h>
#elif USE(QT4_UNICODE)
#include <QString>
#elif USE(GLIB_UNICODE)
#include <glib.h>
#include "GOwnPtr.h"
#endif
#include <wtf/text/CString.h>
#include <wtf/OwnPtr.h>
#include <wtf/StdLibExtras.h>

namespace WebCore {

static const TextEncoding& UTF7Encoding()
{
    static TextEncoding globalUTF7Encoding("UTF-7");
    return globalUTF7Encoding;
}

TextEncoding::TextEncoding(const char* name)
    : m_name(atomicCanonicalTextEncodingName(name))
    , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol())
{
}

TextEncoding::TextEncoding(const String& name)
    : m_name(atomicCanonicalTextEncodingName(name.characters(), name.length()))
    , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol())
{
}

String TextEncoding::decode(const char* data, size_t length, bool stopOnError, bool& sawError) const
{
    if (!m_name)
        return String();

    return newTextCodec(*this)->decode(data, length, true, stopOnError, sawError);
}

CString TextEncoding::encode(const UChar* characters, size_t length, UnencodableHandling handling) const
{
    if (!m_name)
        return CString();

    if (!length)
        return "";

#if USE(ICU_UNICODE)
    // FIXME: What's the right place to do normalization?
    // It's a little strange to do it inside the encode function.
    // Perhaps normalization should be an explicit step done before calling encode.

    const UChar* source = characters;
    size_t sourceLength = length;

    Vector<UChar> normalizedCharacters;

    UErrorCode err = U_ZERO_ERROR;
    if (unorm_quickCheck(source, sourceLength, UNORM_NFC, &err) != UNORM_YES) {
        // First try using the length of the original string, since normalization to NFC rarely increases length.
        normalizedCharacters.grow(sourceLength);
        int32_t normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), length, &err);
        if (err == U_BUFFER_OVERFLOW_ERROR) {
            err = U_ZERO_ERROR;
            normalizedCharacters.resize(normalizedLength);
            normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), normalizedLength, &err);
        }
        ASSERT(U_SUCCESS(err));

        source = normalizedCharacters.data();
        sourceLength = normalizedLength;
    }
    return newTextCodec(*this)->encode(source, sourceLength, handling);
#elif USE(QT4_UNICODE)
    QString str(reinterpret_cast<const QChar*>(characters), length);
    str = str.normalized(QString::NormalizationForm_C);
    return newTextCodec(*this)->encode(reinterpret_cast<const UChar *>(str.utf16()), str.length(), handling);
#elif USE(GLIB_UNICODE)
    GOwnPtr<char> UTF8Source;
    UTF8Source.set(g_utf16_to_utf8(characters, length, 0, 0, 0));
    if (!UTF8Source) {
        // If conversion to UTF-8 failed, try with the string without normalization
        return newTextCodec(*this)->encode(characters, length, handling);
    }

    GOwnPtr<char> UTF8Normalized;
    UTF8Normalized.set(g_utf8_normalize(UTF8Source.get(), -1, G_NORMALIZE_NFC));

    long UTF16Length;
    GOwnPtr<UChar> UTF16Normalized;
    UTF16Normalized.set(g_utf8_to_utf16(UTF8Normalized.get(), -1, 0, &UTF16Length, 0));

    return newTextCodec(*this)->encode(UTF16Normalized.get(), UTF16Length, handling);
#elif OS(WINCE)
    // normalization will be done by Windows CE API
    OwnPtr<TextCodec> textCodec = newTextCodec(*this);
    return textCodec.get() ? textCodec->encode(characters, length, handling) : CString();
#endif
}

const char* TextEncoding::domName() const
{
    if (noExtendedTextEncodingNameUsed())
        return m_name;

    // We treat EUC-KR as windows-949 (its superset), but need to expose
    // the name 'EUC-KR' because the name 'windows-949' is not recognized by
    // most Korean web servers even though they do use the encoding
    // 'windows-949' with the name 'EUC-KR'.
    // FIXME: This is not thread-safe. At the moment, this function is
    // only accessed in a single thread, but eventually has to be made
    // thread-safe along with usesVisualOrdering().
    static const char* const a = atomicCanonicalTextEncodingName("windows-949");
    if (m_name == a)
        return "EUC-KR";
    return m_name;
}

bool TextEncoding::usesVisualOrdering() const
{
    if (noExtendedTextEncodingNameUsed())
        return false;

    static const char* const a = atomicCanonicalTextEncodingName("ISO-8859-8");
    return m_name == a;
}

bool TextEncoding::isJapanese() const
{
    return isJapaneseEncoding(m_name);
}

UChar TextEncoding::backslashAsCurrencySymbol() const
{
    return shouldShowBackslashAsCurrencySymbolIn(m_name) ? 0x00A5 : '\\';
}

bool TextEncoding::isNonByteBasedEncoding() const
{
    if (noExtendedTextEncodingNameUsed()) {
        return *this == UTF16LittleEndianEncoding()
            || *this == UTF16BigEndianEncoding();
    }

    return *this == UTF16LittleEndianEncoding()
        || *this == UTF16BigEndianEncoding()
        || *this == UTF32BigEndianEncoding()
        || *this == UTF32LittleEndianEncoding();
}

bool TextEncoding::isUTF7Encoding() const
{
    if (noExtendedTextEncodingNameUsed())
        return false;

    return *this == UTF7Encoding();
}

const TextEncoding& TextEncoding::closestByteBasedEquivalent() const
{
    if (isNonByteBasedEncoding())
        return UTF8Encoding();
    return *this;
}

// HTML5 specifies that UTF-8 be used in form submission when a form is
// is a part of a document in UTF-16 probably because UTF-16 is not a
// byte-based encoding and can contain 0x00. By extension, the same
// should be done for UTF-32. In case of UTF-7, it is a byte-based encoding,
// but it's fraught with problems and we'd rather steer clear of it.
const TextEncoding& TextEncoding::encodingForFormSubmission() const
{
    if (isNonByteBasedEncoding() || isUTF7Encoding())
        return UTF8Encoding();
    return *this;
}

const TextEncoding& ASCIIEncoding()
{
    static TextEncoding globalASCIIEncoding("ASCII");
    return globalASCIIEncoding;
}

const TextEncoding& Latin1Encoding()
{
    static TextEncoding globalLatin1Encoding("latin1");
    return globalLatin1Encoding;
}

{
    static TextEncoding globalUTF16BigEndianEncoding("UTF-16BE");
    return globalUTF16BigEndianEncoding;
}

const TextEncoding& UTF16LittleEndianEncoding()
{
    static TextEncoding globalUTF16LittleEndianEncoding("UTF-16LE");
    return globalUTF16LittleEndianEncoding;
}

const TextEncoding& UTF32BigEndianEncoding()
{
    static TextEncoding globalUTF32BigEndianEncoding("UTF-32BE");
    return globalUTF32BigEndianEncoding;
}

const TextEncoding& UTF32LittleEndianEncoding()
{
    static TextEncoding globalUTF32LittleEndianEncoding("UTF-32LE");
    return globalUTF32LittleEndianEncoding;
}

const TextEncoding& UTF8Encoding()
{
    static TextEncoding globalUTF8Encoding("UTF-8");
    ASSERT(globalUTF8Encoding.isValid());
    return globalUTF8Encoding;
}

const TextEncoding& WindowsLatin1Encoding()
{
    static TextEncoding globalWindowsLatin1Encoding("WinLatin-1");
    return globalWindowsLatin1Encoding;
}

} // namespace WebCore


{
    static TextEncoding globalUTF32LittleEndianEncoding("UTF-32LE");
    return globalUTF32LittleEndianEncoding;
}

/*
 *
 */

#include "config.h"
#include "TextEncoding.h"

#include "PlatformString.h"
#include "TextCodec.h"
#include "TextEncodingRegistry.h"
#if USE(ICU_UNICODE)
#include <unicode/unorm.h>
#elif USE(QT4_UNICODE)
#include <QString>
#elif USE(GLIB_UNICODE)
#include <glib.h>
#include "GOwnPtr.h"
#endif
#include <wtf/text/CString.h>
#include <wtf/OwnPtr.h>
#include <wtf/StdLibExtras.h>

namespace WebCore {

static const TextEncoding& UTF7Encoding()
{
    static TextEncoding globalUTF7Encoding("UTF-7");
    return globalUTF7Encoding;
}

TextEncoding::TextEncoding(const char* name)
    : m_name(atomicCanonicalTextEncodingName(name))
    , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol())
{
}

TextEncoding::TextEncoding(const String& name)
    : m_name(atomicCanonicalTextEncodingName(name.characters(), name.length()))
    , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol())
{
}

String TextEncoding::decode(const char* data, size_t length, bool stopOnError, bool& sawError) const
{
    if (!m_name)
        return String();

    return newTextCodec(*this)->decode(data, length, true, stopOnError, sawError);
}

CString TextEncoding::encode(const UChar* characters, size_t length, UnencodableHandling handling) const
{
    if (!m_name)
        return CString();

    if (!length)
        return "";

#if USE(ICU_UNICODE)
    // FIXME: What's the right place to do normalization?
    // It's a little strange to do it inside the encode function.
    // Perhaps normalization should be an explicit step done before calling encode.

    const UChar* source = characters;
    size_t sourceLength = length;

    Vector<UChar> normalizedCharacters;

    UErrorCode err = U_ZERO_ERROR;
    if (unorm_quickCheck(source, sourceLength, UNORM_NFC, &err) != UNORM_YES) {
        // First try using the length of the original string, since normalization to NFC rarely increases length.
        normalizedCharacters.grow(sourceLength);
        int32_t normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), length, &err);
        if (err == U_BUFFER_OVERFLOW_ERROR) {
            err = U_ZERO_ERROR;
            normalizedCharacters.resize(normalizedLength);
            normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), normalizedLength, &err);
        }
        ASSERT(U_SUCCESS(err));

        source = normalizedCharacters.data();
        sourceLength = normalizedLength;
    }
    return newTextCodec(*this)->encode(source, sourceLength, handling);
#elif USE(QT4_UNICODE)
    QString str(reinterpret_cast<const QChar*>(characters), length);
    str = str.normalized(QString::NormalizationForm_C);
    return newTextCodec(*this)->encode(reinterpret_cast<const UChar *>(str.utf16()), str.length(), handling);
#elif USE(GLIB_UNICODE)
    GOwnPtr<char> UTF8Source;
    UTF8Source.set(g_utf16_to_utf8(characters, length, 0, 0, 0));
    if (!UTF8Source) {
        // If conversion to UTF-8 failed, try with the string without normalization
        return newTextCodec(*this)->encode(characters, length, handling);
    }

    GOwnPtr<char> UTF8Normalized;
    UTF8Normalized.set(g_utf8_normalize(UTF8Source.get(), -1, G_NORMALIZE_NFC));

    long UTF16Length;
    GOwnPtr<UChar> UTF16Normalized;
    UTF16Normalized.set(g_utf8_to_utf16(UTF8Normalized.get(), -1, 0, &UTF16Length, 0));

    return newTextCodec(*this)->encode(UTF16Normalized.get(), UTF16Length, handling);
#elif OS(WINCE)
    // normalization will be done by Windows CE API
    OwnPtr<TextCodec> textCodec = newTextCodec(*this);
    return textCodec.get() ? textCodec->encode(characters, length, handling) : CString();
#endif
}

const char* TextEncoding::domName() const
{
    if (noExtendedTextEncodingNameUsed())
        return m_name;

    // We treat EUC-KR as windows-949 (its superset), but need to expose
    // the name 'EUC-KR' because the name 'windows-949' is not recognized by
    // most Korean web servers even though they do use the encoding
    // 'windows-949' with the name 'EUC-KR'.
    // FIXME: This is not thread-safe. At the moment, this function is
    // only accessed in a single thread, but eventually has to be made
    // thread-safe along with usesVisualOrdering().
    static const char* const a = atomicCanonicalTextEncodingName("windows-949");
    if (m_name == a)
        return "EUC-KR";
    return m_name;
}

bool TextEncoding::usesVisualOrdering() const
{
    if (noExtendedTextEncodingNameUsed())
        return false;

    static const char* const a = atomicCanonicalTextEncodingName("ISO-8859-8");
    return m_name == a;
}

bool TextEncoding::isJapanese() const
{
    return isJapaneseEncoding(m_name);
}

UChar TextEncoding::backslashAsCurrencySymbol() const
{
    return shouldShowBackslashAsCurrencySymbolIn(m_name) ? 0x00A5 : '\\';
}

bool TextEncoding::isNonByteBasedEncoding() const
{
    if (noExtendedTextEncodingNameUsed()) {
        return *this == UTF16LittleEndianEncoding()
            || *this == UTF16BigEndianEncoding();
    }

    return *this == UTF16LittleEndianEncoding()
        || *this == UTF16BigEndianEncoding()
        || *this == UTF32BigEndianEncoding()
        || *this == UTF32LittleEndianEncoding();
}

bool TextEncoding::isUTF7Encoding() const
{
    if (noExtendedTextEncodingNameUsed())
        return false;

    return *this == UTF7Encoding();
}

const TextEncoding& TextEncoding::closestByteBasedEquivalent() const
{
    if (isNonByteBasedEncoding())
        return UTF8Encoding();
    return *this;
}

// HTML5 specifies that UTF-8 be used in form submission when a form is
// is a part of a document in UTF-16 probably because UTF-16 is not a
// byte-based encoding and can contain 0x00. By extension, the same
// should be done for UTF-32. In case of UTF-7, it is a byte-based encoding,
// but it's fraught with problems and we'd rather steer clear of it.
const TextEncoding& TextEncoding::encodingForFormSubmission() const
{
    if (isNonByteBasedEncoding() || isUTF7Encoding())
        return UTF8Encoding();
    return *this;
}

const TextEncoding& ASCIIEncoding()
{
    static TextEncoding globalASCIIEncoding("ASCII");
    return globalASCIIEncoding;
}

const TextEncoding& Latin1Encoding()
{
    static TextEncoding globalLatin1Encoding("latin1");
    return globalLatin1Encoding;
}

const TextEncoding& UTF16BigEndianEncoding()
{
    static TextEncoding globalUTF16BigEndianEncoding("UTF-16BE");
    return globalUTF16BigEndianEncoding;
}

const TextEncoding& UTF16LittleEndianEncoding()
{
    static TextEncoding globalUTF16LittleEndianEncoding("UTF-16LE");
    return globalUTF16LittleEndianEncoding;
}

const TextEncoding& UTF32BigEndianEncoding()
{
    static TextEncoding globalUTF32BigEndianEncoding("UTF-32BE");
    return globalUTF32BigEndianEncoding;
}

const TextEncoding& UTF32LittleEndianEncoding()

const TextEncoding& UTF8Encoding()
{
    static TextEncoding globalUTF8Encoding("UTF-8");
    ASSERT(globalUTF8Encoding.isValid());
    return globalUTF8Encoding;
}

const TextEncoding& WindowsLatin1Encoding()
{
    static TextEncoding globalWindowsLatin1Encoding("WinLatin-1");
    return globalWindowsLatin1Encoding;
}

} // namespace WebCore


/*
 *
 */

#include "config.h"
#include "TextEncoding.h"

#include "PlatformString.h"
#include "TextCodec.h"
#include "TextEncodingRegistry.h"
#if USE(ICU_UNICODE)
#include <unicode/unorm.h>
#elif USE(QT4_UNICODE)
#include <QString>
#elif USE(GLIB_UNICODE)
#include <glib.h>
#include "GOwnPtr.h"
#endif
#include <wtf/text/CString.h>
#include <wtf/OwnPtr.h>
#include <wtf/StdLibExtras.h>

namespace WebCore {

static const TextEncoding& UTF7Encoding()
{
    static TextEncoding globalUTF7Encoding("UTF-7");
    return globalUTF7Encoding;
}

TextEncoding::TextEncoding(const char* name)
    : m_name(atomicCanonicalTextEncodingName(name))
    , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol())
{
}

TextEncoding::TextEncoding(const String& name)
    : m_name(atomicCanonicalTextEncodingName(name.characters(), name.length()))
    , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol())
{
}

String TextEncoding::decode(const char* data, size_t length, bool stopOnError, bool& sawError) const
{
    if (!m_name)
        return String();

    return newTextCodec(*this)->decode(data, length, true, stopOnError, sawError);
}

CString TextEncoding::encode(const UChar* characters, size_t length, UnencodableHandling handling) const
{
    if (!m_name)
        return CString();

    if (!length)
        return "";

#if USE(ICU_UNICODE)
    // FIXME: What's the right place to do normalization?
    // It's a little strange to do it inside the encode function.
    // Perhaps normalization should be an explicit step done before calling encode.

    const UChar* source = characters;
    size_t sourceLength = length;

    Vector<UChar> normalizedCharacters;

    UErrorCode err = U_ZERO_ERROR;
    if (unorm_quickCheck(source, sourceLength, UNORM_NFC, &err) != UNORM_YES) {
        // First try using the length of the original string, since normalization to NFC rarely increases length.
        normalizedCharacters.grow(sourceLength);
        int32_t normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), length, &err);
        if (err == U_BUFFER_OVERFLOW_ERROR) {
            err = U_ZERO_ERROR;
            normalizedCharacters.resize(normalizedLength);
            normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), normalizedLength, &err);
        }
        ASSERT(U_SUCCESS(err));

        source = normalizedCharacters.data();
        sourceLength = normalizedLength;
    }
    return newTextCodec(*this)->encode(source, sourceLength, handling);
#elif USE(QT4_UNICODE)
    QString str(reinterpret_cast<const QChar*>(characters), length);
    str = str.normalized(QString::NormalizationForm_C);
    return newTextCodec(*this)->encode(reinterpret_cast<const UChar *>(str.utf16()), str.length(), handling);
#elif USE(GLIB_UNICODE)
    GOwnPtr<char> UTF8Source;
    UTF8Source.set(g_utf16_to_utf8(characters, length, 0, 0, 0));
    if (!UTF8Source) {
        // If conversion to UTF-8 failed, try with the string without normalization
        return newTextCodec(*this)->encode(characters, length, handling);
    }

    GOwnPtr<char> UTF8Normalized;
    UTF8Normalized.set(g_utf8_normalize(UTF8Source.get(), -1, G_NORMALIZE_NFC));

    long UTF16Length;
    GOwnPtr<UChar> UTF16Normalized;
    UTF16Normalized.set(g_utf8_to_utf16(UTF8Normalized.get(), -1, 0, &UTF16Length, 0));

    return newTextCodec(*this)->encode(UTF16Normalized.get(), UTF16Length, handling);
#elif OS(WINCE)
    // normalization will be done by Windows CE API
    OwnPtr<TextCodec> textCodec = newTextCodec(*this);
    return textCodec.get() ? textCodec->encode(characters, length, handling) : CString();
#endif
}

const char* TextEncoding::domName() const
{
    if (noExtendedTextEncodingNameUsed())
        return m_name;

    // We treat EUC-KR as windows-949 (its superset), but need to expose
    // the name 'EUC-KR' because the name 'windows-949' is not recognized by
    // most Korean web servers even though they do use the encoding
    // 'windows-949' with the name 'EUC-KR'.
    // FIXME: This is not thread-safe. At the moment, this function is
    // only accessed in a single thread, but eventually has to be made
    // thread-safe along with usesVisualOrdering().
    static const char* const a = atomicCanonicalTextEncodingName("windows-949");
    if (m_name == a)
        return "EUC-KR";
    return m_name;
}

bool TextEncoding::usesVisualOrdering() const

    static const char* const a = atomicCanonicalTextEncodingName("ISO-8859-8");
    return m_name == a;
}

bool TextEncoding::isJapanese() const
{
    return isJapaneseEncoding(m_name);
}

UChar TextEncoding::backslashAsCurrencySymbol() const
{
    return shouldShowBackslashAsCurrencySymbolIn(m_name) ? 0x00A5 : '\\';
}

bool TextEncoding::isNonByteBasedEncoding() const
{
    if (noExtendedTextEncodingNameUsed()) {
        return *this == UTF16LittleEndianEncoding()
            || *this == UTF16BigEndianEncoding();
    }

    return *this == UTF16LittleEndianEncoding()
        || *this == UTF16BigEndianEncoding()
        || *this == UTF32BigEndianEncoding()
        || *this == UTF32LittleEndianEncoding();
}

bool TextEncoding::isUTF7Encoding() const
{
    if (noExtendedTextEncodingNameUsed())
        return false;

    return *this == UTF7Encoding();
}

const TextEncoding& TextEncoding::closestByteBasedEquivalent() const
{
    if (isNonByteBasedEncoding())
        return UTF8Encoding();
    return *this;
}

// HTML5 specifies that UTF-8 be used in form submission when a form is
// is a part of a document in UTF-16 probably because UTF-16 is not a
// byte-based encoding and can contain 0x00. By extension, the same
// should be done for UTF-32. In case of UTF-7, it is a byte-based encoding,
// but it's fraught with problems and we'd rather steer clear of it.
const TextEncoding& TextEncoding::encodingForFormSubmission() const
{
    if (isNonByteBasedEncoding() || isUTF7Encoding())
        return UTF8Encoding();
    return *this;
}

const TextEncoding& ASCIIEncoding()
{
    static TextEncoding globalASCIIEncoding("ASCII");
    return globalASCIIEncoding;
}

const TextEncoding& Latin1Encoding()
{
    static TextEncoding globalLatin1Encoding("latin1");
    return globalLatin1Encoding;
}

const TextEncoding& UTF16BigEndianEncoding()
{
    static TextEncoding globalUTF16BigEndianEncoding("UTF-16BE");
    return globalUTF16BigEndianEncoding;
}

const TextEncoding& UTF16LittleEndianEncoding()
{
    static TextEncoding globalUTF16LittleEndianEncoding("UTF-16LE");
    return globalUTF16LittleEndianEncoding;
}

const TextEncoding& UTF32BigEndianEncoding()
{
    static TextEncoding globalUTF32BigEndianEncoding("UTF-32BE");
    return globalUTF32BigEndianEncoding;
}

const TextEncoding& UTF32LittleEndianEncoding()
{
    static TextEncoding globalUTF32LittleEndianEncoding("UTF-32LE");
    return globalUTF32LittleEndianEncoding;
}

const TextEncoding& UTF8Encoding()
{
    static TextEncoding globalUTF8Encoding("UTF-8");
    ASSERT(globalUTF8Encoding.isValid());
    return globalUTF8Encoding;
}

const TextEncoding& WindowsLatin1Encoding()
{
    static TextEncoding globalWindowsLatin1Encoding("WinLatin-1");
    return globalWindowsLatin1Encoding;
}

} // namespace WebCore


static const char* const a = atomicCanonicalTextEncodingName("ISO-8859-8");

/*
 *
 */

#include "config.h"
#include "TextEncoding.h"

#include "PlatformString.h"
#include "TextCodec.h"
#include "TextEncodingRegistry.h"
#if USE(ICU_UNICODE)
#include <unicode/unorm.h>
#elif USE(QT4_UNICODE)
#include <QString>
#elif USE(GLIB_UNICODE)
#include <glib.h>
#include "GOwnPtr.h"
#endif
#include <wtf/text/CString.h>
#include <wtf/OwnPtr.h>
#include <wtf/StdLibExtras.h>

namespace WebCore {

static const TextEncoding& UTF7Encoding()
{
    static TextEncoding globalUTF7Encoding("UTF-7");
    return globalUTF7Encoding;
}

TextEncoding::TextEncoding(const char* name)
    : m_name(atomicCanonicalTextEncodingName(name))
    , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol())
{
}

TextEncoding::TextEncoding(const String& name)
    : m_name(atomicCanonicalTextEncodingName(name.characters(), name.length()))
    , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol())
{
}

String TextEncoding::decode(const char* data, size_t length, bool stopOnError, bool& sawError) const
{
    if (!m_name)
        return String();

    return newTextCodec(*this)->decode(data, length, true, stopOnError, sawError);
}

CString TextEncoding::encode(const UChar* characters, size_t length, UnencodableHandling handling) const
{
    if (!m_name)
        return CString();

    if (!length)
        return "";

#if USE(ICU_UNICODE)
    // FIXME: What's the right place to do normalization?
    // It's a little strange to do it inside the encode function.
    // Perhaps normalization should be an explicit step done before calling encode.

    const UChar* source = characters;
    size_t sourceLength = length;

    Vector<UChar> normalizedCharacters;

    UErrorCode err = U_ZERO_ERROR;
    if (unorm_quickCheck(source, sourceLength, UNORM_NFC, &err) != UNORM_YES) {
        // First try using the length of the original string, since normalization to NFC rarely increases length.
        normalizedCharacters.grow(sourceLength);
        int32_t normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), length, &err);
        if (err == U_BUFFER_OVERFLOW_ERROR) {
            err = U_ZERO_ERROR;
            normalizedCharacters.resize(normalizedLength);
            normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), normalizedLength, &err);
        }
        ASSERT(U_SUCCESS(err));

        source = normalizedCharacters.data();
        sourceLength = normalizedLength;
    }
    return newTextCodec(*this)->encode(source, sourceLength, handling);
#elif USE(QT4_UNICODE)
    QString str(reinterpret_cast<const QChar*>(characters), length);
    str = str.normalized(QString::NormalizationForm_C);
    return newTextCodec(*this)->encode(reinterpret_cast<const UChar *>(str.utf16()), str.length(), handling);
#elif USE(GLIB_UNICODE)
    GOwnPtr<char> UTF8Source;
    UTF8Source.set(g_utf16_to_utf8(characters, length, 0, 0, 0));
    if (!UTF8Source) {
        // If conversion to UTF-8 failed, try with the string without normalization
        return newTextCodec(*this)->encode(characters, length, handling);
    }

    GOwnPtr<char> UTF8Normalized;
    UTF8Normalized.set(g_utf8_normalize(UTF8Source.get(), -1, G_NORMALIZE_NFC));

    long UTF16Length;
    GOwnPtr<UChar> UTF16Normalized;
    UTF16Normalized.set(g_utf8_to_utf16(UTF8Normalized.get(), -1, 0, &UTF16Length, 0));

    return newTextCodec(*this)->encode(UTF16Normalized.get(), UTF16Length, handling);
#elif OS(WINCE)
    // normalization will be done by Windows CE API
    OwnPtr<TextCodec> textCodec = newTextCodec(*this);
    return textCodec.get() ? textCodec->encode(characters, length, handling) : CString();
#endif
}

const char* TextEncoding::domName() const
{
    if (noExtendedTextEncodingNameUsed())
        return m_name;

    // We treat EUC-KR as windows-949 (its superset), but need to expose
    // the name 'EUC-KR' because the name 'windows-949' is not recognized by
    // most Korean web servers even though they do use the encoding
    // 'windows-949' with the name 'EUC-KR'.
    // FIXME: This is not thread-safe. At the moment, this function is
    // only accessed in a single thread, but eventually has to be made
    // thread-safe along with usesVisualOrdering().
    static const char* const a = atomicCanonicalTextEncodingName("windows-949");
    if (m_name == a)
        return "EUC-KR";
    return m_name;
}

bool TextEncoding::usesVisualOrdering() const
{
    if (noExtendedTextEncodingNameUsed())
        return false;

    return m_name == a;
}

bool TextEncoding::isJapanese() const
{
    return isJapaneseEncoding(m_name);
}

UChar TextEncoding::backslashAsCurrencySymbol() const
{
    return shouldShowBackslashAsCurrencySymbolIn(m_name) ? 0x00A5 : '\\';
}

bool TextEncoding::isNonByteBasedEncoding() const
{
    if (noExtendedTextEncodingNameUsed()) {
        return *this == UTF16LittleEndianEncoding()
            || *this == UTF16BigEndianEncoding();
    }

    return *this == UTF16LittleEndianEncoding()
        || *this == UTF16BigEndianEncoding()
        || *this == UTF32BigEndianEncoding()
        || *this == UTF32LittleEndianEncoding();
}

bool TextEncoding::isUTF7Encoding() const
{
    if (noExtendedTextEncodingNameUsed())
        return false;

    return *this == UTF7Encoding();
}

const TextEncoding& TextEncoding::closestByteBasedEquivalent() const
{
    if (isNonByteBasedEncoding())
        return UTF8Encoding();
    return *this;
}

// HTML5 specifies that UTF-8 be used in form submission when a form is
// is a part of a document in UTF-16 probably because UTF-16 is not a
// byte-based encoding and can contain 0x00. By extension, the same
// should be done for UTF-32. In case of UTF-7, it is a byte-based encoding,
// but it's fraught with problems and we'd rather steer clear of it.
const TextEncoding& TextEncoding::encodingForFormSubmission() const
{
    if (isNonByteBasedEncoding() || isUTF7Encoding())
        return UTF8Encoding();
    return *this;
}

const TextEncoding& ASCIIEncoding()
{
    static TextEncoding globalASCIIEncoding("ASCII");
    return globalASCIIEncoding;
}

const TextEncoding& Latin1Encoding()
{
    static TextEncoding globalLatin1Encoding("latin1");
    return globalLatin1Encoding;
}

const TextEncoding& UTF16BigEndianEncoding()
{
    static TextEncoding globalUTF16BigEndianEncoding("UTF-16BE");
    return globalUTF16BigEndianEncoding;
}

const TextEncoding& UTF16LittleEndianEncoding()
{
    static TextEncoding globalUTF16LittleEndianEncoding("UTF-16LE");
    return globalUTF16LittleEndianEncoding;
}

const TextEncoding& UTF32BigEndianEncoding()
{
    static TextEncoding globalUTF32BigEndianEncoding("UTF-32BE");
    return globalUTF32BigEndianEncoding;
}

const TextEncoding& UTF32LittleEndianEncoding()
{
    static TextEncoding globalUTF32LittleEndianEncoding("UTF-32LE");
    return globalUTF32LittleEndianEncoding;
}

const TextEncoding& UTF8Encoding()
{
    static TextEncoding globalUTF8Encoding("UTF-8");
    ASSERT(globalUTF8Encoding.isValid());
    return globalUTF8Encoding;
}

const TextEncoding& WindowsLatin1Encoding()
{
    static TextEncoding globalWindowsLatin1Encoding("WinLatin-1");
    return globalWindowsLatin1Encoding;
}

} // namespace WebCore


/*
 *
 */

#include "config.h"
#include "TextEncoding.h"

#include "PlatformString.h"
#include "TextCodec.h"
#include "TextEncodingRegistry.h"
#if USE(ICU_UNICODE)
#include <unicode/unorm.h>
#elif USE(QT4_UNICODE)
#include <QString>
#elif USE(GLIB_UNICODE)
#include <glib.h>
#include "GOwnPtr.h"
#endif
#include <wtf/text/CString.h>
#include <wtf/OwnPtr.h>
#include <wtf/StdLibExtras.h>

namespace WebCore {

static const TextEncoding& UTF7Encoding()
{
    static TextEncoding globalUTF7Encoding("UTF-7");
    return globalUTF7Encoding;
}

TextEncoding::TextEncoding(const char* name)
    : m_name(atomicCanonicalTextEncodingName(name))
    , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol())
{
}

TextEncoding::TextEncoding(const String& name)
    : m_name(atomicCanonicalTextEncodingName(name.characters(), name.length()))
    , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol())
{
}

String TextEncoding::decode(const char* data, size_t length, bool stopOnError, bool& sawError) const
{
    if (!m_name)
        return String();

    return newTextCodec(*this)->decode(data, length, true, stopOnError, sawError);
}

CString TextEncoding::encode(const UChar* characters, size_t length, UnencodableHandling handling) const
{
    if (!m_name)
        return CString();

    if (!length)
        return "";

#if USE(ICU_UNICODE)
    // FIXME: What's the right place to do normalization?
    // It's a little strange to do it inside the encode function.
    // Perhaps normalization should be an explicit step done before calling encode.

    const UChar* source = characters;
    size_t sourceLength = length;

    Vector<UChar> normalizedCharacters;

    UErrorCode err = U_ZERO_ERROR;
    if (unorm_quickCheck(source, sourceLength, UNORM_NFC, &err) != UNORM_YES) {
        // First try using the length of the original string, since normalization to NFC rarely increases length.
        normalizedCharacters.grow(sourceLength);
        int32_t normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), length, &err);
        if (err == U_BUFFER_OVERFLOW_ERROR) {
            err = U_ZERO_ERROR;
            normalizedCharacters.resize(normalizedLength);
            normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), normalizedLength, &err);
        }
        ASSERT(U_SUCCESS(err));

        source = normalizedCharacters.data();
        sourceLength = normalizedLength;
    }
    return newTextCodec(*this)->encode(source, sourceLength, handling);
#elif USE(QT4_UNICODE)
    QString str(reinterpret_cast<const QChar*>(characters), length);
    str = str.normalized(QString::NormalizationForm_C);
    return newTextCodec(*this)->encode(reinterpret_cast<const UChar *>(str.utf16()), str.length(), handling);
#elif USE(GLIB_UNICODE)
    GOwnPtr<char> UTF8Source;
    UTF8Source.set(g_utf16_to_utf8(characters, length, 0, 0, 0));
    if (!UTF8Source) {
        // If conversion to UTF-8 failed, try with the string without normalization
        return newTextCodec(*this)->encode(characters, length, handling);
    }

    GOwnPtr<char> UTF8Normalized;
    UTF8Normalized.set(g_utf8_normalize(UTF8Source.get(), -1, G_NORMALIZE_NFC));

    long UTF16Length;
    GOwnPtr<UChar> UTF16Normalized;
    UTF16Normalized.set(g_utf8_to_utf16(UTF8Normalized.get(), -1, 0, &UTF16Length, 0));

    return newTextCodec(*this)->encode(UTF16Normalized.get(), UTF16Length, handling);
#elif OS(WINCE)
    // normalization will be done by Windows CE API
    OwnPtr<TextCodec> textCodec = newTextCodec(*this);
    return textCodec.get() ? textCodec->encode(characters, length, handling) : CString();
#endif
}

const char* TextEncoding::domName() const
{
    if (noExtendedTextEncodingNameUsed())
        return m_name;

    // We treat EUC-KR as windows-949 (its superset), but need to expose
    // the name 'EUC-KR' because the name 'windows-949' is not recognized by
    // most Korean web servers even though they do use the encoding
    // 'windows-949' with the name 'EUC-KR'.
    // FIXME: This is not thread-safe. At the moment, this function is
    // only accessed in a single thread, but eventually has to be made
    // thread-safe along with usesVisualOrdering().
    static const char* const a = atomicCanonicalTextEncodingName("windows-949");
    if (m_name == a)
        return "EUC-KR";
    return m_name;
}

bool TextEncoding::usesVisualOrdering() const
{
    if (noExtendedTextEncodingNameUsed())
        return false;

    static const char* const a = atomicCanonicalTextEncodingName("ISO-8859-8");

bool TextEncoding::isJapanese() const
{
    return isJapaneseEncoding(m_name);
}

UChar TextEncoding::backslashAsCurrencySymbol() const
{
    return shouldShowBackslashAsCurrencySymbolIn(m_name) ? 0x00A5 : '\\';
}

bool TextEncoding::isNonByteBasedEncoding() const
{
    if (noExtendedTextEncodingNameUsed()) {
        return *this == UTF16LittleEndianEncoding()
            || *this == UTF16BigEndianEncoding();
    }

    return *this == UTF16LittleEndianEncoding()
        || *this == UTF16BigEndianEncoding()
        || *this == UTF32BigEndianEncoding()
        || *this == UTF32LittleEndianEncoding();
}

bool TextEncoding::isUTF7Encoding() const
{
    if (noExtendedTextEncodingNameUsed())
        return false;

    return *this == UTF7Encoding();
}

const TextEncoding& TextEncoding::closestByteBasedEquivalent() const
{
    if (isNonByteBasedEncoding())
        return UTF8Encoding();
    return *this;
}

// HTML5 specifies that UTF-8 be used in form submission when a form is
// is a part of a document in UTF-16 probably because UTF-16 is not a
// byte-based encoding and can contain 0x00. By extension, the same
// should be done for UTF-32. In case of UTF-7, it is a byte-based encoding,
// but it's fraught with problems and we'd rather steer clear of it.
const TextEncoding& TextEncoding::encodingForFormSubmission() const
{
    if (isNonByteBasedEncoding() || isUTF7Encoding())
        return UTF8Encoding();
    return *this;
}

const TextEncoding& ASCIIEncoding()
{
    static TextEncoding globalASCIIEncoding("ASCII");
    return globalASCIIEncoding;
}

const TextEncoding& Latin1Encoding()
{
    static TextEncoding globalLatin1Encoding("latin1");
    return globalLatin1Encoding;
}

const TextEncoding& UTF16BigEndianEncoding()
{
    static TextEncoding globalUTF16BigEndianEncoding("UTF-16BE");
    return globalUTF16BigEndianEncoding;
}

const TextEncoding& UTF16LittleEndianEncoding()
{
    static TextEncoding globalUTF16LittleEndianEncoding("UTF-16LE");
    return globalUTF16LittleEndianEncoding;
}

const TextEncoding& UTF32BigEndianEncoding()
{
    static TextEncoding globalUTF32BigEndianEncoding("UTF-32BE");
    return globalUTF32BigEndianEncoding;
}

const TextEncoding& UTF32LittleEndianEncoding()
{
    static TextEncoding globalUTF32LittleEndianEncoding("UTF-32LE");
    return globalUTF32LittleEndianEncoding;
}

const TextEncoding& UTF8Encoding()
{
    static TextEncoding globalUTF8Encoding("UTF-8");
    ASSERT(globalUTF8Encoding.isValid());
    return globalUTF8Encoding;
}

const TextEncoding& WindowsLatin1Encoding()
{
    static TextEncoding globalWindowsLatin1Encoding("WinLatin-1");
    return globalWindowsLatin1Encoding;
}

} // namespace WebCore


/*
 *
 */

#include "config.h"
#include "TextEncoding.h"

#include "PlatformString.h"
#include "TextCodec.h"
#include "TextEncodingRegistry.h"
#if USE(ICU_UNICODE)
#include <unicode/unorm.h>
#elif USE(QT4_UNICODE)
#include <QString>
#elif USE(GLIB_UNICODE)
#include <glib.h>
#include "GOwnPtr.h"
#endif
#include <wtf/text/CString.h>
#include <wtf/OwnPtr.h>
#include <wtf/StdLibExtras.h>

namespace WebCore {

static const TextEncoding& UTF7Encoding()
{
    static TextEncoding globalUTF7Encoding("UTF-7");
    return globalUTF7Encoding;
}

TextEncoding::TextEncoding(const char* name)
    : m_name(atomicCanonicalTextEncodingName(name))
    , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol())
{
}

TextEncoding::TextEncoding(const String& name)
    : m_name(atomicCanonicalTextEncodingName(name.characters(), name.length()))
    , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol())
{
}

String TextEncoding::decode(const char* data, size_t length, bool stopOnError, bool& sawError) const
{
    if (!m_name)
        return String();

    return newTextCodec(*this)->decode(data, length, true, stopOnError, sawError);
}

CString TextEncoding::encode(const UChar* characters, size_t length, UnencodableHandling handling) const
{
    if (!m_name)
        return CString();

    if (!length)
        return "";

#if USE(ICU_UNICODE)
    // FIXME: What's the right place to do normalization?
    // It's a little strange to do it inside the encode function.
    // Perhaps normalization should be an explicit step done before calling encode.

    const UChar* source = characters;
    size_t sourceLength = length;

    Vector<UChar> normalizedCharacters;

    UErrorCode err = U_ZERO_ERROR;
    if (unorm_quickCheck(source, sourceLength, UNORM_NFC, &err) != UNORM_YES) {
        // First try using the length of the original string, since normalization to NFC rarely increases length.
        normalizedCharacters.grow(sourceLength);
        int32_t normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), length, &err);
        if (err == U_BUFFER_OVERFLOW_ERROR) {
            err = U_ZERO_ERROR;
            normalizedCharacters.resize(normalizedLength);
            normalizedLength = unorm_normalize(source, length, UNORM_NFC, 0, normalizedCharacters.data(), normalizedLength, &err);
        }
        ASSERT(U_SUCCESS(err));

        source = normalizedCharacters.data();
        sourceLength = normalizedLength;
    }
    return newTextCodec(*this)->encode(source, sourceLength, handling);
#elif USE(QT4_UNICODE)
    QString str(reinterpret_cast<const QChar*>(characters), length);
    str = str.normalized(QString::NormalizationForm_C);
    return newTextCodec(*this)->encode(reinterpret_cast<const UChar *>(str.utf16()), str.length(), handling);
#elif USE(GLIB_UNICODE)
    GOwnPtr<char> UTF8Source;
    UTF8Source.set(g_utf16_to_utf8(characters, length, 0, 0, 0));
    if (!UTF8Source) {
        // If conversion to UTF-8 failed, try with the string without normalization
        return newTextCodec(*this)->encode(characters, length, handling);
    }

    GOwnPtr<char> UTF8Normalized;
    UTF8Normalized.set(g_utf8_normalize(UTF8Source.get(), -1, G_NORMALIZE_NFC));

    long UTF16Length;
    GOwnPtr<UChar> UTF16Normalized;
    UTF16Normalized.set(g_utf8_to_utf16(UTF8Normalized.get(), -1, 0, &UTF16Length, 0));

    return newTextCodec(*this)->encode(UTF16Normalized.get(), UTF16Length, handling);
#elif OS(WINCE)
    // normalization will be done by Windows CE API
    OwnPtr<TextCodec> textCodec = newTextCodec(*this);
    return textCodec.get() ? textCodec->encode(characters, length, handling) : CString();
#endif
}

const char* TextEncoding::domName() const
{
    if (noExtendedTextEncodingNameUsed())
        return m_name;

    // We treat EUC-KR as windows-949 (its superset), but need to expose
    // the name 'EUC-KR' because the name 'windows-949' is not recognized by
    // most Korean web servers even though they do use the encoding
    // 'windows-949' with the name 'EUC-KR'.
    // FIXME: This is not thread-safe. At the moment, this function is
    // only accessed in a single thread, but eventually has to be made
    // thread-safe along with usesVisualOrdering().
    static const char* const a = atomicCanonicalTextEncodingName("windows-949");
    if (m_name == a)
        return "EUC-KR";
    return m_name;
}

bool TextEncoding::usesVisualOrdering() const
{
    if (noExtendedTextEncodingNameUsed())
        return false;

    static const char* const a = atomicCanonicalTextEncodingName("ISO-8859-8");
    return m_name == a;
}

bool TextEncoding::isJapanese() const
{
    return isJapaneseEncoding(m_name);
}

UChar TextEncoding::backslashAsCurrencySymbol() const
{
    return shouldShowBackslashAsCurrencySymbolIn(m_name) ? 0x00A5 : '\\';
}

bool TextEncoding::isNonByteBasedEncoding() const
{
    if (noExtendedTextEncodingNameUsed()) {
        return *this == UTF16LittleEndianEncoding()
            || *this == UTF16BigEndianEncoding();
    }

    return *this == UTF16LittleEndianEncoding()
        || *this == UTF16BigEndianEncoding()
        || *this == UTF32BigEndianEncoding()
        || *this == UTF32LittleEndianEncoding();
}

bool TextEncoding::isUTF7Encoding() const
{
    if (noExtendedTextEncodingNameUsed())
        return false;

    return *this == UTF7Encoding();
}

const TextEncoding& TextEncoding::closestByteBasedEquivalent() const
{
    if (isNonByteBasedEncoding())
        return UTF8Encoding();
    return *this;
}

// HTML5 specifies that UTF-8 be used in form submission when a form is
// is a part of a document in UTF-16 probably because UTF-16 is not a
// byte-based encoding and can contain 0x00. By extension, the same
// should be done for UTF-32. In case of UTF-7, it is a byte-based encoding,
// but it's fraught with problems and we'd rather steer clear of it.
const TextEncoding& TextEncoding::encodingForFormSubmission() const
{
    if (isNonByteBasedEncoding() || isUTF7Encoding())
        return UTF8Encoding();
    return *this;
}

const TextEncoding& ASCIIEncoding()
{
    static TextEncoding globalASCIIEncoding("ASCII");
    return globalASCIIEncoding;
}

const TextEncoding& Latin1Encoding()
{
    static TextEncoding globalLatin1Encoding("latin1");
    return globalLatin1Encoding;
}

const TextEncoding& UTF16BigEndianEncoding()
{
    static TextEncoding globalUTF16BigEndianEncoding("UTF-16BE");
    return globalUTF16BigEndianEncoding;
}

const TextEncoding& UTF16LittleEndianEncoding()
{
    static TextEncoding globalUTF16LittleEndianEncoding("UTF-16LE");
    return globalUTF16LittleEndianEncoding;
}

const TextEncoding& UTF32BigEndianEncoding()
{
    static TextEncoding globalUTF32BigEndianEncoding("UTF-32BE");
    return globalUTF32BigEndianEncoding;
}

const TextEncoding& UTF32LittleEndianEncoding()
{
    static TextEncoding globalUTF32LittleEndianEncoding("UTF-32LE");
    return globalUTF32LittleEndianEncoding;
}

const TextEncoding& UTF8Encoding()
{
    static TextEncoding globalUTF8Encoding("UTF-8

    ASSERT(globalUTF8Encoding.isValid());
    return globalUTF8Encoding;
}

const TextEncoding& WindowsLatin1Encoding()
{
    static TextEncoding globalWindowsLatin1Encoding("WinLatin-1");
    return globalWindowsLatin1Encoding;
}

} // namespace WebCore