<commit_before>/**
 * @file precipitation.cpp
 *
 * @date Jan 28, 2012
 * @author partio
 */

#include "precipitation.h"
#include <iostream>
#include "plugin_factory.h"
#include "logger_factory.h"
#include <boost/lexical_cast.hpp>

#define HIMAN_AUXILIARY_INCLUDE

#include "fetcher.h"
#include "writer.h"
#include "neons.h"
#include "pcuda.h"

#undef HIMAN_AUXILIARY_INCLUDE

#ifdef DEBUG
#include "timer_factory.h"
#endif

using namespace std;
using namespace himan::plugin;

precipitation::precipitation() : itsUseCuda(false)
{
	itsClearTextFormula = "RR = RR_cur - RR_prev";

	itsLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("precipitation"));

}

void precipitation::Process(std::shared_ptr<const plugin_configuration> conf)
{

	unique_ptr<timer> initTimer;

	if (conf->StatisticsEnabled())
	{
		initTimer = unique_ptr<timer> (timer_factory::Instance()->GetTimer());
		initTimer->Start();
	}

	shared_ptr<plugin::pcuda> c = dynamic_pointer_cast<plugin::pcuda> (plugin_factory::Instance()->Plugin("pcuda"));

	if (c->HaveCuda())
	{
		string msg = "I possess the powers of CUDA";

		if (!conf->UseCuda())
		{
			msg += ", but I won't use them";
		}
		else
		{
			msg += ", and I'm not afraid to use them";
			itsUseCuda = true;
		}

		itsLogger->Info(msg);

	}

	// Get number of threads to use

	unsigned short threadCount = ThreadCount(conf->ThreadCount());

	if (conf->StatisticsEnabled())
	{
		conf->Statistics()->UsedThreadCount(threadCount);
		conf->Statistics()->UsedGPUCount(0);
	}

	boost::thread_group g;

	shared_ptr<info> targetInfo = conf->Info();

	/*
	 * Set target parameter to precipitation.
	 *
	 * We need to specify grib and querydata parameter information
	 * since we don't know which one will be the output format.
	 *
	 */

	vector<param> params;

	//param requestedParam ("RR-1-MM", 353);
	//param requestedParam ("RR-3-MM", 354);
	param requestedParam ("RR-6-MM", 355);

	// GRIB 1

	if (conf->OutputFileType() == kGRIB1)
	{
		shared_ptr<neons> n = dynamic_pointer_cast<neons> (plugin_factory::Instance()->Plugin("neons"));

		long parm_id = n->NeonsDB().GetGridParameterId(targetInfo->Producer().TableVersion(), requestedParam.Name());
		requestedParam.GribIndicatorOfParameter(parm_id);
		requestedParam.GribTableVersion(targetInfo->Producer().TableVersion());

	}
	params.push_back(requestedParam);

	targetInfo->Params(params);

	/*
	 * Create data structures.
	 */

	targetInfo->Create();

	/*
	 * Initialize parent class functions for dimension handling
	 */

	Dimension(kLevelDimension);
	FeederInfo(shared_ptr<info> (new info(*targetInfo)));
	FeederInfo()->Param(requestedParam);

	if (conf->StatisticsEnabled())
	{
		initTimer->Stop();
		conf->Statistics()->AddToInitTime(initTimer->GetTime());
	}

	/*
	 * Each thread will have a copy of the target info.
	 */

	for (size_t i = 0; i < threadCount; i++)
	{

		itsLogger->Info("Thread " + boost::lexical_cast<string> (i + 1) + " starting");

		boost::thread* t = new boost::thread(&precipitation::Run,
											 this,
											 shared_ptr<info> (new info(*targetInfo)),
											 conf,
											 i + 1);

		g.add_thread(t);

	}

	g.join_all();

	if (conf->FileWriteOption() == kSingleFile)
	{

		shared_ptr<writer> theWriter = dynamic_pointer_cast <writer> (plugin_factory::Instance()->Plugin("writer"));

		string theOutputFile = conf->ConfigurationFile();

		theWriter->ToFile(targetInfo, conf, theOutputFile);

	}
}

void precipitation::Run(shared_ptr<info> myTargetInfo,
			   shared_ptr<const plugin_configuration> conf,
			   unsigned short threadIndex)
{

	while (AdjustLeadingDimension(myTargetInfo))
	{
		Calculate(myTargetInfo, conf, threadIndex);
	}

}

/*
 * Calculate()
 *
 * This function does the actual calculation.
 */

void precipitation::Calculate(shared_ptr<info> myTargetInfo,
					 shared_ptr<const plugin_configuration> conf,
					 unsigned short threadIndex)
{

	unique_ptr<logger> myThreadedLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("precipitationThread #" + boost::lexical_cast<string> (threadIndex)));

	ResetNonLeadingDimension(myTargetInfo);

	myTargetInfo->FirstParam();

	long paramStep;

	if (myTargetInfo->Param().Name() == "RR-1-MM")
	{
		paramStep = 1;
	}
	else if (myTargetInfo->Param().Name() == "RR-3-MM")
	{
		paramStep = 3;
	}
	else if (myTargetInfo->Param().Name() == "RR-6-MM")
	{
		paramStep = 6;
	}
	else if (myTargetInfo->Param().Name() == "RR-12-MM")
	{
		paramStep = 12;
	}
	else
	{
		throw runtime_error(ClassName() + ": Unsupported parameter: " + myTargetInfo->Param().Name());
	}

	shared_ptr<info> prevInfo;

	bool dataFoundFromRRParam = true; // Assume that we have parameter RR-KGM2 present

	while (AdjustNonLeadingDimension(myTargetInfo))
	{

		assert(myTargetInfo->Time().StepResolution() == kHourResolution);

		shared_ptr<info> RRInfo;

		try
		{
			if (!prevInfo || myTargetInfo->Time().Step() - prevInfo->Time().Step() != paramStep)
			{

				/*
				 * If this is the first time this loop executed, or if the previous data is not suitable
				 * for calculating against current time step data, fetch source data.
				 */

				forecast_time prevTimeStep = myTargetInfo->Time();

				if (prevTimeStep.Step() >= paramStep)
				{
					prevTimeStep.ValidDateTime()->Adjust(kHourResolution, -paramStep);

					prevInfo = FetchSourcePrecipitation(conf,prevTimeStep,myTargetInfo->Level(),dataFoundFromRRParam);
				}
				else
				{
					continue;
				}
			}

			// Get data for current step

			RRInfo = FetchSourcePrecipitation(conf,myTargetInfo->Time(),myTargetInfo->Level(),dataFoundFromRRParam);

		}
		catch (HPExceptionType e)
		{
			switch (e)
			{
				case kFileDataNotFound:
					itsLogger->Info("Skipping step " + boost::lexical_cast<string> (myTargetInfo->Time().Step()) + ", level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));
					myTargetInfo->Data()->Fill(kFloatMissing);

					if (conf->StatisticsEnabled())
					{
						conf->Statistics()->AddToMissingCount(myTargetInfo->Grid()->Size());
						conf->Statistics()->AddToValueCount(myTargetInfo->Grid()->Size());
					}

					continue;
					break;

				default:
					throw runtime_error(ClassName() + ": Unable to proceed");
					break;
			}
		}

		unique_ptr<timer> processTimer = unique_ptr<timer> (timer_factory::Instance()->GetTimer());

		if (conf->StatisticsEnabled())
		{
			processTimer->Start();
		}

		myThreadedLogger->Debug("Calculating time " + myTargetInfo->Time().ValidDateTime()->String("%Y%m%d%H") +
											  " level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));

		shared_ptr<NFmiGrid> RRGrid(RRInfo->Grid()->ToNewbaseGrid());
		shared_ptr<NFmiGrid> prevGrid(prevInfo->Grid()->ToNewbaseGrid());

		shared_ptr<NFmiGrid> targetGrid(myTargetInfo->Grid()->ToNewbaseGrid());

		int missingCount = 0;
		int count = 0;

		bool equalGrids = (*myTargetInfo->Grid() == *RRInfo->Grid());

		string deviceType = "CPU";

		{
			assert(targetGrid->Size() == myTargetInfo->Data()->Size());

			myTargetInfo->ResetLocation();

			targetGrid->Reset();
			prevGrid->Reset();

#ifdef DEBUG
			unique_ptr<timer> t = unique_ptr<timer> (timer_factory::Instance()->GetTimer());
			t->Start();
#endif

			while (myTargetInfo->NextLocation() && targetGrid->Next() && prevGrid->Next())
			{
				count++;

				double RRcur = kFloatMissing;
				double RRprev = kFloatMissing;

				InterpolateToPoint(targetGrid, RRGrid, equalGrids, RRcur);
				InterpolateToPoint(targetGrid, prevGrid, equalGrids, RRprev);

				if (RRcur == kFloatMissing || RRprev == kFloatMissing)
				{
					missingCount++;

					myTargetInfo->Value(kFloatMissing);
					continue;
				}

				double RR = RRcur - RRprev;

				if (RR < 0)
				{
					RR = 0;
				}

				if (!myTargetInfo->Value(RR))
				{
					throw runtime_error(ClassName() + ": Failed to set value to matrix");
				}

			}

			prevInfo = RRInfo;

			/*
			 * Newbase normalizes scanning mode to bottom left -- if that's not what
			 * the target scanning mode is, we have to swap the data back.
			 */

			SwapTo(myTargetInfo, kBottomLeft);

		}

		if (conf->StatisticsEnabled())
		{
			processTimer->Stop();
			conf->Statistics()->AddToProcessingTime(processTimer->GetTime());

#ifdef DEBUG
			itsLogger->Debug("Calculation took " + boost::lexical_cast<string> (processTimer->GetTime()) + " microseconds on " + deviceType);
#endif
			conf->Statistics()->AddToMissingCount(missingCount);
			conf->Statistics()->AddToValueCount(count);
		}

		/*
		 * Now we are done for this level
		 *
		 * Clone info-instance to writer since it might change our descriptor places
		 */

		myThreadedLogger->Info("Missing values: " + boost::lexical_cast<string> (missingCount) + "/" + boost::lexical_cast<string> (count));

		if (conf->FileWriteOption() == kNeons || conf->FileWriteOption() == kMultipleFiles)
		{
			shared_ptr<writer> w = dynamic_pointer_cast <writer> (plugin_factory::Instance()->Plugin("writer"));

			w->ToFile(shared_ptr<info> (new info(*myTargetInfo)), conf);
		}
	}
}

shared_ptr<himan::info> precipitation::FetchSourcePrecipitation(shared_ptr<const plugin_configuration> conf, const forecast_time& wantedTime, const level& wantedLevel, bool& dataFoundFromRRParam)
{

	try
	{
		if (dataFoundFromRRParam)
		{

			return FetchSourceRR(conf,
								wantedTime,
								wantedLevel);

		}
		else
		{
			return FetchSourceConvectiveAndLSRR(conf,
												wantedTime,
												wantedLevel);
		}
	}
	catch (HPExceptionType e)
	{

		if (e == kFileDataNotFound && dataFoundFromRRParam)
		{
			try
			{

				shared_ptr<info> i = FetchSourceConvectiveAndLSRR(conf,
						wantedTime,
						wantedLevel);

				dataFoundFromRRParam = false;

				return i;

			}
			catch (HPExceptionType e)
			{
				throw e;
			}

		}
		else
		{
			throw e;
		}
	}

	throw runtime_error(ClassName() + ": We should never be here but compiler forces this statement");
}

shared_ptr<himan::info> precipitation::FetchSourceRR(shared_ptr<const plugin_configuration> conf, const forecast_time& wantedTime, const level& wantedLevel)
{
	shared_ptr<fetcher> f = dynamic_pointer_cast <fetcher> (plugin_factory::Instance()->Plugin("fetcher"));

	try
	{
		return f->Fetch(conf,
						wantedTime,
						wantedLevel,
						param("RR-KGM2"));
   	}
	catch (HPExceptionType e)
	{
		throw e;
	}

}

shared_ptr<himan::info> precipitation::FetchSourceConvectiveAndLSRR(shared_ptr<const plugin_configuration> conf, const forecast_time& wantedTime, const level& wantedLevel)
{
	shared_ptr<fetcher> f = dynamic_pointer_cast <fetcher> (plugin_factory::Instance()->Plugin("fetcher"));

	shared_ptr<himan::info> ConvectiveInfo;
	shared_ptr<himan::info> LSInfo;
	shared_ptr<himan::info> RRInfo;

	try
	{

		ConvectiveInfo = f->Fetch(conf,
						wantedTime,
						wantedLevel,
						param("RRC-KGM2"));

		LSInfo = f->Fetch(conf,
						wantedTime,
						wantedLevel,
						param("RRR-KGM2"));
	}
	catch (HPExceptionType e)
	{
		throw e;
	}

	ConvectiveInfo->ResetLocation();
	LSInfo->ResetLocation();

	assert(*ConvectiveInfo->Grid() == *LSInfo->Grid());

	RRInfo->Data()->Resize(ConvectiveInfo->Data()->SizeX(),LSInfo->Data()->SizeY());

	while (ConvectiveInfo->NextLocation() && LSInfo->NextLocation() && RRInfo->NextLocation())
	{
		double C = ConvectiveInfo->Value();
		double LS = LSInfo->Value();

		RRInfo->Value(C+LS);
	}

	return RRInfo;
}
<commit_msg>Support RR parameters with different lengths<commit_after>/**
 * @file precipitation.cpp
 *
 * @date Jan 28, 2012
 * @author partio
 */

#include "precipitation.h"
#include <iostream>
#include "plugin_factory.h"
#include "logger_factory.h"
#include <boost/lexical_cast.hpp>

#define HIMAN_AUXILIARY_INCLUDE

#include "fetcher.h"
#include "writer.h"
#include "neons.h"
#include "pcuda.h"

#undef HIMAN_AUXILIARY_INCLUDE

#ifdef DEBUG
#include "timer_factory.h"
#endif

using namespace std;
using namespace himan::plugin;

precipitation::precipitation() : itsUseCuda(false)
{
	itsClearTextFormula = "RR = RR_cur - RR_prev";

	itsLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("precipitation"));

}

void precipitation::Process(std::shared_ptr<const plugin_configuration> conf)
{

	unique_ptr<timer> initTimer;

	if (conf->StatisticsEnabled())
	{
		initTimer = unique_ptr<timer> (timer_factory::Instance()->GetTimer());
		initTimer->Start();
	}

	shared_ptr<plugin::pcuda> c = dynamic_pointer_cast<plugin::pcuda> (plugin_factory::Instance()->Plugin("pcuda"));

	if (c->HaveCuda())
	{
		string msg = "I possess the powers of CUDA";

		if (!conf->UseCuda())
		{
			msg += ", but I won't use them";
		}
		else
		{
			msg += ", and I'm not afraid to use them";
			itsUseCuda = true;
		}

		itsLogger->Info(msg);

	}

	// Get number of threads to use

	unsigned short threadCount = ThreadCount(conf->ThreadCount());

	if (conf->StatisticsEnabled())
	{
		conf->Statistics()->UsedThreadCount(threadCount);
		conf->Statistics()->UsedGPUCount(0);
	}

	boost::thread_group g;

	shared_ptr<info> targetInfo = conf->Info();

	/*
	 * Set target parameter to precipitation.
	 *
	 * We need to specify grib and querydata parameter information
	 * since we don't know which one will be the output format.
	 *
	 */

	vector<param> params;

	param requestedParam ("RR-6-MM", 355);

	if (conf->Exists("rr1h") && conf->GetValue("rr1h") == "true")
	{
		params.push_back(param("RR-1-MM", 353));
	}

	if (conf->Exists("rr3h") && conf->GetValue("rr3h") == "true")
	{
		params.push_back(param("RR-3-MM", 354));
	}

	if (conf->Exists("rr6h") && conf->GetValue("rr6h") == "true")
	{
		params.push_back(param("RR-6-MM", 355));
	}

	if (conf->Exists("rr12h") && conf->GetValue("rr12h") == "true")
	{
		params.push_back(param("RR-12-MM", 356));
	}

	if (params.empty())
	{
		itsLogger->Trace("No parameter definition given, defaulting to rr6h");
		params.push_back(param("RR-6-MM", 355));
	}

	// GRIB 1

	if (conf->OutputFileType() == kGRIB1)
	{
		shared_ptr<neons> n = dynamic_pointer_cast<neons> (plugin_factory::Instance()->Plugin("neons"));

		for (size_t i = 0; i < params.size(); i++)
		{
			param p = params[i];

			long parm_id = n->NeonsDB().GetGridParameterId(targetInfo->Producer().TableVersion(), p.Name());
			p.GribIndicatorOfParameter(parm_id);
			p.GribTableVersion(targetInfo->Producer().TableVersion());

			params[i] = p;
		}
	}

	targetInfo->Params(params);

	/*
	 * Create data structures.
	 */

	targetInfo->Create();

	/*
	 * Initialize parent class functions for dimension handling
	 */

	Dimension(conf->LeadingDimension());
	FeederInfo(shared_ptr<info> (new info(*targetInfo)));
	FeederInfo()->Param(requestedParam);

	if (conf->StatisticsEnabled())
	{
		initTimer->Stop();
		conf->Statistics()->AddToInitTime(initTimer->GetTime());
	}

	/*
	 * Each thread will have a copy of the target info.
	 */

	unique_ptr<timer> processTimer = unique_ptr<timer> (timer_factory::Instance()->GetTimer());

	if (conf->StatisticsEnabled())
	{
		processTimer->Start();
	}

	for (size_t i = 0; i < threadCount; i++)
	{

		itsLogger->Info("Thread " + boost::lexical_cast<string> (i + 1) + " starting");

		boost::thread* t = new boost::thread(&precipitation::Run,
											 this,
											 shared_ptr<info> (new info(*targetInfo)),
											 conf,
											 i + 1);

		g.add_thread(t);

	}

	g.join_all();

	if (conf->StatisticsEnabled())
	{
		processTimer->Stop();
		conf->Statistics()->AddToProcessingTime(processTimer->GetTime());
	}

	if (conf->FileWriteOption() == kSingleFile)
	{

		shared_ptr<writer> theWriter = dynamic_pointer_cast <writer> (plugin_factory::Instance()->Plugin("writer"));

		string theOutputFile = conf->ConfigurationFile();

		theWriter->ToFile(targetInfo, conf, theOutputFile);

	}
}

void precipitation::Run(shared_ptr<info> myTargetInfo,
			   shared_ptr<const plugin_configuration> conf,
			   unsigned short threadIndex)
{

	while (AdjustLeadingDimension(myTargetInfo))
	{
		Calculate(myTargetInfo, conf, threadIndex);
	}

}

/*
 * Calculate()
 *
 * This function does the actual calculation.
 */

void precipitation::Calculate(shared_ptr<info> myTargetInfo,
					 shared_ptr<const plugin_configuration> conf,
					 unsigned short threadIndex)
{

	unique_ptr<logger> myThreadedLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("precipitationThread #" + boost::lexical_cast<string> (threadIndex)));

	ResetNonLeadingDimension(myTargetInfo);

	myTargetInfo->FirstParam();

	bool dataFoundFromRRParam = true; // Assume that we have parameter RR-KGM2 present

	while (AdjustNonLeadingDimension(myTargetInfo))
	{
		shared_ptr<info> prevInfo;

		assert(myTargetInfo->Time().StepResolution() == kHourResolution);

		for (myTargetInfo->ResetParam(); myTargetInfo->NextParam(); )
		{
			shared_ptr<info> RRInfo;

			long paramStep;

			if (myTargetInfo->Param().Name() == "RR-1-MM")
			{
				paramStep = 1;
			}
			else if (myTargetInfo->Param().Name() == "RR-3-MM")
			{
				paramStep = 3;
			}
			else if (myTargetInfo->Param().Name() == "RR-6-MM")
			{
				paramStep = 6;
			}
			else if (myTargetInfo->Param().Name() == "RR-12-MM")
			{
				paramStep = 12;
			}
			else
			{
				throw runtime_error(ClassName() + ": Unsupported parameter: " + myTargetInfo->Param().Name());
			}

			myThreadedLogger->Warning("Calculating parameter " + myTargetInfo->Param().Name() + " time " + myTargetInfo->Time().ValidDateTime()->String("%Y%m%d%H") +
												  " level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));
			try
			{
				if (!prevInfo || myTargetInfo->Time().Step() - prevInfo->Time().Step() != paramStep)
				{

					/*
					 * If this is the first time this loop executed, or if the previous data is not suitable
					 * for calculating against current time step data, fetch source data.
					 */

					forecast_time prevTimeStep = myTargetInfo->Time();

					if (prevTimeStep.Step() >= paramStep)
					{
						prevTimeStep.ValidDateTime()->Adjust(kHourResolution, -paramStep);

						prevInfo = FetchSourcePrecipitation(conf,prevTimeStep,myTargetInfo->Level(),dataFoundFromRRParam);
					}
					else
					{
						continue;
					}
				}

				// Get data for current step

				RRInfo = FetchSourcePrecipitation(conf,myTargetInfo->Time(),myTargetInfo->Level(),dataFoundFromRRParam);

			}
			catch (HPExceptionType e)
			{
				switch (e)
				{
					case kFileDataNotFound:
						itsLogger->Info("Skipping step " + boost::lexical_cast<string> (myTargetInfo->Time().Step()) + ", level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));
						myTargetInfo->Data()->Fill(kFloatMissing);

						if (conf->StatisticsEnabled())
						{
							conf->Statistics()->AddToMissingCount(myTargetInfo->Grid()->Size());
							conf->Statistics()->AddToValueCount(myTargetInfo->Grid()->Size());
						}

						continue;
						break;

					default:
						throw runtime_error(ClassName() + ": Unable to proceed");
						break;
				}
			}

			myThreadedLogger->Debug("Calculating parameter " + myTargetInfo->Param().Name() + " time " + myTargetInfo->Time().ValidDateTime()->String("%Y%m%d%H") +
												  " level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));

			shared_ptr<NFmiGrid> RRGrid(RRInfo->Grid()->ToNewbaseGrid());
			shared_ptr<NFmiGrid> prevGrid(prevInfo->Grid()->ToNewbaseGrid());

			shared_ptr<NFmiGrid> targetGrid(myTargetInfo->Grid()->ToNewbaseGrid());

			int missingCount = 0;
			int count = 0;

			bool equalGrids = (*myTargetInfo->Grid() == *RRInfo->Grid());

			string deviceType = "CPU";

			{
				assert(targetGrid->Size() == myTargetInfo->Data()->Size());

				myTargetInfo->ResetLocation();

				targetGrid->Reset();
				prevGrid->Reset();

				while (myTargetInfo->NextLocation() && targetGrid->Next() && prevGrid->Next())
				{
					count++;

					double RRcur = kFloatMissing;
					double RRprev = kFloatMissing;

					InterpolateToPoint(targetGrid, RRGrid, equalGrids, RRcur);
					InterpolateToPoint(targetGrid, prevGrid, equalGrids, RRprev);

					if (RRcur == kFloatMissing || RRprev == kFloatMissing)
					{
						missingCount++;

						myTargetInfo->Value(kFloatMissing);
						continue;
					}

					double RR = RRcur - RRprev;

					if (RR < 0)
					{
						RR = 0;
					}

					if (!myTargetInfo->Value(RR))
					{
						throw runtime_error(ClassName() + ": Failed to set value to matrix");
					}

				}

				prevInfo = RRInfo;

				/*
				 * Newbase normalizes scanning mode to bottom left -- if that's not what
				 * the target scanning mode is, we have to swap the data back.
				 */

				SwapTo(myTargetInfo, kBottomLeft);

			}

			if (conf->StatisticsEnabled())
			{
				conf->Statistics()->AddToMissingCount(missingCount);
				conf->Statistics()->AddToValueCount(count);
			}

			/*
			* Now we are done for this param for this level
			*
			* Clone info-instance to writer since it might change our descriptor places
			*/

		   myThreadedLogger->Info("Missing values: " + boost::lexical_cast<string> (missingCount) + "/" + boost::lexical_cast<string> (count));

		   if (conf->FileWriteOption() == kNeons || conf->FileWriteOption() == kMultipleFiles)
		   {
			   shared_ptr<writer> w = dynamic_pointer_cast <writer> (plugin_factory::Instance()->Plugin("writer"));

			   shared_ptr<info> tempInfo(new info(*myTargetInfo));

			   for (tempInfo->ResetParam(); tempInfo->NextParam(); )
			   {
				   w->ToFile(tempInfo, conf);
			   }
		   }
		}
	}
}

shared_ptr<himan::info> precipitation::FetchSourcePrecipitation(shared_ptr<const plugin_configuration> conf, const forecast_time& wantedTime, const level& wantedLevel, bool& dataFoundFromRRParam)
{

	try
	{
		if (dataFoundFromRRParam)
		{

			return FetchSourceRR(conf,
								wantedTime,
								wantedLevel);

		}
		else
		{
			return FetchSourceConvectiveAndLSRR(conf,
												wantedTime,
												wantedLevel);
		}
	}
	catch (HPExceptionType e)
	{

		if (e == kFileDataNotFound && dataFoundFromRRParam)
		{
			try
			{

				shared_ptr<info> i = FetchSourceConvectiveAndLSRR(conf,
						wantedTime,
						wantedLevel);

				dataFoundFromRRParam = false;

				return i;

			}
			catch (HPExceptionType e)
			{
				throw e;
			}

		}
		else
		{
			throw e;
		}
	}

	throw runtime_error(ClassName() + ": We should never be here but compiler forces this statement");
}

shared_ptr<himan::info> precipitation::FetchSourceRR(shared_ptr<const plugin_configuration> conf, const forecast_time& wantedTime, const level& wantedLevel)
{
	shared_ptr<fetcher> f = dynamic_pointer_cast <fetcher> (plugin_factory::Instance()->Plugin("fetcher"));

	try
	{
		return f->Fetch(conf,
						wantedTime,
						wantedLevel,
						param("RR-KGM2"));
   	}
	catch (HPExceptionType e)
	{
		throw e;
	}

}

shared_ptr<himan::info> precipitation::FetchSourceConvectiveAndLSRR(shared_ptr<const plugin_configuration> conf, const forecast_time& wantedTime, const level& wantedLevel)
{
	shared_ptr<fetcher> f = dynamic_pointer_cast <fetcher> (plugin_factory::Instance()->Plugin("fetcher"));

	shared_ptr<himan::info> ConvectiveInfo;
	shared_ptr<himan::info> LSInfo;
	shared_ptr<himan::info> RRInfo;

	try
	{

		ConvectiveInfo = f->Fetch(conf,
						wantedTime,
						wantedLevel,
						param("RRC-KGM2"));

		LSInfo = f->Fetch(conf,
						wantedTime,
						wantedLevel,
						param("RRR-KGM2"));
	}
	catch (HPExceptionType e)
	{
		throw e;
	}

	ConvectiveInfo->ResetLocation();
	LSInfo->ResetLocation();

	assert(*ConvectiveInfo->Grid() == *LSInfo->Grid());

	RRInfo->Data()->Resize(ConvectiveInfo->Data()->SizeX(),LSInfo->Data()->SizeY());

	while (ConvectiveInfo->NextLocation() && LSInfo->NextLocation() && RRInfo->NextLocation())
	{
		double C = ConvectiveInfo->Value();
		double LS = LSInfo->Value();

		RRInfo->Value(C+LS);
	}

	return RRInfo;
}
<|endoftext|>


<commit_before>#pragma once

#include "blackhole/logger.hpp"

namespace blackhole {

template<class Logger, class Mutex = std::mutex>
class synchronized {
public:
    typedef Logger logger_type;
    typedef Mutex mutex_type;

private:
    logger_type logger;
    mutable mutex_type mutex;

public:
    synchronized() {}

    explicit synchronized(logger_type&& logger) :
        logger(std::move(logger))
    {}

    synchronized(synchronized&& other) {
        *this = std::move(other);
    }

    synchronized& operator=(synchronized&& other) {
        std::lock_guard<mutex_type>(other.mutex);
        logger = std::move(other.logger);
        return *this;
    }

    bool enabled() const {
        std::lock_guard<mutex_type> lock(mutex);
        return logger.enabled();
    }

    void enable() {
        std::lock_guard<mutex_type> lock(mutex);
        logger.enable();
    }

    void disable() {
        std::lock_guard<mutex_type> lock(mutex);
        logger.disable();
    }

    void set_filter(filter_t&& filter) {
        std::lock_guard<mutex_type> lock(mutex);
        logger.set_filter(std::move(filter));
    }

    void add_attribute(const log::attribute_pair_t& attr) {
        std::lock_guard<mutex_type> lock(mutex);
        logger.add_attribute(attr);
    }

    void add_frontend(std::unique_ptr<base_frontend_t> frontend) {
        std::lock_guard<mutex_type> lock(mutex);
        logger.add_frontend(std::move(frontend));
    }

    void set_exception_handler(log::exception_handler_t&& handler) {
        std::lock_guard<mutex_type> lock(mutex);
        logger.set_exception_handler(std::move(handler));
    }

    template<typename... Args>
    log::record_t open_record(Args&&... args) const {
        std::lock_guard<mutex_type> lock(mutex);
        return logger.open_record(std::forward<Args>(args)...);
    }

    void push(log::record_t&& record) const {
        std::lock_guard<mutex_type> lock(mutex);
        logger.push(std::move(record));
    }
};

} // namespace blackhole
<commit_msg>[Bug Fix] Acquiring both locks to prevent data race.<commit_after>#pragma once

#include "blackhole/logger.hpp"

namespace blackhole {

template<class Logger, class Mutex = std::mutex>
class synchronized {
public:
    typedef Logger logger_type;
    typedef Mutex mutex_type;

private:
    logger_type logger;
    mutable mutex_type mutex;

public:
    synchronized() {}

    explicit synchronized(logger_type&& logger) :
        logger(std::move(logger))
    {}

    synchronized(synchronized&& other) {
        *this = std::move(other);
    }

    synchronized& operator=(synchronized&& other) {
        std::lock(mutex, other.mutex);
        logger = std::move(other.logger);
        return *this;
    }

    bool enabled() const {
        std::lock_guard<mutex_type> lock(mutex);
        return logger.enabled();
    }

    void enable() {
        std::lock_guard<mutex_type> lock(mutex);
        logger.enable();
    }

    void disable() {
        std::lock_guard<mutex_type> lock(mutex);
        logger.disable();
    }

    void set_filter(filter_t&& filter) {
        std::lock_guard<mutex_type> lock(mutex);
        logger.set_filter(std::move(filter));
    }

    void add_attribute(const log::attribute_pair_t& attr) {
        std::lock_guard<mutex_type> lock(mutex);
        logger.add_attribute(attr);
    }

    void add_frontend(std::unique_ptr<base_frontend_t> frontend) {
        std::lock_guard<mutex_type> lock(mutex);
        logger.add_frontend(std::move(frontend));
    }

    void set_exception_handler(log::exception_handler_t&& handler) {
        std::lock_guard<mutex_type> lock(mutex);
        logger.set_exception_handler(std::move(handler));
    }

    template<typename... Args>
    log::record_t open_record(Args&&... args) const {
        std::lock_guard<mutex_type> lock(mutex);
        return logger.open_record(std::forward<Args>(args)...);
    }

    void push(log::record_t&& record) const {
        std::lock_guard<mutex_type> lock(mutex);
        logger.push(std::move(record));
    }
};

} // namespace blackhole
<|endoftext|>


<commit_before>#ifndef LIGHTGBM_BOOSTING_SCORE_UPDATER_HPP_
#define LIGHTGBM_BOOSTING_SCORE_UPDATER_HPP_

#include <LightGBM/utils/openmp_wrapper.h>
#include <LightGBM/meta.h>
#include <LightGBM/dataset.h>
#include <LightGBM/tree.h>
#include <LightGBM/tree_learner.h>

#include <cstring>

namespace LightGBM {
/*!
* \brief Used to store and update score for data
*/
class ScoreUpdater {
public:
  /*!
  * \brief Constructor, will pass a const pointer of dataset
  * \param data This class will bind with this data set
  */
  ScoreUpdater(const Dataset* data, int num_tree_per_iteration) : data_(data) {
    num_data_ = data->num_data();
    int64_t total_size = static_cast<int64_t>(num_data_) * num_tree_per_iteration;
    score_.resize(total_size);
    // default start score is zero
    #pragma omp parallel for schedule(static)
    for (int64_t i = 0; i < total_size; ++i) {
      score_[i] = 0.0f;
    }
    has_init_score_ = false;
    const double* init_score = data->metadata().init_score();
    // if exists initial score, will start from it
    if (init_score != nullptr) {
      if ((data->metadata().num_init_score() % num_data_) != 0
          || (data->metadata().num_init_score() / num_data_) != num_tree_per_iteration) {
        Log::Fatal("number of class for initial score error");
      }
      has_init_score_ = true;
      #pragma omp parallel for schedule(static)
      for (int64_t i = 0; i < total_size; ++i) {
        score_[i] = init_score[i];
      }
    }
  }
  /*! \brief Destructor */
  ~ScoreUpdater() {

  }

  inline bool has_init_score() const { return has_init_score_; }

  inline void AddScore(double val, int cur_tree_id) {
    int64_t offset = cur_tree_id * num_data_;
    #pragma omp parallel for schedule(static)
    for (int64_t i = 0; i < num_data_; ++i) {
      score_[offset + i] += val;
    }
  }
  /*!
  * \brief Using tree model to get prediction number, then adding to scores for all data
  *        Note: this function generally will be used on validation data too.
  * \param tree Trained tree model
  * \param cur_tree_id Current tree for multiclass training
  */
  inline void AddScore(const Tree* tree, int cur_tree_id) {
    tree->AddPredictionToScore(data_, num_data_, score_.data() + cur_tree_id * num_data_);
  }
  /*!
  * \brief Adding prediction score, only used for training data.
  *        The training data is partitioned into tree leaves after training
  *        Based on which We can get prediction quickly.
  * \param tree_learner
  * \param cur_tree_id Current tree for multiclass training
  */
  inline void AddScore(const TreeLearner* tree_learner, const Tree* tree, int cur_tree_id) {
    tree_learner->AddPredictionToScore(tree, score_.data() + cur_tree_id * num_data_);
  }
  /*!
  * \brief Using tree model to get prediction number, then adding to scores for parts of data
  *        Used for prediction of training out-of-bag data
  * \param tree Trained tree model
  * \param data_indices Indices of data that will be processed
  * \param data_cnt Number of data that will be processed
  * \param cur_tree_id Current tree for multiclass training
  */
  inline void AddScore(const Tree* tree, const data_size_t* data_indices,
                       data_size_t data_cnt, int cur_tree_id) {
    tree->AddPredictionToScore(data_, data_indices, data_cnt, score_.data() + cur_tree_id * num_data_);
  }
  /*! \brief Pointer of score */
  inline const double* score() const { return score_.data(); }
  inline const data_size_t num_data() const { return num_data_; }

  /*! \brief Disable copy */
  ScoreUpdater& operator=(const ScoreUpdater&) = delete;
  /*! \brief Disable copy */
  ScoreUpdater(const ScoreUpdater&) = delete;
private:
  /*! \brief Number of total data */
  data_size_t num_data_;
  /*! \brief Pointer of data set */
  const Dataset* data_;
  /*! \brief Scores for data set */
  std::vector<double> score_;
  bool has_init_score_;
};

}  // namespace LightGBM
#endif   // LightGBM_BOOSTING_SCORE_UPDATER_HPP_
<commit_msg>Shut up warning (#534)<commit_after>#ifndef LIGHTGBM_BOOSTING_SCORE_UPDATER_HPP_
#define LIGHTGBM_BOOSTING_SCORE_UPDATER_HPP_

#include <LightGBM/utils/openmp_wrapper.h>
#include <LightGBM/meta.h>
#include <LightGBM/dataset.h>
#include <LightGBM/tree.h>
#include <LightGBM/tree_learner.h>

#include <cstring>

namespace LightGBM {
/*!
* \brief Used to store and update score for data
*/
class ScoreUpdater {
public:
  /*!
  * \brief Constructor, will pass a const pointer of dataset
  * \param data This class will bind with this data set
  */
  ScoreUpdater(const Dataset* data, int num_tree_per_iteration) : data_(data) {
    num_data_ = data->num_data();
    int64_t total_size = static_cast<int64_t>(num_data_) * num_tree_per_iteration;
    score_.resize(total_size);
    // default start score is zero
    #pragma omp parallel for schedule(static)
    for (int64_t i = 0; i < total_size; ++i) {
      score_[i] = 0.0f;
    }
    has_init_score_ = false;
    const double* init_score = data->metadata().init_score();
    // if exists initial score, will start from it
    if (init_score != nullptr) {
      if ((data->metadata().num_init_score() % num_data_) != 0
          || (data->metadata().num_init_score() / num_data_) != num_tree_per_iteration) {
        Log::Fatal("number of class for initial score error");
      }
      has_init_score_ = true;
      #pragma omp parallel for schedule(static)
      for (int64_t i = 0; i < total_size; ++i) {
        score_[i] = init_score[i];
      }
    }
  }
  /*! \brief Destructor */
  ~ScoreUpdater() {

  }

  inline bool has_init_score() const { return has_init_score_; }

  inline void AddScore(double val, int cur_tree_id) {
    int64_t offset = cur_tree_id * num_data_;
    #pragma omp parallel for schedule(static)
    for (int64_t i = 0; i < num_data_; ++i) {
      score_[offset + i] += val;
    }
  }
  /*!
  * \brief Using tree model to get prediction number, then adding to scores for all data
  *        Note: this function generally will be used on validation data too.
  * \param tree Trained tree model
  * \param cur_tree_id Current tree for multiclass training
  */
  inline void AddScore(const Tree* tree, int cur_tree_id) {
    tree->AddPredictionToScore(data_, num_data_, score_.data() + cur_tree_id * num_data_);
  }
  /*!
  * \brief Adding prediction score, only used for training data.
  *        The training data is partitioned into tree leaves after training
  *        Based on which We can get prediction quickly.
  * \param tree_learner
  * \param cur_tree_id Current tree for multiclass training
  */
  inline void AddScore(const TreeLearner* tree_learner, const Tree* tree, int cur_tree_id) {
    tree_learner->AddPredictionToScore(tree, score_.data() + cur_tree_id * num_data_);
  }
  /*!
  * \brief Using tree model to get prediction number, then adding to scores for parts of data
  *        Used for prediction of training out-of-bag data
  * \param tree Trained tree model
  * \param data_indices Indices of data that will be processed
  * \param data_cnt Number of data that will be processed
  * \param cur_tree_id Current tree for multiclass training
  */
  inline void AddScore(const Tree* tree, const data_size_t* data_indices,
                       data_size_t data_cnt, int cur_tree_id) {
    tree->AddPredictionToScore(data_, data_indices, data_cnt, score_.data() + cur_tree_id * num_data_);
  }
  /*! \brief Pointer of score */
  inline const double* score() const { return score_.data(); }
  inline data_size_t num_data() const { return num_data_; }

  /*! \brief Disable copy */
  ScoreUpdater& operator=(const ScoreUpdater&) = delete;
  /*! \brief Disable copy */
  ScoreUpdater(const ScoreUpdater&) = delete;
private:
  /*! \brief Number of total data */
  data_size_t num_data_;
  /*! \brief Pointer of data set */
  const Dataset* data_;
  /*! \brief Scores for data set */
  std::vector<double> score_;
  bool has_init_score_;
};

}  // namespace LightGBM
#endif   // LightGBM_BOOSTING_SCORE_UPDATER_HPP_
<|endoftext|>


<commit_before>#include <wayfire/plugin.hpp>
#include <wayfire/debug.hpp>
#include <wayfire/output.hpp>
#include <wayfire/core.hpp>
#include <wayfire/view.hpp>
#include <wayfire/workspace-manager.hpp>
#include <wayfire/render-manager.hpp>
#include <algorithm>
#include <cmath>
#include <linux/input-event-codes.h>
#include "wayfire/signal-definitions.hpp"
#include <wayfire/plugins/common/geometry-animation.hpp>

#include "snap_signal.hpp"
#include "../wobbly/wobbly-signal.hpp"

extern "C"
{
#include <wlr/util/edges.h>
}

const std::string grid_view_id = "grid-view";

class wayfire_grid_view_cdata : public wf::custom_data_t
{
    bool is_active = true;

    wayfire_view view;
    wf::output_t *output;
    wf::effect_hook_t pre_hook;
    wf::signal_callback_t unmapped;

    int32_t tiled_edges = -1;
    const wf::plugin_grab_interface_uptr& iface;

    wf::option_wrapper_t<std::string> animation_type{"grid/type"};
    wf::option_wrapper_t<int> animation_duration{"grid/duration"};
    wf::geometry_animation_t animation{animation_duration};

    public:

    wayfire_grid_view_cdata(wayfire_view view,
        const wf::plugin_grab_interface_uptr& _iface)
        : iface(_iface)
    {
        this->view = view;
        this->output = view->get_output();
        this->animation = wf::geometry_animation_t{animation_duration};

        if (!view->get_output()->activate_plugin(iface,
                wf::PLUGIN_ACTIVATE_ALLOW_MULTIPLE))
        {
            is_active = false;
            return;
        }

        pre_hook = [=] () {
            adjust_geometry();
        };
        output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);

        unmapped = [=] (wf::signal_data_t *data)
        {
            if (get_signaled_view(data) == view)
                destroy();
        };

        output->render->set_redraw_always(true);
        output->connect_signal("view-disappeared", &unmapped);
        output->connect_signal("detach-view", &unmapped);
    }

    void destroy()
    {
        view->erase_data<wayfire_grid_view_cdata>();
    }

    void adjust_target_geometry(wf::geometry_t geometry, int32_t target_edges)
    {
        animation.set_start(view->get_wm_geometry());
        animation.set_end(geometry);

        /* Restore tiled edges if we don't need to set something special when
         * grid is ready */
        if (target_edges < 0) {
            this->tiled_edges = view->tiled_edges;
        } else {
            this->tiled_edges = target_edges;
        }

        std::string type = animation_type;
        if (view->get_transformer("wobbly") || !is_active)
            type = "wobbly";

        if (type == "none")
        {
            set_end_state(geometry, tiled_edges);
            return destroy();
        }

        if (type == "wobbly")
        {
            /* Order is important here: first we set the view geometry, and
             * after that we set the snap request. Otherwise the wobbly plugin
             * will think the view actually moved */
            set_end_state(geometry, tiled_edges);
            activate_wobbly(view);
            return destroy();
        }

        view->set_tiled(wf::TILED_EDGES_ALL);
        view->set_moving(1);
        view->set_resizing(1);
        animation.start();
    }

    void set_end_state(wf::geometry_t geometry, int32_t edges)
    {
        view->set_geometry(geometry);
        if (edges >= 0)
            view->set_tiled(edges);
    }

    void adjust_geometry()
    {
        if (!animation.running())
        {
            set_end_state(animation, tiled_edges);
            view->set_moving(0);
            view->set_resizing(0);

            return destroy();
        }

        view->set_geometry((wf::geometry_t) animation);
    }

    ~wayfire_grid_view_cdata()
    {
        if (!is_active)
            return;

        output->render->rem_effect(&pre_hook);
        output->deactivate_plugin(iface);
        output->render->set_redraw_always(false);
        output->disconnect_signal("view-disappeared", &unmapped);
        output->disconnect_signal("detach-view", &unmapped);
    }
};

class wf_grid_slot_data : public wf::custom_data_t
{
    public:
        int slot;
};

nonstd::observer_ptr<wayfire_grid_view_cdata> ensure_grid_view(wayfire_view view,
        const wf::plugin_grab_interface_uptr& iface)
{
    if (!view->has_data<wayfire_grid_view_cdata>())
    {
        view->store_data(
            std::make_unique<wayfire_grid_view_cdata> (view, iface));
    }

    return view->get_data<wayfire_grid_view_cdata> ();
}

class wf_grid_saved_view_geometry : public wf::custom_data_t
{
    public:
    wf::geometry_t geometry;
    uint32_t tiled_edges;
};

/*
 * 7 8 9
 * 4 5 6
 * 1 2 3
 */
static uint32_t get_tiled_edges_for_slot(uint32_t slot)
{
    if (slot == 0)
        return 0;

    uint32_t edges = wf::TILED_EDGES_ALL;
    if (slot % 3 == 0)
        edges &= ~WLR_EDGE_LEFT;
    if (slot % 3 == 1)
        edges &= ~WLR_EDGE_RIGHT;
    if (slot <= 3)
        edges &= ~WLR_EDGE_TOP;
    if (slot >= 7)
        edges &= ~WLR_EDGE_BOTTOM;

    return edges;
}

static uint32_t get_slot_from_tiled_edges(uint32_t edges)
{
    for (int slot = 0; slot <= 9; slot++)
    {
        if (get_tiled_edges_for_slot(slot) == edges)
            return slot;
    }

    return 0;
}

class wayfire_grid : public wf::plugin_interface_t
{
    std::vector<std::string> slots = {"unused", "bl", "b", "br", "l", "c", "r", "tl", "t", "tr"};
    wf::activator_callback bindings[10];
    wf::option_wrapper_t<wf::activatorbinding_t> keys[10];
    wf::option_wrapper_t<wf::activatorbinding_t> restore_opt{"grid/restore"};

    wf::activator_callback restore = [=] (wf::activator_source_t, uint32_t)
    {
        if (!output->can_activate_plugin(grab_interface))
            return false;

        auto view = output->get_active_view();
        if (!view || view->role != wf::VIEW_ROLE_TOPLEVEL)
            return false;

        view->tile_request(0);
        return true;
    };

    nonstd::observer_ptr<wayfire_grid_view_cdata>
        ensure_grid_view(wayfire_view view)
    {
        return ::ensure_grid_view(view, grab_interface);
    }

    public:
    void init() override
    {
        grab_interface->name = "grid";
        grab_interface->capabilities = wf::CAPABILITY_MANAGE_DESKTOP;

        for (int i = 1; i < 10; i++)
        {
            keys[i].load_option("grid/slot_" + slots[i]);
            bindings[i] = [=] (wf::activator_source_t, uint32_t)
            {
                auto view = output->get_active_view();
                if (!view || view->role != wf::VIEW_ROLE_TOPLEVEL)
                    return false;

                handle_slot(view, i);

                return true;
            };

            output->add_activator(keys[i], &bindings[i]);
        }

        output->add_activator(restore_opt, &restore);

        output->connect_signal("reserved-workarea", &on_workarea_changed);
        output->connect_signal("view-snap", &on_snap_signal);
        output->connect_signal("query-snap-geometry", &on_snap_query);
        output->connect_signal("view-maximized-request", &on_maximize_signal);
        output->connect_signal("view-fullscreen-request", &on_fullscreen_signal);
    }

    bool can_adjust_view(wayfire_view view)
    {
        auto workspace_impl =
            output->workspace->get_workspace_implementation();
        return workspace_impl->view_movable(view) &&
            workspace_impl->view_resizable(view);
    }

    void handle_slot(wayfire_view view, int slot, wf::point_t delta = {0, 0})
    {
        if (!can_adjust_view(view))
            return;

        view->get_data_safe<wf_grid_slot_data>()->slot = slot;
        ensure_grid_view(view)->adjust_target_geometry(
            get_slot_dimensions(slot) + delta,
            get_tiled_edges_for_slot(slot));
    }

    /*
     * 7 8 9
     * 4 5 6
     * 1 2 3
     * */
    wf::geometry_t get_slot_dimensions(int n)
    {
        auto area = output->workspace->get_workarea();
        int w2 = area.width / 2;
        int h2 = area.height / 2;

        if (n % 3 == 1)
            area.width = w2;
        if (n % 3 == 0)
            area.width = w2, area.x += w2;

        if (n >= 7)
            area.height = h2;
        else if (n <= 3)
            area.height = h2, area.y += h2;

        return area;
    }

    wf::signal_callback_t on_workarea_changed = [=] (wf::signal_data_t *data)
    {
        auto ev = static_cast<reserved_workarea_signal*> (data);
        for (auto& view : output->workspace->get_views_in_layer(wf::LAYER_WORKSPACE))
        {
            if (!view->is_mapped())
                continue;

            auto data = view->get_data_safe<wf_grid_slot_data>();

            /* Detect if the view was maximized outside of the grid plugin */
            auto wm = view->get_wm_geometry();
            if (view->tiled_edges && wm.width == ev->old_workarea.width
                && wm.height == ev->old_workarea.height)
            {
                data->slot = SLOT_CENTER;
            }

            if (!data->slot)
                continue;

            /* Workarea changed, and we have a view which is tiled into some slot.
             * We need to make sure it remains in its slot. So we calculate the
             * viewport of the view, and tile it there */
            auto output_geometry = output->get_relative_geometry();

            int vx = std::floor(1.0 * wm.x / output_geometry.width);
            int vy = std::floor(1.0 * wm.y / output_geometry.height);

            handle_slot(view, data->slot,
                {vx * output_geometry.width, vy * output_geometry.height});
        }
    };

    wf::signal_callback_t on_snap_query = [=] (wf::signal_data_t *data)
    {
        auto query = dynamic_cast<snap_query_signal*> (data);
        assert(query);
        query->out_geometry = get_slot_dimensions(query->slot);
    };

    wf::signal_callback_t on_snap_signal = [=] (wf::signal_data_t *ddata)
    {
        snap_signal *data = dynamic_cast<snap_signal*>(ddata);
        handle_slot(data->view, data->slot);
    };

    wf::signal_callback_t on_maximize_signal = [=] (wf::signal_data_t *ddata)
    {
        auto data = static_cast<view_tiled_signal*> (ddata);

        if (data->carried_out || data->desired_size.width <= 0 ||
            !can_adjust_view(data->view))
        {
            return;
        }

        data->carried_out = true;
        uint32_t slot = get_slot_from_tiled_edges(data->edges);
        if (slot > 0)
            data->desired_size = get_slot_dimensions(slot);

        data->view->get_data_safe<wf_grid_slot_data>()->slot = slot;
        ensure_grid_view(data->view)->adjust_target_geometry(data->desired_size,
            get_tiled_edges_for_slot(slot));
    };

    wf::signal_callback_t on_fullscreen_signal = [=] (wf::signal_data_t *ev)
    {
        auto data = static_cast<view_fullscreen_signal*> (ev);
        static const std::string fs_data_name = "grid-saved-fs";

        if (data->carried_out || data->desired_size.width <= 0 ||
            !can_adjust_view(data->view))
        {
            return;
        }

        data->carried_out = true;
        ensure_grid_view(data->view)->adjust_target_geometry(
            data->desired_size, -1);
    };

    void fini() override
    {
        for (int i = 1; i < 10; i++)
            output->rem_binding(&bindings[i]);

        output->rem_binding(&restore);

        output->disconnect_signal("reserved-workarea", &on_workarea_changed);
        output->disconnect_signal("view-snap", &on_snap_signal);
        output->disconnect_signal("query-snap-geometry", &on_snap_query);
        output->disconnect_signal("view-maximized-request", &on_maximize_signal);
        output->disconnect_signal("view-fullscreen-request", &on_fullscreen_signal);
    }
};

DECLARE_WAYFIRE_PLUGIN(wayfire_grid);
<commit_msg>grid: set geometry after setting tiled edges<commit_after>#include <wayfire/plugin.hpp>
#include <wayfire/debug.hpp>
#include <wayfire/output.hpp>
#include <wayfire/core.hpp>
#include <wayfire/view.hpp>
#include <wayfire/workspace-manager.hpp>
#include <wayfire/render-manager.hpp>
#include <algorithm>
#include <cmath>
#include <linux/input-event-codes.h>
#include "wayfire/signal-definitions.hpp"
#include <wayfire/plugins/common/geometry-animation.hpp>

#include "snap_signal.hpp"
#include "../wobbly/wobbly-signal.hpp"

extern "C"
{
#include <wlr/util/edges.h>
}

const std::string grid_view_id = "grid-view";

class wayfire_grid_view_cdata : public wf::custom_data_t
{
    bool is_active = true;

    wayfire_view view;
    wf::output_t *output;
    wf::effect_hook_t pre_hook;
    wf::signal_callback_t unmapped;

    int32_t tiled_edges = -1;
    const wf::plugin_grab_interface_uptr& iface;

    wf::option_wrapper_t<std::string> animation_type{"grid/type"};
    wf::option_wrapper_t<int> animation_duration{"grid/duration"};
    wf::geometry_animation_t animation{animation_duration};

    public:

    wayfire_grid_view_cdata(wayfire_view view,
        const wf::plugin_grab_interface_uptr& _iface)
        : iface(_iface)
    {
        this->view = view;
        this->output = view->get_output();
        this->animation = wf::geometry_animation_t{animation_duration};

        if (!view->get_output()->activate_plugin(iface,
                wf::PLUGIN_ACTIVATE_ALLOW_MULTIPLE))
        {
            is_active = false;
            return;
        }

        pre_hook = [=] () {
            adjust_geometry();
        };
        output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);

        unmapped = [=] (wf::signal_data_t *data)
        {
            if (get_signaled_view(data) == view)
                destroy();
        };

        output->render->set_redraw_always(true);
        output->connect_signal("view-disappeared", &unmapped);
        output->connect_signal("detach-view", &unmapped);
    }

    void destroy()
    {
        view->erase_data<wayfire_grid_view_cdata>();
    }

    void adjust_target_geometry(wf::geometry_t geometry, int32_t target_edges)
    {
        animation.set_start(view->get_wm_geometry());
        animation.set_end(geometry);

        /* Restore tiled edges if we don't need to set something special when
         * grid is ready */
        if (target_edges < 0) {
            this->tiled_edges = view->tiled_edges;
        } else {
            this->tiled_edges = target_edges;
        }

        std::string type = animation_type;
        if (view->get_transformer("wobbly") || !is_active)
            type = "wobbly";

        if (type == "none")
        {
            set_end_state(geometry, tiled_edges);
            return destroy();
        }

        if (type == "wobbly")
        {
            /* Order is important here: first we set the view geometry, and
             * after that we set the snap request. Otherwise the wobbly plugin
             * will think the view actually moved */
            set_end_state(geometry, tiled_edges);
            activate_wobbly(view);
            return destroy();
        }

        view->set_tiled(wf::TILED_EDGES_ALL);
        view->set_moving(1);
        view->set_resizing(1);
        animation.start();
    }

    void set_end_state(wf::geometry_t geometry, int32_t edges)
    {
        if (edges >= 0)
            view->set_tiled(edges);
        view->set_geometry(geometry);
    }

    void adjust_geometry()
    {
        if (!animation.running())
        {
            set_end_state(animation, tiled_edges);
            view->set_moving(0);
            view->set_resizing(0);

            return destroy();
        }

        view->set_geometry((wf::geometry_t) animation);
    }

    ~wayfire_grid_view_cdata()
    {
        if (!is_active)
            return;

        output->render->rem_effect(&pre_hook);
        output->deactivate_plugin(iface);
        output->render->set_redraw_always(false);
        output->disconnect_signal("view-disappeared", &unmapped);
        output->disconnect_signal("detach-view", &unmapped);
    }
};

class wf_grid_slot_data : public wf::custom_data_t
{
    public:
        int slot;
};

nonstd::observer_ptr<wayfire_grid_view_cdata> ensure_grid_view(wayfire_view view,
        const wf::plugin_grab_interface_uptr& iface)
{
    if (!view->has_data<wayfire_grid_view_cdata>())
    {
        view->store_data(
            std::make_unique<wayfire_grid_view_cdata> (view, iface));
    }

    return view->get_data<wayfire_grid_view_cdata> ();
}

class wf_grid_saved_view_geometry : public wf::custom_data_t
{
    public:
    wf::geometry_t geometry;
    uint32_t tiled_edges;
};

/*
 * 7 8 9
 * 4 5 6
 * 1 2 3
 */
static uint32_t get_tiled_edges_for_slot(uint32_t slot)
{
    if (slot == 0)
        return 0;

    uint32_t edges = wf::TILED_EDGES_ALL;
    if (slot % 3 == 0)
        edges &= ~WLR_EDGE_LEFT;
    if (slot % 3 == 1)
        edges &= ~WLR_EDGE_RIGHT;
    if (slot <= 3)
        edges &= ~WLR_EDGE_TOP;
    if (slot >= 7)
        edges &= ~WLR_EDGE_BOTTOM;

    return edges;
}

static uint32_t get_slot_from_tiled_edges(uint32_t edges)
{
    for (int slot = 0; slot <= 9; slot++)
    {
        if (get_tiled_edges_for_slot(slot) == edges)
            return slot;
    }

    return 0;
}

class wayfire_grid : public wf::plugin_interface_t
{
    std::vector<std::string> slots = {"unused", "bl", "b", "br", "l", "c", "r", "tl", "t", "tr"};
    wf::activator_callback bindings[10];
    wf::option_wrapper_t<wf::activatorbinding_t> keys[10];
    wf::option_wrapper_t<wf::activatorbinding_t> restore_opt{"grid/restore"};

    wf::activator_callback restore = [=] (wf::activator_source_t, uint32_t)
    {
        if (!output->can_activate_plugin(grab_interface))
            return false;

        auto view = output->get_active_view();
        if (!view || view->role != wf::VIEW_ROLE_TOPLEVEL)
            return false;

        view->tile_request(0);
        return true;
    };

    nonstd::observer_ptr<wayfire_grid_view_cdata>
        ensure_grid_view(wayfire_view view)
    {
        return ::ensure_grid_view(view, grab_interface);
    }

    public:
    void init() override
    {
        grab_interface->name = "grid";
        grab_interface->capabilities = wf::CAPABILITY_MANAGE_DESKTOP;

        for (int i = 1; i < 10; i++)
        {
            keys[i].load_option("grid/slot_" + slots[i]);
            bindings[i] = [=] (wf::activator_source_t, uint32_t)
            {
                auto view = output->get_active_view();
                if (!view || view->role != wf::VIEW_ROLE_TOPLEVEL)
                    return false;

                handle_slot(view, i);

                return true;
            };

            output->add_activator(keys[i], &bindings[i]);
        }

        output->add_activator(restore_opt, &restore);

        output->connect_signal("reserved-workarea", &on_workarea_changed);
        output->connect_signal("view-snap", &on_snap_signal);
        output->connect_signal("query-snap-geometry", &on_snap_query);
        output->connect_signal("view-maximized-request", &on_maximize_signal);
        output->connect_signal("view-fullscreen-request", &on_fullscreen_signal);
    }

    bool can_adjust_view(wayfire_view view)
    {
        auto workspace_impl =
            output->workspace->get_workspace_implementation();
        return workspace_impl->view_movable(view) &&
            workspace_impl->view_resizable(view);
    }

    void handle_slot(wayfire_view view, int slot, wf::point_t delta = {0, 0})
    {
        if (!can_adjust_view(view))
            return;

        view->get_data_safe<wf_grid_slot_data>()->slot = slot;
        ensure_grid_view(view)->adjust_target_geometry(
            get_slot_dimensions(slot) + delta,
            get_tiled_edges_for_slot(slot));
    }

    /*
     * 7 8 9
     * 4 5 6
     * 1 2 3
     * */
    wf::geometry_t get_slot_dimensions(int n)
    {
        auto area = output->workspace->get_workarea();
        int w2 = area.width / 2;
        int h2 = area.height / 2;

        if (n % 3 == 1)
            area.width = w2;
        if (n % 3 == 0)
            area.width = w2, area.x += w2;

        if (n >= 7)
            area.height = h2;
        else if (n <= 3)
            area.height = h2, area.y += h2;

        return area;
    }

    wf::signal_callback_t on_workarea_changed = [=] (wf::signal_data_t *data)
    {
        auto ev = static_cast<reserved_workarea_signal*> (data);
        for (auto& view : output->workspace->get_views_in_layer(wf::LAYER_WORKSPACE))
        {
            if (!view->is_mapped())
                continue;

            auto data = view->get_data_safe<wf_grid_slot_data>();

            /* Detect if the view was maximized outside of the grid plugin */
            auto wm = view->get_wm_geometry();
            if (view->tiled_edges && wm.width == ev->old_workarea.width
                && wm.height == ev->old_workarea.height)
            {
                data->slot = SLOT_CENTER;
            }

            if (!data->slot)
                continue;

            /* Workarea changed, and we have a view which is tiled into some slot.
             * We need to make sure it remains in its slot. So we calculate the
             * viewport of the view, and tile it there */
            auto output_geometry = output->get_relative_geometry();

            int vx = std::floor(1.0 * wm.x / output_geometry.width);
            int vy = std::floor(1.0 * wm.y / output_geometry.height);

            handle_slot(view, data->slot,
                {vx * output_geometry.width, vy * output_geometry.height});
        }
    };

    wf::signal_callback_t on_snap_query = [=] (wf::signal_data_t *data)
    {
        auto query = dynamic_cast<snap_query_signal*> (data);
        assert(query);
        query->out_geometry = get_slot_dimensions(query->slot);
    };

    wf::signal_callback_t on_snap_signal = [=] (wf::signal_data_t *ddata)
    {
        snap_signal *data = dynamic_cast<snap_signal*>(ddata);
        handle_slot(data->view, data->slot);
    };

    wf::signal_callback_t on_maximize_signal = [=] (wf::signal_data_t *ddata)
    {
        auto data = static_cast<view_tiled_signal*> (ddata);

        if (data->carried_out || data->desired_size.width <= 0 ||
            !can_adjust_view(data->view))
        {
            return;
        }

        data->carried_out = true;
        uint32_t slot = get_slot_from_tiled_edges(data->edges);
        if (slot > 0)
            data->desired_size = get_slot_dimensions(slot);

        data->view->get_data_safe<wf_grid_slot_data>()->slot = slot;
        ensure_grid_view(data->view)->adjust_target_geometry(data->desired_size,
            get_tiled_edges_for_slot(slot));
    };

    wf::signal_callback_t on_fullscreen_signal = [=] (wf::signal_data_t *ev)
    {
        auto data = static_cast<view_fullscreen_signal*> (ev);
        static const std::string fs_data_name = "grid-saved-fs";

        if (data->carried_out || data->desired_size.width <= 0 ||
            !can_adjust_view(data->view))
        {
            return;
        }

        data->carried_out = true;
        ensure_grid_view(data->view)->adjust_target_geometry(
            data->desired_size, -1);
    };

    void fini() override
    {
        for (int i = 1; i < 10; i++)
            output->rem_binding(&bindings[i]);

        output->rem_binding(&restore);

        output->disconnect_signal("reserved-workarea", &on_workarea_changed);
        output->disconnect_signal("view-snap", &on_snap_signal);
        output->disconnect_signal("query-snap-geometry", &on_snap_query);
        output->disconnect_signal("view-maximized-request", &on_maximize_signal);
        output->disconnect_signal("view-fullscreen-request", &on_fullscreen_signal);
    }
};

DECLARE_WAYFIRE_PLUGIN(wayfire_grid);
<|endoftext|>


<commit_before>/*
    Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>

    This file is part of Magnum.

    Magnum is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 3
    only, as published by the Free Software Foundation.

    Magnum 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 version 3 for more details.
*/

#include "Camera.h"
#include "Scene.h"

using namespace std;

namespace Magnum {

Camera::Camera(Object* parent): Object(parent), _aspectRatioPolicy(Extend) {}

void Camera::setOrthographic(GLfloat size, GLfloat near, GLfloat far) {
    _near = near;
    _far = far;

    /* Scale the volume down so it fits in (-1, 1) in all directions */
    GLfloat xyScale = 2/size;
    GLfloat zScale = 2/(far-near);
    rawProjectionMatrix = Matrix4::scaling({xyScale, xyScale, -zScale});

    /* Move the volume on z into (-1, 1) range */
    rawProjectionMatrix = Matrix4::translation(Vector3::zAxis(-1-near*zScale))*rawProjectionMatrix;

    fixAspectRatio();
}

void Camera::setPerspective(GLfloat fov, GLfloat near, GLfloat far) {
    _near = near;
    _far = far;

    /* First move the volume on z in (-1, 1) range */
    rawProjectionMatrix = Matrix4::translation(Vector3::zAxis(2*far*near/(far+near)));

    /* Then apply magic perspective matrix (with reversed Z) */
    static const Matrix4 a(1.0f, 0.0f,  0.0f,  0.0f,
                           0.0f, 1.0f,  0.0f,  0.0f,
                           0.0f, 0.0f,  -1.0f,  -1.0f,
                           0.0f, 0.0f,  0.0f,  0.0f);
    rawProjectionMatrix = a*rawProjectionMatrix;

    /* Then scale the volume down so it fits in (-1, 1) in all directions */
    GLfloat xyScale = 1/tan(fov/2);
    GLfloat zScale = 1+2*near/(far-near);
    rawProjectionMatrix = Matrix4::scaling({xyScale, xyScale, zScale})*rawProjectionMatrix;

    /* And... another magic */
    rawProjectionMatrix[3][3] = 0;

    fixAspectRatio();
}

void Camera::setViewport(const Math::Vector2<GLsizei>& size) {
    glViewport(0, 0, size.x(), size.y());

    _viewport = size;
    fixAspectRatio();
}

void Camera::clean(const Matrix4& absoluteTransformation) {
    Object::clean(absoluteTransformation);

    _cameraMatrix = absoluteTransformation.inverted();
}

void Camera::fixAspectRatio() {
    /* Don't divide by zero */
    if(_viewport.x() == 0 || _viewport.y() == 0) {
        _projectionMatrix = rawProjectionMatrix;
        return;
    }

    /* Extend on larger side = scale larger side down */
    if(_aspectRatioPolicy == Extend) {
        _projectionMatrix = ((_viewport.x() > _viewport.y()) ?
            Matrix4::scaling({GLfloat(_viewport.y())/_viewport.x(), 1, 1}) :
            Matrix4::scaling({1, GLfloat(_viewport.x())/_viewport.y(), 1})
        )*rawProjectionMatrix;

    /* Clip on smaller side = scale smaller side up */
    } else if(_aspectRatioPolicy == Clip) {
        _projectionMatrix = ((_viewport.x() > _viewport.y()) ?
            Matrix4::scaling({1, GLfloat(_viewport.x())/_viewport.y(), 1}) :
            Matrix4::scaling({GLfloat(_viewport.y())/_viewport.x(), 1, 1})
        )*rawProjectionMatrix;

    /* Don't preserve anything */
    } else _projectionMatrix = rawProjectionMatrix;
}

void Camera::setClearColor(const Magnum::Vector4& color) {
    glClearColor(color.r(), color.g(), color.b(), color.a());
    _clearColor = color;
}

void Camera::draw() {
    /** @todo Clear only set features */
    glClear(GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    /* Recursively draw child objects */
    drawChildren(scene(), cameraMatrix());
}

void Camera::drawChildren(Object* object, const Matrix4& transformationMatrix) {
    for(set<Object*>::const_iterator it = object->children().begin(); it != object->children().end(); ++it) {
        /* Transformation matrix for the object */
        Matrix4 matrix = transformationMatrix*(*it)->transformation();

        /* Draw the object and its children */
        (*it)->draw(matrix, this);
        drawChildren(*it, matrix);
    }
}

}
<commit_msg>Camera must be attached to scene when attempting to draw.<commit_after>/*
    Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>

    This file is part of Magnum.

    Magnum is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 3
    only, as published by the Free Software Foundation.

    Magnum 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 version 3 for more details.
*/

#include "Camera.h"
#include "Scene.h"

using namespace std;

namespace Magnum {

Camera::Camera(Object* parent): Object(parent), _aspectRatioPolicy(Extend) {}

void Camera::setOrthographic(GLfloat size, GLfloat near, GLfloat far) {
    _near = near;
    _far = far;

    /* Scale the volume down so it fits in (-1, 1) in all directions */
    GLfloat xyScale = 2/size;
    GLfloat zScale = 2/(far-near);
    rawProjectionMatrix = Matrix4::scaling({xyScale, xyScale, -zScale});

    /* Move the volume on z into (-1, 1) range */
    rawProjectionMatrix = Matrix4::translation(Vector3::zAxis(-1-near*zScale))*rawProjectionMatrix;

    fixAspectRatio();
}

void Camera::setPerspective(GLfloat fov, GLfloat near, GLfloat far) {
    _near = near;
    _far = far;

    /* First move the volume on z in (-1, 1) range */
    rawProjectionMatrix = Matrix4::translation(Vector3::zAxis(2*far*near/(far+near)));

    /* Then apply magic perspective matrix (with reversed Z) */
    static const Matrix4 a(1.0f, 0.0f,  0.0f,  0.0f,
                           0.0f, 1.0f,  0.0f,  0.0f,
                           0.0f, 0.0f,  -1.0f,  -1.0f,
                           0.0f, 0.0f,  0.0f,  0.0f);
    rawProjectionMatrix = a*rawProjectionMatrix;

    /* Then scale the volume down so it fits in (-1, 1) in all directions */
    GLfloat xyScale = 1/tan(fov/2);
    GLfloat zScale = 1+2*near/(far-near);
    rawProjectionMatrix = Matrix4::scaling({xyScale, xyScale, zScale})*rawProjectionMatrix;

    /* And... another magic */
    rawProjectionMatrix[3][3] = 0;

    fixAspectRatio();
}

void Camera::setViewport(const Math::Vector2<GLsizei>& size) {
    glViewport(0, 0, size.x(), size.y());

    _viewport = size;
    fixAspectRatio();
}

void Camera::clean(const Matrix4& absoluteTransformation) {
    Object::clean(absoluteTransformation);

    _cameraMatrix = absoluteTransformation.inverted();
}

void Camera::fixAspectRatio() {
    /* Don't divide by zero */
    if(_viewport.x() == 0 || _viewport.y() == 0) {
        _projectionMatrix = rawProjectionMatrix;
        return;
    }

    /* Extend on larger side = scale larger side down */
    if(_aspectRatioPolicy == Extend) {
        _projectionMatrix = ((_viewport.x() > _viewport.y()) ?
            Matrix4::scaling({GLfloat(_viewport.y())/_viewport.x(), 1, 1}) :
            Matrix4::scaling({1, GLfloat(_viewport.x())/_viewport.y(), 1})
        )*rawProjectionMatrix;

    /* Clip on smaller side = scale smaller side up */
    } else if(_aspectRatioPolicy == Clip) {
        _projectionMatrix = ((_viewport.x() > _viewport.y()) ?
            Matrix4::scaling({1, GLfloat(_viewport.x())/_viewport.y(), 1}) :
            Matrix4::scaling({GLfloat(_viewport.y())/_viewport.x(), 1, 1})
        )*rawProjectionMatrix;

    /* Don't preserve anything */
    } else _projectionMatrix = rawProjectionMatrix;
}

void Camera::setClearColor(const Magnum::Vector4& color) {
    glClearColor(color.r(), color.g(), color.b(), color.a());
    _clearColor = color;
}

void Camera::draw() {
    Scene* s = scene();
    CORRADE_ASSERT(s, "Camera: cannot draw without camera attached to scene", )

    /** @todo Clear only set features */
    glClear(GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    /* Recursively draw child objects */
    drawChildren(s, cameraMatrix());
}

void Camera::drawChildren(Object* object, const Matrix4& transformationMatrix) {
    for(set<Object*>::const_iterator it = object->children().begin(); it != object->children().end(); ++it) {
        /* Transformation matrix for the object */
        Matrix4 matrix = transformationMatrix*(*it)->transformation();

        /* Draw the object and its children */
        (*it)->draw(matrix, this);
        drawChildren(*it, matrix);
    }
}

}
<|endoftext|>


<commit_before>/* Copyright 2016 Streampunk Media Ltd

  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.
*/

/* -LICENSE-START-
 ** Copyright (c) 2010 Blackmagic Design
 **
 ** Permission is hereby granted, free of charge, to any person or organization
 ** obtaining a copy of the software and accompanying documentation covered by
 ** this license (the "Software") to use, reproduce, display, distribute,
 ** execute, and transmit the Software, and to prepare derivative works of the
 ** Software, and to permit third-parties to whom the Software is furnished to
 ** do so, all subject to the following:
 **
 ** The copyright notices in the Software and this entire statement, including
 ** the above license grant, this restriction and the following disclaimer,
 ** must be included in all copies of the Software, in whole or in part, and
 ** all derivative works of the Software, unless such copies or derivative
 ** works are solely in the form of machine-executable object code generated by
 ** a source language processor.
 **
 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 ** DEALINGS IN THE SOFTWARE.
 ** -LICENSE-END-
 */

#include "Capture.h"

namespace streampunk {

using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::Persistent;
using v8::String;
using v8::Value;
using v8::EscapableHandleScope;
using v8::HandleScope;
using v8::Exception;

Persistent<Function> Capture::constructor;

Capture::Capture(uint32_t deviceIndex, uint32_t displayMode,
    uint32_t pixelFormat) : deviceIndex_(deviceIndex),
    displayMode_(displayMode), pixelFormat_(pixelFormat), latestFrame_(NULL) {
  async = new uv_async_t;
  uv_async_init(uv_default_loop(), async, FrameCallback);
  async->data = this;
}

Capture::~Capture() {
  if (!captureCB_.IsEmpty())
    captureCB_.Reset();
}

void Capture::Init(Local<Object> exports) {
  Isolate* isolate = exports->GetIsolate();

  #ifdef WIN32
  HRESULT result;
  result = CoInitialize(NULL);
	if (FAILED(result))
	{
		fprintf(stderr, "Initialization of COM failed - result = %08x.\n", result);
	}
  #endif

  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
  tpl->SetClassName(String::NewFromUtf8(isolate, "Capture"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  // Prototype
  NODE_SET_PROTOTYPE_METHOD(tpl, "init", BMInit);
  NODE_SET_PROTOTYPE_METHOD(tpl, "doCapture", DoCapture);
  NODE_SET_PROTOTYPE_METHOD(tpl, "stop", StopCapture);

  constructor.Reset(isolate, tpl->GetFunction());
  exports->Set(String::NewFromUtf8(isolate, "Capture"),
               tpl->GetFunction());
}

void Capture::New(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();

  if (args.IsConstructCall()) {
    // Invoked as constructor: `new Capture(...)`
    double deviceIndex = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
    double displayMode = args[1]->IsUndefined() ? 0 : args[1]->NumberValue();
    double pixelFormat = args[2]->IsUndefined() ? 0 : args[2]->NumberValue();
    Capture* obj = new Capture(deviceIndex, displayMode, pixelFormat);
    obj->Wrap(args.This());
    args.GetReturnValue().Set(args.This());
  } else {
    // Invoked as plain function `Capture(...)`, turn into construct call.
    const int argc = 3;
    Local<Value> argv[argc] = { args[0], args[1], args[2] };
    Local<Function> cons = Local<Function>::New(isolate, constructor);
    args.GetReturnValue().Set(cons->NewInstance(argc, argv));
  }
}

void Capture::BMInit(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();

  IDeckLinkIterator* deckLinkIterator;
  HRESULT	result;
  IDeckLinkAPIInformation *deckLinkAPIInformation;
  IDeckLink* deckLink;
  #ifdef WIN32
  CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&deckLinkIterator);
  #else
  deckLinkIterator = CreateDeckLinkIteratorInstance();
  #endif
  result = deckLinkIterator->QueryInterface(IID_IDeckLinkAPIInformation, (void**)&deckLinkAPIInformation);
  if (result != S_OK) {
    isolate->ThrowException(Exception::Error(
      String::NewFromUtf8(isolate, "Error connecting to DeckLinkAPI.")));
  }
  Capture* obj = ObjectWrap::Unwrap<Capture>(args.Holder());

  for ( uint32_t x = 0 ; x <= obj->deviceIndex_ ; x++ ) {
    if (deckLinkIterator->Next(&deckLink) != S_OK) {
      args.GetReturnValue().Set(Undefined(isolate));
      return;
    }
  }

  obj->m_deckLink = deckLink;

  IDeckLinkInput *deckLinkInput;
  if (deckLink->QueryInterface(IID_IDeckLinkInput, (void **)&deckLinkInput) != S_OK)
	{
    isolate->ThrowException(Exception::Error(
      String::NewFromUtf8(isolate, "Could not obtain the DeckLink Input interface.")));
	}
  obj->m_deckLinkInput = deckLinkInput;
  if (deckLinkInput)
    args.GetReturnValue().Set(String::NewFromUtf8(isolate, "made it!"));
  else
    args.GetReturnValue().Set(String::NewFromUtf8(isolate, "sad :-("));
}

void Capture::DoCapture(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();

  Local<Function> cb = Local<Function>::Cast(args[0]);
  Capture* obj = ObjectWrap::Unwrap<Capture>(args.Holder());
  obj->captureCB_.Reset(isolate, cb);

  obj->setupDeckLinkInput();

  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "Capture started."));
}

void Capture::StopCapture(const v8::FunctionCallbackInfo<v8::Value>& args) {
  Isolate* isolate = args.GetIsolate();

  Capture* obj = ObjectWrap::Unwrap<Capture>(args.Holder());

  obj->cleanupDeckLinkInput();

  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "Capture stopped."));
}

// Stop video input
void Capture::cleanupDeckLinkInput()
{
	m_deckLinkInput->StopStreams();
	m_deckLinkInput->DisableVideoInput();
	m_deckLinkInput->SetCallback(NULL);
}

bool Capture::setupDeckLinkInput() {
  // bool result = false;
  IDeckLinkDisplayModeIterator*	displayModeIterator = NULL;
  IDeckLinkDisplayMode*			deckLinkDisplayMode = NULL;

  m_width = -1;

  // get frame scale and duration for the video mode
  if (m_deckLinkInput->GetDisplayModeIterator(&displayModeIterator) != S_OK)
    return false;

  while (displayModeIterator->Next(&deckLinkDisplayMode) == S_OK)
  {
    if (deckLinkDisplayMode->GetDisplayMode() == displayMode_)
    {
      m_width = deckLinkDisplayMode->GetWidth();
      m_height = deckLinkDisplayMode->GetHeight();
      deckLinkDisplayMode->GetFrameRate(&m_frameDuration, &m_timeScale);
      deckLinkDisplayMode->Release();

      break;
    }

    deckLinkDisplayMode->Release();
  }

  printf("Width %li Height %li\n", m_width, m_height);

  displayModeIterator->Release();

  if (m_width == -1)
    return false;

  m_deckLinkInput->SetCallback(this);

  if (m_deckLinkInput->EnableVideoInput((BMDDisplayMode) displayMode_, pixelFormat_, bmdVideoInputFlagDefault) != S_OK)
	  return false;

  if (m_deckLinkInput->StartStreams() != S_OK)
    return false;

  return true;
}

HRESULT	Capture::VideoInputFrameArrived (IDeckLinkVideoInputFrame* arrivedFrame, IDeckLinkAudioInputPacket*)
{
  arrivedFrame->AddRef();
  latestFrame_ = arrivedFrame;
  uv_async_send(async);
  return S_OK;
}

HRESULT	Capture::VideoInputFormatChanged (BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode* newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags) {
  return S_OK;
};

void Capture::TestUV() {
  uv_async_send(async);
}

void FreeCallback(char* data, void* hint) {
  Isolate* isolate = v8::Isolate::GetCurrent();
  IDeckLinkVideoInputFrame* frame = static_cast<IDeckLinkVideoInputFrame*>(hint);
  isolate->AdjustAmountOfExternalAllocatedMemory(-(frame->GetRowBytes() * frame->GetHeight()));
  frame->Release();
}

void Capture::FrameCallback(uv_async_t *handle) {
  Isolate* isolate = v8::Isolate::GetCurrent();
  HandleScope scope(isolate);
  Capture *capture = static_cast<Capture*>(handle->data);
  Local<Function> cb = Local<Function>::New(isolate, capture->captureCB_);
  char* new_data;
  capture->latestFrame_->GetBytes((void**) &new_data);
  long new_data_size = capture->latestFrame_->GetRowBytes() * capture->latestFrame_->GetHeight();
  Local<Object> b = node::Buffer::New(isolate, new_data, new_data_size,
    FreeCallback, capture->latestFrame_).ToLocalChecked();
  long extSize = isolate->AdjustAmountOfExternalAllocatedMemory(new_data_size);
  if (extSize > 100000000) {
    isolate->LowMemoryNotification();
    printf("Requesting bin collection.\n");
  }
  Local<Value> argv[1] = { b };
  cb->Call(Null(isolate), 1, argv);
}

}
<commit_msg>Adding explict casts for one more enumeration required by Windows compiler.<commit_after>/* Copyright 2016 Streampunk Media Ltd

  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.
*/

/* -LICENSE-START-
 ** Copyright (c) 2010 Blackmagic Design
 **
 ** Permission is hereby granted, free of charge, to any person or organization
 ** obtaining a copy of the software and accompanying documentation covered by
 ** this license (the "Software") to use, reproduce, display, distribute,
 ** execute, and transmit the Software, and to prepare derivative works of the
 ** Software, and to permit third-parties to whom the Software is furnished to
 ** do so, all subject to the following:
 **
 ** The copyright notices in the Software and this entire statement, including
 ** the above license grant, this restriction and the following disclaimer,
 ** must be included in all copies of the Software, in whole or in part, and
 ** all derivative works of the Software, unless such copies or derivative
 ** works are solely in the form of machine-executable object code generated by
 ** a source language processor.
 **
 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 ** DEALINGS IN THE SOFTWARE.
 ** -LICENSE-END-
 */

#include "Capture.h"

namespace streampunk {

using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::Persistent;
using v8::String;
using v8::Value;
using v8::EscapableHandleScope;
using v8::HandleScope;
using v8::Exception;

Persistent<Function> Capture::constructor;

Capture::Capture(uint32_t deviceIndex, uint32_t displayMode,
    uint32_t pixelFormat) : deviceIndex_(deviceIndex),
    displayMode_(displayMode), pixelFormat_(pixelFormat), latestFrame_(NULL) {
  async = new uv_async_t;
  uv_async_init(uv_default_loop(), async, FrameCallback);
  async->data = this;
}

Capture::~Capture() {
  if (!captureCB_.IsEmpty())
    captureCB_.Reset();
}

void Capture::Init(Local<Object> exports) {
  Isolate* isolate = exports->GetIsolate();

  #ifdef WIN32
  HRESULT result;
  result = CoInitialize(NULL);
	if (FAILED(result))
	{
		fprintf(stderr, "Initialization of COM failed - result = %08x.\n", result);
	}
  #endif

  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
  tpl->SetClassName(String::NewFromUtf8(isolate, "Capture"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  // Prototype
  NODE_SET_PROTOTYPE_METHOD(tpl, "init", BMInit);
  NODE_SET_PROTOTYPE_METHOD(tpl, "doCapture", DoCapture);
  NODE_SET_PROTOTYPE_METHOD(tpl, "stop", StopCapture);

  constructor.Reset(isolate, tpl->GetFunction());
  exports->Set(String::NewFromUtf8(isolate, "Capture"),
               tpl->GetFunction());
}

void Capture::New(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();

  if (args.IsConstructCall()) {
    // Invoked as constructor: `new Capture(...)`
    double deviceIndex = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
    double displayMode = args[1]->IsUndefined() ? 0 : args[1]->NumberValue();
    double pixelFormat = args[2]->IsUndefined() ? 0 : args[2]->NumberValue();
    Capture* obj = new Capture(deviceIndex, displayMode, pixelFormat);
    obj->Wrap(args.This());
    args.GetReturnValue().Set(args.This());
  } else {
    // Invoked as plain function `Capture(...)`, turn into construct call.
    const int argc = 3;
    Local<Value> argv[argc] = { args[0], args[1], args[2] };
    Local<Function> cons = Local<Function>::New(isolate, constructor);
    args.GetReturnValue().Set(cons->NewInstance(argc, argv));
  }
}

void Capture::BMInit(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();

  IDeckLinkIterator* deckLinkIterator;
  HRESULT	result;
  IDeckLinkAPIInformation *deckLinkAPIInformation;
  IDeckLink* deckLink;
  #ifdef WIN32
  CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&deckLinkIterator);
  #else
  deckLinkIterator = CreateDeckLinkIteratorInstance();
  #endif
  result = deckLinkIterator->QueryInterface(IID_IDeckLinkAPIInformation, (void**)&deckLinkAPIInformation);
  if (result != S_OK) {
    isolate->ThrowException(Exception::Error(
      String::NewFromUtf8(isolate, "Error connecting to DeckLinkAPI.")));
  }
  Capture* obj = ObjectWrap::Unwrap<Capture>(args.Holder());

  for ( uint32_t x = 0 ; x <= obj->deviceIndex_ ; x++ ) {
    if (deckLinkIterator->Next(&deckLink) != S_OK) {
      args.GetReturnValue().Set(Undefined(isolate));
      return;
    }
  }

  obj->m_deckLink = deckLink;

  IDeckLinkInput *deckLinkInput;
  if (deckLink->QueryInterface(IID_IDeckLinkInput, (void **)&deckLinkInput) != S_OK)
	{
    isolate->ThrowException(Exception::Error(
      String::NewFromUtf8(isolate, "Could not obtain the DeckLink Input interface.")));
	}
  obj->m_deckLinkInput = deckLinkInput;
  if (deckLinkInput)
    args.GetReturnValue().Set(String::NewFromUtf8(isolate, "made it!"));
  else
    args.GetReturnValue().Set(String::NewFromUtf8(isolate, "sad :-("));
}

void Capture::DoCapture(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();

  Local<Function> cb = Local<Function>::Cast(args[0]);
  Capture* obj = ObjectWrap::Unwrap<Capture>(args.Holder());
  obj->captureCB_.Reset(isolate, cb);

  obj->setupDeckLinkInput();

  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "Capture started."));
}

void Capture::StopCapture(const v8::FunctionCallbackInfo<v8::Value>& args) {
  Isolate* isolate = args.GetIsolate();

  Capture* obj = ObjectWrap::Unwrap<Capture>(args.Holder());

  obj->cleanupDeckLinkInput();

  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "Capture stopped."));
}

// Stop video input
void Capture::cleanupDeckLinkInput()
{
	m_deckLinkInput->StopStreams();
	m_deckLinkInput->DisableVideoInput();
	m_deckLinkInput->SetCallback(NULL);
}

bool Capture::setupDeckLinkInput() {
  // bool result = false;
  IDeckLinkDisplayModeIterator*	displayModeIterator = NULL;
  IDeckLinkDisplayMode*			deckLinkDisplayMode = NULL;

  m_width = -1;

  // get frame scale and duration for the video mode
  if (m_deckLinkInput->GetDisplayModeIterator(&displayModeIterator) != S_OK)
    return false;

  while (displayModeIterator->Next(&deckLinkDisplayMode) == S_OK)
  {
    if (deckLinkDisplayMode->GetDisplayMode() == displayMode_)
    {
      m_width = deckLinkDisplayMode->GetWidth();
      m_height = deckLinkDisplayMode->GetHeight();
      deckLinkDisplayMode->GetFrameRate(&m_frameDuration, &m_timeScale);
      deckLinkDisplayMode->Release();

      break;
    }

    deckLinkDisplayMode->Release();
  }

  printf("Width %li Height %li\n", m_width, m_height);

  displayModeIterator->Release();

  if (m_width == -1)
    return false;

  m_deckLinkInput->SetCallback(this);

  if (m_deckLinkInput->EnableVideoInput((BMDDisplayMode) displayMode_, (BMDPixelFormat) pixelFormat_, bmdVideoInputFlagDefault) != S_OK)
	  return false;

  if (m_deckLinkInput->StartStreams() != S_OK)
    return false;

  return true;
}

HRESULT	Capture::VideoInputFrameArrived (IDeckLinkVideoInputFrame* arrivedFrame, IDeckLinkAudioInputPacket*)
{
  arrivedFrame->AddRef();
  latestFrame_ = arrivedFrame;
  uv_async_send(async);
  return S_OK;
}

HRESULT	Capture::VideoInputFormatChanged (BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode* newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags) {
  return S_OK;
};

void Capture::TestUV() {
  uv_async_send(async);
}

void FreeCallback(char* data, void* hint) {
  Isolate* isolate = v8::Isolate::GetCurrent();
  IDeckLinkVideoInputFrame* frame = static_cast<IDeckLinkVideoInputFrame*>(hint);
  isolate->AdjustAmountOfExternalAllocatedMemory(-(frame->GetRowBytes() * frame->GetHeight()));
  frame->Release();
}

void Capture::FrameCallback(uv_async_t *handle) {
  Isolate* isolate = v8::Isolate::GetCurrent();
  HandleScope scope(isolate);
  Capture *capture = static_cast<Capture*>(handle->data);
  Local<Function> cb = Local<Function>::New(isolate, capture->captureCB_);
  char* new_data;
  capture->latestFrame_->GetBytes((void**) &new_data);
  long new_data_size = capture->latestFrame_->GetRowBytes() * capture->latestFrame_->GetHeight();
  Local<Object> b = node::Buffer::New(isolate, new_data, new_data_size,
    FreeCallback, capture->latestFrame_).ToLocalChecked();
  long extSize = isolate->AdjustAmountOfExternalAllocatedMemory(new_data_size);
  if (extSize > 100000000) {
    isolate->LowMemoryNotification();
    printf("Requesting bin collection.\n");
  }
  Local<Value> argv[1] = { b };
  cb->Call(Null(isolate), 1, argv);
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/test/test_timeouts.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "chrome/test/test_switches.h"

namespace {

void InitializeTimeout(const char* switch_name, int* value) {
  DCHECK(value);
  if (CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) {
    std::string string_value(
        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name));
    int timeout;
    base::StringToInt(string_value, &timeout);
    *value = std::max(*value, timeout);
  }
}

}  // namespace

// static
bool TestTimeouts::initialized_ = false;

// The timeout values should increase in the order they appear in this block.
// static
int TestTimeouts::action_timeout_ms_ = 2000;
int TestTimeouts::action_max_timeout_ms_ = 15000;
int TestTimeouts::medium_test_timeout_ms_ = 60 * 1000;
int TestTimeouts::large_test_timeout_ms_ = 10 * 60 * 1000;

// static
int TestTimeouts::sleep_timeout_ms_ = 2000;

// static
int TestTimeouts::command_execution_timeout_ms_ = 25000;

// static
int TestTimeouts::wait_for_terminate_timeout_ms_ = 15000;

// static
void TestTimeouts::Initialize() {
  if (initialized_) {
    NOTREACHED();
    return;
  }
  initialized_ = true;

  InitializeTimeout(switches::kUiTestActionTimeout, &action_timeout_ms_);
  InitializeTimeout(switches::kUiTestActionMaxTimeout,
                    &action_max_timeout_ms_);
  InitializeTimeout(switches::kMediumTestTimeout, &medium_test_timeout_ms_);
  InitializeTimeout(switches::kUiTestTimeout, &large_test_timeout_ms_);

  // The timeout values should be increasing in the right order.
  CHECK(action_timeout_ms_ <= action_max_timeout_ms_);
  CHECK(action_max_timeout_ms_ <= medium_test_timeout_ms_);
  CHECK(medium_test_timeout_ms_ <= large_test_timeout_ms_);

  InitializeTimeout(switches::kUiTestSleepTimeout, &sleep_timeout_ms_);
  InitializeTimeout(switches::kUiTestCommandExecutionTimeout,
                    &command_execution_timeout_ms_);
  InitializeTimeout(switches::kUiTestTerminateTimeout,
                    &wait_for_terminate_timeout_ms_);
}
<commit_msg>Revert 59421 - GTTF: Increase the timeout for medium tests to one minute.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/test/test_timeouts.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "chrome/test/test_switches.h"

namespace {

void InitializeTimeout(const char* switch_name, int* value) {
  DCHECK(value);
  if (CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) {
    std::string string_value(
        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name));
    int timeout;
    base::StringToInt(string_value, &timeout);
    *value = std::max(*value, timeout);
  }
}

}  // namespace

// static
bool TestTimeouts::initialized_ = false;

// The timeout values should increase in the order they appear in this block.
// static
int TestTimeouts::action_timeout_ms_ = 2000;
int TestTimeouts::action_max_timeout_ms_ = 15000;
int TestTimeouts::medium_test_timeout_ms_ = 30 * 1000;
int TestTimeouts::large_test_timeout_ms_ = 10 * 60 * 1000;

// static
int TestTimeouts::sleep_timeout_ms_ = 2000;

// static
int TestTimeouts::command_execution_timeout_ms_ = 25000;

// static
int TestTimeouts::wait_for_terminate_timeout_ms_ = 15000;

// static
void TestTimeouts::Initialize() {
  if (initialized_) {
    NOTREACHED();
    return;
  }
  initialized_ = true;

  InitializeTimeout(switches::kUiTestActionTimeout, &action_timeout_ms_);
  InitializeTimeout(switches::kUiTestActionMaxTimeout,
                    &action_max_timeout_ms_);
  InitializeTimeout(switches::kMediumTestTimeout, &medium_test_timeout_ms_);
  InitializeTimeout(switches::kUiTestTimeout, &large_test_timeout_ms_);

  // The timeout values should be increasing in the right order.
  CHECK(action_timeout_ms_ <= action_max_timeout_ms_);
  CHECK(action_max_timeout_ms_ <= medium_test_timeout_ms_);
  CHECK(medium_test_timeout_ms_ <= large_test_timeout_ms_);

  InitializeTimeout(switches::kUiTestSleepTimeout, &sleep_timeout_ms_);
  InitializeTimeout(switches::kUiTestCommandExecutionTimeout,
                    &command_execution_timeout_ms_);
  InitializeTimeout(switches::kUiTestTerminateTimeout,
                    &wait_for_terminate_timeout_ms_);
}
<|endoftext|>