1/*
2 * Copyright 2009, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Lotz <mmlr@mlotz.ch>
7 *		Fran��ois Revol <revol@free.fr>
8 */
9
10#include "CanvasMessage.h"
11
12#include "DrawState.h"
13#include "ServerBitmap.h"
14#include "ServerCursor.h"
15
16#include <Bitmap.h>
17#include <Font.h>
18#include <View.h>
19
20#include <Gradient.h>
21#include <GradientLinear.h>
22#include <GradientRadial.h>
23#include <GradientRadialFocus.h>
24#include <GradientDiamond.h>
25#include <GradientConic.h>
26
27#include <new>
28
29
30status_t
31CanvasMessage::NextMessage(uint16& code)
32{
33	if (fDataLeft > 0) {
34		// discard remainder of message
35		int32 readSize = fSource->Read(NULL, fDataLeft);
36		if (readSize < 0)
37			return readSize;
38	}
39
40	static const uint32 kHeaderSize = sizeof(uint16) + sizeof(uint32);
41
42	fDataLeft = kHeaderSize;
43	Read(code);
44	uint32 dataLeft;
45	status_t result = Read(dataLeft);
46	if (result != B_OK)
47		return result;
48
49	if (dataLeft < kHeaderSize)
50		return B_ERROR;
51
52	fDataLeft = dataLeft - kHeaderSize;
53	fCode = code;
54	return B_OK;
55}
56
57
58void
59CanvasMessage::Cancel()
60{
61	fAvailable += fWriteIndex;
62	fWriteIndex = 0;
63}
64
65
66void
67CanvasMessage::AddBitmap(const ServerBitmap& bitmap, bool minimal)
68{
69	//TODO:send PNG / as data: or as http: url
70	Add(bitmap.Width());
71	Add(bitmap.Height());
72	Add(bitmap.BytesPerRow());
73
74	if (!minimal) {
75		Add(bitmap.ColorSpace());
76		Add(bitmap.Flags());
77	}
78
79	uint32 bitsLength = bitmap.BitsLength();
80	Add(bitsLength);
81
82	if (!_MakeSpace(bitsLength))
83		return;
84
85	memcpy(fBuffer + fWriteIndex, bitmap.Bits(), bitsLength);
86	fWriteIndex += bitsLength;
87	fAvailable -= bitsLength;
88}
89
90
91void
92CanvasMessage::AddFont(const ServerFont& font)
93{
94	//TODO:Use TTF/WOFF URL
95	Add(font.Direction());
96	Add((uint8)font.Encoding());
97	Add(font.Flags());
98	Add((uint8)font.Spacing());
99	Add(font.Shear());
100	Add(font.Rotation());
101	Add(font.FalseBoldWidth());
102	Add(font.Size());
103	Add(font.Face());
104	Add(font.GetFamilyAndStyle());
105}
106
107
108void
109CanvasMessage::AddDrawState(const DrawState& drawState)
110{
111	Add(drawState.PenSize());
112	Add(drawState.SubPixelPrecise());
113	Add(drawState.GetDrawingMode());
114	Add(drawState.AlphaSrcMode());
115	Add(drawState.AlphaFncMode());
116	AddPattern(drawState.GetPattern());
117	Add(drawState.LineCapMode());
118	Add(drawState.LineJoinMode());
119	Add(drawState.MiterLimit());
120	Add(drawState.HighColor());
121	Add(drawState.LowColor());
122}
123
124
125void
126CanvasMessage::AddArrayLine(const ViewLineArrayInfo& line)
127{
128	Add(line.startPoint);
129	Add(line.endPoint);
130	Add(line.color);
131}
132
133
134void
135CanvasMessage::AddCursor(const ServerCursor& cursor)
136{
137	//TODO:send as .cur data:
138	Add(cursor.GetHotSpot());
139	AddBitmap(cursor);
140}
141
142
143void
144CanvasMessage::AddPattern(const Pattern& pattern)
145{
146	Add(pattern.GetPattern());
147}
148
149
150void
151CanvasMessage::AddGradient(const BGradient& gradient)
152{
153	Add(gradient.GetType());
154
155	switch (gradient.GetType()) {
156		case BGradient::TYPE_NONE:
157			break;
158
159		case BGradient::TYPE_LINEAR:
160		{
161			const BGradientLinear* linear
162				= dynamic_cast<const BGradientLinear *>(&gradient);
163			if (linear == NULL)
164				return;
165
166			Add(linear->Start());
167			Add(linear->End());
168			break;
169		}
170
171		case BGradient::TYPE_RADIAL:
172		{
173			const BGradientRadial* radial
174				= dynamic_cast<const BGradientRadial *>(&gradient);
175			if (radial == NULL)
176				return;
177
178			Add(radial->Center());
179			Add(radial->Radius());
180			break;
181		}
182
183		case BGradient::TYPE_RADIAL_FOCUS:
184		{
185			const BGradientRadialFocus* radialFocus
186				= dynamic_cast<const BGradientRadialFocus *>(&gradient);
187			if (radialFocus == NULL)
188				return;
189
190			Add(radialFocus->Center());
191			Add(radialFocus->Focal());
192			Add(radialFocus->Radius());
193			break;
194		}
195
196		case BGradient::TYPE_DIAMOND:
197		{
198			const BGradientDiamond* diamond
199				= dynamic_cast<const BGradientDiamond *>(&gradient);
200			if (diamond == NULL)
201				return;
202
203			Add(diamond->Center());
204			break;
205		}
206
207		case BGradient::TYPE_CONIC:
208		{
209			const BGradientConic* conic
210				= dynamic_cast<const BGradientConic *>(&gradient);
211			if (conic == NULL)
212				return;
213
214			Add(conic->Center());
215			Add(conic->Angle());
216			break;
217		}
218	}
219
220	int32 stopCount = gradient.CountColorStops();
221	Add(stopCount);
222
223	for (int32 i = 0; i < stopCount; i++) {
224		BGradient::ColorStop* stop = gradient.ColorStopAt(i);
225		if (stop == NULL)
226			return;
227
228		Add(stop->color);
229		Add(stop->offset);
230	}
231}
232
233
234status_t
235CanvasMessage::ReadString(char** _string, size_t& _length)
236{
237	uint32 length;
238	status_t result = Read(length);
239	if (result != B_OK)
240		return result;
241
242	if (length > fDataLeft)
243		return B_ERROR;
244
245	char *string = (char *)malloc(length + 1);
246	if (string == NULL)
247		return B_NO_MEMORY;
248
249	int32 readSize = fSource->Read(string, length);
250	if (readSize < 0) {
251		free(string);
252		return readSize;
253	}
254
255	if ((uint32)readSize != length) {
256		free(string);
257		return B_ERROR;
258	}
259
260	fDataLeft -= readSize;
261
262	string[length] = 0;
263	*_string = string;
264	_length = length;
265	return B_OK;
266}
267
268
269status_t
270CanvasMessage::ReadBitmap(BBitmap** _bitmap, bool minimal,
271	color_space colorSpace, uint32 flags)
272{
273	uint32 bitsLength;
274	int32 width, height, bytesPerRow;
275
276	Read(width);
277	Read(height);
278	Read(bytesPerRow);
279
280	if (!minimal) {
281		Read(colorSpace);
282		Read(flags);
283	}
284
285	Read(bitsLength);
286
287	if (bitsLength > fDataLeft)
288		return B_ERROR;
289
290#ifndef CLIENT_COMPILE
291	flags = B_BITMAP_NO_SERVER_LINK;
292#endif
293
294	BBitmap *bitmap = new(std::nothrow) BBitmap(
295		BRect(0, 0, width - 1, height - 1), flags, colorSpace, bytesPerRow);
296	if (bitmap == NULL)
297		return B_NO_MEMORY;
298
299	status_t result = bitmap->InitCheck();
300	if (result != B_OK) {
301		delete bitmap;
302		return result;
303	}
304
305	if (bitmap->BitsLength() < (int32)bitsLength) {
306		delete bitmap;
307		return B_ERROR;
308	}
309
310	int32 readSize = fSource->Read(bitmap->Bits(), bitsLength);
311	if ((uint32)readSize != bitsLength) {
312		delete bitmap;
313		return readSize < 0 ? readSize : B_ERROR;
314	}
315
316	fDataLeft -= readSize;
317	*_bitmap = bitmap;
318	return B_OK;
319}
320
321
322status_t
323CanvasMessage::ReadFontState(BFont& font)
324{
325	uint8 encoding, spacing;
326	uint16 face;
327	uint32 flags, familyAndStyle;
328	font_direction direction;
329	float falseBoldWidth, rotation, shear, size;
330
331	Read(direction);
332	Read(encoding);
333	Read(flags);
334	Read(spacing);
335	Read(shear);
336	Read(rotation);
337	Read(falseBoldWidth);
338	Read(size);
339	Read(face);
340	status_t result = Read(familyAndStyle);
341	if (result != B_OK)
342		return result;
343
344	font.SetFamilyAndStyle(familyAndStyle);
345	font.SetEncoding(encoding);
346	font.SetFlags(flags);
347	font.SetSpacing(spacing);
348	font.SetShear(shear);
349	font.SetRotation(rotation);
350	font.SetFalseBoldWidth(falseBoldWidth);
351	font.SetSize(size);
352	font.SetFace(face);
353	return B_OK;
354}
355
356
357status_t
358CanvasMessage::ReadViewState(BView& view, ::pattern& pattern)
359{
360	bool subPixelPrecise;
361	float penSize, miterLimit;
362	drawing_mode drawingMode;
363	source_alpha sourceAlpha;
364	alpha_function alphaFunction;
365	cap_mode capMode;
366	join_mode joinMode;
367	rgb_color highColor, lowColor;
368
369	Read(penSize);
370	Read(subPixelPrecise);
371	Read(drawingMode);
372	Read(sourceAlpha);
373	Read(alphaFunction);
374	Read(pattern);
375	Read(capMode);
376	Read(joinMode);
377	Read(miterLimit);
378	Read(highColor);
379	status_t result = Read(lowColor);
380	if (result != B_OK)
381		return result;
382
383	uint32 flags = view.Flags() & ~B_SUBPIXEL_PRECISE;
384	view.SetFlags(flags | (subPixelPrecise ? B_SUBPIXEL_PRECISE : 0));
385	view.SetPenSize(penSize);
386	view.SetDrawingMode(drawingMode);
387	view.SetBlendingMode(sourceAlpha, alphaFunction);
388	view.SetLineMode(capMode, joinMode, miterLimit);
389	view.SetHighColor(highColor);
390	view.SetLowColor(lowColor);
391	return B_OK;
392}
393
394
395status_t
396CanvasMessage::ReadGradient(BGradient** _gradient)
397{
398	BGradient::Type type;
399	Read(type);
400
401	BGradient *gradient = NULL;
402	switch (type) {
403		case BGradient::TYPE_NONE:
404			break;
405
406		case BGradient::TYPE_LINEAR:
407		{
408			BPoint start, end;
409
410			Read(start);
411			Read(end);
412
413			gradient = new(std::nothrow) BGradientLinear(start, end);
414			break;
415		}
416
417		case BGradient::TYPE_RADIAL:
418		{
419			BPoint center;
420			float radius;
421
422			Read(center);
423			Read(radius);
424
425			gradient = new(std::nothrow) BGradientRadial(center, radius);
426			break;
427		}
428
429		case BGradient::TYPE_RADIAL_FOCUS:
430		{
431			BPoint center, focal;
432			float radius;
433
434			Read(center);
435			Read(focal);
436			Read(radius);
437
438			gradient = new(std::nothrow) BGradientRadialFocus(center, radius,
439				focal);
440			break;
441		}
442
443		case BGradient::TYPE_DIAMOND:
444		{
445			BPoint center;
446
447			Read(center);
448
449			gradient = new(std::nothrow) BGradientDiamond(center);
450			break;
451		}
452
453		case BGradient::TYPE_CONIC:
454		{
455			BPoint center;
456			float angle;
457
458			Read(center);
459			Read(angle);
460
461			gradient = new(std::nothrow) BGradientConic(center, angle);
462			break;
463		}
464	}
465
466	if (gradient == NULL)
467		return B_NO_MEMORY;
468
469	int32 stopCount;
470	status_t result = Read(stopCount);
471	if (result != B_OK) {
472		delete gradient;
473		return result;
474	}
475
476	for (int32 i = 0; i < stopCount; i++) {
477		rgb_color color;
478		float offset;
479
480		Read(color);
481		result = Read(offset);
482		if (result != B_OK)
483			return result;
484
485		gradient->AddColor(color, offset);
486	}
487
488	*_gradient = gradient;
489	return B_OK;
490}
491
492
493status_t
494CanvasMessage::ReadArrayLine(BPoint& startPoint, BPoint& endPoint,
495	rgb_color& color)
496{
497	Read(startPoint);
498	Read(endPoint);
499	return Read(color);
500}
501