⛏️ index : haiku.git

/*
 * Copyright 2009-2019, Haiku, Inc.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Michael Lotz <mmlr@mlotz.ch>
 */

#include "RemoteMessage.h"

#ifndef CLIENT_COMPILE
#include "DrawState.h"
#include "ServerBitmap.h"
#include "ServerCursor.h"
#endif

#include <Bitmap.h>
#include <Font.h>
#include <View.h>

#include <Gradient.h>
#include <GradientLinear.h>
#include <GradientRadial.h>
#include <GradientRadialFocus.h>
#include <GradientDiamond.h>
#include <GradientConic.h>

#include <new>


#ifdef CLIENT_COMPILE
#define TRACE_ALWAYS(x...)		printf("RemoteMessage: " x)
#else
#define TRACE_ALWAYS(x...)		debug_printf("RemoteMessage: " x)
#endif

#define TRACE(x...)				/*TRACE_ALWAYS(x)*/
#define TRACE_ERROR(x...)		TRACE_ALWAYS(x)


status_t
RemoteMessage::NextMessage(uint16& code)
{
	if (fDataLeft > 0) {
		// discard remainder of message
		int32 readSize = fSource->Read(NULL, fDataLeft);
		if (readSize < 0) {
			TRACE_ERROR("failed to read from source: %s\n", strerror(readSize));
			return readSize;
		}
	}

	static const uint32 kHeaderSize = sizeof(uint16) + sizeof(uint32);

	fDataLeft = kHeaderSize;
	status_t result = Read(code);
	if (result != B_OK) {
		TRACE_ERROR("failed to read message code: %s\n", strerror(result));
		return result;
	}

	uint32 dataLeft;
	result = Read(dataLeft);
	if (result != B_OK) {
		TRACE_ERROR("failed to read message length: %s\n", strerror(result));
		return result;
	}

	if (dataLeft < kHeaderSize) {
		TRACE_ERROR("message claims %" B_PRIu32 " bytes, needed at least %"
			B_PRIu32 " for the header\n", dataLeft, kHeaderSize);
		return B_ERROR;
	}

	fDataLeft = dataLeft - kHeaderSize;
	fCode = code;
	return B_OK;
}


void
RemoteMessage::Cancel()
{
	fAvailable += fWriteIndex;
	fWriteIndex = 0;
}


#ifndef CLIENT_COMPILE
void
RemoteMessage::AddBitmap(const ServerBitmap& bitmap, bool minimal)
{
	Add(bitmap.Width());
	Add(bitmap.Height());
	Add(bitmap.BytesPerRow());

	if (!minimal) {
		Add(bitmap.ColorSpace());
		Add(bitmap.Flags());
	}

	uint32 bitsLength = bitmap.BitsLength();
	Add(bitsLength);

	if (!_MakeSpace(bitsLength))
		return;

	memcpy(fBuffer + fWriteIndex, bitmap.Bits(), bitsLength);
	fWriteIndex += bitsLength;
	fAvailable -= bitsLength;
}


void
RemoteMessage::AddFont(const ServerFont& font)
{
	Add((uint8)font.Direction());
	Add((uint8)font.Encoding());
	Add(font.Flags());
	Add((uint8)font.Spacing());
	Add(font.Shear());
	Add(font.Rotation());
	Add(font.FalseBoldWidth());
	Add(font.Size());
	Add(font.Face());
	Add(font.GetFamilyAndStyle());
}


void
RemoteMessage::AddDrawState(const DrawState& drawState)
{
	Add(drawState.PenSize());
	Add(drawState.SubPixelPrecise());
	Add(drawState.GetDrawingMode());
	Add(drawState.AlphaSrcMode());
	Add(drawState.AlphaFncMode());
	AddPattern(drawState.GetPattern());
	Add(drawState.LineCapMode());
	Add(drawState.LineJoinMode());
	Add(drawState.MiterLimit());
	Add(drawState.HighColor());
	Add(drawState.LowColor());
}


void
RemoteMessage::AddArrayLine(const ViewLineArrayInfo& line)
{
	Add(line.startPoint);
	Add(line.endPoint);
	Add(line.color);
}


void
RemoteMessage::AddCursor(const ServerCursor& cursor)
{
	Add(cursor.GetHotSpot());
	AddBitmap(cursor);
}


void
RemoteMessage::AddPattern(const Pattern& pattern)
{
	Add(pattern.GetPattern());
}

#else // !CLIENT_COMPILE

void
RemoteMessage::AddBitmap(const BBitmap& bitmap)
{
	BRect bounds = bitmap.Bounds();
	Add(bounds.IntegerWidth() + 1);
	Add(bounds.IntegerHeight() + 1);
	Add(bitmap.BytesPerRow());
	Add((uint32)bitmap.ColorSpace());
	Add(bitmap.Flags());

	uint32 bitsLength = bitmap.BitsLength();
	Add(bitsLength);

	if (!_MakeSpace(bitsLength))
		return;

	memcpy(fBuffer + fWriteIndex, bitmap.Bits(), bitsLength);
	fWriteIndex += bitsLength;
	fAvailable -= bitsLength;
}
#endif // !CLIENT_COMPILE


void
RemoteMessage::AddGradient(const BGradient& gradient)
{
	Add((uint32)gradient.GetType());

	switch (gradient.GetType()) {
		case BGradient::TYPE_NONE:
			break;

		case BGradient::TYPE_LINEAR:
		{
			const BGradientLinear* linear
				= dynamic_cast<const BGradientLinear *>(&gradient);
			if (linear == NULL)
				return;

			Add(linear->Start());
			Add(linear->End());
			break;
		}

		case BGradient::TYPE_RADIAL:
		{
			const BGradientRadial* radial
				= dynamic_cast<const BGradientRadial *>(&gradient);
			if (radial == NULL)
				return;

			Add(radial->Center());
			Add(radial->Radius());
			break;
		}

		case BGradient::TYPE_RADIAL_FOCUS:
		{
			const BGradientRadialFocus* radialFocus
				= dynamic_cast<const BGradientRadialFocus *>(&gradient);
			if (radialFocus == NULL)
				return;

			Add(radialFocus->Center());
			Add(radialFocus->Focal());
			Add(radialFocus->Radius());
			break;
		}

		case BGradient::TYPE_DIAMOND:
		{
			const BGradientDiamond* diamond
				= dynamic_cast<const BGradientDiamond *>(&gradient);
			if (diamond == NULL)
				return;

			Add(diamond->Center());
			break;
		}

		case BGradient::TYPE_CONIC:
		{
			const BGradientConic* conic
				= dynamic_cast<const BGradientConic *>(&gradient);
			if (conic == NULL)
				return;

			Add(conic->Center());
			Add(conic->Angle());
			break;
		}
	}

	int32 stopCount = gradient.CountColorStops();
	Add(stopCount);

	for (int32 i = 0; i < stopCount; i++) {
		BGradient::ColorStop* stop = gradient.ColorStopAt(i);
		if (stop == NULL)
			return;

		Add(stop->color);
		Add(stop->offset);
	}
}


void
RemoteMessage::AddTransform(const BAffineTransform& transform)
{
	bool isIdentity = transform.IsIdentity();
	Add(isIdentity);

	if (isIdentity)
		return;

	Add(transform.sx);
	Add(transform.shy);
	Add(transform.shx);
	Add(transform.sy);
	Add(transform.tx);
	Add(transform.ty);
}


status_t
RemoteMessage::ReadString(char** _string, size_t& _length)
{
	uint32 length;
	status_t result = Read(length);
	if (result != B_OK)
		return result;

	if (length > fDataLeft)
		return B_ERROR;

	char *string = (char *)malloc(length + 1);
	if (string == NULL)
		return B_NO_MEMORY;

	int32 readSize = fSource->Read(string, length);
	if (readSize < 0) {
		free(string);
		return readSize;
	}

	if ((uint32)readSize != length) {
		free(string);
		return B_ERROR;
	}

	fDataLeft -= readSize;

	string[length] = 0;
	*_string = string;
	_length = length;
	return B_OK;
}


status_t
RemoteMessage::ReadBitmap(BBitmap** _bitmap, bool minimal,
	color_space colorSpace, uint32 flags)
{
	uint32 bitsLength;
	int32 width, height, bytesPerRow;

	Read(width);
	Read(height);
	Read(bytesPerRow);

	if (!minimal) {
		Read(colorSpace);
		Read(flags);
	}

	Read(bitsLength);

	if (bitsLength > fDataLeft)
		return B_ERROR;

#ifndef CLIENT_COMPILE
	flags = B_BITMAP_NO_SERVER_LINK;
#endif

	BBitmap *bitmap = new(std::nothrow) BBitmap(
		BRect(0, 0, width - 1, height - 1), flags, colorSpace, bytesPerRow);
	if (bitmap == NULL)
		return B_NO_MEMORY;

	status_t result = bitmap->InitCheck();
	if (result != B_OK) {
		delete bitmap;
		return result;
	}

	if (bitmap->BitsLength() < (int32)bitsLength) {
		delete bitmap;
		return B_ERROR;
	}

	int32 readSize = fSource->Read(bitmap->Bits(), bitsLength);
	if ((uint32)readSize != bitsLength) {
		delete bitmap;
		return readSize < 0 ? readSize : B_ERROR;
	}

	fDataLeft -= readSize;
	*_bitmap = bitmap;
	return B_OK;
}


status_t
RemoteMessage::ReadFontState(BFont& font)
{
	uint8 direction;
	uint8 encoding;
	uint8 spacing;
	uint16 face;
	uint32 flags, familyAndStyle;
	float falseBoldWidth, rotation, shear, size;

	Read(direction);
	Read(encoding);
	Read(flags);
	Read(spacing);
	Read(shear);
	Read(rotation);
	Read(falseBoldWidth);
	Read(size);
	Read(face);
	status_t result = Read(familyAndStyle);
	if (result != B_OK)
		return result;

	font.SetFamilyAndStyle(familyAndStyle);
	font.SetEncoding(encoding);
	font.SetFlags(flags);
	font.SetSpacing(spacing);
	font.SetShear(shear);
	font.SetRotation(rotation);
	font.SetFalseBoldWidth(falseBoldWidth);
	font.SetSize(size);
	font.SetFace(face);
	return B_OK;
}


status_t
RemoteMessage::ReadViewState(BView& view, ::pattern& pattern)
{
	bool subPixelPrecise;
	float penSize, miterLimit;
	drawing_mode drawingMode;
	source_alpha sourceAlpha;
	alpha_function alphaFunction;
	cap_mode capMode;
	join_mode joinMode;
	rgb_color highColor, lowColor;

	Read(penSize);
	Read(subPixelPrecise);
	Read(drawingMode);
	Read(sourceAlpha);
	Read(alphaFunction);
	Read(pattern);
	Read(capMode);
	Read(joinMode);
	Read(miterLimit);
	Read(highColor);
	status_t result = Read(lowColor);
	if (result != B_OK)
		return result;

	uint32 flags = view.Flags() & ~B_SUBPIXEL_PRECISE;
	view.SetFlags(flags | (subPixelPrecise ? B_SUBPIXEL_PRECISE : 0));
	view.SetPenSize(penSize);
	view.SetDrawingMode(drawingMode);
	view.SetBlendingMode(sourceAlpha, alphaFunction);
	view.SetLineMode(capMode, joinMode, miterLimit);
	view.SetHighColor(highColor);
	view.SetLowColor(lowColor);
	return B_OK;
}


status_t
RemoteMessage::ReadGradient(BGradient** _gradient)
{
	BGradient::Type type;
	Read(type);

	BGradient *gradient = NULL;
	switch (type) {
		case BGradient::TYPE_NONE:
			break;

		case BGradient::TYPE_LINEAR:
		{
			BPoint start, end;

			Read(start);
			Read(end);

			gradient = new(std::nothrow) BGradientLinear(start, end);
			break;
		}

		case BGradient::TYPE_RADIAL:
		{
			BPoint center;
			float radius;

			Read(center);
			Read(radius);

			gradient = new(std::nothrow) BGradientRadial(center, radius);
			break;
		}

		case BGradient::TYPE_RADIAL_FOCUS:
		{
			BPoint center, focal;
			float radius;

			Read(center);
			Read(focal);
			Read(radius);

			gradient = new(std::nothrow) BGradientRadialFocus(center, radius,
				focal);
			break;
		}

		case BGradient::TYPE_DIAMOND:
		{
			BPoint center;

			Read(center);

			gradient = new(std::nothrow) BGradientDiamond(center);
			break;
		}

		case BGradient::TYPE_CONIC:
		{
			BPoint center;
			float angle;

			Read(center);
			Read(angle);

			gradient = new(std::nothrow) BGradientConic(center, angle);
			break;
		}
	}

	if (gradient == NULL)
		return B_NO_MEMORY;

	int32 stopCount;
	status_t result = Read(stopCount);
	if (result != B_OK) {
		delete gradient;
		return result;
	}

	for (int32 i = 0; i < stopCount; i++) {
		rgb_color color;
		float offset;

		Read(color);
		result = Read(offset);
		if (result != B_OK) {
			delete gradient;
			return result;
		}

		gradient->AddColor(color, offset);
	}

	*_gradient = gradient;
	return B_OK;
}


status_t
RemoteMessage::ReadTransform(BAffineTransform& transform)
{
	bool isIdentity;
	status_t result = Read(isIdentity);
	if (result != B_OK)
		return result;

	if (isIdentity) {
		transform = BAffineTransform();
		return B_OK;
	}

	Read(transform.sx);
	Read(transform.shy);
	Read(transform.shx);
	Read(transform.sy);
	Read(transform.tx);
	return Read(transform.ty);
}


status_t
RemoteMessage::ReadArrayLine(BPoint& startPoint, BPoint& endPoint,
	rgb_color& color)
{
	Read(startPoint);
	Read(endPoint);
	return Read(color);
}