<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2012, John Haddon. All rights reserved.
//  Copyright (c) 2012-2015, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "tbb/tbb.h"

#include "IECore/Exception.h"
#include "IECore/BoxOps.h"
#include "IECore/BoxAlgo.h"

#include "Gaffer/Context.h"

#include "GafferImage/ImagePlug.h"
#include "GafferImage/AtomicFormatPlug.h"

using namespace std;
using namespace Imath;
using namespace IECore;
using namespace Gaffer;
using namespace GafferImage;
using namespace tbb;

IE_CORE_DEFINERUNTIMETYPED( ImagePlug );

//////////////////////////////////////////////////////////////////////////
// Implementation of CopyTiles:
// A simple class for multithreading the copying of
// image tiles from an input plug to an output plug.
//////////////////////////////////////////////////////////////////////////

namespace GafferImage
{

namespace Detail
{

class CopyTiles
{
	public:
		CopyTiles(
				const vector<float *> &imageChannelData,
				const vector<string> &channelNames,
				const Gaffer::FloatVectorDataPlug *channelDataPlug,
				const Box2i& dataWindow,
				const Context *context, const int tileSize
			) :
				m_imageChannelData( imageChannelData ),
				m_channelNames( channelNames ),
				m_channelDataPlug( channelDataPlug ),
				m_dataWindow( dataWindow ),
				m_parentContext( context ),
				m_tileSize( tileSize )
		{}

		void operator()( const blocked_range3d<size_t>& r ) const
		{
			ContextPtr context = new Context( *m_parentContext, Context::Borrowed );
			Context::Scope scope( context.get() );

			const Box2i operationWindow( V2i( r.rows().begin()+m_dataWindow.min.x, r.cols().begin()+m_dataWindow.min.y ), V2i( r.rows().end()+m_dataWindow.min.x, r.cols().end()+m_dataWindow.min.y ) );

			V2i minTileOrigin = ImagePlug::tileOrigin( operationWindow.min );
			V2i maxTileOrigin = ImagePlug::tileOrigin( operationWindow.max - V2i( 1 ) );

			size_t imageStride = m_dataWindow.size().x;

			for( size_t channelIndex = r.pages().begin(); channelIndex < r.pages().end(); ++channelIndex )
			{
				context->set( ImagePlug::channelNameContextName, m_channelNames[channelIndex] );
				float *channelBegin = m_imageChannelData[channelIndex];

				for( int tileOriginY = minTileOrigin.y; tileOriginY <= maxTileOrigin.y; tileOriginY += m_tileSize )
				{
					for( int tileOriginX = minTileOrigin.x; tileOriginX <= maxTileOrigin.x; tileOriginX += m_tileSize )
					{
						context->set( ImagePlug::tileOriginContextName, V2i( tileOriginX, tileOriginY ) );

						Box2i tileBound( V2i( tileOriginX, tileOriginY ), V2i( tileOriginX + m_tileSize, tileOriginY + m_tileSize ) );
						Box2i b = boxIntersection( tileBound, operationWindow );

						size_t tileStrideSize = sizeof(float) * b.size().x;

						ConstFloatVectorDataPtr tileData = m_channelDataPlug->getValue();
						const float *tileDataBegin = &(tileData->readable()[0]);

						for( int y = b.min.y; y<b.max.y; y++ )
						{
							const float *tilePtr = tileDataBegin + (y - tileOriginY) * m_tileSize + (b.min.x - tileOriginX);
							float *channelPtr = channelBegin + ( m_dataWindow.size().y - ( 1 + y - m_dataWindow.min.y ) ) * imageStride + (b.min.x - m_dataWindow.min.x);
							std::memcpy( channelPtr, tilePtr, tileStrideSize );
						}
					}
				}
			}
		}

	private:
		const vector<float *> &m_imageChannelData;
		const vector<string> &m_channelNames;
		const Gaffer::FloatVectorDataPlug *m_channelDataPlug;
		const Box2i &m_dataWindow;
		const Context *m_parentContext;
		const int m_tileSize;
};

};

};

//////////////////////////////////////////////////////////////////////////
// Implementation of ImagePlug
//////////////////////////////////////////////////////////////////////////
const IECore::InternedString ImagePlug::channelNameContextName = "image:channelName";
const IECore::InternedString ImagePlug::tileOriginContextName = "image:tileOrigin";

size_t ImagePlug::g_firstPlugIndex = 0;

ImagePlug::ImagePlug( const std::string &name, Direction direction, unsigned flags )
	:	ValuePlug( name, direction, flags )
{
	storeIndexOfNextChild( g_firstPlugIndex );

	// we don't want the children to be serialised in any way - we always create
	// them ourselves in this constructor so they aren't Dynamic, and we don't ever
	// want to store their values because they are meaningless without an input
	// connection, so they aren't Serialisable either.
	unsigned childFlags = flags & ~(Dynamic | Serialisable);

	addChild(
		new AtomicFormatPlug(
			"format",
			direction,
			Format(),
			childFlags
		)
	);

	addChild(
		new AtomicBox2iPlug(
			"dataWindow",
			direction,
			Imath::Box2i(),
			childFlags
		)
	);

	addChild(
		new CompoundObjectPlug(
			"metadata",
			direction,
			new IECore::CompoundObject,
			childFlags
		)
	);

	IECore::StringVectorDataPtr channelStrVectorData( new IECore::StringVectorData() );
	std::vector<std::string> &channelStrVector( channelStrVectorData->writable() );
	channelStrVector.push_back("R");
	channelStrVector.push_back("G");
	channelStrVector.push_back("B");

	addChild(
		new StringVectorDataPlug(
			"channelNames",
			direction,
			channelStrVectorData,
			childFlags
		)
	);

	addChild(
		new FloatVectorDataPlug(
			"channelData",
			direction,
			blackTile(),
			childFlags
		)
	);

}

ImagePlug::~ImagePlug()
{
}

const IECore::FloatVectorData *ImagePlug::whiteTile()
{
	static IECore::ConstFloatVectorDataPtr g_whiteTile( new IECore::FloatVectorData( std::vector<float>( ImagePlug::tileSize()*ImagePlug::tileSize(), 1. ) ) );
	return g_whiteTile.get();
};

const IECore::FloatVectorData *ImagePlug::blackTile()
{
	static IECore::ConstFloatVectorDataPtr g_blackTile( new IECore::FloatVectorData( std::vector<float>( ImagePlug::tileSize()*ImagePlug::tileSize(), 0. ) ) );
	return g_blackTile.get();
};

bool ImagePlug::acceptsChild( const GraphComponent *potentialChild ) const
{
	if( !ValuePlug::acceptsChild( potentialChild ) )
	{
		return false;
	}
	return children().size() != 5;
}

bool ImagePlug::acceptsInput( const Gaffer::Plug *input ) const
{
	if( !ValuePlug::acceptsInput( input ) )
	{
		return false;
	}
	if( input )
	{
		return input->isInstanceOf( staticTypeId() );
	}
	return true;
}

Gaffer::PlugPtr ImagePlug::createCounterpart( const std::string &name, Direction direction ) const
{
	return new ImagePlug( name, direction, getFlags() );
}

GafferImage::AtomicFormatPlug *ImagePlug::formatPlug()
{
	return getChild<AtomicFormatPlug>( g_firstPlugIndex );
}

const GafferImage::AtomicFormatPlug *ImagePlug::formatPlug() const
{
	return getChild<AtomicFormatPlug>( g_firstPlugIndex );
}

Gaffer::AtomicBox2iPlug *ImagePlug::dataWindowPlug()
{
	return getChild<AtomicBox2iPlug>( g_firstPlugIndex+1 );
}

const Gaffer::AtomicBox2iPlug *ImagePlug::dataWindowPlug() const
{
	return getChild<AtomicBox2iPlug>( g_firstPlugIndex+1 );
}

Gaffer::CompoundObjectPlug *ImagePlug::metadataPlug()
{
	return getChild<CompoundObjectPlug>( g_firstPlugIndex+2 );
}

const Gaffer::CompoundObjectPlug *ImagePlug::metadataPlug() const
{
	return getChild<CompoundObjectPlug>( g_firstPlugIndex+2 );
}

Gaffer::StringVectorDataPlug *ImagePlug::channelNamesPlug()
{
	return getChild<StringVectorDataPlug>( g_firstPlugIndex+3 );
}

const Gaffer::StringVectorDataPlug *ImagePlug::channelNamesPlug() const
{
	return getChild<StringVectorDataPlug>( g_firstPlugIndex+3 );
}

Gaffer::FloatVectorDataPlug *ImagePlug::channelDataPlug()
{
	return getChild<FloatVectorDataPlug>( g_firstPlugIndex+4 );
}

const Gaffer::FloatVectorDataPlug *ImagePlug::channelDataPlug() const
{
	return getChild<FloatVectorDataPlug>( g_firstPlugIndex+4 );
}

IECore::ConstFloatVectorDataPtr ImagePlug::channelData( const std::string &channelName, const Imath::V2i &tile ) const
{
	if( direction()==In && !getInput<Plug>() )
	{
		return channelDataPlug()->defaultValue();
	}

	ContextPtr tmpContext = new Context( *Context::current(), Context::Borrowed );
	tmpContext->set( ImagePlug::channelNameContextName, channelName );
	tmpContext->set( ImagePlug::tileOriginContextName, tile );
	Context::Scope scopedContext( tmpContext.get() );

	return channelDataPlug()->getValue();
}

IECore::MurmurHash ImagePlug::channelDataHash( const std::string &channelName, const Imath::V2i &tile ) const
{
	ContextPtr tmpContext = new Context( *Context::current(), Context::Borrowed );
	tmpContext->set( ImagePlug::channelNameContextName, channelName );
	tmpContext->set( ImagePlug::tileOriginContextName, tile );
	Context::Scope scopedContext( tmpContext.get() );
	return channelDataPlug()->hash();
}

IECore::ImagePrimitivePtr ImagePlug::image() const
{
	Format format = formatPlug()->getValue();
	Box2i dataWindow = dataWindowPlug()->getValue();
	Box2i newDataWindow( Imath::V2i( 0 ) );

	if( dataWindow.hasVolume() )
	{
		newDataWindow = format.toEXRSpace( dataWindow );
	}
	else
	{
		dataWindow = newDataWindow;
	}

	// use the default format if we don't have an explicit one.
	/// \todo: remove this once AtomicFormatPlug is handling it for
	/// us during ExecutableNode::execute (see issue #887).
	if( format.getDisplayWindow().isEmpty() )
	{
		format = Context::current()->get<Format>( Format::defaultFormatContextName, Format() );
	}

	Box2i newDisplayWindow = format.toEXRSpace( format.getDisplayWindow() );

	ImagePrimitivePtr result = new ImagePrimitive( newDataWindow, newDisplayWindow );

	ConstCompoundObjectPtr metadata = metadataPlug()->getValue();
	compoundObjectToCompoundData( metadata.get(), result->blindData() );

	ConstStringVectorDataPtr channelNamesData = channelNamesPlug()->getValue();
	const vector<string> &channelNames = channelNamesData->readable();

	vector<float *> imageChannelData;
	for( vector<string>::const_iterator it = channelNames.begin(), eIt = channelNames.end(); it!=eIt; it++ )
	{
		FloatVectorDataPtr cd = new FloatVectorData;
		vector<float> &c = cd->writable();
		c.resize( result->variableSize( PrimitiveVariable::Vertex ), 0.0f );
		result->variables[*it] = PrimitiveVariable( PrimitiveVariable::Vertex, cd );
		imageChannelData.push_back( &(c[0]) );
	}

	parallel_for( blocked_range3d<size_t>( 0, imageChannelData.size(), 1, 0, dataWindow.size().x, tileSize(), 0, dataWindow.size().y, tileSize() ),
		      GafferImage::Detail::CopyTiles( imageChannelData, channelNames, channelDataPlug(), dataWindow, Context::current(), tileSize()) );

	return result;
}

IECore::MurmurHash ImagePlug::imageHash() const
{
	const Box2i dataWindow = dataWindowPlug()->getValue();
	ConstStringVectorDataPtr channelNamesData = channelNamesPlug()->getValue();
	const vector<string> &channelNames = channelNamesData->readable();

	MurmurHash result = formatPlug()->hash();
	result.append( dataWindowPlug()->hash() );
	result.append( metadataPlug()->hash() );
	result.append( channelNamesPlug()->hash() );

	V2i minTileOrigin = tileOrigin( dataWindow.min );
	V2i maxTileOrigin = tileOrigin( dataWindow.max );

	ContextPtr context = new Context( *Context::current(), Context::Borrowed );
	Context::Scope scope( context.get() );

	for( vector<string>::const_iterator it = channelNames.begin(), eIt = channelNames.end(); it!=eIt; it++ )
	{
		context->set( ImagePlug::channelNameContextName, *it );
		for( int tileOriginY = minTileOrigin.y; tileOriginY<=maxTileOrigin.y; tileOriginY += tileSize() )
		{
			for( int tileOriginX = minTileOrigin.x; tileOriginX<=maxTileOrigin.x; tileOriginX += tileSize() )
			{
				context->set( ImagePlug::tileOriginContextName, V2i( tileOriginX, tileOriginY ) );
				channelDataPlug()->hash( result );
			}
		}
	}

	return result;
}

// \todo This function may be useful on other situations. Add as Converter?
void ImagePlug::compoundObjectToCompoundData( const CompoundObject *object, CompoundData *data )
{
	CompoundDataMap &dataMap = data->writable();
	const CompoundObject::ObjectMap &objectMap = object->members();
	for ( CompoundObject::ObjectMap::const_iterator it = objectMap.begin(); it != objectMap.end(); ++it )
	{
		if ( it->second->typeId() == CompoundObjectTypeId )
		{
			CompoundDataPtr newData = new CompoundData();
			dataMap[ it->first ] = newData;
			compoundObjectToCompoundData( static_cast<const CompoundObject *>( it->second.get() ), newData.get() );
		}
		else if ( Data *value = IECore::runTimeCast<Data>( it->second.get() ) )
		{
			dataMap[ it->first ] = value;
		}
	}
}
<commit_msg>ImagePlug : Update for default format API changes.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2012, John Haddon. All rights reserved.
//  Copyright (c) 2012-2015, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "tbb/tbb.h"

#include "IECore/Exception.h"
#include "IECore/BoxOps.h"
#include "IECore/BoxAlgo.h"

#include "Gaffer/Context.h"

#include "GafferImage/ImagePlug.h"
#include "GafferImage/AtomicFormatPlug.h"
#include "GafferImage/FormatPlug.h"

using namespace std;
using namespace Imath;
using namespace IECore;
using namespace Gaffer;
using namespace GafferImage;
using namespace tbb;

IE_CORE_DEFINERUNTIMETYPED( ImagePlug );

//////////////////////////////////////////////////////////////////////////
// Implementation of CopyTiles:
// A simple class for multithreading the copying of
// image tiles from an input plug to an output plug.
//////////////////////////////////////////////////////////////////////////

namespace GafferImage
{

namespace Detail
{

class CopyTiles
{
	public:
		CopyTiles(
				const vector<float *> &imageChannelData,
				const vector<string> &channelNames,
				const Gaffer::FloatVectorDataPlug *channelDataPlug,
				const Box2i& dataWindow,
				const Context *context, const int tileSize
			) :
				m_imageChannelData( imageChannelData ),
				m_channelNames( channelNames ),
				m_channelDataPlug( channelDataPlug ),
				m_dataWindow( dataWindow ),
				m_parentContext( context ),
				m_tileSize( tileSize )
		{}

		void operator()( const blocked_range3d<size_t>& r ) const
		{
			ContextPtr context = new Context( *m_parentContext, Context::Borrowed );
			Context::Scope scope( context.get() );

			const Box2i operationWindow( V2i( r.rows().begin()+m_dataWindow.min.x, r.cols().begin()+m_dataWindow.min.y ), V2i( r.rows().end()+m_dataWindow.min.x, r.cols().end()+m_dataWindow.min.y ) );

			V2i minTileOrigin = ImagePlug::tileOrigin( operationWindow.min );
			V2i maxTileOrigin = ImagePlug::tileOrigin( operationWindow.max - V2i( 1 ) );

			size_t imageStride = m_dataWindow.size().x;

			for( size_t channelIndex = r.pages().begin(); channelIndex < r.pages().end(); ++channelIndex )
			{
				context->set( ImagePlug::channelNameContextName, m_channelNames[channelIndex] );
				float *channelBegin = m_imageChannelData[channelIndex];

				for( int tileOriginY = minTileOrigin.y; tileOriginY <= maxTileOrigin.y; tileOriginY += m_tileSize )
				{
					for( int tileOriginX = minTileOrigin.x; tileOriginX <= maxTileOrigin.x; tileOriginX += m_tileSize )
					{
						context->set( ImagePlug::tileOriginContextName, V2i( tileOriginX, tileOriginY ) );

						Box2i tileBound( V2i( tileOriginX, tileOriginY ), V2i( tileOriginX + m_tileSize, tileOriginY + m_tileSize ) );
						Box2i b = boxIntersection( tileBound, operationWindow );

						size_t tileStrideSize = sizeof(float) * b.size().x;

						ConstFloatVectorDataPtr tileData = m_channelDataPlug->getValue();
						const float *tileDataBegin = &(tileData->readable()[0]);

						for( int y = b.min.y; y<b.max.y; y++ )
						{
							const float *tilePtr = tileDataBegin + (y - tileOriginY) * m_tileSize + (b.min.x - tileOriginX);
							float *channelPtr = channelBegin + ( m_dataWindow.size().y - ( 1 + y - m_dataWindow.min.y ) ) * imageStride + (b.min.x - m_dataWindow.min.x);
							std::memcpy( channelPtr, tilePtr, tileStrideSize );
						}
					}
				}
			}
		}

	private:
		const vector<float *> &m_imageChannelData;
		const vector<string> &m_channelNames;
		const Gaffer::FloatVectorDataPlug *m_channelDataPlug;
		const Box2i &m_dataWindow;
		const Context *m_parentContext;
		const int m_tileSize;
};

};

};

//////////////////////////////////////////////////////////////////////////
// Implementation of ImagePlug
//////////////////////////////////////////////////////////////////////////
const IECore::InternedString ImagePlug::channelNameContextName = "image:channelName";
const IECore::InternedString ImagePlug::tileOriginContextName = "image:tileOrigin";

size_t ImagePlug::g_firstPlugIndex = 0;

ImagePlug::ImagePlug( const std::string &name, Direction direction, unsigned flags )
	:	ValuePlug( name, direction, flags )
{
	storeIndexOfNextChild( g_firstPlugIndex );

	// we don't want the children to be serialised in any way - we always create
	// them ourselves in this constructor so they aren't Dynamic, and we don't ever
	// want to store their values because they are meaningless without an input
	// connection, so they aren't Serialisable either.
	unsigned childFlags = flags & ~(Dynamic | Serialisable);

	addChild(
		new AtomicFormatPlug(
			"format",
			direction,
			Format(),
			childFlags
		)
	);

	addChild(
		new AtomicBox2iPlug(
			"dataWindow",
			direction,
			Imath::Box2i(),
			childFlags
		)
	);

	addChild(
		new CompoundObjectPlug(
			"metadata",
			direction,
			new IECore::CompoundObject,
			childFlags
		)
	);

	IECore::StringVectorDataPtr channelStrVectorData( new IECore::StringVectorData() );
	std::vector<std::string> &channelStrVector( channelStrVectorData->writable() );
	channelStrVector.push_back("R");
	channelStrVector.push_back("G");
	channelStrVector.push_back("B");

	addChild(
		new StringVectorDataPlug(
			"channelNames",
			direction,
			channelStrVectorData,
			childFlags
		)
	);

	addChild(
		new FloatVectorDataPlug(
			"channelData",
			direction,
			blackTile(),
			childFlags
		)
	);

}

ImagePlug::~ImagePlug()
{
}

const IECore::FloatVectorData *ImagePlug::whiteTile()
{
	static IECore::ConstFloatVectorDataPtr g_whiteTile( new IECore::FloatVectorData( std::vector<float>( ImagePlug::tileSize()*ImagePlug::tileSize(), 1. ) ) );
	return g_whiteTile.get();
};

const IECore::FloatVectorData *ImagePlug::blackTile()
{
	static IECore::ConstFloatVectorDataPtr g_blackTile( new IECore::FloatVectorData( std::vector<float>( ImagePlug::tileSize()*ImagePlug::tileSize(), 0. ) ) );
	return g_blackTile.get();
};

bool ImagePlug::acceptsChild( const GraphComponent *potentialChild ) const
{
	if( !ValuePlug::acceptsChild( potentialChild ) )
	{
		return false;
	}
	return children().size() != 5;
}

bool ImagePlug::acceptsInput( const Gaffer::Plug *input ) const
{
	if( !ValuePlug::acceptsInput( input ) )
	{
		return false;
	}
	if( input )
	{
		return input->isInstanceOf( staticTypeId() );
	}
	return true;
}

Gaffer::PlugPtr ImagePlug::createCounterpart( const std::string &name, Direction direction ) const
{
	return new ImagePlug( name, direction, getFlags() );
}

GafferImage::AtomicFormatPlug *ImagePlug::formatPlug()
{
	return getChild<AtomicFormatPlug>( g_firstPlugIndex );
}

const GafferImage::AtomicFormatPlug *ImagePlug::formatPlug() const
{
	return getChild<AtomicFormatPlug>( g_firstPlugIndex );
}

Gaffer::AtomicBox2iPlug *ImagePlug::dataWindowPlug()
{
	return getChild<AtomicBox2iPlug>( g_firstPlugIndex+1 );
}

const Gaffer::AtomicBox2iPlug *ImagePlug::dataWindowPlug() const
{
	return getChild<AtomicBox2iPlug>( g_firstPlugIndex+1 );
}

Gaffer::CompoundObjectPlug *ImagePlug::metadataPlug()
{
	return getChild<CompoundObjectPlug>( g_firstPlugIndex+2 );
}

const Gaffer::CompoundObjectPlug *ImagePlug::metadataPlug() const
{
	return getChild<CompoundObjectPlug>( g_firstPlugIndex+2 );
}

Gaffer::StringVectorDataPlug *ImagePlug::channelNamesPlug()
{
	return getChild<StringVectorDataPlug>( g_firstPlugIndex+3 );
}

const Gaffer::StringVectorDataPlug *ImagePlug::channelNamesPlug() const
{
	return getChild<StringVectorDataPlug>( g_firstPlugIndex+3 );
}

Gaffer::FloatVectorDataPlug *ImagePlug::channelDataPlug()
{
	return getChild<FloatVectorDataPlug>( g_firstPlugIndex+4 );
}

const Gaffer::FloatVectorDataPlug *ImagePlug::channelDataPlug() const
{
	return getChild<FloatVectorDataPlug>( g_firstPlugIndex+4 );
}

IECore::ConstFloatVectorDataPtr ImagePlug::channelData( const std::string &channelName, const Imath::V2i &tile ) const
{
	if( direction()==In && !getInput<Plug>() )
	{
		return channelDataPlug()->defaultValue();
	}

	ContextPtr tmpContext = new Context( *Context::current(), Context::Borrowed );
	tmpContext->set( ImagePlug::channelNameContextName, channelName );
	tmpContext->set( ImagePlug::tileOriginContextName, tile );
	Context::Scope scopedContext( tmpContext.get() );

	return channelDataPlug()->getValue();
}

IECore::MurmurHash ImagePlug::channelDataHash( const std::string &channelName, const Imath::V2i &tile ) const
{
	ContextPtr tmpContext = new Context( *Context::current(), Context::Borrowed );
	tmpContext->set( ImagePlug::channelNameContextName, channelName );
	tmpContext->set( ImagePlug::tileOriginContextName, tile );
	Context::Scope scopedContext( tmpContext.get() );
	return channelDataPlug()->hash();
}

IECore::ImagePrimitivePtr ImagePlug::image() const
{
	Format format = formatPlug()->getValue();
	Box2i dataWindow = dataWindowPlug()->getValue();
	Box2i newDataWindow( Imath::V2i( 0 ) );

	if( dataWindow.hasVolume() )
	{
		newDataWindow = format.toEXRSpace( dataWindow );
	}
	else
	{
		dataWindow = newDataWindow;
	}

	// use the default format if we don't have an explicit one.
	/// \todo: remove this once FormatPlug is handling it for
	/// us during ExecutableNode::execute (see issue #887).
	if( format.getDisplayWindow().isEmpty() )
	{
		format = FormatPlug::getDefaultFormat( Context::current() );
	}

	Box2i newDisplayWindow = format.toEXRSpace( format.getDisplayWindow() );

	ImagePrimitivePtr result = new ImagePrimitive( newDataWindow, newDisplayWindow );

	ConstCompoundObjectPtr metadata = metadataPlug()->getValue();
	compoundObjectToCompoundData( metadata.get(), result->blindData() );

	ConstStringVectorDataPtr channelNamesData = channelNamesPlug()->getValue();
	const vector<string> &channelNames = channelNamesData->readable();

	vector<float *> imageChannelData;
	for( vector<string>::const_iterator it = channelNames.begin(), eIt = channelNames.end(); it!=eIt; it++ )
	{
		FloatVectorDataPtr cd = new FloatVectorData;
		vector<float> &c = cd->writable();
		c.resize( result->variableSize( PrimitiveVariable::Vertex ), 0.0f );
		result->variables[*it] = PrimitiveVariable( PrimitiveVariable::Vertex, cd );
		imageChannelData.push_back( &(c[0]) );
	}

	parallel_for( blocked_range3d<size_t>( 0, imageChannelData.size(), 1, 0, dataWindow.size().x, tileSize(), 0, dataWindow.size().y, tileSize() ),
		      GafferImage::Detail::CopyTiles( imageChannelData, channelNames, channelDataPlug(), dataWindow, Context::current(), tileSize()) );

	return result;
}

IECore::MurmurHash ImagePlug::imageHash() const
{
	const Box2i dataWindow = dataWindowPlug()->getValue();
	ConstStringVectorDataPtr channelNamesData = channelNamesPlug()->getValue();
	const vector<string> &channelNames = channelNamesData->readable();

	MurmurHash result = formatPlug()->hash();
	result.append( dataWindowPlug()->hash() );
	result.append( metadataPlug()->hash() );
	result.append( channelNamesPlug()->hash() );

	V2i minTileOrigin = tileOrigin( dataWindow.min );
	V2i maxTileOrigin = tileOrigin( dataWindow.max );

	ContextPtr context = new Context( *Context::current(), Context::Borrowed );
	Context::Scope scope( context.get() );

	for( vector<string>::const_iterator it = channelNames.begin(), eIt = channelNames.end(); it!=eIt; it++ )
	{
		context->set( ImagePlug::channelNameContextName, *it );
		for( int tileOriginY = minTileOrigin.y; tileOriginY<=maxTileOrigin.y; tileOriginY += tileSize() )
		{
			for( int tileOriginX = minTileOrigin.x; tileOriginX<=maxTileOrigin.x; tileOriginX += tileSize() )
			{
				context->set( ImagePlug::tileOriginContextName, V2i( tileOriginX, tileOriginY ) );
				channelDataPlug()->hash( result );
			}
		}
	}

	return result;
}

// \todo This function may be useful on other situations. Add as Converter?
void ImagePlug::compoundObjectToCompoundData( const CompoundObject *object, CompoundData *data )
{
	CompoundDataMap &dataMap = data->writable();
	const CompoundObject::ObjectMap &objectMap = object->members();
	for ( CompoundObject::ObjectMap::const_iterator it = objectMap.begin(); it != objectMap.end(); ++it )
	{
		if ( it->second->typeId() == CompoundObjectTypeId )
		{
			CompoundDataPtr newData = new CompoundData();
			dataMap[ it->first ] = newData;
			compoundObjectToCompoundData( static_cast<const CompoundObject *>( it->second.get() ), newData.get() );
		}
		else if ( Data *value = IECore::runTimeCast<Data>( it->second.get() ) )
		{
			dataMap[ it->first ] = value;
		}
	}
}
<|endoftext|>


<commit_before>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <af/dim4.hpp>
#include <af/defines.h>
#include <af/index.h>
#include <backend.hpp>
#include <err_common.hpp>
#include <handle.hpp>
#include <backend.hpp>
#include <copy.hpp>

using af::dim4;
using namespace detail;

template<typename T>
af_array modDims(const af_array in, const af::dim4 &newDims)
{
    const Array<T> &In = getArray<T>(in);
    Array<T> Out = In;

    if (!In.isLinear()) {
        Out = copyArray<T>(In);
    }
    Out.modDims(newDims);

    return getHandle(Out);
}

af_err af_moddims(af_array *out, const af_array in,
                  const unsigned ndims, const dim_type * const dims)
{
    try {
        ARG_ASSERT(2, ndims >= 1);
        ARG_ASSERT(3, dims != NULL);

        af_array output = 0;
        dim4 newDims(ndims, dims);
        ArrayInfo info = getInfo(in);
        dim_type in_elements = info.elements();
        dim_type new_elements = newDims.elements();

        DIM_ASSERT(1, in_elements == new_elements);

        af_dtype type = info.getType();

        switch(type) {
        case f32: output = modDims<float  >(in, newDims); break;
        case c32: output = modDims<cfloat >(in, newDims); break;
        case f64: output = modDims<double >(in, newDims); break;
        case c64: output = modDims<cdouble>(in, newDims); break;
        case b8:  output = modDims<char   >(in, newDims); break;
        case s32: output = modDims<int    >(in, newDims); break;
        case u32: output = modDims<uint   >(in, newDims); break;
        case u8:  output = modDims<uchar  >(in, newDims); break;
        case s64: output = modDims<intl   >(in, newDims); break;
        case u64: output = modDims<uintl  >(in, newDims); break;
        default: TYPE_ERROR(1, type);
        }
        std::swap(*out,output);
    }
    CATCHALL

    return AF_SUCCESS;
}

af_err af_flat(af_array *out, const af_array in)
{
    af_array res;
    try {

        ArrayInfo in_info = getInfo(in);

        if (in_info.ndims() == 1) {
            AF_CHECK(af_weak_copy(&res, in));
        } else {
            const dim_type num = (dim_type)(in_info.elements());
            AF_CHECK(af_moddims(&res, in, 1, &num));
        }

        std::swap(*out, res);
    } CATCHALL;
    return AF_SUCCESS;
}
<commit_msg>BUGFIX: in moddims when input is a jit node<commit_after>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <af/dim4.hpp>
#include <af/defines.h>
#include <af/index.h>
#include <backend.hpp>
#include <err_common.hpp>
#include <handle.hpp>
#include <backend.hpp>
#include <copy.hpp>

using af::dim4;
using namespace detail;

template<typename T>
af_array modDims(const af_array in, const af::dim4 &newDims)
{
    const Array<T> &In = getArray<T>(in);

    //FIXME: Figure out a better way
    evalArray<T>(In);

    Array<T> Out = In;

    if (!In.isLinear()) {
        Out = copyArray<T>(In);
    }
    Out.modDims(newDims);

    return getHandle(Out);
}

af_err af_moddims(af_array *out, const af_array in,
                  const unsigned ndims, const dim_type * const dims)
{
    try {
        ARG_ASSERT(2, ndims >= 1);
        ARG_ASSERT(3, dims != NULL);

        af_array output = 0;
        dim4 newDims(ndims, dims);
        ArrayInfo info = getInfo(in);
        dim_type in_elements = info.elements();
        dim_type new_elements = newDims.elements();

        DIM_ASSERT(1, in_elements == new_elements);

        af_dtype type = info.getType();

        switch(type) {
        case f32: output = modDims<float  >(in, newDims); break;
        case c32: output = modDims<cfloat >(in, newDims); break;
        case f64: output = modDims<double >(in, newDims); break;
        case c64: output = modDims<cdouble>(in, newDims); break;
        case b8:  output = modDims<char   >(in, newDims); break;
        case s32: output = modDims<int    >(in, newDims); break;
        case u32: output = modDims<uint   >(in, newDims); break;
        case u8:  output = modDims<uchar  >(in, newDims); break;
        case s64: output = modDims<intl   >(in, newDims); break;
        case u64: output = modDims<uintl  >(in, newDims); break;
        default: TYPE_ERROR(1, type);
        }
        std::swap(*out,output);
    }
    CATCHALL

    return AF_SUCCESS;
}

af_err af_flat(af_array *out, const af_array in)
{
    af_array res;
    try {

        ArrayInfo in_info = getInfo(in);

        if (in_info.ndims() == 1) {
            AF_CHECK(af_weak_copy(&res, in));
        } else {
            const dim_type num = (dim_type)(in_info.elements());
            AF_CHECK(af_moddims(&res, in, 1, &num));
        }

        std::swap(*out, res);
    } CATCHALL;
    return AF_SUCCESS;
}
<|endoftext|>


<commit_before>// Time:  O(n^3)
// Space: O(n^2)

class Solution {
public:
    int cherryPickup(vector<vector<int>>& grid) {
        // dp holds the max # of cherries two k-length paths can pickup.
        // The two k-length paths arrive at (i, k - i) and (j, k - j),
        // respectively.
        const int n = grid.size();
        vector<vector<int>> dp(n, vector<int>(n, -1));
        dp[0][0] = grid[0][0];

        const int max_len = 2 * (n - 1);
        for (int k = 1; k <= max_len; ++k) {
            for (int i = min(k, n - 1); i >= max(0, k - n - 1); --i) {
                for (int j = min(k , n - 1); j >= i; --j) {
                    if (grid[i][k - i] == -1 ||
                        grid[j][k - j] == -1) {
                        dp[i][j] = -1;
                        continue;
                    }
                    int cnt = grid[i][k - i] + ((i == j) ? 0 : grid[j][k - j]);
                    int max_cnt = -1;
                    static const vector<pair<int, int>> directions{{0, 0}, {-1, 0}, {0, -1}, {-1, -1}};
                    for (const auto& direction : directions) {
                        const auto ii = i + direction.first;
                        const auto jj = j + direction.second;
                        if (ii >= 0 && jj >= 0 && dp[ii][jj] >= 0) {
                            max_cnt = max(max_cnt, dp[ii][jj] + cnt);
                        }
                    }
                    dp[i][j] = max_cnt;
                }
            }
        }
        return max(dp[n - 1][n - 1], 0);
    }
};
<commit_msg>Update cherry-pickup.cpp<commit_after>// Time:  O(n^3)
// Space: O(n^2)

class Solution {
public:
    int cherryPickup(vector<vector<int>>& grid) {
        // dp holds the max # of cherries two k-length paths can pickup.
        // The two k-length paths arrive at (i, k - i) and (j, k - j),
        // respectively.
        const int n = grid.size();
        vector<vector<int>> dp(n, vector<int>(n, -1));
        dp[0][0] = grid[0][0];

        const int max_len = 2 * (n - 1);
        for (int k = 1; k <= max_len; ++k) {
            for (int i = min(k, n - 1); i >= max(0, k - n + 1); --i) {  // 0 <= i < n, 0 <= k-i < n
                for (int j = min(k , n - 1); j >= i; --j) {             // i <= j < n, 0 <= k-j < n
                    if (grid[i][k - i] == -1 ||
                        grid[j][k - j] == -1) {
                        dp[i][j] = -1;
                        continue;
                    }
                    int cnt = grid[i][k - i] + ((i == j) ? 0 : grid[j][k - j]);
                    int max_cnt = -1;
                    static const vector<pair<int, int>> directions{{0, 0}, {-1, 0}, {0, -1}, {-1, -1}};
                    for (const auto& direction : directions) {
                        const auto ii = i + direction.first;
                        const auto jj = j + direction.second;
                        if (ii >= 0 && jj >= 0 && dp[ii][jj] >= 0) {
                            max_cnt = max(max_cnt, dp[ii][jj] + cnt);
                        }
                    }
                    dp[i][j] = max_cnt;
                }
            }
        }
        return max(dp[n - 1][n - 1], 0);
    }
};
<|endoftext|>


<commit_before>///===--- FileManager.cpp - File System Probing and Caching ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the FileManager interface.
//
//===----------------------------------------------------------------------===//
//
// TODO: This should index all interesting directories with dirent calls.
//  getdirentries ?
//  opendir/readdir_r/closedir ?
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/FileManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Bitcode/Serialize.h"
#include "llvm/Bitcode/Deserialize.h"
#include <iostream>
using namespace clang;

// FIXME: Enhance libsystem to support inode and other fields.
#include <sys/stat.h>

#if defined(_MSC_VER)
#define S_ISDIR(s) (_S_IFDIR & s)
#endif

/// NON_EXISTANT_DIR - A special value distinct from null that is used to
/// represent a dir name that doesn't exist on the disk.
#define NON_EXISTANT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)

/// getDirectory - Lookup, cache, and verify the specified directory.  This
/// returns null if the directory doesn't exist.
///
const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
                                                const char *NameEnd) {
  ++NumDirLookups;
  llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
    DirEntries.GetOrCreateValue(NameStart, NameEnd);

  // See if there is already an entry in the map.
  if (NamedDirEnt.getValue())
    return NamedDirEnt.getValue() == NON_EXISTANT_DIR
              ? 0 : NamedDirEnt.getValue();

  ++NumDirCacheMisses;

  // By default, initialize it to invalid.
  NamedDirEnt.setValue(NON_EXISTANT_DIR);

  // Get the null-terminated directory name as stored as the key of the
  // DirEntries map.
  const char *InterndDirName = NamedDirEnt.getKeyData();

  // Check to see if the directory exists.
  struct stat StatBuf;
  if (stat(InterndDirName, &StatBuf) ||   // Error stat'ing.
      !S_ISDIR(StatBuf.st_mode))          // Not a directory?
    return 0;

  // It exists.  See if we have already opened a directory with the same inode.
  // This occurs when one dir is symlinked to another, for example.
  DirectoryEntry &UDE =
    UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];

  NamedDirEnt.setValue(&UDE);
  if (UDE.getName()) // Already have an entry with this inode, return it.
    return &UDE;

  // Otherwise, we don't have this directory yet, add it.  We use the string
  // key from the DirEntries map as the string.
  UDE.Name  = InterndDirName;
  return &UDE;
}

/// NON_EXISTANT_FILE - A special value distinct from null that is used to
/// represent a filename that doesn't exist on the disk.
#define NON_EXISTANT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)

/// getFile - Lookup, cache, and verify the specified file.  This returns null
/// if the file doesn't exist.
///
const FileEntry *FileManager::getFile(const char *NameStart,
                                      const char *NameEnd) {
  ++NumFileLookups;

  // See if there is already an entry in the map.
  llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
    FileEntries.GetOrCreateValue(NameStart, NameEnd);

  // See if there is already an entry in the map.
  if (NamedFileEnt.getValue())
    return NamedFileEnt.getValue() == NON_EXISTANT_FILE
                 ? 0 : NamedFileEnt.getValue();

  ++NumFileCacheMisses;

  // By default, initialize it to invalid.
  NamedFileEnt.setValue(NON_EXISTANT_FILE);

  // Figure out what directory it is in.   If the string contains a / in it,
  // strip off everything after it.
  // FIXME: this logic should be in sys::Path.
  const char *SlashPos = NameEnd-1;
  while (SlashPos >= NameStart && SlashPos[0] != '/')
    --SlashPos;

  const DirectoryEntry *DirInfo;
  if (SlashPos < NameStart) {
    // Use the current directory if file has no path component.
    const char *Name = ".";
    DirInfo = getDirectory(Name, Name+1);
  } else if (SlashPos == NameEnd-1)
    return 0;       // If filename ends with a /, it's a directory.
  else
    DirInfo = getDirectory(NameStart, SlashPos);

  if (DirInfo == 0)  // Directory doesn't exist, file can't exist.
    return 0;

  // Get the null-terminated file name as stored as the key of the
  // FileEntries map.
  const char *InterndFileName = NamedFileEnt.getKeyData();

  // FIXME: Use the directory info to prune this, before doing the stat syscall.
  // FIXME: This will reduce the # syscalls.

  // Nope, there isn't.  Check to see if the file exists.
  struct stat StatBuf;
  //std::cerr << "STATING: " << Filename;
  if (stat(InterndFileName, &StatBuf) ||   // Error stat'ing.
      S_ISDIR(StatBuf.st_mode)) {           // A directory?
    // If this file doesn't exist, we leave a null in FileEntries for this path.
    //std::cerr << ": Not existing\n";
    return 0;
  }
  //std::cerr << ": exists\n";

  // It exists.  See if we have already opened a file with the same inode.
  // This occurs when one dir is symlinked to another, for example.
  FileEntry &UFE =
   const_cast<FileEntry&>(*UniqueFiles.insert(FileEntry(StatBuf.st_dev,
                                                        StatBuf.st_ino)).first);

  NamedFileEnt.setValue(&UFE);
  if (UFE.getName())  // Already have an entry with this inode, return it.
    return &UFE;

  // Otherwise, we don't have this directory yet, add it.
  // FIXME: Change the name to be a char* that points back to the 'FileEntries'
  // key.
  UFE.Name    = InterndFileName;
  UFE.Size    = StatBuf.st_size;
  UFE.ModTime = StatBuf.st_mtime;
  UFE.Dir     = DirInfo;
  UFE.UID     = NextFileUID++;
  return &UFE;
}

void FileManager::PrintStats() const {
  std::cerr << "\n*** File Manager Stats:\n";
  std::cerr << UniqueFiles.size() << " files found, "
            << UniqueDirs.size() << " dirs found.\n";
  std::cerr << NumDirLookups << " dir lookups, "
            << NumDirCacheMisses << " dir cache misses.\n";
  std::cerr << NumFileLookups << " file lookups, "
            << NumFileCacheMisses << " file cache misses.\n";

  //std::cerr << PagesMapped << BytesOfPagesMapped << FSLookups;
}
<commit_msg>Fix misspelling of "existent". Do not use std::cerr; use llvm::cerr instead.<commit_after>///===--- FileManager.cpp - File System Probing and Caching ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the FileManager interface.
//
//===----------------------------------------------------------------------===//
//
// TODO: This should index all interesting directories with dirent calls.
//  getdirentries ?
//  opendir/readdir_r/closedir ?
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/FileManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Bitcode/Serialize.h"
#include "llvm/Bitcode/Deserialize.h"
#include "llvm/Support/Streams.h"
using namespace clang;

// FIXME: Enhance libsystem to support inode and other fields.
#include <sys/stat.h>

#if defined(_MSC_VER)
#define S_ISDIR(s) (_S_IFDIR & s)
#endif

/// NON_EXISTENT_DIR - A special value distinct from null that is used to
/// represent a dir name that doesn't exist on the disk.
#define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)

/// getDirectory - Lookup, cache, and verify the specified directory.  This
/// returns null if the directory doesn't exist.
///
const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
                                                const char *NameEnd) {
  ++NumDirLookups;
  llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
    DirEntries.GetOrCreateValue(NameStart, NameEnd);

  // See if there is already an entry in the map.
  if (NamedDirEnt.getValue())
    return NamedDirEnt.getValue() == NON_EXISTENT_DIR
              ? 0 : NamedDirEnt.getValue();

  ++NumDirCacheMisses;

  // By default, initialize it to invalid.
  NamedDirEnt.setValue(NON_EXISTENT_DIR);

  // Get the null-terminated directory name as stored as the key of the
  // DirEntries map.
  const char *InterndDirName = NamedDirEnt.getKeyData();

  // Check to see if the directory exists.
  struct stat StatBuf;
  if (stat(InterndDirName, &StatBuf) ||   // Error stat'ing.
      !S_ISDIR(StatBuf.st_mode))          // Not a directory?
    return 0;

  // It exists.  See if we have already opened a directory with the same inode.
  // This occurs when one dir is symlinked to another, for example.
  DirectoryEntry &UDE =
    UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];

  NamedDirEnt.setValue(&UDE);
  if (UDE.getName()) // Already have an entry with this inode, return it.
    return &UDE;

  // Otherwise, we don't have this directory yet, add it.  We use the string
  // key from the DirEntries map as the string.
  UDE.Name  = InterndDirName;
  return &UDE;
}

/// NON_EXISTENT_FILE - A special value distinct from null that is used to
/// represent a filename that doesn't exist on the disk.
#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)

/// getFile - Lookup, cache, and verify the specified file.  This returns null
/// if the file doesn't exist.
///
const FileEntry *FileManager::getFile(const char *NameStart,
                                      const char *NameEnd) {
  ++NumFileLookups;

  // See if there is already an entry in the map.
  llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
    FileEntries.GetOrCreateValue(NameStart, NameEnd);

  // See if there is already an entry in the map.
  if (NamedFileEnt.getValue())
    return NamedFileEnt.getValue() == NON_EXISTENT_FILE
                 ? 0 : NamedFileEnt.getValue();

  ++NumFileCacheMisses;

  // By default, initialize it to invalid.
  NamedFileEnt.setValue(NON_EXISTENT_FILE);

  // Figure out what directory it is in.   If the string contains a / in it,
  // strip off everything after it.
  // FIXME: this logic should be in sys::Path.
  const char *SlashPos = NameEnd-1;
  while (SlashPos >= NameStart && SlashPos[0] != '/')
    --SlashPos;

  const DirectoryEntry *DirInfo;
  if (SlashPos < NameStart) {
    // Use the current directory if file has no path component.
    const char *Name = ".";
    DirInfo = getDirectory(Name, Name+1);
  } else if (SlashPos == NameEnd-1)
    return 0;       // If filename ends with a /, it's a directory.
  else
    DirInfo = getDirectory(NameStart, SlashPos);

  if (DirInfo == 0)  // Directory doesn't exist, file can't exist.
    return 0;

  // Get the null-terminated file name as stored as the key of the
  // FileEntries map.
  const char *InterndFileName = NamedFileEnt.getKeyData();

  // FIXME: Use the directory info to prune this, before doing the stat syscall.
  // FIXME: This will reduce the # syscalls.

  // Nope, there isn't.  Check to see if the file exists.
  struct stat StatBuf;
  //llvm::cerr << "STATING: " << Filename;
  if (stat(InterndFileName, &StatBuf) ||   // Error stat'ing.
      S_ISDIR(StatBuf.st_mode)) {           // A directory?
    // If this file doesn't exist, we leave a null in FileEntries for this path.
    //llvm::cerr << ": Not existing\n";
    return 0;
  }
  //llvm::cerr << ": exists\n";

  // It exists.  See if we have already opened a file with the same inode.
  // This occurs when one dir is symlinked to another, for example.
  FileEntry &UFE =
   const_cast<FileEntry&>(*UniqueFiles.insert(FileEntry(StatBuf.st_dev,
                                                        StatBuf.st_ino)).first);

  NamedFileEnt.setValue(&UFE);
  if (UFE.getName())  // Already have an entry with this inode, return it.
    return &UFE;

  // Otherwise, we don't have this directory yet, add it.
  // FIXME: Change the name to be a char* that points back to the 'FileEntries'
  // key.
  UFE.Name    = InterndFileName;
  UFE.Size    = StatBuf.st_size;
  UFE.ModTime = StatBuf.st_mtime;
  UFE.Dir     = DirInfo;
  UFE.UID     = NextFileUID++;
  return &UFE;
}

void FileManager::PrintStats() const {
  llvm::cerr << "\n*** File Manager Stats:\n";
  llvm::cerr << UniqueFiles.size() << " files found, "
             << UniqueDirs.size() << " dirs found.\n";
  llvm::cerr << NumDirLookups << " dir lookups, "
             << NumDirCacheMisses << " dir cache misses.\n";
  llvm::cerr << NumFileLookups << " file lookups, "
             << NumFileCacheMisses << " file cache misses.\n";

  //llvm::cerr << PagesMapped << BytesOfPagesMapped << FSLookups;
}
<|endoftext|>


<commit_before>#include <mu/io/analyzer/name_map.h>
#include <mu/core/errors/error_list.h>
#include <mu/io/debugging/context.h>
#include <mu/core/expression.h>

#include <gtest/gtest.h>

#include <gc_cpp.h>

TEST (io_test, name_map1)
{
    mu::io::analyzer::name_map map;
}

TEST (io_test, name_map2)
{
    mu::io::analyzer::name_map map;
    map.free_locals ();
}

// Test that unknown references reserve a spot in the expression
TEST (io_test, name_map3)
{
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    map.fill_reference (mu::string (U"thing"), context, expression);
    ASSERT_TRUE (expression.dependencies.size () == 1);
    EXPECT_TRUE (expression.dependencies [0] == nullptr);
}

// Check that unknown references can be filled by globals
TEST (io_test, name_map4)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    map.fill_reference (mu::string (U"thing"), context, expression);
    mu::core::node node;
    map.insert_global(errors, mu::string (U"thing"), &node);
    EXPECT_TRUE (errors.errors.empty ());
    ASSERT_TRUE (expression.dependencies.size () == 1);
    EXPECT_TRUE (expression.dependencies [0] == &node);
}

// Check that unknown references can be filled by locals
TEST (io_test, name_map5)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    map.fill_reference (mu::string (U"thing"), context, expression);
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    EXPECT_TRUE (errors.errors.empty ());
    ASSERT_TRUE (expression.dependencies.size () == 1);
    EXPECT_TRUE (expression.dependencies [0] == &node);
}

// Check that two different globals can be inserted
TEST (io_test, name_map6)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    mu::core::node node2;
    map.insert_local (errors, mu::string (U"thing2"), &node2);
    EXPECT_TRUE (errors.errors.empty ());
}

// Check that two globals with the same name can't be inserted
TEST (io_test, name_map7)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    mu::core::node node2;
    map.insert_local (errors, mu::string (U"thing"), &node2);
    EXPECT_TRUE (!errors.errors.empty ());
}

// Check that two different locals can be inserted
TEST (io_test, name_map8)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    mu::core::node node2;
    map.insert_local (errors, mu::string (U"thing2"), &node2);
    EXPECT_TRUE (errors.errors.empty ());
}

// Check that two locals with the same name can't be inserted
TEST (io_test, name_map9)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    mu::core::node node2;
    map.insert_local (errors, mu::string (U"thing"), &node2);
    EXPECT_TRUE (!errors.errors.empty ());
}

// Check that a local name can be reused after clearing them
TEST (io_test, name_map10)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    map.free_locals ();
    mu::core::node node2;
    map.insert_local (errors, mu::string (U"thing"), &node2);
    EXPECT_TRUE (errors.errors.empty ());
}

// Check that a local name can't collide with an existing global name
TEST (io_test, name_map11)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_global (errors, mu::string (U"thing"), &node);
    mu::core::node node2;
    map.insert_local (errors, mu::string (U"thing"), &node2);
    EXPECT_TRUE (!errors.errors.empty ());
}

// Check that a global name can't collide with an existing local name in local scope
TEST (io_test, name_map12)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    mu::core::node node2;
    map.insert_global (errors, mu::string (U"thing"), &node2);
    EXPECT_TRUE (!errors.errors.empty ());
}

// Check that a global name can't collide with an existing local name out of local scope
TEST (io_test, name_map13)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    map.free_locals ();
    mu::core::node node2;
    map.insert_global (errors, mu::string (U"thing"), &node2);
    EXPECT_TRUE (!errors.errors.empty ());
}

// Check that multiple references can be resolved
TEST (io_test, name_map14)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.fill_reference (mu::string (U"thing"), context, expression);
    map.fill_reference (mu::string (U"thing"), context, expression);
    map.insert_global (errors, mu::string (U"thing"), &node);
    EXPECT_TRUE (errors.errors.empty ());
    EXPECT_TRUE (expression.dependencies.size () == 2);
    EXPECT_TRUE (expression.dependencies [0] == &node);
    EXPECT_TRUE (expression.dependencies [1] == &node);
}

// Check that there are no errors when there are no names
TEST (io_test, name_map15)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.finalize (errors);
    EXPECT_TRUE (errors.errors.empty ());
}

// Check that there are no errors when everything is resolved
TEST (io_test, name_map16)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_global (errors, mu::string (U"thing"), &node);
    map.fill_reference (mu::string (U"thing"), context, expression);
    map.finalize (errors);
    EXPECT_TRUE (errors.errors.empty ());
}

// Check that there are errors when there are unresolved references
TEST (io_test, name_map17)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.fill_reference (mu::string (U"thing"), context, expression);
    map.finalize (errors);
    EXPECT_TRUE (!errors.errors.empty ());
}<commit_msg>Added test for local resolution.<commit_after>#include <mu/io/analyzer/name_map.h>
#include <mu/core/errors/error_list.h>
#include <mu/io/debugging/context.h>
#include <mu/core/expression.h>

#include <gtest/gtest.h>

#include <gc_cpp.h>

TEST (io_test, name_map1)
{
    mu::io::analyzer::name_map map;
}

TEST (io_test, name_map2)
{
    mu::io::analyzer::name_map map;
    map.free_locals ();
}

// Test that unknown references reserve a spot in the expression
TEST (io_test, name_map3)
{
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    map.fill_reference (mu::string (U"thing"), context, expression);
    ASSERT_TRUE (expression.dependencies.size () == 1);
    EXPECT_TRUE (expression.dependencies [0] == nullptr);
}

// Check that unknown references can be filled by globals
TEST (io_test, name_map4)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    map.fill_reference (mu::string (U"thing"), context, expression);
    mu::core::node node;
    map.insert_global(errors, mu::string (U"thing"), &node);
    EXPECT_TRUE (errors.errors.empty ());
    ASSERT_TRUE (expression.dependencies.size () == 1);
    EXPECT_TRUE (expression.dependencies [0] == &node);
}

// Check that unknown references can be filled by locals
TEST (io_test, name_map5)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    map.fill_reference (mu::string (U"thing"), context, expression);
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    EXPECT_TRUE (errors.errors.empty ());
    ASSERT_TRUE (expression.dependencies.size () == 1);
    EXPECT_TRUE (expression.dependencies [0] == &node);
}

// Check that two different globals can be inserted
TEST (io_test, name_map6)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    mu::core::node node2;
    map.insert_local (errors, mu::string (U"thing2"), &node2);
    EXPECT_TRUE (errors.errors.empty ());
}

// Check that two globals with the same name can't be inserted
TEST (io_test, name_map7)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    mu::core::node node2;
    map.insert_local (errors, mu::string (U"thing"), &node2);
    EXPECT_TRUE (!errors.errors.empty ());
}

// Check that two different locals can be inserted
TEST (io_test, name_map8)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    mu::core::node node2;
    map.insert_local (errors, mu::string (U"thing2"), &node2);
    EXPECT_TRUE (errors.errors.empty ());
}

// Check that two locals with the same name can't be inserted
TEST (io_test, name_map9)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    mu::core::node node2;
    map.insert_local (errors, mu::string (U"thing"), &node2);
    EXPECT_TRUE (!errors.errors.empty ());
}

// Check that a local name can be reused after clearing them
TEST (io_test, name_map10)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    map.free_locals ();
    mu::core::node node2;
    map.insert_local (errors, mu::string (U"thing"), &node2);
    EXPECT_TRUE (errors.errors.empty ());
}

// Check that a local name can't collide with an existing global name
TEST (io_test, name_map11)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_global (errors, mu::string (U"thing"), &node);
    mu::core::node node2;
    map.insert_local (errors, mu::string (U"thing"), &node2);
    EXPECT_TRUE (!errors.errors.empty ());
}

// Check that a global name can't collide with an existing local name in local scope
TEST (io_test, name_map12)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    mu::core::node node2;
    map.insert_global (errors, mu::string (U"thing"), &node2);
    EXPECT_TRUE (!errors.errors.empty ());
}

// Check that a global name can't collide with an existing local name out of local scope
TEST (io_test, name_map13)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_local (errors, mu::string (U"thing"), &node);
    map.free_locals ();
    mu::core::node node2;
    map.insert_global (errors, mu::string (U"thing"), &node2);
    EXPECT_TRUE (!errors.errors.empty ());
}

// Check that multiple references can be resolved
TEST (io_test, name_map14)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.fill_reference (mu::string (U"thing"), context, expression);
    map.fill_reference (mu::string (U"thing"), context, expression);
    map.insert_global (errors, mu::string (U"thing"), &node);
    EXPECT_TRUE (errors.errors.empty ());
    EXPECT_TRUE (expression.dependencies.size () == 2);
    EXPECT_TRUE (expression.dependencies [0] == &node);
    EXPECT_TRUE (expression.dependencies [1] == &node);
}

// Check that there are no errors when there are no names
TEST (io_test, name_map15)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.finalize (errors);
    EXPECT_TRUE (errors.errors.empty ());
}

// Check that there are no errors when everything is resolved
TEST (io_test, name_map16)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.insert_global (errors, mu::string (U"thing"), &node);
    map.fill_reference (mu::string (U"thing"), context, expression);
    map.finalize (errors);
    EXPECT_TRUE (errors.errors.empty ());
}

// Check that there are errors when there are unresolved references
TEST (io_test, name_map17)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.fill_reference (mu::string (U"thing"), context, expression);
    map.finalize (errors);
    EXPECT_TRUE (!errors.errors.empty ());
}

// Check that a local declaration can't resolve references in other functions
TEST (io_test, name_map18)
{
    mu::core::errors::error_list errors;
    mu::io::analyzer::name_map map;
    mu::io::debugging::context context;
    mu::core::expression expression;
    mu::core::node node;
    map.fill_reference (mu::string (U"thing"), context, expression);
    map.free_locals ();
    map.insert_local (errors, mu::string (U"thing"), &node);
    EXPECT_TRUE (!errors.errors.empty ());
}<|endoftext|>


<commit_before>#include "TPNode.h"

#include <stdio.h>
#include <assert.h>
#include <algorithm>

namespace d2d
{

TPNode::TPNode()
	: m_image(NULL)
{
	m_xmin = m_ymin = m_xmax = m_ymax = 0;
	m_is_rotated = m_is_split_y = false;

	m_next = m_child = m_parent = NULL;

	m_remain_area = m_remain_len = m_remain_space = 0;
}

TPNode::TPNode(int width, int height)
	: m_image(NULL)
{
	m_xmin = m_ymin = 0;
	m_xmax = width;
	m_ymax = height;
	m_is_rotated = m_is_split_y = false;

	m_next = m_child = m_parent = NULL;

	m_remain_area = width * height;
	m_remain_len = std::max(width, height);
	m_remain_space = width;
}

TPNode* TPNode::Insert(const Image* image, int w, int h)
{
// 	Rect r = img.getSymbol().getImage()->getRegion();
// 	int w = r.xLength(),
// 		h = r.yLength();

	int dw = m_xmax - m_xmin,
		dh = m_ymax - m_ymin;
	if ((w > dw && h > dh) || (w > dh && h > dw)) {
		return NULL;
	}

	if (!m_child)
	{
		if (m_image) {
			return NULL;
		}

		//if (w <= dw && h <= dh)
		//{
		//	TPNode* n = Split(w, h);
		//	if (n) {
		//		n->m_image = image;
		//	}
		//	return n;
		//}
		//else if (w <= dh && h <= dw)
		//{
		//	TPNode* n = Split(h, w);
		//	if (n) {
		//		n->m_image = image;
		//		n->m_is_rotated = true;
		//	}
		//	return n;
		//}
		//else
		//{
		//	return NULL;
		//}

		if (w <= dh && h <= dw)
		{
			TPNode* n = Split(h, w);
			if (n) {
				n->m_image = image;
				n->m_is_rotated = true;
			}
			return n;
		}
		else
		{
			return NULL;
		}
	}
	else
	{
		TPNode* next = m_child;
		while (next)
		{
			TPNode* n = NULL;
			if (next->IsRoomEnough(w, h)) {
				n = next->Insert(image, w, h);
			}
			if (n) {
				return n;
			} else {
				next = next->m_next;
			}
		}
		return NULL;
	}
}

bool TPNode::IsRoomEnough(int w, int h) const
{
	return (w <= m_remain_space || h <= m_remain_space)
		&& w*h <= m_remain_area
		&& w <= m_remain_len && h <= m_remain_len;
}

TPNode* TPNode::Split(int w, int h)
{
	TPNode* _next = new TPNode;
	TPNode* _child = new TPNode;
	TPNode* _child_next = new TPNode;
	assert(_child_next);

	if (m_is_split_y)
	{
		_next->m_xmin = m_xmin;
		_next->m_xmax = m_xmax;
		_next->m_ymin = m_ymin+h;
		_next->m_ymax = m_ymax;
		m_ymax = _next->m_ymin;
		_next->m_is_split_y = true;

		_child->m_ymin = m_ymin;
		_child->m_ymax = m_ymax;
		_child->m_xmin = m_xmin;
		_child->m_xmax = m_xmin+w;
		_child->m_is_split_y = false;

		_child_next->m_ymin = m_ymin;
		_child_next->m_ymax = m_ymax;
		_child_next->m_xmin = _child->m_xmax;
		_child_next->m_xmax = m_xmax;
		_child_next->m_is_split_y = false;
	}
	else
	{
		_next->m_ymin = m_ymin;
		_next->m_ymax = m_ymax;
		_next->m_xmin = m_xmin+w;
		_next->m_xmax = m_xmax;
		m_xmax = _next->m_xmin;
		_next->m_is_split_y = false;

		_child->m_xmin = m_xmin;
		_child->m_xmax = m_xmax;
		_child->m_ymin = m_ymin;
		_child->m_ymax = m_ymin+h;
		_child->m_is_split_y = true;

		_child_next->m_xmin = m_xmin;
		_child_next->m_xmax = m_xmax;
		_child_next->m_ymin = _child->m_ymax;
		_child_next->m_ymax = m_ymax;
		_child_next->m_is_split_y = true;
	}
	m_next = _next;
	_next->m_parent = m_parent;
	m_child = _child;
	_child->m_parent = m_parent;
	_child->m_next = _child_next;
	_child_next->m_parent = this;

	// remain area
	_next->m_remain_area = _next->GetArea();
	_child_next->m_remain_area = _child_next->GetArea();
	_child->m_remain_area = 0;
	m_remain_area = _child_next->m_remain_area;
	// remain len
	_next->m_remain_len = _next->GetMaxLength();
	_child_next->m_remain_len = _child_next->GetMaxLength();
	_child->m_remain_len = 0;
	m_remain_len = _child_next->m_remain_len;
	// remain_space
	if (m_is_split_y)
	{
		_next->m_remain_space = _next->m_ymax - _next->m_ymin;
		_child_next->m_remain_space = _child_next->m_xmax - _child_next->m_xmin;
		_child->m_remain_space = 0;
		m_remain_space = _child_next->m_remain_space;
	}
	else
	{
		_next->m_remain_space = _next->m_xmax - _next->m_xmin;
		_child_next->m_remain_space = _child_next->m_ymax - _child_next->m_ymin;
		_child->m_remain_space = 0;
		m_remain_space = _child_next->m_remain_space;
	}
	UpdateRemain();

	return _child;
}

float TPNode::GetMaxLength() const
{
	int w = m_xmax - m_xmin,
		h = m_ymax - m_ymin;
	return w > h ? w : h;
}

float TPNode::GetArea() const
{
	return (m_xmax-m_xmin)*(m_ymax-m_ymin);
}

void TPNode::UpdateRemain()
{
	TPNode* p = m_parent;
	while (p)
	{
		p->m_remain_area = 0;
		p->m_remain_len = 0;
		p->m_remain_space = 0;
		TPNode* c = p->m_child;
		while (c)
		{
			if (c->m_remain_area > p->m_remain_area)
				p->m_remain_area = c->m_remain_area;
			if (c->m_remain_len > p->m_remain_len)
				p->m_remain_len = c->m_remain_len;
			if (c->m_remain_space > p->m_remain_space)
				p->m_remain_space = c->m_remain_space;
			c = c->m_next;
		}
		p = p->m_parent;
	}
}

}<commit_msg>注释调试代码<commit_after>#include "TPNode.h"

#include <stdio.h>
#include <assert.h>
#include <algorithm>

namespace d2d
{

TPNode::TPNode()
	: m_image(NULL)
{
	m_xmin = m_ymin = m_xmax = m_ymax = 0;
	m_is_rotated = m_is_split_y = false;

	m_next = m_child = m_parent = NULL;

	m_remain_area = m_remain_len = m_remain_space = 0;
}

TPNode::TPNode(int width, int height)
	: m_image(NULL)
{
	m_xmin = m_ymin = 0;
	m_xmax = width;
	m_ymax = height;
	m_is_rotated = m_is_split_y = false;

	m_next = m_child = m_parent = NULL;

	m_remain_area = width * height;
	m_remain_len = std::max(width, height);
	m_remain_space = width;
}

TPNode* TPNode::Insert(const Image* image, int w, int h)
{
// 	Rect r = img.getSymbol().getImage()->getRegion();
// 	int w = r.xLength(),
// 		h = r.yLength();

	int dw = m_xmax - m_xmin,
		dh = m_ymax - m_ymin;
	if ((w > dw && h > dh) || (w > dh && h > dw)) {
		return NULL;
	}

	if (!m_child)
	{
		if (m_image) {
			return NULL;
		}

		if (w <= dw && h <= dh)
		{
			TPNode* n = Split(w, h);
			if (n) {
				n->m_image = image;
			}
			return n;
		}
		else if (w <= dh && h <= dw)
		{
			TPNode* n = Split(h, w);
			if (n) {
				n->m_image = image;
				n->m_is_rotated = true;
			}
			return n;
		}
		else
		{
			return NULL;
		}
	}
	else
	{
		TPNode* next = m_child;
		while (next)
		{
			TPNode* n = NULL;
			if (next->IsRoomEnough(w, h)) {
				n = next->Insert(image, w, h);
			}
			if (n) {
				return n;
			} else {
				next = next->m_next;
			}
		}
		return NULL;
	}
}

bool TPNode::IsRoomEnough(int w, int h) const
{
	return (w <= m_remain_space || h <= m_remain_space)
		&& w*h <= m_remain_area
		&& w <= m_remain_len && h <= m_remain_len;
}

TPNode* TPNode::Split(int w, int h)
{
	TPNode* _next = new TPNode;
	TPNode* _child = new TPNode;
	TPNode* _child_next = new TPNode;
	assert(_child_next);

	if (m_is_split_y)
	{
		_next->m_xmin = m_xmin;
		_next->m_xmax = m_xmax;
		_next->m_ymin = m_ymin+h;
		_next->m_ymax = m_ymax;
		m_ymax = _next->m_ymin;
		_next->m_is_split_y = true;

		_child->m_ymin = m_ymin;
		_child->m_ymax = m_ymax;
		_child->m_xmin = m_xmin;
		_child->m_xmax = m_xmin+w;
		_child->m_is_split_y = false;

		_child_next->m_ymin = m_ymin;
		_child_next->m_ymax = m_ymax;
		_child_next->m_xmin = _child->m_xmax;
		_child_next->m_xmax = m_xmax;
		_child_next->m_is_split_y = false;
	}
	else
	{
		_next->m_ymin = m_ymin;
		_next->m_ymax = m_ymax;
		_next->m_xmin = m_xmin+w;
		_next->m_xmax = m_xmax;
		m_xmax = _next->m_xmin;
		_next->m_is_split_y = false;

		_child->m_xmin = m_xmin;
		_child->m_xmax = m_xmax;
		_child->m_ymin = m_ymin;
		_child->m_ymax = m_ymin+h;
		_child->m_is_split_y = true;

		_child_next->m_xmin = m_xmin;
		_child_next->m_xmax = m_xmax;
		_child_next->m_ymin = _child->m_ymax;
		_child_next->m_ymax = m_ymax;
		_child_next->m_is_split_y = true;
	}
	m_next = _next;
	_next->m_parent = m_parent;
	m_child = _child;
	_child->m_parent = m_parent;
	_child->m_next = _child_next;
	_child_next->m_parent = this;

	// remain area
	_next->m_remain_area = _next->GetArea();
	_child_next->m_remain_area = _child_next->GetArea();
	_child->m_remain_area = 0;
	m_remain_area = _child_next->m_remain_area;
	// remain len
	_next->m_remain_len = _next->GetMaxLength();
	_child_next->m_remain_len = _child_next->GetMaxLength();
	_child->m_remain_len = 0;
	m_remain_len = _child_next->m_remain_len;
	// remain_space
	if (m_is_split_y)
	{
		_next->m_remain_space = _next->m_ymax - _next->m_ymin;
		_child_next->m_remain_space = _child_next->m_xmax - _child_next->m_xmin;
		_child->m_remain_space = 0;
		m_remain_space = _child_next->m_remain_space;
	}
	else
	{
		_next->m_remain_space = _next->m_xmax - _next->m_xmin;
		_child_next->m_remain_space = _child_next->m_ymax - _child_next->m_ymin;
		_child->m_remain_space = 0;
		m_remain_space = _child_next->m_remain_space;
	}
	UpdateRemain();

	return _child;
}

float TPNode::GetMaxLength() const
{
	int w = m_xmax - m_xmin,
		h = m_ymax - m_ymin;
	return w > h ? w : h;
}

float TPNode::GetArea() const
{
	return (m_xmax-m_xmin)*(m_ymax-m_ymin);
}

void TPNode::UpdateRemain()
{
	TPNode* p = m_parent;
	while (p)
	{
		p->m_remain_area = 0;
		p->m_remain_len = 0;
		p->m_remain_space = 0;
		TPNode* c = p->m_child;
		while (c)
		{
			if (c->m_remain_area > p->m_remain_area)
				p->m_remain_area = c->m_remain_area;
			if (c->m_remain_len > p->m_remain_len)
				p->m_remain_len = c->m_remain_len;
			if (c->m_remain_space > p->m_remain_space)
				p->m_remain_space = c->m_remain_space;
			c = c->m_next;
		}
		p = p->m_parent;
	}
}

}<|endoftext|>


<commit_before>#include "ShapeRenderer.h"

#include "Graphics/Shader/ShaderProgram.h"
#include "Graphics/Memory/VertexArrayObject.h"
#include "Graphics/Memory/Buffer.h"
#include "Graphics/Color.h"
#include "Graphics/RenderSystem.h"

#include "Resource/Resources.h"

#include "Math/Matrix3f.h"
#include "Math/Vector2f.h"

#include <cmath>

#include "Math/Constants.h"

const uint32 ShapeRenderer::CIRCLE_DIVS = 128;

const float32 ShapeRenderer::FILLED_RECTANGLE_VERTS[8] = {
	-0.5f,-0.5f,
	-0.5f,0.5f,
	0.5f,-0.5f,
	0.5f,0.5f
};

const float32 ShapeRenderer::OUTLINE_RECTANGLE_VERTS[8] = {
	-0.5f,-0.5f,
	-0.5f,0.5f,
	0.5f,0.5f,
	0.5f,-0.5f
};

ShapeRenderer::ShapeRenderer(RenderSystem* rs) : Renderer(rs) {
	m_shapeShaderProgram.reset(new ShaderProgram(loadSrc("vertex/mvp_no_uv_vert.shader"), loadSrc("fragment/unlit_color_frag.shader")));

	initLineBuffers();
	initRectangleBuffers();
	initEllipseBuffers();
}

ShapeRenderer::~ShapeRenderer() {}

void ShapeRenderer::initLineBuffers() {
	m_lineVAO.reset(new VertexArrayObject());
	m_lineVAO->bind();

	m_lineBuffer = new Buffer(Buffer::Target::ARRAY_BUFFER);
	m_lineBuffer->bind();
	m_lineBuffer->bufferData(sizeof(float32) * 2 * 2, Buffer::Usage::DYNAMIC_DRAW); // 2 vertices * 2 floats per vertex * 4 bytes per float = 16 bytes
#ifdef DEBUG_BUILD
	m_lineBuffer->setDebugLabel("LINE_BUFFER");
#endif

	m_lineVAO->enableAttribute(0);
	m_lineBuffer->vertexAttributePointer(0, 2, GL_FLOAT);

	m_lineVAO->addArrayBuffer(m_lineBuffer);

	m_lineBuffer->unbind();
	m_lineVAO->unbind();
}

void ShapeRenderer::initRectangleBuffers() {
	// Filled Rectangle
	m_filledRectVAO.reset(new VertexArrayObject());
	m_filledRectVAO->bind();

	m_filledRectVAO->addArrayBuffer(0, FILLED_RECTANGLE_VERTS, sizeof(float32) * 8, 2, GL_FLOAT, Buffer::Usage::STATIC_DRAW);
	m_filledRectVAO->unbind();

	// Outline Rectangle
	m_outlineRectVAO.reset(new VertexArrayObject());
	m_outlineRectVAO->bind();

	m_outlineRectVAO->addArrayBuffer(0, OUTLINE_RECTANGLE_VERTS, sizeof(float32) * 8, 2, GL_FLOAT, Buffer::Usage::STATIC_DRAW);
	m_outlineRectVAO->unbind();

#ifdef DEBUG_BUILD
	m_filledRectVAO->getBuffer(0)->setDebugLabel("FILLED_RECT_BUFFER");
	m_outlineRectVAO->getBuffer(0)->setDebugLabel("OUTLINE_RECT_BUFFER");
#endif
}

void ShapeRenderer::initEllipseBuffers() {
	uint32 dataSize = 0;
	float32* data = generateCircleVertices(0.5f, CIRCLE_DIVS, dataSize);

	float32* buffer = new float32[dataSize + 4];
	buffer[0] = 0.0f;
	buffer[1] = 0.0f;

	for (uint32 i = 0; i < dataSize; i++) {
		buffer[2 + i] = data[i];
	}

	buffer[dataSize + 2] = data[0];
	buffer[dataSize + 3] = data[1];

	m_ellipseVAO.reset(new VertexArrayObject());
	m_ellipseVAO->bind();
	m_ellipseVAO->addArrayBuffer(0, buffer, sizeof(float32) * (dataSize + 4), 2, GL_FLOAT, Buffer::Usage::STATIC_DRAW);

#ifdef DEBUG_BUILD
	m_ellipseVAO->getBuffer(0)->setDebugLabel("ELLIPSE_BUFFER");
#endif

	m_ellipseVAO->unbind();
}

float32* ShapeRenderer::generateCircleVertices(float32 radius, uint32 divs, uint32& dataSize) const {
	dataSize = divs * 2;
	float32* data = new float32[dataSize];

	for (uint32 i = 0; i < divs; i++) {
		float32 angle = (float32)((2 * PI * i) / ((float32)divs));

		float32 x = (float32)(radius * cos(angle));
		float32 y = (float32)(radius * sin(angle));

		data[i * 2] = x;
		data[(i * 2) + 1] = y;

	}

	return data;
}

void ShapeRenderer::loadLineData(float32 xi, float32 yi, float32 xf, float32 yf) {
	float32 verts[4] = { xi, yi, xf, yf };
	m_lineBuffer->bind();
	m_lineBuffer->bufferSubData(0, sizeof(float32) * 4, verts);
	m_lineBuffer->unbind();
}

void ShapeRenderer::drawVector(float32 x, float32 y, const Vector2f& vector, const Color& color) {
	drawLine(x, y, vector.x + x, vector.y + y, color);
}

void ShapeRenderer::drawLine(float32 xi, float32 yi, float32 xf, float32 yf, const Color& color) {
	glUseProgram(m_shapeShaderProgram->getProgramId());

	m_lineVAO->bind();

	// load line info into buffer
	loadLineData(xi, yi, xf, yf);

	// Set color uniform
	glUniform4fv(m_shapeShaderProgram->getUniform("color").getLocation(), 1, color.values);

	// Set mvpMatrix uniform
	glUniformMatrix3fv(m_shapeShaderProgram->getUniform("mvpMatrix").getLocation(), 1, true, m_rs->getCamera().getViewProjectionMatrix().values);

	// Draw line
	glDrawArrays(GL_LINES, 0, 2);
}

void ShapeRenderer::drawRectangle(const Rectangle& rect, const Color& color, bool filled) {
	drawRectangle(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), color, filled);
}

void ShapeRenderer::drawRectangle(float32 x, float32 y, float32 width, float32 height, const Color& color, bool filled) {
	glUseProgram(m_shapeShaderProgram->getProgramId());

	if (filled) {
		m_filledRectVAO->bind();
	}
	else {
		m_outlineRectVAO->bind();
	}

	// Set color uniform
	glUniform4fv(m_shapeShaderProgram->getUniform("color").getLocation(), 1, color.values);

	Matrix3f finalMatrix = m_rs->getCamera().getViewProjectionMatrix() * Matrix3f::translation(x, y) * Matrix3f::scale(width, height);

	glUniformMatrix3fv(m_shapeShaderProgram->getUniform("mvpMatrix").getLocation(), 1, true, finalMatrix.values);

	glDrawArrays((filled) ? GL_TRIANGLE_STRIP : GL_LINE_LOOP, 0, 4); // Both outline and filled rectangle have same number of vertices
}

void ShapeRenderer::drawCircle(float32 x, float32 y, float32 radius, const Color& color, bool filled) {
	drawEllipse(x, y, 2 * radius, 2 * radius, color, filled);
}

void ShapeRenderer::drawEllipse(float32 x, float32 y, float32 width, float32 height, const Color& color, bool filled) {
	glUseProgram(m_shapeShaderProgram->getProgramId());

	m_ellipseVAO->bind();

	// Set color uniform
	glUniform4fv(m_shapeShaderProgram->getUniform("color").getLocation(), 1, color.values);

	// Set mvpMatrix uniform
	Matrix3f finalMatrix = m_rs->getCamera().getViewProjectionMatrix() * Matrix3f::translation(x, y) * Matrix3f::scale(width, height);

	glUniformMatrix3fv(m_shapeShaderProgram->getUniform("mvpMatrix").getLocation(), 1, true, finalMatrix.values);

	if (filled) {
		glDrawArrays(GL_TRIANGLE_FAN, 0, CIRCLE_DIVS + 2);
	}
	else {
		glDrawArrays(GL_LINE_STRIP, 1, CIRCLE_DIVS + 1);
	}
}<commit_msg>Fix memory leak in shape renderer<commit_after>#include "ShapeRenderer.h"

#include "Graphics/Shader/ShaderProgram.h"
#include "Graphics/Memory/VertexArrayObject.h"
#include "Graphics/Memory/Buffer.h"
#include "Graphics/Color.h"
#include "Graphics/RenderSystem.h"

#include "Resource/Resources.h"

#include "Math/Matrix3f.h"
#include "Math/Vector2f.h"

#include <cmath>

#include "Math/Constants.h"

const uint32 ShapeRenderer::CIRCLE_DIVS = 128;

const float32 ShapeRenderer::FILLED_RECTANGLE_VERTS[8] = {
	-0.5f,-0.5f,
	-0.5f,0.5f,
	0.5f,-0.5f,
	0.5f,0.5f
};

const float32 ShapeRenderer::OUTLINE_RECTANGLE_VERTS[8] = {
	-0.5f,-0.5f,
	-0.5f,0.5f,
	0.5f,0.5f,
	0.5f,-0.5f
};

ShapeRenderer::ShapeRenderer(RenderSystem* rs) : Renderer(rs) {
	m_shapeShaderProgram.reset(new ShaderProgram(loadSrc("vertex/mvp_no_uv_vert.shader"), loadSrc("fragment/unlit_color_frag.shader")));

	initLineBuffers();
	initRectangleBuffers();
	initEllipseBuffers();
}

ShapeRenderer::~ShapeRenderer() {}

void ShapeRenderer::initLineBuffers() {
	m_lineVAO.reset(new VertexArrayObject());
	m_lineVAO->bind();

	m_lineBuffer = new Buffer(Buffer::Target::ARRAY_BUFFER);
	m_lineBuffer->bind();
	m_lineBuffer->bufferData(sizeof(float32) * 2 * 2, Buffer::Usage::DYNAMIC_DRAW); // 2 vertices * 2 floats per vertex * 4 bytes per float = 16 bytes
#ifdef DEBUG_BUILD
	m_lineBuffer->setDebugLabel("LINE_BUFFER");
#endif

	m_lineVAO->enableAttribute(0);
	m_lineBuffer->vertexAttributePointer(0, 2, GL_FLOAT);

	m_lineVAO->addArrayBuffer(m_lineBuffer);

	m_lineBuffer->unbind();
	m_lineVAO->unbind();
}

void ShapeRenderer::initRectangleBuffers() {
	// Filled Rectangle
	m_filledRectVAO.reset(new VertexArrayObject());
	m_filledRectVAO->bind();

	m_filledRectVAO->addArrayBuffer(0, FILLED_RECTANGLE_VERTS, sizeof(float32) * 8, 2, GL_FLOAT, Buffer::Usage::STATIC_DRAW);
	m_filledRectVAO->unbind();

	// Outline Rectangle
	m_outlineRectVAO.reset(new VertexArrayObject());
	m_outlineRectVAO->bind();

	m_outlineRectVAO->addArrayBuffer(0, OUTLINE_RECTANGLE_VERTS, sizeof(float32) * 8, 2, GL_FLOAT, Buffer::Usage::STATIC_DRAW);
	m_outlineRectVAO->unbind();

#ifdef DEBUG_BUILD
	m_filledRectVAO->getBuffer(0)->setDebugLabel("FILLED_RECT_BUFFER");
	m_outlineRectVAO->getBuffer(0)->setDebugLabel("OUTLINE_RECT_BUFFER");
#endif
}

void ShapeRenderer::initEllipseBuffers() {
	uint32 dataSize = 0;
	float32* data = generateCircleVertices(0.5f, CIRCLE_DIVS, dataSize);

	float32* buffer = new float32[dataSize + 4];
	buffer[0] = 0.0f;
	buffer[1] = 0.0f;

	for (uint32 i = 0; i < dataSize; i++) {
		buffer[2 + i] = data[i];
	}

	buffer[dataSize + 2] = data[0];
	buffer[dataSize + 3] = data[1];

	m_ellipseVAO.reset(new VertexArrayObject());
	m_ellipseVAO->bind();
	m_ellipseVAO->addArrayBuffer(0, buffer, sizeof(float32) * (dataSize + 4), 2, GL_FLOAT, Buffer::Usage::STATIC_DRAW);

#ifdef DEBUG_BUILD
	m_ellipseVAO->getBuffer(0)->setDebugLabel("ELLIPSE_BUFFER");
#endif

	delete[] data;
	delete[] buffer;
	m_ellipseVAO->unbind();
}

float32* ShapeRenderer::generateCircleVertices(float32 radius, uint32 divs, uint32& dataSize) const {
	dataSize = divs * 2;
	float32* data = new float32[dataSize];

	for (uint32 i = 0; i < divs; i++) {
		float32 angle = (float32)((2 * PI * i) / ((float32)divs));

		float32 x = (float32)(radius * cos(angle));
		float32 y = (float32)(radius * sin(angle));

		data[i * 2] = x;
		data[(i * 2) + 1] = y;

	}

	return data;
}

void ShapeRenderer::loadLineData(float32 xi, float32 yi, float32 xf, float32 yf) {
	float32 verts[4] = { xi, yi, xf, yf };
	m_lineBuffer->bind();
	m_lineBuffer->bufferSubData(0, sizeof(float32) * 4, verts);
	m_lineBuffer->unbind();
}

void ShapeRenderer::drawVector(float32 x, float32 y, const Vector2f& vector, const Color& color) {
	drawLine(x, y, vector.x + x, vector.y + y, color);
}

void ShapeRenderer::drawLine(float32 xi, float32 yi, float32 xf, float32 yf, const Color& color) {
	glUseProgram(m_shapeShaderProgram->getProgramId());

	m_lineVAO->bind();

	// load line info into buffer
	loadLineData(xi, yi, xf, yf);

	// Set color uniform
	glUniform4fv(m_shapeShaderProgram->getUniform("color").getLocation(), 1, color.values);

	// Set mvpMatrix uniform
	glUniformMatrix3fv(m_shapeShaderProgram->getUniform("mvpMatrix").getLocation(), 1, true, m_rs->getCamera().getViewProjectionMatrix().values);

	// Draw line
	glDrawArrays(GL_LINES, 0, 2);
}

void ShapeRenderer::drawRectangle(const Rectangle& rect, const Color& color, bool filled) {
	drawRectangle(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), color, filled);
}

void ShapeRenderer::drawRectangle(float32 x, float32 y, float32 width, float32 height, const Color& color, bool filled) {
	glUseProgram(m_shapeShaderProgram->getProgramId());

	if (filled) {
		m_filledRectVAO->bind();
	}
	else {
		m_outlineRectVAO->bind();
	}

	// Set color uniform
	glUniform4fv(m_shapeShaderProgram->getUniform("color").getLocation(), 1, color.values);

	Matrix3f finalMatrix = m_rs->getCamera().getViewProjectionMatrix() * Matrix3f::translation(x, y) * Matrix3f::scale(width, height);

	glUniformMatrix3fv(m_shapeShaderProgram->getUniform("mvpMatrix").getLocation(), 1, true, finalMatrix.values);

	glDrawArrays((filled) ? GL_TRIANGLE_STRIP : GL_LINE_LOOP, 0, 4); // Both outline and filled rectangle have same number of vertices
}

void ShapeRenderer::drawCircle(float32 x, float32 y, float32 radius, const Color& color, bool filled) {
	drawEllipse(x, y, 2 * radius, 2 * radius, color, filled);
}

void ShapeRenderer::drawEllipse(float32 x, float32 y, float32 width, float32 height, const Color& color, bool filled) {
	glUseProgram(m_shapeShaderProgram->getProgramId());

	m_ellipseVAO->bind();

	// Set color uniform
	glUniform4fv(m_shapeShaderProgram->getUniform("color").getLocation(), 1, color.values);

	// Set mvpMatrix uniform
	Matrix3f finalMatrix = m_rs->getCamera().getViewProjectionMatrix() * Matrix3f::translation(x, y) * Matrix3f::scale(width, height);

	glUniformMatrix3fv(m_shapeShaderProgram->getUniform("mvpMatrix").getLocation(), 1, true, finalMatrix.values);

	if (filled) {
		glDrawArrays(GL_TRIANGLE_FAN, 0, CIRCLE_DIVS + 2);
	}
	else {
		glDrawArrays(GL_LINE_STRIP, 1, CIRCLE_DIVS + 1);
	}
}<|endoftext|>


<commit_before>#include "content/nw/src/api/nw_app_api.h"

#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "chrome/browser/browsing_data/browsing_data_appcache_helper.h"
#include "chrome/browser/browsing_data/browsing_data_helper.h"
#include "chrome/browser/browsing_data/browsing_data_remover_factory.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/extensions/devtools_util.h"
#include "chrome/browser/extensions/extension_service.h"
#include "content/nw/src/nw_base.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/browser/app_window/native_app_window.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/error_utils.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"

namespace {
void SetProxyConfigCallback(
    base::WaitableEvent* done,
    const scoped_refptr<net::URLRequestContextGetter>& url_request_context_getter,
    const net::ProxyConfig& proxy_config) {
  net::ProxyService* proxy_service =
      url_request_context_getter->GetURLRequestContext()->proxy_service();
  proxy_service->ResetConfigService(base::WrapUnique(new net::ProxyConfigServiceFixed(proxy_config)));
  done->Signal();
}
} // namespace

namespace extensions {
NwAppQuitFunction::NwAppQuitFunction() {

}

NwAppQuitFunction::~NwAppQuitFunction() {
}

bool NwAppQuitFunction::RunAsync() {
  ExtensionService* service =
    ExtensionSystem::Get(browser_context())->extension_service();
  base::MessageLoop::current()->task_runner()->PostTask(
        FROM_HERE,
        base::Bind(&ExtensionService::TerminateExtension,
                   service->AsWeakPtr(),
                   extension_id()));
  return true;
}

bool NwAppCloseAllWindowsFunction::RunAsync() {
  AppWindowRegistry* registry = AppWindowRegistry::Get(browser_context());
  if (!registry)
    return false;

  AppWindowRegistry::AppWindowList windows =
    registry->GetAppWindowsForApp(extension()->id());

  for (AppWindow* window : windows) {
    if (window->NWCanClose())
      window->GetBaseWindow()->Close();
  }
  SendResponse(true);
  return true;
}

NwAppGetArgvSyncFunction::NwAppGetArgvSyncFunction() {
}

NwAppGetArgvSyncFunction::~NwAppGetArgvSyncFunction() {
}

bool NwAppGetArgvSyncFunction::RunNWSync(base::ListValue* response, std::string* error) {

  nw::Package* package = nw::package();
  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  base::CommandLine::StringVector args = command_line->GetArgs();
  base::CommandLine::StringVector argv = command_line->original_argv();

  // Ignore first non-switch arg if it's not a standalone package.
  bool ignore_arg = !package->self_extract();
  for (unsigned i = 1; i < argv.size(); ++i) {
    if (ignore_arg && args.size() && argv[i] == args[0]) {
      ignore_arg = false;
      continue;
    }

    response->AppendString(argv[i]);
  }
  return true;
}

NwAppClearAppCacheFunction::NwAppClearAppCacheFunction() {
}

NwAppClearAppCacheFunction::~NwAppClearAppCacheFunction() {
}

bool NwAppClearAppCacheFunction::RunNWSync(base::ListValue* response, std::string* error) {
  std::string manifest;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &manifest));

  GURL manifest_url(manifest);
  scoped_refptr<CannedBrowsingDataAppCacheHelper> helper(
        new CannedBrowsingDataAppCacheHelper(Profile::FromBrowserContext(context_)));

  helper->DeleteAppCacheGroup(manifest_url);
  return true;
}

NwAppClearCacheFunction::NwAppClearCacheFunction() {
}

NwAppClearCacheFunction::~NwAppClearCacheFunction() {
}

bool NwAppClearCacheFunction::RunNWSync(base::ListValue* response, std::string* error) {
  BrowsingDataRemover* remover = BrowsingDataRemoverFactory::GetForBrowserContext(
      Profile::FromBrowserContext(context_));

  remover->AddObserver(this);
  remover->Remove(BrowsingDataRemover::Unbounded(),
                  BrowsingDataRemover::REMOVE_CACHE,
                  BrowsingDataHelper::ALL);
  // BrowsingDataRemover deletes itself.
  base::MessageLoop::ScopedNestableTaskAllower allow(
        base::MessageLoop::current());
  run_loop_.Run();
  remover->RemoveObserver(this);
  return true;
}

void NwAppClearCacheFunction::OnBrowsingDataRemoverDone() {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  run_loop_.Quit();
}

NwAppSetProxyConfigFunction::NwAppSetProxyConfigFunction() {
}

NwAppSetProxyConfigFunction::~NwAppSetProxyConfigFunction() {
}

bool NwAppSetProxyConfigFunction::RunNWSync(base::ListValue* response, std::string* error) {
  std::string proxy_config;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &proxy_config));

  base::ThreadRestrictions::ScopedAllowWait allow_wait;

  net::ProxyConfig config;
  config.proxy_rules().ParseFromString(proxy_config);
  content::RenderProcessHost* render_process_host = GetSenderWebContents()->GetRenderProcessHost();
  net::URLRequestContextGetter* context_getter =
    render_process_host->GetStoragePartition()->GetURLRequestContext();

  base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                           base::WaitableEvent::InitialState::NOT_SIGNALED);
  content::BrowserThread::PostTask(
      content::BrowserThread::IO, FROM_HERE,
      base::Bind(&SetProxyConfigCallback, &done,
                 make_scoped_refptr(context_getter), config));
  done.Wait();
  return true;
}

bool NwAppGetDataPathFunction::RunNWSync(base::ListValue* response, std::string* error) {
  response->AppendString(browser_context()->GetPath().value());
  return true;
}

bool NwAppCrashBrowserFunction::RunAsync() {
  int* ptr = nullptr;
  *ptr = 1;
  return true;
}

} // namespace extensions
<commit_msg>Fix #5368: gui.App.clearCache() freez apllication nwjs 0.18.0<commit_after>#include "content/nw/src/api/nw_app_api.h"

#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "chrome/browser/browsing_data/browsing_data_appcache_helper.h"
#include "chrome/browser/browsing_data/browsing_data_helper.h"
#include "chrome/browser/browsing_data/browsing_data_remover_factory.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/extensions/devtools_util.h"
#include "chrome/browser/extensions/extension_service.h"
#include "content/nw/src/nw_base.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/browser/app_window/native_app_window.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/error_utils.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"

namespace {
void SetProxyConfigCallback(
    base::WaitableEvent* done,
    const scoped_refptr<net::URLRequestContextGetter>& url_request_context_getter,
    const net::ProxyConfig& proxy_config) {
  net::ProxyService* proxy_service =
      url_request_context_getter->GetURLRequestContext()->proxy_service();
  proxy_service->ResetConfigService(base::WrapUnique(new net::ProxyConfigServiceFixed(proxy_config)));
  done->Signal();
}
} // namespace

namespace extensions {
NwAppQuitFunction::NwAppQuitFunction() {

}

NwAppQuitFunction::~NwAppQuitFunction() {
}

bool NwAppQuitFunction::RunAsync() {
  ExtensionService* service =
    ExtensionSystem::Get(browser_context())->extension_service();
  base::MessageLoop::current()->task_runner()->PostTask(
        FROM_HERE,
        base::Bind(&ExtensionService::TerminateExtension,
                   service->AsWeakPtr(),
                   extension_id()));
  return true;
}

bool NwAppCloseAllWindowsFunction::RunAsync() {
  AppWindowRegistry* registry = AppWindowRegistry::Get(browser_context());
  if (!registry)
    return false;

  AppWindowRegistry::AppWindowList windows =
    registry->GetAppWindowsForApp(extension()->id());

  for (AppWindow* window : windows) {
    if (window->NWCanClose())
      window->GetBaseWindow()->Close();
  }
  SendResponse(true);
  return true;
}

NwAppGetArgvSyncFunction::NwAppGetArgvSyncFunction() {
}

NwAppGetArgvSyncFunction::~NwAppGetArgvSyncFunction() {
}

bool NwAppGetArgvSyncFunction::RunNWSync(base::ListValue* response, std::string* error) {

  nw::Package* package = nw::package();
  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  base::CommandLine::StringVector args = command_line->GetArgs();
  base::CommandLine::StringVector argv = command_line->original_argv();

  // Ignore first non-switch arg if it's not a standalone package.
  bool ignore_arg = !package->self_extract();
  for (unsigned i = 1; i < argv.size(); ++i) {
    if (ignore_arg && args.size() && argv[i] == args[0]) {
      ignore_arg = false;
      continue;
    }

    response->AppendString(argv[i]);
  }
  return true;
}

NwAppClearAppCacheFunction::NwAppClearAppCacheFunction() {
}

NwAppClearAppCacheFunction::~NwAppClearAppCacheFunction() {
}

bool NwAppClearAppCacheFunction::RunNWSync(base::ListValue* response, std::string* error) {
  std::string manifest;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &manifest));

  GURL manifest_url(manifest);
  scoped_refptr<CannedBrowsingDataAppCacheHelper> helper(
        new CannedBrowsingDataAppCacheHelper(Profile::FromBrowserContext(context_)));

  helper->DeleteAppCacheGroup(manifest_url);
  return true;
}

NwAppClearCacheFunction::NwAppClearCacheFunction() {
}

NwAppClearCacheFunction::~NwAppClearCacheFunction() {
}

bool NwAppClearCacheFunction::RunNWSync(base::ListValue* response, std::string* error) {
  BrowsingDataRemover* remover = BrowsingDataRemoverFactory::GetForBrowserContext(
      Profile::FromBrowserContext(context_));

  remover->AddObserver(this);
  remover->RemoveAndReply(BrowsingDataRemover::Unbounded(),
                          BrowsingDataRemover::REMOVE_CACHE,
                          BrowsingDataHelper::ALL,
                          this);
  // BrowsingDataRemover deletes itself.
  base::MessageLoop::ScopedNestableTaskAllower allow(
        base::MessageLoop::current());
  run_loop_.Run();
  remover->RemoveObserver(this);
  return true;
}

void NwAppClearCacheFunction::OnBrowsingDataRemoverDone() {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  run_loop_.Quit();
}

NwAppSetProxyConfigFunction::NwAppSetProxyConfigFunction() {
}

NwAppSetProxyConfigFunction::~NwAppSetProxyConfigFunction() {
}

bool NwAppSetProxyConfigFunction::RunNWSync(base::ListValue* response, std::string* error) {
  std::string proxy_config;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &proxy_config));

  base::ThreadRestrictions::ScopedAllowWait allow_wait;

  net::ProxyConfig config;
  config.proxy_rules().ParseFromString(proxy_config);
  content::RenderProcessHost* render_process_host = GetSenderWebContents()->GetRenderProcessHost();
  net::URLRequestContextGetter* context_getter =
    render_process_host->GetStoragePartition()->GetURLRequestContext();

  base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                           base::WaitableEvent::InitialState::NOT_SIGNALED);
  content::BrowserThread::PostTask(
      content::BrowserThread::IO, FROM_HERE,
      base::Bind(&SetProxyConfigCallback, &done,
                 make_scoped_refptr(context_getter), config));
  done.Wait();
  return true;
}

bool NwAppGetDataPathFunction::RunNWSync(base::ListValue* response, std::string* error) {
  response->AppendString(browser_context()->GetPath().value());
  return true;
}

bool NwAppCrashBrowserFunction::RunAsync() {
  int* ptr = nullptr;
  *ptr = 1;
  return true;
}

} // namespace extensions
<|endoftext|>


<commit_before><commit_msg>unfinished, dont use that commit<commit_after><|endoftext|>