/*
	This file is a part of Awesomium, a library that makes it easy for 
	developers to embed web-content in their applications.

	Copyright (C) 2009 Adam J. Simmons

	Project Website:
	<http://princeofcode.com/awesomium.php>

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

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

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
	02110-1301 USA
*/

#include "WebView/RenderBuffer.h"

#include <string.h>
#include <assert.h>
#include "base/gfx/rect.h"

using namespace Awesomium;

namespace {

void copyBuffers(int width, int height, unsigned char* src, int srcRowSpan, unsigned char* dest, int destRowSpan, bool convertToRGBA)
{
	if(!convertToRGBA)
	{
		for(int row = 0; row < height; row++)
			memcpy(dest + row * destRowSpan, src + row * srcRowSpan, srcRowSpan);
	}
	else
	{
		int srcRowOffset, destRowOffset;
		for(int row = 0; row < height; row++)
		{
			srcRowOffset = row * srcRowSpan;
			destRowOffset = row * destRowSpan;

			for(int colOffset = 0; colOffset < srcRowSpan; colOffset += 4)
			{
				dest[destRowOffset + colOffset] = src[srcRowOffset + colOffset + 2];
				dest[destRowOffset + colOffset + 1] = src[srcRowOffset + colOffset + 1];
				dest[destRowOffset + colOffset + 2] = src[srcRowOffset + colOffset];
				dest[destRowOffset + colOffset + 3] = src[srcRowOffset + colOffset + 3];
			}
		}
	}
}

}

RenderBuffer::RenderBuffer(int width_, int height_) : buffer(0), width(width_), height(height_), rowSpan(width_*4)
{
	reserve(width, height);
}

RenderBuffer::~RenderBuffer()
{
	if(buffer)
		delete[] buffer;
}

void RenderBuffer::reserve(int width, int height)
{
	delete [] buffer;

	buffer = new unsigned char[width * height * 4];
	memset(buffer, 255, width * height * 4);
}

void RenderBuffer::copyBufferFrom(const RenderBuffer& src)
{
  assert(width == src.width && height == src.height);
  memcpy(buffer, src.buffer, width*height*4);
}

void RenderBuffer::copyArea(unsigned char* srcBuffer, int srcRowSpan, const gfx::Rect& srcRect, bool forceOpaque)
{
	if(gfx::Rect(width, height).Contains(srcRect))
	{
		for(int row = 0; row < srcRect.height(); row++)
			memcpy(buffer + (row + srcRect.y()) * rowSpan + (srcRect.x() * 4), srcBuffer + row * srcRowSpan, srcRect.width() * 4);

		if(forceOpaque)
			for(int row = 0; row < srcRect.height(); row++)
				for(int col = 0; col < srcRect.width(); col++)
					buffer[(row + srcRect.y()) * rowSpan + (col + srcRect.x()) * 4 + 3] = 255;
	}
	else
	{
		gfx::Rect intersect = gfx::Rect(width, height).Intersect(srcRect);
		if(intersect.IsEmpty())
			return;

		int srcOffsetX = intersect.x() - srcRect.x();
		int srcOffsetY = intersect.y() - srcRect.y();

		for(int row = 0; row < intersect.height(); row++)
			memcpy(buffer + (row + intersect.y()) * rowSpan + (intersect.x() * 4), srcBuffer + (row + srcOffsetY) * srcRowSpan + (srcOffsetX * 4), intersect.width() * 4);

		if(forceOpaque)
			for(int row = 0; row < intersect.height(); row++)
				for(int col = 0; col < intersect.width(); col++)
					buffer[(row + intersect.y()) * rowSpan + (col + intersect.x()) * 4 + 3] = 255;
	}
}

void RenderBuffer::copyTo(unsigned char* destBuffer, int destRowSpan, bool convertToRGBA)
{
  if(destRowSpan == -1)
    destRowSpan = width * 4;

	copyBuffers(width, height, buffer, width * 4, destBuffer, destRowSpan, convertToRGBA);
}
