<commit_before>// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "PixelProgram.hpp"

#include "SamplerCore.hpp"
#include "Device/Primitive.hpp"
#include "Device/Renderer.hpp"

namespace sw
{
	extern bool postBlendSRGB;

	void PixelProgram::setBuiltins(Int &x, Int &y, Float4(&z)[4], Float4 &w)
	{
		routine.windowSpacePosition[0] = x + SIMD::Int(0,1,0,1);
		routine.windowSpacePosition[1] = y + SIMD::Int(0,0,1,1);

		auto it = spirvShader->inputBuiltins.find(spv::BuiltInFragCoord);
		if (it != spirvShader->inputBuiltins.end())
		{
			auto &var = routine.getVariable(it->second.Id);
			var[it->second.FirstComponent] = SIMD::Float(Float(x)) + SIMD::Float(0.5f, 1.5f, 0.5f, 1.5f);
			var[it->second.FirstComponent+1] = SIMD::Float(Float(y)) + SIMD::Float(0.5f, 0.5f, 1.5f, 1.5f);
			var[it->second.FirstComponent+2] = z[0];	// sample 0
			var[it->second.FirstComponent+3] = w;
		}

		it = spirvShader->inputBuiltins.find(spv::BuiltInSubgroupSize);
		if (it != spirvShader->inputBuiltins.end())
		{
			ASSERT(it->second.SizeInComponents == 1);
			routine.getVariable(it->second.Id)[it->second.FirstComponent] = As<SIMD::Float>(SIMD::Int(SIMD::Width));
		}

		it = spirvShader->inputBuiltins.find(spv::BuiltInSubgroupLocalInvocationId);
		if (it != spirvShader->inputBuiltins.end())
		{
			ASSERT(it->second.SizeInComponents == 1);
			routine.getVariable(it->second.Id)[it->second.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 1, 2, 3));
		}
	}

	void PixelProgram::applyShader(Int cMask[4])
	{
		routine.descriptorSets = data + OFFSET(DrawData, descriptorSets);
		routine.descriptorDynamicOffsets = data + OFFSET(DrawData, descriptorDynamicOffsets);
		routine.pushConstants = data + OFFSET(DrawData, pushConstants);
		routine.constants = *Pointer<Pointer<Byte>>(data + OFFSET(DrawData, constants));

		auto it = spirvShader->inputBuiltins.find(spv::BuiltInFrontFacing);
		if (it != spirvShader->inputBuiltins.end())
		{
			ASSERT(it->second.SizeInComponents == 1);
			auto frontFacing = Int4(*Pointer<Int>(primitive + OFFSET(Primitive, clockwiseMask)));
			routine.getVariable(it->second.Id)[it->second.FirstComponent] = As<Float4>(frontFacing);
		}

		// Note: all lanes initially active to facilitate derivatives etc. Actual coverage is
		// handled separately, through the cMask.
		auto activeLaneMask = SIMD::Int(0xFFFFFFFF);
		routine.killMask = 0;

		spirvShader->emit(&routine, activeLaneMask, descriptorSets);
		spirvShader->emitEpilog(&routine);

		for(int i = 0; i < RENDERTARGETS; i++)
		{
			c[i].x = routine.outputs[i * 4];
			c[i].y = routine.outputs[i * 4 + 1];
			c[i].z = routine.outputs[i * 4 + 2];
			c[i].w = routine.outputs[i * 4 + 3];
		}

		clampColor(c);

		if(spirvShader->getModes().ContainsKill)
		{
			for (auto i = 0u; i < state.multiSample; i++)
			{
				cMask[i] &= ~routine.killMask;
			}
		}

		it = spirvShader->outputBuiltins.find(spv::BuiltInFragDepth);
		if (it != spirvShader->outputBuiltins.end())
		{
			oDepth = routine.getVariable(it->second.Id)[it->second.FirstComponent];
		}

		if(spirvShader->getModes().DepthReplacing)
		{
			oDepth = Min(Max(oDepth, Float4(0.0f)), Float4(1.0f));
		}
	}

	Bool PixelProgram::alphaTest(Int cMask[4])
	{
		if(!state.alphaToCoverage)
		{
			return true;
		}

		alphaToCoverage(cMask, c[0].w);

		Int pass = cMask[0];

		for(unsigned int q = 1; q < state.multiSample; q++)
		{
			pass = pass | cMask[q];
		}

		return pass != 0x0;
	}

	void PixelProgram::rasterOperation(Pointer<Byte> cBuffer[4], Int &x, Int sMask[4], Int zMask[4], Int cMask[4])
	{
		for(int index = 0; index < RENDERTARGETS; index++)
		{
			if(!state.colorWriteActive(index))
			{
				continue;
			}

			switch(state.targetFormat[index])
			{
			case VK_FORMAT_R5G6B5_UNORM_PACK16:
			case VK_FORMAT_B8G8R8A8_UNORM:
			case VK_FORMAT_B8G8R8A8_SRGB:
			case VK_FORMAT_R8G8B8A8_UNORM:
			case VK_FORMAT_R8G8B8A8_SRGB:
			case VK_FORMAT_R8G8_UNORM:
			case VK_FORMAT_R8_UNORM:
			case VK_FORMAT_R16G16_UNORM:
			case VK_FORMAT_R16G16B16A16_UNORM:
			case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
			case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
				for(unsigned int q = 0; q < state.multiSample; q++)
				{
					Pointer<Byte> buffer = cBuffer[index] + q * *Pointer<Int>(data + OFFSET(DrawData, colorSliceB[index]));
					Vector4s color;

					if(state.targetFormat[index] == VK_FORMAT_R5G6B5_UNORM_PACK16)
					{
						color.x = UShort4(c[index].x * Float4(0xFBFF), false);
						color.y = UShort4(c[index].y * Float4(0xFDFF), false);
						color.z = UShort4(c[index].z * Float4(0xFBFF), false);
						color.w = UShort4(c[index].w * Float4(0xFFFF), false);
					}
					else
					{
						color.x = convertFixed16(c[index].x, false);
						color.y = convertFixed16(c[index].y, false);
						color.z = convertFixed16(c[index].z, false);
						color.w = convertFixed16(c[index].w, false);
					}

					if(state.multiSampleMask & (1 << q))
					{
						alphaBlend(index, buffer, color, x);
						writeColor(index, buffer, x, color, sMask[q], zMask[q], cMask[q]);
					}
				}
				break;
			case VK_FORMAT_R32_SFLOAT:
			case VK_FORMAT_R32G32_SFLOAT:
			case VK_FORMAT_R32G32B32A32_SFLOAT:
			case VK_FORMAT_R32_SINT:
			case VK_FORMAT_R32G32_SINT:
			case VK_FORMAT_R32G32B32A32_SINT:
			case VK_FORMAT_R32_UINT:
			case VK_FORMAT_R32G32_UINT:
			case VK_FORMAT_R32G32B32A32_UINT:
			case VK_FORMAT_R16_SINT:
			case VK_FORMAT_R16G16_SINT:
			case VK_FORMAT_R16G16B16A16_SINT:
			case VK_FORMAT_R16_UINT:
			case VK_FORMAT_R16G16_UINT:
			case VK_FORMAT_R16G16B16A16_UINT:
			case VK_FORMAT_R8_SINT:
			case VK_FORMAT_R8G8_SINT:
			case VK_FORMAT_R8G8B8A8_SINT:
			case VK_FORMAT_R8_UINT:
			case VK_FORMAT_R8G8_UINT:
			case VK_FORMAT_R8G8B8A8_UINT:
			case VK_FORMAT_A8B8G8R8_UINT_PACK32:
			case VK_FORMAT_A8B8G8R8_SINT_PACK32:
				for(unsigned int q = 0; q < state.multiSample; q++)
				{
					Pointer<Byte> buffer = cBuffer[index] + q * *Pointer<Int>(data + OFFSET(DrawData, colorSliceB[index]));
					Vector4f color = c[index];

					if(state.multiSampleMask & (1 << q))
					{
						alphaBlend(index, buffer, color, x);
						writeColor(index, buffer, x, color, sMask[q], zMask[q], cMask[q]);
					}
				}
				break;
			default:
				UNIMPLEMENTED("VkFormat: %d", int(state.targetFormat[index]));
			}
		}
	}

	void PixelProgram::clampColor(Vector4f oC[RENDERTARGETS])
	{
		for(int index = 0; index < RENDERTARGETS; index++)
		{
			if(!state.colorWriteActive(index) && !(index == 0 && state.alphaToCoverage))
			{
				continue;
			}

			switch(state.targetFormat[index])
			{
			case VK_FORMAT_UNDEFINED:
				break;
			case VK_FORMAT_R5G6B5_UNORM_PACK16:
			case VK_FORMAT_B8G8R8A8_UNORM:
			case VK_FORMAT_B8G8R8A8_SRGB:
			case VK_FORMAT_R8G8B8A8_UNORM:
			case VK_FORMAT_R8G8B8A8_SRGB:
			case VK_FORMAT_R8G8_UNORM:
			case VK_FORMAT_R8_UNORM:
			case VK_FORMAT_R16G16_UNORM:
			case VK_FORMAT_R16G16B16A16_UNORM:
			case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
			case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
				oC[index].x = Max(oC[index].x, Float4(0.0f)); oC[index].x = Min(oC[index].x, Float4(1.0f));
				oC[index].y = Max(oC[index].y, Float4(0.0f)); oC[index].y = Min(oC[index].y, Float4(1.0f));
				oC[index].z = Max(oC[index].z, Float4(0.0f)); oC[index].z = Min(oC[index].z, Float4(1.0f));
				oC[index].w = Max(oC[index].w, Float4(0.0f)); oC[index].w = Min(oC[index].w, Float4(1.0f));
				break;
			case VK_FORMAT_R32_SFLOAT:
			case VK_FORMAT_R32G32_SFLOAT:
			case VK_FORMAT_R32G32B32A32_SFLOAT:
			case VK_FORMAT_R32_SINT:
			case VK_FORMAT_R32G32_SINT:
			case VK_FORMAT_R32G32B32A32_SINT:
			case VK_FORMAT_R32_UINT:
			case VK_FORMAT_R32G32_UINT:
			case VK_FORMAT_R32G32B32A32_UINT:
			case VK_FORMAT_R16_SINT:
			case VK_FORMAT_R16G16_SINT:
			case VK_FORMAT_R16G16B16A16_SINT:
			case VK_FORMAT_R16_UINT:
			case VK_FORMAT_R16G16_UINT:
			case VK_FORMAT_R16G16B16A16_UINT:
			case VK_FORMAT_R8_SINT:
			case VK_FORMAT_R8G8_SINT:
			case VK_FORMAT_R8G8B8A8_SINT:
			case VK_FORMAT_R8_UINT:
			case VK_FORMAT_R8G8_UINT:
			case VK_FORMAT_R8G8B8A8_UINT:
			case VK_FORMAT_A8B8G8R8_UINT_PACK32:
			case VK_FORMAT_A8B8G8R8_SINT_PACK32:
				break;
			default:
				UNIMPLEMENTED("VkFormat: %d", int(state.targetFormat[index]));
			}
		}
	}

	Float4 PixelProgram::linearToSRGB(const Float4 &x)   // Approximates x^(1.0/2.2)
	{
		Float4 sqrtx = Rcp_pp(RcpSqrt_pp(x));
		Float4 sRGB = sqrtx * Float4(1.14f) - x * Float4(0.14f);

		return Min(Max(sRGB, Float4(0.0f)), Float4(1.0f));
	}
}
<commit_msg>Minor tidying in PixelProgram<commit_after>// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "PixelProgram.hpp"

#include "SamplerCore.hpp"
#include "Device/Primitive.hpp"
#include "Device/Renderer.hpp"

namespace sw
{
	extern bool postBlendSRGB;

	void PixelProgram::setBuiltins(Int &x, Int &y, Float4(&z)[4], Float4 &w)
	{
		routine.windowSpacePosition[0] = x + SIMD::Int(0,1,0,1);
		routine.windowSpacePosition[1] = y + SIMD::Int(0,0,1,1);

		auto it = spirvShader->inputBuiltins.find(spv::BuiltInFragCoord);
		if (it != spirvShader->inputBuiltins.end())
		{
			auto &var = routine.getVariable(it->second.Id);
			var[it->second.FirstComponent] = SIMD::Float(Float(x)) + SIMD::Float(0.5f, 1.5f, 0.5f, 1.5f);
			var[it->second.FirstComponent+1] = SIMD::Float(Float(y)) + SIMD::Float(0.5f, 0.5f, 1.5f, 1.5f);
			var[it->second.FirstComponent+2] = z[0];	// sample 0
			var[it->second.FirstComponent+3] = w;
		}

		it = spirvShader->inputBuiltins.find(spv::BuiltInSubgroupSize);
		if (it != spirvShader->inputBuiltins.end())
		{
			ASSERT(it->second.SizeInComponents == 1);
			routine.getVariable(it->second.Id)[it->second.FirstComponent] = As<SIMD::Float>(SIMD::Int(SIMD::Width));
		}

		it = spirvShader->inputBuiltins.find(spv::BuiltInSubgroupLocalInvocationId);
		if (it != spirvShader->inputBuiltins.end())
		{
			ASSERT(it->second.SizeInComponents == 1);
			routine.getVariable(it->second.Id)[it->second.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 1, 2, 3));
		}
	}

	void PixelProgram::applyShader(Int cMask[4])
	{
		routine.descriptorSets = data + OFFSET(DrawData, descriptorSets);
		routine.descriptorDynamicOffsets = data + OFFSET(DrawData, descriptorDynamicOffsets);
		routine.pushConstants = data + OFFSET(DrawData, pushConstants);
		routine.constants = *Pointer<Pointer<Byte>>(data + OFFSET(DrawData, constants));

		auto it = spirvShader->inputBuiltins.find(spv::BuiltInFrontFacing);
		if (it != spirvShader->inputBuiltins.end())
		{
			ASSERT(it->second.SizeInComponents == 1);
			auto frontFacing = Int4(*Pointer<Int>(primitive + OFFSET(Primitive, clockwiseMask)));
			routine.getVariable(it->second.Id)[it->second.FirstComponent] = As<Float4>(frontFacing);
		}

		// Note: all lanes initially active to facilitate derivatives etc. Actual coverage is
		// handled separately, through the cMask.
		auto activeLaneMask = SIMD::Int(0xFFFFFFFF);
		routine.killMask = 0;

		spirvShader->emit(&routine, activeLaneMask, descriptorSets);
		spirvShader->emitEpilog(&routine);

		for(int i = 0; i < RENDERTARGETS; i++)
		{
			c[i].x = routine.outputs[i * 4];
			c[i].y = routine.outputs[i * 4 + 1];
			c[i].z = routine.outputs[i * 4 + 2];
			c[i].w = routine.outputs[i * 4 + 3];
		}

		clampColor(c);

		if(spirvShader->getModes().ContainsKill)
		{
			for (auto i = 0u; i < state.multiSample; i++)
			{
				cMask[i] &= ~routine.killMask;
			}
		}

		it = spirvShader->outputBuiltins.find(spv::BuiltInFragDepth);
		if (it != spirvShader->outputBuiltins.end())
		{
			oDepth = Min(Max(routine.getVariable(it->second.Id)[it->second.FirstComponent], Float4(0.0f)), Float4(1.0f));
		}
	}

	Bool PixelProgram::alphaTest(Int cMask[4])
	{
		if(!state.alphaToCoverage)
		{
			return true;
		}

		alphaToCoverage(cMask, c[0].w);

		Int pass = cMask[0];

		for(unsigned int q = 1; q < state.multiSample; q++)
		{
			pass = pass | cMask[q];
		}

		return pass != 0x0;
	}

	void PixelProgram::rasterOperation(Pointer<Byte> cBuffer[4], Int &x, Int sMask[4], Int zMask[4], Int cMask[4])
	{
		for(int index = 0; index < RENDERTARGETS; index++)
		{
			if(!state.colorWriteActive(index))
			{
				continue;
			}

			switch(state.targetFormat[index])
			{
			case VK_FORMAT_R5G6B5_UNORM_PACK16:
			case VK_FORMAT_B8G8R8A8_UNORM:
			case VK_FORMAT_B8G8R8A8_SRGB:
			case VK_FORMAT_R8G8B8A8_UNORM:
			case VK_FORMAT_R8G8B8A8_SRGB:
			case VK_FORMAT_R8G8_UNORM:
			case VK_FORMAT_R8_UNORM:
			case VK_FORMAT_R16G16_UNORM:
			case VK_FORMAT_R16G16B16A16_UNORM:
			case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
			case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
				for(unsigned int q = 0; q < state.multiSample; q++)
				{
					Pointer<Byte> buffer = cBuffer[index] + q * *Pointer<Int>(data + OFFSET(DrawData, colorSliceB[index]));
					Vector4s color;

					if(state.targetFormat[index] == VK_FORMAT_R5G6B5_UNORM_PACK16)
					{
						color.x = UShort4(c[index].x * Float4(0xFBFF), false);
						color.y = UShort4(c[index].y * Float4(0xFDFF), false);
						color.z = UShort4(c[index].z * Float4(0xFBFF), false);
						color.w = UShort4(c[index].w * Float4(0xFFFF), false);
					}
					else
					{
						color.x = convertFixed16(c[index].x, false);
						color.y = convertFixed16(c[index].y, false);
						color.z = convertFixed16(c[index].z, false);
						color.w = convertFixed16(c[index].w, false);
					}

					if(state.multiSampleMask & (1 << q))
					{
						alphaBlend(index, buffer, color, x);
						writeColor(index, buffer, x, color, sMask[q], zMask[q], cMask[q]);
					}
				}
				break;
			case VK_FORMAT_R32_SFLOAT:
			case VK_FORMAT_R32G32_SFLOAT:
			case VK_FORMAT_R32G32B32A32_SFLOAT:
			case VK_FORMAT_R32_SINT:
			case VK_FORMAT_R32G32_SINT:
			case VK_FORMAT_R32G32B32A32_SINT:
			case VK_FORMAT_R32_UINT:
			case VK_FORMAT_R32G32_UINT:
			case VK_FORMAT_R32G32B32A32_UINT:
			case VK_FORMAT_R16_SINT:
			case VK_FORMAT_R16G16_SINT:
			case VK_FORMAT_R16G16B16A16_SINT:
			case VK_FORMAT_R16_UINT:
			case VK_FORMAT_R16G16_UINT:
			case VK_FORMAT_R16G16B16A16_UINT:
			case VK_FORMAT_R8_SINT:
			case VK_FORMAT_R8G8_SINT:
			case VK_FORMAT_R8G8B8A8_SINT:
			case VK_FORMAT_R8_UINT:
			case VK_FORMAT_R8G8_UINT:
			case VK_FORMAT_R8G8B8A8_UINT:
			case VK_FORMAT_A8B8G8R8_UINT_PACK32:
			case VK_FORMAT_A8B8G8R8_SINT_PACK32:
				for(unsigned int q = 0; q < state.multiSample; q++)
				{
					Pointer<Byte> buffer = cBuffer[index] + q * *Pointer<Int>(data + OFFSET(DrawData, colorSliceB[index]));
					Vector4f color = c[index];

					if(state.multiSampleMask & (1 << q))
					{
						alphaBlend(index, buffer, color, x);
						writeColor(index, buffer, x, color, sMask[q], zMask[q], cMask[q]);
					}
				}
				break;
			default:
				UNIMPLEMENTED("VkFormat: %d", int(state.targetFormat[index]));
			}
		}
	}

	void PixelProgram::clampColor(Vector4f oC[RENDERTARGETS])
	{
		for(int index = 0; index < RENDERTARGETS; index++)
		{
			if(!state.colorWriteActive(index) && !(index == 0 && state.alphaToCoverage))
			{
				continue;
			}

			switch(state.targetFormat[index])
			{
			case VK_FORMAT_UNDEFINED:
				break;
			case VK_FORMAT_R5G6B5_UNORM_PACK16:
			case VK_FORMAT_B8G8R8A8_UNORM:
			case VK_FORMAT_B8G8R8A8_SRGB:
			case VK_FORMAT_R8G8B8A8_UNORM:
			case VK_FORMAT_R8G8B8A8_SRGB:
			case VK_FORMAT_R8G8_UNORM:
			case VK_FORMAT_R8_UNORM:
			case VK_FORMAT_R16G16_UNORM:
			case VK_FORMAT_R16G16B16A16_UNORM:
			case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
			case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
				oC[index].x = Max(oC[index].x, Float4(0.0f)); oC[index].x = Min(oC[index].x, Float4(1.0f));
				oC[index].y = Max(oC[index].y, Float4(0.0f)); oC[index].y = Min(oC[index].y, Float4(1.0f));
				oC[index].z = Max(oC[index].z, Float4(0.0f)); oC[index].z = Min(oC[index].z, Float4(1.0f));
				oC[index].w = Max(oC[index].w, Float4(0.0f)); oC[index].w = Min(oC[index].w, Float4(1.0f));
				break;
			case VK_FORMAT_R32_SFLOAT:
			case VK_FORMAT_R32G32_SFLOAT:
			case VK_FORMAT_R32G32B32A32_SFLOAT:
			case VK_FORMAT_R32_SINT:
			case VK_FORMAT_R32G32_SINT:
			case VK_FORMAT_R32G32B32A32_SINT:
			case VK_FORMAT_R32_UINT:
			case VK_FORMAT_R32G32_UINT:
			case VK_FORMAT_R32G32B32A32_UINT:
			case VK_FORMAT_R16_SINT:
			case VK_FORMAT_R16G16_SINT:
			case VK_FORMAT_R16G16B16A16_SINT:
			case VK_FORMAT_R16_UINT:
			case VK_FORMAT_R16G16_UINT:
			case VK_FORMAT_R16G16B16A16_UINT:
			case VK_FORMAT_R8_SINT:
			case VK_FORMAT_R8G8_SINT:
			case VK_FORMAT_R8G8B8A8_SINT:
			case VK_FORMAT_R8_UINT:
			case VK_FORMAT_R8G8_UINT:
			case VK_FORMAT_R8G8B8A8_UINT:
			case VK_FORMAT_A8B8G8R8_UINT_PACK32:
			case VK_FORMAT_A8B8G8R8_SINT_PACK32:
				break;
			default:
				UNIMPLEMENTED("VkFormat: %d", int(state.targetFormat[index]));
			}
		}
	}

	Float4 PixelProgram::linearToSRGB(const Float4 &x)   // Approximates x^(1.0/2.2)
	{
		Float4 sqrtx = Rcp_pp(RcpSqrt_pp(x));
		Float4 sRGB = sqrtx * Float4(1.14f) - x * Float4(0.14f);

		return Min(Max(sRGB, Float4(0.0f)), Float4(1.0f));
	}
}
<|endoftext|>


<commit_before>/*
* Copyright (C) 2005-2006 Tommi Maekitalo
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* As a special exception, you may use this file as part of a free
* software library without restriction. Specifically, if other files
* instantiate templates or use macros or inline functions from this
* file, or you compile this file and link it with other files to
* produce an executable, this file does not by itself cause the
* resulting executable to be covered by the GNU General Public
* License. This exception does not however invalidate any other
* reasons why the executable file might be covered by the GNU Library
* General Public License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "tnt/pollerimpl.h"
#include "tnt/tntnet.h"
#include <cxxtools/systemerror.h>
#include <cxxtools/log.h>
#include <ios>
#include <unistd.h>
#include <fcntl.h>
#ifdef WITH_EPOLL
# include <sys/epoll.h>
# include <errno.h>
#endif

log_define("tntnet.pollerimpl")

namespace tnt
{
#ifdef WITH_EPOLL

  PollerImpl::PollerImpl(Jobqueue& q)
    : _queue(q),
      _pollFd(-1),
      _pollTimeout(-1)
  {
#ifdef HAVE_EPOLL_CREATE1
    _pollFd = ::epoll_create1(EPOLL_CLOEXEC);
#else
    _pollFd = ::epoll_create(1);
#endif
    if (_pollFd < 0)
      throw cxxtools::SystemError("epoll_create");

    fcntl(_notifyPipe.getReadFd(), F_SETFL, O_NONBLOCK);
    addFd(_notifyPipe.getReadFd());
  }

  PollerImpl::~PollerImpl()
    { close(_pollFd); }

  void PollerImpl::addFd(int fd)
  {
    log_trace("addFd(" << fd << ')');

    epoll_event e;
    e.events = EPOLLIN;
    e.data.fd = fd;
    int ret = ::epoll_ctl(_pollFd, EPOLL_CTL_ADD, fd, &e);
    if (ret < 0)
      throw cxxtools::SystemError("epoll_ctl(EPOLL_CTL_ADD)");
  }

  bool PollerImpl::removeFd(int fd)
  {
    epoll_event e;
    e.data.fd = fd;
    int ret = ::epoll_ctl(_pollFd, EPOLL_CTL_DEL, fd, &e);
    if (ret < 0)
    {
      if (errno == EBADF || errno == ENOENT)
        return false;
      else
        throw cxxtools::SystemError("epoll_ctl(EPOLL_CTL_DEL)");
    }

    return true;
  }

  void PollerImpl::doStop()
    { _notifyPipe.write('A'); }

  void PollerImpl::addIdleJob(Jobqueue::JobPtr& job)
  {
    if (job->getFd() == -1)
    {
      log_debug("ignore idle socket which is not connected any more");
      cxxtools::MutexLock lock(_mutex);
      job = 0;
    }
    else
    {
      log_debug("add idle socket " << job->getFd());
      cxxtools::MutexLock lock(_mutex);
      _newJobs.push_back(job);
      job = 0;
    }
    _notifyPipe.write('A');
  }

  void PollerImpl::appendNewJobs()
  {
    cxxtools::MutexLock lock(_mutex);
    if (!_newJobs.empty())
    {
      // append new jobs to current
      log_trace("append " << _newJobs.size() << " sockets to poll");
      time_t currentTime;
      time(&currentTime);
      for (new_jobs_type::iterator it = _newJobs.begin();
           it != _newJobs.end(); ++it)
      {
        try
        {
          addFd((*it)->getFd());
          _jobs[(*it)->getFd()] = *it;

          int msec = (*it)->msecToTimeout(currentTime);
          if (_pollTimeout < 0)
            _pollTimeout = msec;
          else if (msec < _pollTimeout)
            _pollTimeout = msec;
        }
        catch (const std::exception& e)
        {
          log_error("failed to add fd " << (*it)->getFd() << " to poll: " << e.what());
        }
      }

      _newJobs.clear();
    }
  }

  void PollerImpl::run()
  {
    epoll_event events[16];

    time_t pollTime;
    time(&pollTime);
    while (!Tntnet::shouldStop())
    {
      usleep(100);

      appendNewJobs();

      if (_jobs.empty())
        _pollTimeout = -1;

      int ret = ::epoll_wait(_pollFd, events, 16, _pollTimeout);

      if (ret < 0)
      {
        if (errno != EINTR)
          throw cxxtools::SystemError("epoll_wait");
      }
      else if (ret == 0)
      {
        // timeout reached - check for timed out requests and get next timeout

        _pollTimeout = -1;
        time_t currentTime;
        time(&currentTime);
        for (jobs_type::iterator it = _jobs.begin(); it != _jobs.end(); )
        {
          int msec = it->second->msecToTimeout(currentTime);
          if (msec <= 0)
          {
            log_debug("timeout for fd " << it->second->getFd() << " reached");
            jobs_type::iterator it2 = it++;
            _jobs.erase(it2);
          }
          else
          {
            if (_pollTimeout < 0 || msec < _pollTimeout)
              _pollTimeout = msec;
            ++it;
          }
        }
      }
      else
      {
        time_t currentTime;
        time(&currentTime);
        _pollTimeout -= (currentTime - pollTime) * 1000;
        if (_pollTimeout <= 0)
          _pollTimeout = 100;

        pollTime = currentTime;

        // no timeout - process events

        bool rebuildPollFd = false;

        for (int i = 0; i < ret; ++i)
        {
          if (events[i].data.fd == _notifyPipe.getReadFd())
          {
            if (Tntnet::shouldStop())
            {
              log_info("stop poller");
              break;
            }

            char buffer[64];
            _notifyPipe.read(buffer, sizeof(buffer));
          }
          else
          {
            jobs_type::iterator it = _jobs.find(events[i].data.fd);
            if (it == _jobs.end())
            {
              log_fatal("internal error: job for fd " << events[i].data.fd << " not found in jobs-list");
              ::close(events[i].data.fd);
              rebuildPollFd = true;
            }
            else
            {
              Jobqueue::JobPtr j = it->second;
              int ev = events[i].events;
              _jobs.erase(it);

              if (!removeFd(events[i].data.fd))
                rebuildPollFd = true;

              if (ev & EPOLLIN)
                _queue.put(j);
            }
          }
        }

        if (rebuildPollFd)
        {
          // rebuild poll-structure
          log_warn("need to rebuild poll structure");
          close(_pollFd);
          _pollFd = ::epoll_create(256);
          if (_pollFd < 0)
            throw cxxtools::SystemError("epoll_create");

          int ret = fcntl(_notifyPipe.getReadFd(), F_SETFL, O_NONBLOCK);
          if (ret < 0)
            throw cxxtools::SystemError("fcntl");

          addFd(_notifyPipe.getReadFd());
          for (jobs_type::iterator it = _jobs.begin(); it != _jobs.end(); ++it)
            addFd(it->first);
        }
      }
    }
  }

#else

  PollerImpl::PollerImpl(Jobqueue& q)
    : _queue(q),
      _pollTimeout(-1)
  {
    fcntl(_notifyPipe.getReadFd(), F_SETFL, O_NONBLOCK);

    _pollfds.push_back(pollfd());
    _pollfds.back().fd = _notifyPipe.getReadFd();
    _pollfds.back().events = POLLIN;
    _pollfds.back().revents = 0;
  }

  void PollerImpl::appendNewJobs()
  {
    cxxtools::MutexLock lock(_mutex);
    if (!_newJobs.empty())
    {
      // append new jobs to current
      log_trace("append " << _newJobs.size() << " sockets to poll");
      time_t currentTime;
      time(&currentTime);
      for (jobs_type::iterator it = _newJobs.begin();
           it != _newJobs.end(); ++it)
      {
        append(*it);
        int msec = (*it)->msecToTimeout(currentTime);
        if (_pollTimeout < 0 || msec < _pollTimeout)
          _pollTimeout = msec;
      }

      _newJobs.clear();
    }
  }

  void PollerImpl::append(Jobqueue::JobPtr& job)
  {
    _currentJobs.push_back(job);

    _pollfds.push_back(pollfd());
    _pollfds.back().fd = job->getFd();
    _pollfds.back().events = POLLIN;
  }

  void PollerImpl::run()
  {
    while (!Tntnet::shouldStop())
    {
      usleep(100);
      appendNewJobs();

      try
      {
        ::poll(&_pollfds[0], _pollfds.size(), _pollTimeout);
        _pollTimeout = -1;

        if (_pollfds[0].revents != 0)
        {
          if (Tntnet::shouldStop())
          {
            log_info("stop poller");
            break;
          }

          char buffer[64];
          _notifyPipe.read(buffer, sizeof(buffer));
          _pollfds[0].revents = 0;
        }

        if (_currentJobs.size() > 0)
          dispatch();
      }
      catch (const std::exception& e)
      {
        log_error("error in poll-loop: " << e.what());
      }
    }
  }

  void PollerImpl::doStop()
    { _notifyPipe.write('A'); }

  void PollerImpl::dispatch()
  {
    time_t currentTime;
    time(&currentTime);
    for (unsigned i = 0; i < _currentJobs.size(); )
    {
      if (_pollfds[i + 1].revents & POLLIN)
      {
        // put job into work-queue
        _queue.put(_currentJobs[i]);
        remove(i);
      }
      else if (_pollfds[i + 1].revents != 0)
        remove(i);
      else
      {
        // check timeout
        int msec = _currentJobs[i]->msecToTimeout(currentTime);
        if (msec <= 0)
          remove(i);
        else if (_pollTimeout < 0 || msec < _pollTimeout)
          _pollTimeout = msec;

        ++i;
      }
    }
  }

  void PollerImpl::remove(jobs_type::size_type n)
  {
    // replace job with last job in poller-list
    jobs_type::size_type last = _currentJobs.size() - 1;

    if (n != last)
    {
      _pollfds[n + 1] = _pollfds[last + 1];
      _currentJobs[n] = _currentJobs[last];
    }

    _pollfds.pop_back();
    _currentJobs.pop_back();
  }

  void PollerImpl::addIdleJob(Jobqueue::JobPtr& job)
  {
    if (job->getFd() == -1)
    {
      log_debug("ignore idle socket which is not connected any more");
      cxxtools::MutexLock lock(_mutex);
      job = 0;
    }
    else
    {
      log_debug("add idle socket " << job->getFd());
      cxxtools::MutexLock lock(_mutex);
      _newJobs.push_back(job);
      job = 0;
    }

    _notifyPipe.write('A');
  }

#endif // #else WITH_EPOLL
}
<commit_msg>set close on exec flag on poll fd also on systems, which do not have epoll_create1<commit_after>/*
* Copyright (C) 2005-2006 Tommi Maekitalo
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* As a special exception, you may use this file as part of a free
* software library without restriction. Specifically, if other files
* instantiate templates or use macros or inline functions from this
* file, or you compile this file and link it with other files to
* produce an executable, this file does not by itself cause the
* resulting executable to be covered by the GNU General Public
* License. This exception does not however invalidate any other
* reasons why the executable file might be covered by the GNU Library
* General Public License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "tnt/pollerimpl.h"
#include "tnt/tntnet.h"
#include <cxxtools/systemerror.h>
#include <cxxtools/log.h>
#include <ios>
#include <unistd.h>
#include <fcntl.h>
#ifdef WITH_EPOLL
# include <sys/epoll.h>
# include <errno.h>
#endif

log_define("tntnet.pollerimpl")

namespace tnt
{
#ifdef WITH_EPOLL

  PollerImpl::PollerImpl(Jobqueue& q)
    : _queue(q),
      _pollFd(-1),
      _pollTimeout(-1)
  {
#ifdef HAVE_EPOLL_CREATE1
    _pollFd = ::epoll_create1(EPOLL_CLOEXEC);
    if (_pollFd < 0)
      throw cxxtools::SystemError("epoll_create1");
#else
    _pollFd = ::epoll_create(1);
    if (_pollFd < 0)
      throw cxxtools::SystemError("epoll_create");

    int flags = ::fcntl(_pollFd, F_GETFD);
    flags |= FD_CLOEXEC ;
    int ret = ::fcntl(_pollFd, F_SETFD, flags);
    if(-1 == ret)
        throw cxxtools::SystemError("fcntl(FD_CLOEXEC)");
#endif

    fcntl(_notifyPipe.getReadFd(), F_SETFL, O_NONBLOCK);
    addFd(_notifyPipe.getReadFd());
  }

  PollerImpl::~PollerImpl()
    { close(_pollFd); }

  void PollerImpl::addFd(int fd)
  {
    log_trace("addFd(" << fd << ')');

    epoll_event e;
    e.events = EPOLLIN;
    e.data.fd = fd;
    int ret = ::epoll_ctl(_pollFd, EPOLL_CTL_ADD, fd, &e);
    if (ret < 0)
      throw cxxtools::SystemError("epoll_ctl(EPOLL_CTL_ADD)");
  }

  bool PollerImpl::removeFd(int fd)
  {
    epoll_event e;
    e.data.fd = fd;
    int ret = ::epoll_ctl(_pollFd, EPOLL_CTL_DEL, fd, &e);
    if (ret < 0)
    {
      if (errno == EBADF || errno == ENOENT)
        return false;
      else
        throw cxxtools::SystemError("epoll_ctl(EPOLL_CTL_DEL)");
    }

    return true;
  }

  void PollerImpl::doStop()
    { _notifyPipe.write('A'); }

  void PollerImpl::addIdleJob(Jobqueue::JobPtr& job)
  {
    if (job->getFd() == -1)
    {
      log_debug("ignore idle socket which is not connected any more");
      cxxtools::MutexLock lock(_mutex);
      job = 0;
    }
    else
    {
      log_debug("add idle socket " << job->getFd());
      cxxtools::MutexLock lock(_mutex);
      _newJobs.push_back(job);
      job = 0;
    }
    _notifyPipe.write('A');
  }

  void PollerImpl::appendNewJobs()
  {
    cxxtools::MutexLock lock(_mutex);
    if (!_newJobs.empty())
    {
      // append new jobs to current
      log_trace("append " << _newJobs.size() << " sockets to poll");
      time_t currentTime;
      time(&currentTime);
      for (new_jobs_type::iterator it = _newJobs.begin();
           it != _newJobs.end(); ++it)
      {
        try
        {
          addFd((*it)->getFd());
          _jobs[(*it)->getFd()] = *it;

          int msec = (*it)->msecToTimeout(currentTime);
          if (_pollTimeout < 0)
            _pollTimeout = msec;
          else if (msec < _pollTimeout)
            _pollTimeout = msec;
        }
        catch (const std::exception& e)
        {
          log_error("failed to add fd " << (*it)->getFd() << " to poll: " << e.what());
        }
      }

      _newJobs.clear();
    }
  }

  void PollerImpl::run()
  {
    epoll_event events[16];

    time_t pollTime;
    time(&pollTime);
    while (!Tntnet::shouldStop())
    {
      usleep(100);

      appendNewJobs();

      if (_jobs.empty())
        _pollTimeout = -1;

      int ret = ::epoll_wait(_pollFd, events, 16, _pollTimeout);

      if (ret < 0)
      {
        if (errno != EINTR)
          throw cxxtools::SystemError("epoll_wait");
      }
      else if (ret == 0)
      {
        // timeout reached - check for timed out requests and get next timeout

        _pollTimeout = -1;
        time_t currentTime;
        time(&currentTime);
        for (jobs_type::iterator it = _jobs.begin(); it != _jobs.end(); )
        {
          int msec = it->second->msecToTimeout(currentTime);
          if (msec <= 0)
          {
            log_debug("timeout for fd " << it->second->getFd() << " reached");
            jobs_type::iterator it2 = it++;
            _jobs.erase(it2);
          }
          else
          {
            if (_pollTimeout < 0 || msec < _pollTimeout)
              _pollTimeout = msec;
            ++it;
          }
        }
      }
      else
      {
        time_t currentTime;
        time(&currentTime);
        _pollTimeout -= (currentTime - pollTime) * 1000;
        if (_pollTimeout <= 0)
          _pollTimeout = 100;

        pollTime = currentTime;

        // no timeout - process events

        bool rebuildPollFd = false;

        for (int i = 0; i < ret; ++i)
        {
          if (events[i].data.fd == _notifyPipe.getReadFd())
          {
            if (Tntnet::shouldStop())
            {
              log_info("stop poller");
              break;
            }

            char buffer[64];
            _notifyPipe.read(buffer, sizeof(buffer));
          }
          else
          {
            jobs_type::iterator it = _jobs.find(events[i].data.fd);
            if (it == _jobs.end())
            {
              log_fatal("internal error: job for fd " << events[i].data.fd << " not found in jobs-list");
              ::close(events[i].data.fd);
              rebuildPollFd = true;
            }
            else
            {
              Jobqueue::JobPtr j = it->second;
              int ev = events[i].events;
              _jobs.erase(it);

              if (!removeFd(events[i].data.fd))
                rebuildPollFd = true;

              if (ev & EPOLLIN)
                _queue.put(j);
            }
          }
        }

        if (rebuildPollFd)
        {
          // rebuild poll-structure
          log_warn("need to rebuild poll structure");
          close(_pollFd);
          _pollFd = ::epoll_create(256);
          if (_pollFd < 0)
            throw cxxtools::SystemError("epoll_create");

          int ret = fcntl(_notifyPipe.getReadFd(), F_SETFL, O_NONBLOCK);
          if (ret < 0)
            throw cxxtools::SystemError("fcntl");

          addFd(_notifyPipe.getReadFd());
          for (jobs_type::iterator it = _jobs.begin(); it != _jobs.end(); ++it)
            addFd(it->first);
        }
      }
    }
  }

#else

  PollerImpl::PollerImpl(Jobqueue& q)
    : _queue(q),
      _pollTimeout(-1)
  {
    fcntl(_notifyPipe.getReadFd(), F_SETFL, O_NONBLOCK);

    _pollfds.push_back(pollfd());
    _pollfds.back().fd = _notifyPipe.getReadFd();
    _pollfds.back().events = POLLIN;
    _pollfds.back().revents = 0;
  }

  void PollerImpl::appendNewJobs()
  {
    cxxtools::MutexLock lock(_mutex);
    if (!_newJobs.empty())
    {
      // append new jobs to current
      log_trace("append " << _newJobs.size() << " sockets to poll");
      time_t currentTime;
      time(&currentTime);
      for (jobs_type::iterator it = _newJobs.begin();
           it != _newJobs.end(); ++it)
      {
        append(*it);
        int msec = (*it)->msecToTimeout(currentTime);
        if (_pollTimeout < 0 || msec < _pollTimeout)
          _pollTimeout = msec;
      }

      _newJobs.clear();
    }
  }

  void PollerImpl::append(Jobqueue::JobPtr& job)
  {
    _currentJobs.push_back(job);

    _pollfds.push_back(pollfd());
    _pollfds.back().fd = job->getFd();
    _pollfds.back().events = POLLIN;
  }

  void PollerImpl::run()
  {
    while (!Tntnet::shouldStop())
    {
      usleep(100);
      appendNewJobs();

      try
      {
        ::poll(&_pollfds[0], _pollfds.size(), _pollTimeout);
        _pollTimeout = -1;

        if (_pollfds[0].revents != 0)
        {
          if (Tntnet::shouldStop())
          {
            log_info("stop poller");
            break;
          }

          char buffer[64];
          _notifyPipe.read(buffer, sizeof(buffer));
          _pollfds[0].revents = 0;
        }

        if (_currentJobs.size() > 0)
          dispatch();
      }
      catch (const std::exception& e)
      {
        log_error("error in poll-loop: " << e.what());
      }
    }
  }

  void PollerImpl::doStop()
    { _notifyPipe.write('A'); }

  void PollerImpl::dispatch()
  {
    time_t currentTime;
    time(&currentTime);
    for (unsigned i = 0; i < _currentJobs.size(); )
    {
      if (_pollfds[i + 1].revents & POLLIN)
      {
        // put job into work-queue
        _queue.put(_currentJobs[i]);
        remove(i);
      }
      else if (_pollfds[i + 1].revents != 0)
        remove(i);
      else
      {
        // check timeout
        int msec = _currentJobs[i]->msecToTimeout(currentTime);
        if (msec <= 0)
          remove(i);
        else if (_pollTimeout < 0 || msec < _pollTimeout)
          _pollTimeout = msec;

        ++i;
      }
    }
  }

  void PollerImpl::remove(jobs_type::size_type n)
  {
    // replace job with last job in poller-list
    jobs_type::size_type last = _currentJobs.size() - 1;

    if (n != last)
    {
      _pollfds[n + 1] = _pollfds[last + 1];
      _currentJobs[n] = _currentJobs[last];
    }

    _pollfds.pop_back();
    _currentJobs.pop_back();
  }

  void PollerImpl::addIdleJob(Jobqueue::JobPtr& job)
  {
    if (job->getFd() == -1)
    {
      log_debug("ignore idle socket which is not connected any more");
      cxxtools::MutexLock lock(_mutex);
      job = 0;
    }
    else
    {
      log_debug("add idle socket " << job->getFd());
      cxxtools::MutexLock lock(_mutex);
      _newJobs.push_back(job);
      job = 0;
    }

    _notifyPipe.write('A');
  }

#endif // #else WITH_EPOLL
}
<|endoftext|>


<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                          License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#ifndef __OPENCV_OBJDETECT_ERFILTER_HPP__
#define __OPENCV_OBJDETECT_ERFILTER_HPP__

#include "opencv2/core.hpp"
#include <vector>
#include <deque>

namespace cv
{

/*!
    Extremal Region Stat structure

    The ERStat structure represents a class-specific Extremal Region (ER).

    An ER is a 4-connected set of pixels with all its grey-level values smaller than the values
    in its outer boundary. A class-specific ER is selected (using a classifier) from all the ER's
    in the component tree of the image.
*/
struct CV_EXPORTS ERStat
{
public:
    //! Constructor
    ERStat(int level = 256, int pixel = 0, int x = 0, int y = 0);
    //! Destructor
    ~ERStat(){};

    //! seed point and the threshold (max grey-level value)
    int pixel;
    int level;

    //! incrementally computable features
    int area;
    int perimeter;
    int euler;                 //!< euler number
    int bbox[4];
    double raw_moments[2];     //!< order 1 raw moments to derive the centroid
    double central_moments[3]; //!< order 2 central moments to construct the covariance matrix
    std::deque<int> *crossings;//!< horizontal crossings

    //! 1st stage features
    float aspect_ratio;
    float compactness;
    float num_holes;
    float med_crossings;

    //! 2nd stage features
    float hole_area_ratio;
    float convex_hull_ratio;
    float num_inflexion_points;

    // TODO Other features can be added (average color, standard deviation, and such)

    // TODO shall we include the pixel list whenever available (i.e. after 2nd stage) ?
    std::vector<int> *pixels;

    //! probability that the ER belongs to the class we are looking for
    double probability;

    //! pointers preserving the tree structure of the component tree
    ERStat* parent;
    ERStat* child;
    ERStat* next;
    ERStat* prev;

    //! wenever the regions is a local maxima of the probability
    bool local_maxima;
    ERStat* max_probability_ancestor;
    ERStat* min_probability_ancestor;
};

/*!
    Base class for 1st and 2nd stages of Neumann and Matas scene text detection algorithms
    Neumann L., Matas J.: Real-Time Scene Text Localization and Recognition, CVPR 2012

    Extracts the component tree (if needed) and filter the extremal regions (ER's) by using a given classifier.
*/
class CV_EXPORTS ERFilter : public cv::Algorithm
{
public:

    //! callback with the classifier is made a class. By doing it we hide SVM, Boost etc.
    class CV_EXPORTS Callback
    {
    public:
        virtual ~Callback(){};
        //! The classifier must return probability measure for the region.
        virtual double eval(const ERStat& stat) = 0; //const = 0; //TODO why cannot use const = 0 here?
    };

    /*!
        the key method. Takes image on input and returns the selected regions in a vector of ERStat
        only distinctive ERs which correspond to characters are selected by a sequential classifier
        \param image   is the input image
        \param regions is output for the first stage, input/output for the second one.
    */
    virtual void run( cv::InputArray image, std::vector<ERStat>& regions ) = 0;

    //! set/get methods to set the algorithm properties,
    virtual void setCallback(const cv::Ptr<ERFilter::Callback>& cb) = 0;
    virtual void setThresholdDelta(int thresholdDelta) = 0;
    virtual void setMinArea(float minArea) = 0;
    virtual void setMaxArea(float maxArea) = 0;
    virtual void setMinProbability(float minProbability) = 0;
    virtual void setMinProbabilityDiff(float minProbabilityDiff) = 0;
    virtual void setNonMaxSuppression(bool nonMaxSuppression) = 0;
    virtual int  getNumRejected() = 0;
};

/*!
    Create an Extremal Region Filter for the 1st stage classifier of N&M algorithm
    Neumann L., Matas J.: Real-Time Scene Text Localization and Recognition, CVPR 2012

    The component tree of the image is extracted by a threshold increased step by step
    from 0 to 255, incrementally computable descriptors (aspect_ratio, compactness,
    number of holes, and number of horizontal crossings) are computed for each ER
    and used as features for a classifier which estimates the class-conditional
    probability P(er|character). The value of P(er|character) is tracked using the inclusion
    relation of ER across all thresholds and only the ERs which correspond to local maximum
    of the probability P(er|character) are selected (if the local maximum of the
    probability is above a global limit pmin and the difference between local maximum and
    local minimum is greater than minProbabilityDiff).

    \param  cb                Callback with the classifier.
                              if omitted tries to load a default classifier from file trained_classifierNM1.xml
    \param  thresholdDelta    Threshold step in subsequent thresholds when extracting the component tree
    \param  minArea           The minimum area (% of image size) allowed for retreived ER's
    \param  minArea           The maximum area (% of image size) allowed for retreived ER's
    \param  minProbability    The minimum probability P(er|character) allowed for retreived ER's
    \param  nonMaxSuppression Whenever non-maximum suppression is done over the branch probabilities
    \param  minProbability    The minimum probability difference between local maxima and local minima ERs
*/
CV_EXPORTS cv::Ptr<ERFilter> createERFilterNM1(const cv::Ptr<ERFilter::Callback>& cb = NULL,
                                                  int thresholdDelta = 1, float minArea = 0.000025,
                                                  float maxArea = 0.13, float minProbability = 0.2,
                                                  bool nonMaxSuppression = true,
                                                  float minProbabilityDiff = 0.1);

/*!
    Create an Extremal Region Filter for the 2nd stage classifier of N&M algorithm
    Neumann L., Matas J.: Real-Time Scene Text Localization and Recognition, CVPR 2012

    In the second stage, the ERs that passed the first stage are classified into character
    and non-character classes using more informative but also more computationally expensive
    features. The classifier uses all the features calculated in the first stage and the following
    additional features: hole area ratio, convex hull ratio, and number of outer inflexion points.

    \param  cb             Callback with the classifier
                           if omitted tries to load a default classifier from file trained_classifierNM2.xml
    \param  minProbability The minimum probability P(er|character) allowed for retreived ER's
*/
CV_EXPORTS cv::Ptr<ERFilter> createERFilterNM2(const cv::Ptr<ERFilter::Callback>& cb = NULL,
                                                  float minProbability = 0.85);

}
#endif // _OPENCV_ERFILTER_HPP_
<commit_msg>using explicit keyword in the ERStat constructor for safe contruction<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                          License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#ifndef __OPENCV_OBJDETECT_ERFILTER_HPP__
#define __OPENCV_OBJDETECT_ERFILTER_HPP__

#include "opencv2/core.hpp"
#include <vector>
#include <deque>

namespace cv
{

/*!
    Extremal Region Stat structure

    The ERStat structure represents a class-specific Extremal Region (ER).

    An ER is a 4-connected set of pixels with all its grey-level values smaller than the values
    in its outer boundary. A class-specific ER is selected (using a classifier) from all the ER's
    in the component tree of the image.
*/
struct CV_EXPORTS ERStat
{
public:
    //! Constructor
    explicit ERStat(int level = 256, int pixel = 0, int x = 0, int y = 0);
    //! Destructor
    ~ERStat(){};

    //! seed point and the threshold (max grey-level value)
    int pixel;
    int level;

    //! incrementally computable features
    int area;
    int perimeter;
    int euler;                 //!< euler number
    int bbox[4];
    double raw_moments[2];     //!< order 1 raw moments to derive the centroid
    double central_moments[3]; //!< order 2 central moments to construct the covariance matrix
    std::deque<int> *crossings;//!< horizontal crossings

    //! 1st stage features
    float aspect_ratio;
    float compactness;
    float num_holes;
    float med_crossings;

    //! 2nd stage features
    float hole_area_ratio;
    float convex_hull_ratio;
    float num_inflexion_points;

    // TODO Other features can be added (average color, standard deviation, and such)

    // TODO shall we include the pixel list whenever available (i.e. after 2nd stage) ?
    std::vector<int> *pixels;

    //! probability that the ER belongs to the class we are looking for
    double probability;

    //! pointers preserving the tree structure of the component tree
    ERStat* parent;
    ERStat* child;
    ERStat* next;
    ERStat* prev;

    //! wenever the regions is a local maxima of the probability
    bool local_maxima;
    ERStat* max_probability_ancestor;
    ERStat* min_probability_ancestor;
};

/*!
    Base class for 1st and 2nd stages of Neumann and Matas scene text detection algorithms
    Neumann L., Matas J.: Real-Time Scene Text Localization and Recognition, CVPR 2012

    Extracts the component tree (if needed) and filter the extremal regions (ER's) by using a given classifier.
*/
class CV_EXPORTS ERFilter : public cv::Algorithm
{
public:

    //! callback with the classifier is made a class. By doing it we hide SVM, Boost etc.
    class CV_EXPORTS Callback
    {
    public:
        virtual ~Callback(){};
        //! The classifier must return probability measure for the region.
        virtual double eval(const ERStat& stat) = 0; //const = 0; //TODO why cannot use const = 0 here?
    };

    /*!
        the key method. Takes image on input and returns the selected regions in a vector of ERStat
        only distinctive ERs which correspond to characters are selected by a sequential classifier
        \param image   is the input image
        \param regions is output for the first stage, input/output for the second one.
    */
    virtual void run( cv::InputArray image, std::vector<ERStat>& regions ) = 0;

    //! set/get methods to set the algorithm properties,
    virtual void setCallback(const cv::Ptr<ERFilter::Callback>& cb) = 0;
    virtual void setThresholdDelta(int thresholdDelta) = 0;
    virtual void setMinArea(float minArea) = 0;
    virtual void setMaxArea(float maxArea) = 0;
    virtual void setMinProbability(float minProbability) = 0;
    virtual void setMinProbabilityDiff(float minProbabilityDiff) = 0;
    virtual void setNonMaxSuppression(bool nonMaxSuppression) = 0;
    virtual int  getNumRejected() = 0;
};

/*!
    Create an Extremal Region Filter for the 1st stage classifier of N&M algorithm
    Neumann L., Matas J.: Real-Time Scene Text Localization and Recognition, CVPR 2012

    The component tree of the image is extracted by a threshold increased step by step
    from 0 to 255, incrementally computable descriptors (aspect_ratio, compactness,
    number of holes, and number of horizontal crossings) are computed for each ER
    and used as features for a classifier which estimates the class-conditional
    probability P(er|character). The value of P(er|character) is tracked using the inclusion
    relation of ER across all thresholds and only the ERs which correspond to local maximum
    of the probability P(er|character) are selected (if the local maximum of the
    probability is above a global limit pmin and the difference between local maximum and
    local minimum is greater than minProbabilityDiff).

    \param  cb                Callback with the classifier.
                              if omitted tries to load a default classifier from file trained_classifierNM1.xml
    \param  thresholdDelta    Threshold step in subsequent thresholds when extracting the component tree
    \param  minArea           The minimum area (% of image size) allowed for retreived ER's
    \param  minArea           The maximum area (% of image size) allowed for retreived ER's
    \param  minProbability    The minimum probability P(er|character) allowed for retreived ER's
    \param  nonMaxSuppression Whenever non-maximum suppression is done over the branch probabilities
    \param  minProbability    The minimum probability difference between local maxima and local minima ERs
*/
CV_EXPORTS cv::Ptr<ERFilter> createERFilterNM1(const cv::Ptr<ERFilter::Callback>& cb = NULL,
                                                  int thresholdDelta = 1, float minArea = 0.000025,
                                                  float maxArea = 0.13, float minProbability = 0.2,
                                                  bool nonMaxSuppression = true,
                                                  float minProbabilityDiff = 0.1);

/*!
    Create an Extremal Region Filter for the 2nd stage classifier of N&M algorithm
    Neumann L., Matas J.: Real-Time Scene Text Localization and Recognition, CVPR 2012

    In the second stage, the ERs that passed the first stage are classified into character
    and non-character classes using more informative but also more computationally expensive
    features. The classifier uses all the features calculated in the first stage and the following
    additional features: hole area ratio, convex hull ratio, and number of outer inflexion points.

    \param  cb             Callback with the classifier
                           if omitted tries to load a default classifier from file trained_classifierNM2.xml
    \param  minProbability The minimum probability P(er|character) allowed for retreived ER's
*/
CV_EXPORTS cv::Ptr<ERFilter> createERFilterNM2(const cv::Ptr<ERFilter::Callback>& cb = NULL,
                                                  float minProbability = 0.85);

}
#endif // _OPENCV_ERFILTER_HPP_
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Manjeet Dahiya
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppDiscoveryManager.h"

#include <QDomElement>
#include <QCoreApplication>

#include "QXmppClient.h"
#include "QXmppConstants.h"
#include "QXmppDiscoveryIq.h"
#include "QXmppStream.h"
#include "QXmppGlobal.h"

QXmppDiscoveryManager::QXmppDiscoveryManager() : QXmppClientExtension(),
    m_clientCategory("client"),
    m_clientType("pc"),
    m_clientName(QString("%1 %2").arg(qApp->applicationName(), qApp->applicationVersion()))
{
    if(m_clientName.isEmpty())
    {
        m_clientName = QString("%1 %2").arg("Based on QXmpp", QXmppVersion());
    }
}

bool QXmppDiscoveryManager::handleStanza(QXmppStream *stream, const QDomElement &element)
{
    if (element.tagName() == "iq" && QXmppDiscoveryIq::isDiscoveryIq(element))
    {
        QXmppDiscoveryIq receivedIq;
        receivedIq.parse(element);

        if(receivedIq.type() == QXmppIq::Get &&
           receivedIq.queryType() == QXmppDiscoveryIq::InfoQuery &&
           (receivedIq.queryNode().isEmpty() || receivedIq.queryNode().startsWith(QString(capabilities_node))))
        {
            // respond to query
            QXmppDiscoveryIq qxmppFeatures = capabilities();
            qxmppFeatures.setId(receivedIq.id());
            qxmppFeatures.setTo(receivedIq.from());
            qxmppFeatures.setQueryNode(receivedIq.queryNode());
            stream->sendPacket(qxmppFeatures);
        }
        else if(receivedIq.queryType() == QXmppDiscoveryIq::InfoQuery)
            emit infoReceived(receivedIq);
        else if(receivedIq.queryType() == QXmppDiscoveryIq::ItemsQuery)
            emit itemsReceived(receivedIq);

        return true;
    }
    return false;
}

QString QXmppDiscoveryManager::requestInfo(const QString& jid, const QString& node)
{
    QXmppDiscoveryIq request;
    request.setType(QXmppIq::Get);
    request.setQueryType(QXmppDiscoveryIq::InfoQuery);
    request.setTo(jid);
    request.setFrom(client()->configuration().jid());
    if(!node.isEmpty())
        request.setQueryNode(node);
    if(client()->sendPacket(request))
        return request.id();
    else
        return "";
}

QString QXmppDiscoveryManager::requestItems(const QString& jid, const QString& node)
{
    QXmppDiscoveryIq request;
    request.setType(QXmppIq::Get);
    request.setQueryType(QXmppDiscoveryIq::ItemsQuery);
    request.setTo(jid);
    request.setFrom(client()->configuration().jid());
    if(!node.isEmpty())
        request.setQueryNode(node);
    if(client()->sendPacket(request))
        return request.id();
    else
        return "";
}

QStringList QXmppDiscoveryManager::discoveryFeatures() const
{
    return QStringList() << ns_disco_info;
}

QXmppDiscoveryIq QXmppDiscoveryManager::capabilities()
{
    QXmppDiscoveryIq iq;
    iq.setType(QXmppIq::Result);
    iq.setQueryType(QXmppDiscoveryIq::InfoQuery);

    // features
    QStringList features;
    features
        << ns_rpc               // XEP-0009: Jabber-RPC
//        << ns_disco_info        // XEP-0030: Service Discovery
        << ns_ibb               // XEP-0047: In-Band Bytestreams
        << ns_vcard             // XEP-0054: vcard-temp
        << ns_bytestreams       // XEP-0065: SOCKS5 Bytestreams
        << ns_chat_states       // XEP-0085: Chat State Notifications
        << ns_stream_initiation // XEP-0095: Stream Initiation
        << ns_stream_initiation_file_transfer // XEP-0096: SI File Transfer
        << ns_capabilities      // XEP-0115 : Entity Capabilities
        << ns_jingle            // XEP-0166 : Jingle
        << ns_jingle_rtp        // XEP-0167 : Jingle RTP Sessions
        << ns_jingle_rtp_audio
        << ns_jingle_ice_udp    // XEP-0176 : Jingle ICE-UDP Transport Method
        << ns_ping;             // XEP-0199: XMPP Ping

    foreach(QXmppClientExtension* extension, client()->extensions())
    {
        if(extension)
            features << extension->discoveryFeatures();
    }

    iq.setFeatures(features);

    // TODO: get identities from the extensions itself like the features
    // identities
    QList<QXmppDiscoveryIq::Identity> identities;
    QXmppDiscoveryIq::Identity identity;

    identity.setCategory("automation");
    identity.setType("rpc");
    identities.append(identity);

    identity.setCategory(clientCategory());
    identity.setType(clientType());
    identity.setName(clientName());
    identities.append(identity);

    iq.setIdentities(identities);
    return iq;
}

/// http://xmpp.org/registrar/disco-categories.html#client
void QXmppDiscoveryManager::setClientCategory(const QString& category)
{
    m_clientCategory = category;
}

void QXmppDiscoveryManager::setClientType(const QString& type)
{
    m_clientType = type;
}

void QXmppDiscoveryManager::setClientName(const QString& name)
{
    m_clientName = name;
}

QString QXmppDiscoveryManager::clientCategory()
{
    return m_clientCategory;
}

QString QXmppDiscoveryManager::clientType()
{
    return m_clientType;
}

QString QXmppDiscoveryManager::clientName()
{
    return m_clientName;
}
<commit_msg>feature will come from discoveryFeatures<commit_after>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Manjeet Dahiya
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppDiscoveryManager.h"

#include <QDomElement>
#include <QCoreApplication>

#include "QXmppClient.h"
#include "QXmppConstants.h"
#include "QXmppDiscoveryIq.h"
#include "QXmppStream.h"
#include "QXmppGlobal.h"

QXmppDiscoveryManager::QXmppDiscoveryManager() : QXmppClientExtension(),
    m_clientCategory("client"),
    m_clientType("pc"),
    m_clientName(QString("%1 %2").arg(qApp->applicationName(), qApp->applicationVersion()))
{
    if(m_clientName.isEmpty())
    {
        m_clientName = QString("%1 %2").arg("Based on QXmpp", QXmppVersion());
    }
}

bool QXmppDiscoveryManager::handleStanza(QXmppStream *stream, const QDomElement &element)
{
    if (element.tagName() == "iq" && QXmppDiscoveryIq::isDiscoveryIq(element))
    {
        QXmppDiscoveryIq receivedIq;
        receivedIq.parse(element);

        if(receivedIq.type() == QXmppIq::Get &&
           receivedIq.queryType() == QXmppDiscoveryIq::InfoQuery &&
           (receivedIq.queryNode().isEmpty() || receivedIq.queryNode().startsWith(QString(capabilities_node))))
        {
            // respond to query
            QXmppDiscoveryIq qxmppFeatures = capabilities();
            qxmppFeatures.setId(receivedIq.id());
            qxmppFeatures.setTo(receivedIq.from());
            qxmppFeatures.setQueryNode(receivedIq.queryNode());
            stream->sendPacket(qxmppFeatures);
        }
        else if(receivedIq.queryType() == QXmppDiscoveryIq::InfoQuery)
            emit infoReceived(receivedIq);
        else if(receivedIq.queryType() == QXmppDiscoveryIq::ItemsQuery)
            emit itemsReceived(receivedIq);

        return true;
    }
    return false;
}

QString QXmppDiscoveryManager::requestInfo(const QString& jid, const QString& node)
{
    QXmppDiscoveryIq request;
    request.setType(QXmppIq::Get);
    request.setQueryType(QXmppDiscoveryIq::InfoQuery);
    request.setTo(jid);
    request.setFrom(client()->configuration().jid());
    if(!node.isEmpty())
        request.setQueryNode(node);
    if(client()->sendPacket(request))
        return request.id();
    else
        return "";
}

QString QXmppDiscoveryManager::requestItems(const QString& jid, const QString& node)
{
    QXmppDiscoveryIq request;
    request.setType(QXmppIq::Get);
    request.setQueryType(QXmppDiscoveryIq::ItemsQuery);
    request.setTo(jid);
    request.setFrom(client()->configuration().jid());
    if(!node.isEmpty())
        request.setQueryNode(node);
    if(client()->sendPacket(request))
        return request.id();
    else
        return "";
}

QStringList QXmppDiscoveryManager::discoveryFeatures() const
{
    return QStringList() << ns_disco_info;
}

QXmppDiscoveryIq QXmppDiscoveryManager::capabilities()
{
    QXmppDiscoveryIq iq;
    iq.setType(QXmppIq::Result);
    iq.setQueryType(QXmppDiscoveryIq::InfoQuery);

    // features
    QStringList features;
    features
        << ns_rpc               // XEP-0009: Jabber-RPC
//        << ns_disco_info        // XEP-0030: Service Discovery
        << ns_ibb               // XEP-0047: In-Band Bytestreams
//        << ns_vcard             // XEP-0054: vcard-temp
        << ns_bytestreams       // XEP-0065: SOCKS5 Bytestreams
        << ns_chat_states       // XEP-0085: Chat State Notifications
        << ns_stream_initiation // XEP-0095: Stream Initiation
        << ns_stream_initiation_file_transfer // XEP-0096: SI File Transfer
        << ns_capabilities      // XEP-0115 : Entity Capabilities
        << ns_jingle            // XEP-0166 : Jingle
        << ns_jingle_rtp        // XEP-0167 : Jingle RTP Sessions
        << ns_jingle_rtp_audio
        << ns_jingle_ice_udp    // XEP-0176 : Jingle ICE-UDP Transport Method
        << ns_ping;             // XEP-0199: XMPP Ping

    foreach(QXmppClientExtension* extension, client()->extensions())
    {
        if(extension)
            features << extension->discoveryFeatures();
    }

    iq.setFeatures(features);

    // TODO: get identities from the extensions itself like the features
    // identities
    QList<QXmppDiscoveryIq::Identity> identities;
    QXmppDiscoveryIq::Identity identity;

    identity.setCategory("automation");
    identity.setType("rpc");
    identities.append(identity);

    identity.setCategory(clientCategory());
    identity.setType(clientType());
    identity.setName(clientName());
    identities.append(identity);

    iq.setIdentities(identities);
    return iq;
}

/// http://xmpp.org/registrar/disco-categories.html#client
void QXmppDiscoveryManager::setClientCategory(const QString& category)
{
    m_clientCategory = category;
}

void QXmppDiscoveryManager::setClientType(const QString& type)
{
    m_clientType = type;
}

void QXmppDiscoveryManager::setClientName(const QString& name)
{
    m_clientName = name;
}

QString QXmppDiscoveryManager::clientCategory()
{
    return m_clientCategory;
}

QString QXmppDiscoveryManager::clientType()
{
    return m_clientType;
}

QString QXmppDiscoveryManager::clientName()
{
    return m_clientName;
}
<|endoftext|>


<commit_before>/*
  $Id$
  $URL$

  Copyright (c) 1998 - 2012

  This file is part of tscan

  tscan is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 3 of the License, or
  (at your option) any later version.

  tscan is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, see <http://www.gnu.org/licenses/>.

  For questions and suggestions, see:

  or send mail to:

*/

#include <cstdio> // for remove()
#include <cstring> // for strerror()
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include "config.h"
#include "libfolia/folia.h"
#include "libfolia/document.h"
#include "tscan/Alpino.h"

using namespace std;
//using namespace TiCC;
using namespace folia;

void addSU( xmlNode *n, vector<Word*>& words, FoliaElement *s ){
  if ( Name( n ) == "node" ){
    KWargs atts = getAttributes( n );
    string cls = atts["cat"];
    bool leaf = false;
    if ( cls.empty() ){
      cls = atts["lcat"];
      leaf = true;
    }
    if ( !cls.empty() ){
      FoliaElement *e =
	s->append( new SyntacticUnit( s->doc(), "cls='" + cls + "'" ) );
      if ( leaf ){
	string posS = atts["begin"];
	int start = stringTo<int>( posS );
	e->append( words[start] );
      }
      else {
	xmlNode *pnt = n->children;
	while ( pnt ){
	  addSU( pnt, words, e );
	  pnt = pnt->next;
	}
      }
    }
  }
}

void extractSyntax( xmlNode *node, Sentence *s ){
  Document *doc = s->doc();
  doc->declare( AnnotationType::SYNTAX,
		"mysyntaxse4t",
		"annotator='alpino'" );
  vector<Word*> words = s->words();
  FoliaElement *layer = s->append( new SyntaxLayer( doc ) );
  FoliaElement *sent = layer->append( new SyntacticUnit( doc, "cls='s'" ) );
  xmlNode *pnt = node->children;
  while ( pnt ){
    addSU( pnt, words, sent );
    pnt = pnt->next;
  }
}

xmlNode *findSubHead( xmlNode *node ){
  xmlNode *pnt = node->children;
  while ( pnt ){
    KWargs atts = getAttributes( pnt );
    string rel = atts["rel"];
    if ( rel == "hd" ){
      return pnt;
      break;
    }
    pnt = pnt->next;
  }
  return 0;
}

void addDep( xmlNode *node, vector<Word*>& words, FoliaElement *layer ){
  KWargs atts = getAttributes( node );
  cerr << "addDep rel=" << atts["rel"] << endl;
  xmlNode *hd = 0;
  xmlNode *pnt = node->children;
  while ( pnt ){
    KWargs atts = getAttributes( pnt );
    string rel = atts["rel"];
    if ( rel == "hd" ){
      hd = pnt;
      break;
    }
    pnt = pnt->next;
  }
  if ( hd ){
    KWargs atts = getAttributes( hd );
    string posH = atts["begin"];
    int headStart = stringTo<int>( posH );
    cerr << "found a head: " << words[headStart]->text() << endl;
    pnt = node->children;
    while ( pnt ){
      if ( pnt != hd ){
	KWargs atts = getAttributes( pnt );
	string rel = atts["rel"];
	cerr << "bekijk REL=" << rel << endl;
	FoliaElement *dep = layer->append( new Dependency( layer->doc(),
							   "class='" + rel + "'" ) );
	FoliaElement *h = dep->append( new DependencyHead() );
	h->append( words[headStart] );
	xmlNode *sub = findSubHead( pnt );
	if ( !sub ){
	  cerr << "geen subHead " << endl;
	  string posD = atts["begin"];
	  int start = stringTo<int>( posD );
	  FoliaElement *d = dep->append( new DependencyDependent() );
	  d->append( words[start] );
	}
	else {
	  KWargs atts = getAttributes( sub );
	  string posD = atts["begin"];
	  int start = stringTo<int>( posD );
	  cerr << "er is een subHead " << words[start]->text() << endl;
	  FoliaElement *d = dep->append( new DependencyDependent() );
	  d->append( words[start] );
	  addDep( pnt, words, layer );
	}
      }
      pnt = pnt->next;
    }
  }
  else {
    cerr << "found no head, recurse " << endl;
    xmlNode *pnt = node->children;
    while ( pnt ){
      addDep( pnt, words, layer );
      pnt = pnt->next;
    }
  }
}

void extractDependency( xmlNode *node, folia::Sentence *s ){
  Document *doc = s->doc();
  doc->declare( AnnotationType::DEPENDENCY,
		"mysdepset",
		"annotator='alpino'" );
  vector<Word*> words = s->words();
  FoliaElement *layer = s->append( new DependenciesLayer( doc ) );
  addDep( node, words, layer );
}

void extractAndAppendParse( xmlDoc *doc, folia::Sentence *s ){
  cerr << "extract the Alpino results!" << endl;
  xmlNode *root = xmlDocGetRootElement( doc );
  xmlNode *pnt = root->children;
  while ( pnt ){
    if ( folia::Name( pnt ) == "node" ){
      cerr << "found a node" << endl;
      // 1 top node i hope
      extractSyntax( pnt, s );
      extractDependency( pnt, s );
      cerr << "added syntax and dependencies " << s->xmlstring() << endl;
      break;
    }
    pnt = pnt->next;
  }
}

bool AlpinoParse( folia::Sentence *s ){
  string txt = folia::UnicodeToUTF8(s->toktext());
  cerr << "parse line: " << txt << endl;
  struct stat sbuf;
  int res = stat( "/tmp/alpino", &sbuf );
  if ( !S_ISDIR(sbuf.st_mode) ){
    res = mkdir( "/tmp/alpino/", S_IRWXU|S_IRWXG );
  }
  res = stat( "/tmp/alpino/parses", &sbuf );
  if ( !S_ISDIR(sbuf.st_mode) ){
    res = mkdir( "/tmp/alpino/parses",  S_IRWXU|S_IRWXG );
  }
  ofstream os( "/tmp/alpino/tempparse.txt" );
  os << txt;
  os.close();
  string parseCmd = "Alpino -fast -flag treebank /tmp/alpino/parses end_hook=xml -parse < /tmp/alpino/tempparse.txt -notk > /dev/null 2>&1";
  res = system( parseCmd.c_str() );
  cerr << "parse res: " << res << endl;
  remove( "/tmp/alpino/tempparse.txt" );
  xmlDoc *xmldoc = xmlReadFile( "/tmp/alpino/parses/1.xml", 0, XML_PARSE_NOBLANKS );
  if ( xmldoc ){
    extractAndAppendParse( xmldoc, s );
  }
  return (xmldoc != 0 );
}

<commit_msg>cleanup <commit_after>/*
  $Id$
  $URL$

  Copyright (c) 1998 - 2012

  This file is part of tscan

  tscan is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 3 of the License, or
  (at your option) any later version.

  tscan is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, see <http://www.gnu.org/licenses/>.

  For questions and suggestions, see:

  or send mail to:

*/

#include <cstdio> // for remove()
#include <cstring> // for strerror()
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include "config.h"
#include "libfolia/folia.h"
#include "libfolia/document.h"
#include "tscan/Alpino.h"

using namespace std;
using namespace folia;

void addSU( xmlNode *n, vector<Word*>& words, FoliaElement *s ){
  if ( Name( n ) == "node" ){
    KWargs atts = getAttributes( n );
    string cls = atts["cat"];
    bool leaf = false;
    if ( cls.empty() ){
      cls = atts["lcat"];
      leaf = true;
    }
    if ( !cls.empty() ){
      FoliaElement *e =
	s->append( new SyntacticUnit( s->doc(), "cls='" + cls + "'" ) );
      if ( leaf ){
	string posS = atts["begin"];
	int start = stringTo<int>( posS );
	e->append( words[start] );
      }
      else {
	xmlNode *pnt = n->children;
	while ( pnt ){
	  addSU( pnt, words, e );
	  pnt = pnt->next;
	}
      }
    }
  }
}

void extractSyntax( xmlNode *node, Sentence *s ){
  Document *doc = s->doc();
  doc->declare( AnnotationType::SYNTAX,
		"mysyntaxset",
		"annotator='alpino'" );
  vector<Word*> words = s->words();
  FoliaElement *layer = s->append( new SyntaxLayer( doc ) );
  FoliaElement *sent = layer->append( new SyntacticUnit( doc, "cls='s'" ) );
  xmlNode *pnt = node->children;
  while ( pnt ){
    addSU( pnt, words, sent );
    pnt = pnt->next;
  }
}

xmlNode *findSubHead( xmlNode *node ){
  xmlNode *pnt = node->children;
  while ( pnt ){
    KWargs atts = getAttributes( pnt );
    string rel = atts["rel"];
    if ( rel == "hd" ){
      return pnt;
      break;
    }
    pnt = pnt->next;
  }
  return 0;
}

void addDep( xmlNode *node, vector<Word*>& words, FoliaElement *layer ){
  KWargs atts = getAttributes( node );
  xmlNode *hd = 0;
  xmlNode *pnt = node->children;
  while ( pnt ){
    KWargs atts = getAttributes( pnt );
    string rel = atts["rel"];
    if ( rel == "hd" ){
      hd = pnt;
      break;
    }
    pnt = pnt->next;
  }
  if ( hd ){
    KWargs atts = getAttributes( hd );
    string posH = atts["begin"];
    int headStart = stringTo<int>( posH );
    pnt = node->children;
    while ( pnt ){
      if ( pnt != hd ){
	KWargs atts = getAttributes( pnt );
	string rel = atts["rel"];
	FoliaElement *dep = layer->append( new Dependency( layer->doc(),
							   "class='" + rel + "'" ) );
	FoliaElement *h = dep->append( new DependencyHead() );
	h->append( words[headStart] );
	xmlNode *sub = findSubHead( pnt );
	if ( !sub ){
	  string posD = atts["begin"];
	  int start = stringTo<int>( posD );
	  FoliaElement *d = dep->append( new DependencyDependent() );
	  d->append( words[start] );
	}
	else {
	  KWargs atts = getAttributes( sub );
	  string posD = atts["begin"];
	  int start = stringTo<int>( posD );
	  FoliaElement *d = dep->append( new DependencyDependent() );
	  d->append( words[start] );
	  addDep( pnt, words, layer );
	}
      }
      pnt = pnt->next;
    }
  }
  else {
    xmlNode *pnt = node->children;
    while ( pnt ){
      addDep( pnt, words, layer );
      pnt = pnt->next;
    }
  }
}

void extractDependency( xmlNode *node, folia::Sentence *s ){
  Document *doc = s->doc();
  doc->declare( AnnotationType::DEPENDENCY,
		"mysdepset",
		"annotator='alpino'" );
  vector<Word*> words = s->words();
  FoliaElement *layer = s->append( new DependenciesLayer( doc ) );
  addDep( node, words, layer );
}

void extractAndAppendParse( xmlDoc *doc, folia::Sentence *s ){
  xmlNode *root = xmlDocGetRootElement( doc );
  xmlNode *pnt = root->children;
  while ( pnt ){
    if ( folia::Name( pnt ) == "node" ){
      // 1 top node i hope
      extractSyntax( pnt, s );
      extractDependency( pnt, s );
      break;
    }
    pnt = pnt->next;
  }
}

bool AlpinoParse( folia::Sentence *s ){
  string txt = folia::UnicodeToUTF8(s->toktext());
  //  cerr << "parse line: " << txt << endl;
  struct stat sbuf;
  int res = stat( "/tmp/alpino", &sbuf );
  if ( !S_ISDIR(sbuf.st_mode) ){
    res = mkdir( "/tmp/alpino/", S_IRWXU|S_IRWXG );
  }
  res = stat( "/tmp/alpino/parses", &sbuf );
  if ( !S_ISDIR(sbuf.st_mode) ){
    res = mkdir( "/tmp/alpino/parses",  S_IRWXU|S_IRWXG );
  }
  ofstream os( "/tmp/alpino/tempparse.txt" );
  os << txt;
  os.close();
  string parseCmd = "Alpino -fast -flag treebank /tmp/alpino/parses end_hook=xml -parse < /tmp/alpino/tempparse.txt -notk > /dev/null 2>&1";
  res = system( parseCmd.c_str() );
  remove( "/tmp/alpino/tempparse.txt" );
  xmlDoc *xmldoc = xmlReadFile( "/tmp/alpino/parses/1.xml", 0, XML_PARSE_NOBLANKS );
  if ( xmldoc ){
    extractAndAppendParse( xmldoc, s );
  }
  return (xmldoc != 0 );
}

<|endoftext|>