* 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...)
#define TRACE_ERROR(x...) TRACE_ALWAYS(x)
status_t
RemoteMessage::NextMessage(uint16& code)
{
if (fDataLeft > 0) {
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
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
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);
}