An html5 <canvas> based drawing engine
This implements an html5 rendering engine. Inspired by the Broadway GDK backend for Gnome. Work in progress. For now it just connects and dumps debug output.
This commit is contained in:
parent
d1abffcaa2
commit
8d33dc2971
@ -84,7 +84,8 @@ Server app_server :
|
||||
# libraries
|
||||
:
|
||||
libtranslation.so libbe.so libbnetapi.so
|
||||
libasdrawing.a libasremote.a libpainter.a libagg.a $(HAIKU_FREETYPE_LIB)
|
||||
libasdrawing.a libasremote.a libashtml5.a
|
||||
libpainter.a libagg.a $(HAIKU_FREETYPE_LIB)
|
||||
libstackandtile.a liblinprog.a libtextencoding.so libshared.a
|
||||
$(TARGET_LIBSTDC++)
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "ServerConfig.h"
|
||||
|
||||
#include "remote/RemoteHWInterface.h"
|
||||
#include "html5/HTML5HWInterface.h"
|
||||
|
||||
#include <Autolock.h>
|
||||
#include <Entry.h>
|
||||
@ -109,7 +110,15 @@ ScreenManager::AcquireScreens(ScreenOwner* owner, int32* wishList,
|
||||
// there's a specific target screen we want to initialize
|
||||
// TODO: right now we only support remote screens, but we could
|
||||
// also target specific accelerants to support other graphics cards
|
||||
RemoteHWInterface* interface = new(nothrow) RemoteHWInterface(target);
|
||||
HWInterface* interface;
|
||||
/*
|
||||
if (strncmp(target, "vnc:", 4) == 0)
|
||||
interface = new(nothrow) VNCHWInterface(target);
|
||||
else*/
|
||||
if (strncmp(target, "html5:", 6) == 0)
|
||||
interface = new(nothrow) HTML5HWInterface(target);
|
||||
else
|
||||
interface = new(nothrow) RemoteHWInterface(target);
|
||||
if (interface != NULL) {
|
||||
screen_item* item = _AddHWInterface(interface);
|
||||
if (item != NULL && list.AddItem(item->screen)) {
|
||||
|
@ -30,3 +30,4 @@ StaticLibrary libasdrawing.a :
|
||||
|
||||
SubInclude HAIKU_TOP src servers app drawing Painter ;
|
||||
SubInclude HAIKU_TOP src servers app drawing remote ;
|
||||
SubInclude HAIKU_TOP src servers app drawing html5 ;
|
||||
|
218
src/servers/app/drawing/html5/CanvasEventStream.cpp
Normal file
218
src/servers/app/drawing/html5/CanvasEventStream.cpp
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
*/
|
||||
|
||||
#include "CanvasEventStream.h"
|
||||
|
||||
#include "CanvasMessage.h"
|
||||
#include "StreamingRingBuffer.h"
|
||||
|
||||
#include <Autolock.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
|
||||
CanvasEventStream::CanvasEventStream()
|
||||
:
|
||||
fEventList(10, true),
|
||||
fEventListLocker("canvas event list"),
|
||||
fEventNotification(-1),
|
||||
fWaitingOnEvent(false),
|
||||
fLatestMouseMovedEvent(NULL),
|
||||
fMousePosition(0, 0),
|
||||
fMouseButtons(0),
|
||||
fModifiers(0)
|
||||
{
|
||||
fEventNotification = create_sem(0, "canvas event notification");
|
||||
}
|
||||
|
||||
|
||||
CanvasEventStream::~CanvasEventStream()
|
||||
{
|
||||
delete_sem(fEventNotification);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CanvasEventStream::UpdateScreenBounds(BRect bounds)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CanvasEventStream::GetNextEvent(BMessage** _event)
|
||||
{
|
||||
BAutolock lock(fEventListLocker);
|
||||
while (fEventList.CountItems() == 0) {
|
||||
fWaitingOnEvent = true;
|
||||
lock.Unlock();
|
||||
|
||||
status_t result;
|
||||
do {
|
||||
result = acquire_sem(fEventNotification);
|
||||
} while (result == B_INTERRUPTED);
|
||||
|
||||
lock.Lock();
|
||||
if (!lock.IsLocked())
|
||||
return false;
|
||||
}
|
||||
|
||||
*_event = fEventList.RemoveItemAt(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CanvasEventStream::InsertEvent(BMessage* event)
|
||||
{
|
||||
BAutolock lock(fEventListLocker);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
if (!fEventList.AddItem(event))
|
||||
return B_ERROR;
|
||||
|
||||
if (event->what == B_MOUSE_MOVED)
|
||||
fLatestMouseMovedEvent = event;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
BMessage*
|
||||
CanvasEventStream::PeekLatestMouseMoved()
|
||||
{
|
||||
return fLatestMouseMovedEvent;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CanvasEventStream::EventReceived(CanvasMessage& message)
|
||||
{
|
||||
uint16 code = message.Code();
|
||||
uint32 what = 0;
|
||||
switch (code) {
|
||||
case RP_MOUSE_MOVED:
|
||||
what = B_MOUSE_MOVED;
|
||||
break;
|
||||
case RP_MOUSE_DOWN:
|
||||
what = B_MOUSE_DOWN;
|
||||
break;
|
||||
case RP_MOUSE_UP:
|
||||
what = B_MOUSE_UP;
|
||||
break;
|
||||
case RP_MOUSE_WHEEL_CHANGED:
|
||||
what = B_MOUSE_WHEEL_CHANGED;
|
||||
break;
|
||||
case RP_KEY_DOWN:
|
||||
what = B_KEY_DOWN;
|
||||
break;
|
||||
case RP_KEY_UP:
|
||||
what = B_KEY_UP;
|
||||
break;
|
||||
case RP_MODIFIERS_CHANGED:
|
||||
what = B_MODIFIERS_CHANGED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (what == 0)
|
||||
return false;
|
||||
|
||||
BMessage* event = new BMessage(what);
|
||||
if (event == NULL)
|
||||
return false;
|
||||
|
||||
event->AddInt64("when", system_time());
|
||||
|
||||
switch (code) {
|
||||
case RP_MOUSE_MOVED:
|
||||
case RP_MOUSE_DOWN:
|
||||
case RP_MOUSE_UP:
|
||||
{
|
||||
message.Read(fMousePosition);
|
||||
if (code != RP_MOUSE_MOVED)
|
||||
message.Read(fMouseButtons);
|
||||
|
||||
event->AddPoint("where", fMousePosition);
|
||||
event->AddInt32("buttons", fMouseButtons);
|
||||
event->AddInt32("modifiers", fModifiers);
|
||||
|
||||
if (code == RP_MOUSE_DOWN) {
|
||||
int32 clicks;
|
||||
if (message.Read(clicks) == B_OK)
|
||||
event->AddInt32("clicks", clicks);
|
||||
}
|
||||
|
||||
if (code == RP_MOUSE_MOVED)
|
||||
fLatestMouseMovedEvent = event;
|
||||
break;
|
||||
}
|
||||
|
||||
case RP_MOUSE_WHEEL_CHANGED:
|
||||
{
|
||||
float xDelta, yDelta;
|
||||
message.Read(xDelta);
|
||||
message.Read(yDelta);
|
||||
event->AddFloat("be:wheel_delta_x", xDelta);
|
||||
event->AddFloat("be:wheel_delta_y", yDelta);
|
||||
break;
|
||||
}
|
||||
|
||||
case RP_KEY_DOWN:
|
||||
case RP_KEY_UP:
|
||||
{
|
||||
int32 numBytes;
|
||||
if (message.Read(numBytes) != B_OK)
|
||||
break;
|
||||
|
||||
char* bytes = (char*)malloc(numBytes + 1);
|
||||
if (bytes == NULL)
|
||||
break;
|
||||
|
||||
if (message.ReadList(bytes, numBytes) != B_OK) {
|
||||
free(bytes);
|
||||
break;
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < numBytes; i++)
|
||||
event->AddInt8("byte", (int8)bytes[i]);
|
||||
|
||||
bytes[numBytes] = 0;
|
||||
event->AddData("bytes", B_STRING_TYPE, bytes, numBytes + 1, false);
|
||||
event->AddInt32("modifiers", fModifiers);
|
||||
|
||||
int32 rawChar;
|
||||
if (message.Read(rawChar) == B_OK)
|
||||
event->AddInt32("raw_char", rawChar);
|
||||
|
||||
int32 key;
|
||||
if (message.Read(key) == B_OK)
|
||||
event->AddInt32("key", key);
|
||||
|
||||
free(bytes);
|
||||
break;
|
||||
}
|
||||
|
||||
case RP_MODIFIERS_CHANGED:
|
||||
{
|
||||
event->AddInt32("be:old_modifiers", fModifiers);
|
||||
message.Read(fModifiers);
|
||||
event->AddInt32("modifiers", fModifiers);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BAutolock lock(fEventListLocker);
|
||||
fEventList.AddItem(event);
|
||||
if (fWaitingOnEvent) {
|
||||
fWaitingOnEvent = false;
|
||||
lock.Unlock();
|
||||
release_sem(fEventNotification);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
45
src/servers/app/drawing/html5/CanvasEventStream.h
Normal file
45
src/servers/app/drawing/html5/CanvasEventStream.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
*/
|
||||
#ifndef CANVAS_EVENT_STREAM_H
|
||||
#define CANVAS_EVENT_STREAM_H
|
||||
|
||||
#include "EventStream.h"
|
||||
|
||||
#include <Locker.h>
|
||||
#include <ObjectList.h>
|
||||
|
||||
class CanvasMessage;
|
||||
|
||||
class CanvasEventStream : public EventStream {
|
||||
public:
|
||||
CanvasEventStream();
|
||||
virtual ~CanvasEventStream();
|
||||
|
||||
virtual bool IsValid() { return true; }
|
||||
virtual void SendQuit() {}
|
||||
|
||||
virtual void UpdateScreenBounds(BRect bounds);
|
||||
virtual bool GetNextEvent(BMessage** _event);
|
||||
virtual status_t InsertEvent(BMessage* event);
|
||||
virtual BMessage* PeekLatestMouseMoved();
|
||||
|
||||
bool EventReceived(CanvasMessage& message);
|
||||
|
||||
private:
|
||||
BObjectList<BMessage> fEventList;
|
||||
BLocker fEventListLocker;
|
||||
sem_id fEventNotification;
|
||||
bool fWaitingOnEvent;
|
||||
BMessage* fLatestMouseMovedEvent;
|
||||
|
||||
BPoint fMousePosition;
|
||||
uint32 fMouseButtons;
|
||||
uint32 fModifiers;
|
||||
};
|
||||
|
||||
#endif // CANVAS_EVENT_STREAM_H
|
500
src/servers/app/drawing/html5/CanvasMessage.cpp
Normal file
500
src/servers/app/drawing/html5/CanvasMessage.cpp
Normal file
@ -0,0 +1,500 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* François Revol <revol@free.fr>
|
||||
*/
|
||||
|
||||
#include "CanvasMessage.h"
|
||||
|
||||
#include "DrawState.h"
|
||||
#include "ServerBitmap.h"
|
||||
#include "ServerCursor.h"
|
||||
|
||||
#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>
|
||||
|
||||
|
||||
status_t
|
||||
CanvasMessage::NextMessage(uint16& code)
|
||||
{
|
||||
if (fDataLeft > 0) {
|
||||
// discard remainder of message
|
||||
int32 readSize = fSource->Read(NULL, fDataLeft);
|
||||
if (readSize < 0)
|
||||
return readSize;
|
||||
}
|
||||
|
||||
static const uint32 kHeaderSize = sizeof(uint16) + sizeof(uint32);
|
||||
|
||||
fDataLeft = kHeaderSize;
|
||||
Read(code);
|
||||
uint32 dataLeft;
|
||||
status_t result = Read(dataLeft);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if (dataLeft < kHeaderSize)
|
||||
return B_ERROR;
|
||||
|
||||
fDataLeft = dataLeft - kHeaderSize;
|
||||
fCode = code;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CanvasMessage::Cancel()
|
||||
{
|
||||
fAvailable += fWriteIndex;
|
||||
fWriteIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CanvasMessage::AddBitmap(const ServerBitmap& bitmap, bool minimal)
|
||||
{
|
||||
//TODO:send PNG / as data: or as http: url
|
||||
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
|
||||
CanvasMessage::AddFont(const ServerFont& font)
|
||||
{
|
||||
//TODO:Use TTF/WOFF URL
|
||||
Add(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
|
||||
CanvasMessage::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
|
||||
CanvasMessage::AddArrayLine(const ViewLineArrayInfo& line)
|
||||
{
|
||||
Add(line.startPoint);
|
||||
Add(line.endPoint);
|
||||
Add(line.color);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CanvasMessage::AddCursor(const ServerCursor& cursor)
|
||||
{
|
||||
//TODO:send as .cur data:
|
||||
Add(cursor.GetHotSpot());
|
||||
AddBitmap(cursor);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CanvasMessage::AddPattern(const Pattern& pattern)
|
||||
{
|
||||
Add(pattern.GetPattern());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CanvasMessage::AddGradient(const BGradient& gradient)
|
||||
{
|
||||
Add(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CanvasMessage::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
|
||||
CanvasMessage::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
|
||||
CanvasMessage::ReadFontState(BFont& font)
|
||||
{
|
||||
uint8 encoding, spacing;
|
||||
uint16 face;
|
||||
uint32 flags, familyAndStyle;
|
||||
font_direction direction;
|
||||
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
|
||||
CanvasMessage::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
|
||||
CanvasMessage::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)
|
||||
return result;
|
||||
|
||||
gradient->AddColor(color, offset);
|
||||
}
|
||||
|
||||
*_gradient = gradient;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CanvasMessage::ReadArrayLine(BPoint& startPoint, BPoint& endPoint,
|
||||
rgb_color& color)
|
||||
{
|
||||
Read(startPoint);
|
||||
Read(endPoint);
|
||||
return Read(color);
|
||||
}
|
371
src/servers/app/drawing/html5/CanvasMessage.h
Normal file
371
src/servers/app/drawing/html5/CanvasMessage.h
Normal file
@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* François Revol <revol@free.fr>
|
||||
*/
|
||||
#ifndef CANVAS_MESSAGE_H
|
||||
#define CANCAS_MESSAGE_H
|
||||
|
||||
#include "PatternHandler.h"
|
||||
#include <ViewPrivate.h>
|
||||
|
||||
#include "StreamingRingBuffer.h"
|
||||
#include "base64.h"
|
||||
|
||||
#include <GraphicsDefs.h>
|
||||
#include <Region.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
class BBitmap;
|
||||
class BFont;
|
||||
class BGradient;
|
||||
class BView;
|
||||
class DrawState;
|
||||
class Pattern;
|
||||
class RemotePainter;
|
||||
class ServerBitmap;
|
||||
class ServerCursor;
|
||||
class ServerFont;
|
||||
class ViewLineArrayInfo;
|
||||
|
||||
enum {
|
||||
RP_INIT_CONNECTION = 1,
|
||||
RP_UPDATE_DISPLAY_MODE,
|
||||
RP_CLOSE_CONNECTION,
|
||||
|
||||
RP_CREATE_STATE = 20,
|
||||
RP_DELETE_STATE,
|
||||
RP_ENABLE_SYNC_DRAWING,
|
||||
RP_DISABLE_SYNC_DRAWING,
|
||||
RP_INVALIDATE_RECT,
|
||||
RP_INVALIDATE_REGION,
|
||||
|
||||
RP_SET_OFFSETS = 40,
|
||||
RP_SET_HIGH_COLOR,
|
||||
RP_SET_LOW_COLOR,
|
||||
RP_SET_PEN_SIZE,
|
||||
RP_SET_STROKE_MODE,
|
||||
RP_SET_BLENDING_MODE,
|
||||
RP_SET_PATTERN,
|
||||
RP_SET_DRAWING_MODE,
|
||||
RP_SET_FONT,
|
||||
|
||||
RP_CONSTRAIN_CLIPPING_REGION = 60,
|
||||
RP_COPY_RECT_NO_CLIPPING,
|
||||
RP_INVERT_RECT,
|
||||
RP_DRAW_BITMAP,
|
||||
RP_DRAW_BITMAP_RECTS,
|
||||
|
||||
RP_STROKE_ARC = 80,
|
||||
RP_STROKE_BEZIER,
|
||||
RP_STROKE_ELLIPSE,
|
||||
RP_STROKE_POLYGON,
|
||||
RP_STROKE_RECT,
|
||||
RP_STROKE_ROUND_RECT,
|
||||
RP_STROKE_SHAPE,
|
||||
RP_STROKE_TRIANGLE,
|
||||
RP_STROKE_LINE,
|
||||
RP_STROKE_LINE_ARRAY,
|
||||
|
||||
RP_FILL_ARC = 100,
|
||||
RP_FILL_BEZIER,
|
||||
RP_FILL_ELLIPSE,
|
||||
RP_FILL_POLYGON,
|
||||
RP_FILL_RECT,
|
||||
RP_FILL_ROUND_RECT,
|
||||
RP_FILL_SHAPE,
|
||||
RP_FILL_TRIANGLE,
|
||||
RP_FILL_REGION,
|
||||
|
||||
RP_FILL_ARC_GRADIENT = 120,
|
||||
RP_FILL_BEZIER_GRADIENT,
|
||||
RP_FILL_ELLIPSE_GRADIENT,
|
||||
RP_FILL_POLYGON_GRADIENT,
|
||||
RP_FILL_RECT_GRADIENT,
|
||||
RP_FILL_ROUND_RECT_GRADIENT,
|
||||
RP_FILL_SHAPE_GRADIENT,
|
||||
RP_FILL_TRIANGLE_GRADIENT,
|
||||
RP_FILL_REGION_GRADIENT,
|
||||
|
||||
RP_STROKE_POINT_COLOR = 140,
|
||||
RP_STROKE_LINE_1PX_COLOR,
|
||||
RP_STROKE_RECT_1PX_COLOR,
|
||||
|
||||
RP_FILL_RECT_COLOR = 160,
|
||||
RP_FILL_REGION_COLOR_NO_CLIPPING,
|
||||
|
||||
RP_DRAW_STRING = 180,
|
||||
RP_DRAW_STRING_WITH_OFFSETS,
|
||||
RP_DRAW_STRING_RESULT,
|
||||
RP_STRING_WIDTH,
|
||||
RP_STRING_WIDTH_RESULT,
|
||||
RP_READ_BITMAP,
|
||||
RP_READ_BITMAP_RESULT,
|
||||
|
||||
RP_SET_CURSOR = 200,
|
||||
RP_SET_CURSOR_VISIBLE,
|
||||
RP_MOVE_CURSOR_TO,
|
||||
|
||||
RP_MOUSE_MOVED = 220,
|
||||
RP_MOUSE_DOWN,
|
||||
RP_MOUSE_UP,
|
||||
RP_MOUSE_WHEEL_CHANGED,
|
||||
|
||||
RP_KEY_DOWN = 240,
|
||||
RP_KEY_UP,
|
||||
RP_UNMAPPED_KEY_DOWN,
|
||||
RP_UNMAPPED_KEY_UP,
|
||||
RP_MODIFIERS_CHANGED
|
||||
};
|
||||
|
||||
|
||||
class CanvasMessage {
|
||||
public:
|
||||
CanvasMessage(StreamingRingBuffer* source,
|
||||
StreamingRingBuffer *target);
|
||||
~CanvasMessage();
|
||||
|
||||
void Start(uint16 code);
|
||||
status_t Flush();
|
||||
void Cancel();
|
||||
|
||||
status_t NextMessage(uint16& code);
|
||||
uint16 Code() { return fCode; }
|
||||
uint32 DataLeft() { return fDataLeft; }
|
||||
|
||||
template<typename T>
|
||||
void Add(const T& value);
|
||||
|
||||
void AddString(const char* string, size_t length);
|
||||
void AddRegion(const BRegion& region);
|
||||
void AddGradient(const BGradient& gradient);
|
||||
|
||||
void AddBitmap(const ServerBitmap& bitmap,
|
||||
bool minimal = false);
|
||||
void AddFont(const ServerFont& font);
|
||||
void AddPattern(const Pattern& pattern);
|
||||
void AddDrawState(const DrawState& drawState);
|
||||
void AddArrayLine(const ViewLineArrayInfo& line);
|
||||
void AddCursor(const ServerCursor& cursor);
|
||||
|
||||
template<typename T>
|
||||
void AddList(const T* array, int32 count);
|
||||
|
||||
template<typename T>
|
||||
status_t Read(T& value);
|
||||
|
||||
status_t ReadRegion(BRegion& region);
|
||||
status_t ReadFontState(BFont& font);
|
||||
// sets font state
|
||||
status_t ReadViewState(BView& view, ::pattern& pattern);
|
||||
// sets viewstate and returns pattern
|
||||
|
||||
status_t ReadString(char** _string, size_t& length);
|
||||
status_t ReadBitmap(BBitmap** _bitmap,
|
||||
bool minimal = false,
|
||||
color_space colorSpace = B_RGB32,
|
||||
uint32 flags = 0);
|
||||
status_t ReadGradient(BGradient** _gradient);
|
||||
status_t ReadArrayLine(BPoint& startPoint,
|
||||
BPoint& endPoint, rgb_color& color);
|
||||
|
||||
template<typename T>
|
||||
status_t ReadList(T* array, int32 count);
|
||||
|
||||
private:
|
||||
bool _MakeSpace(size_t size);
|
||||
|
||||
StreamingRingBuffer* fSource;
|
||||
StreamingRingBuffer* fTarget;
|
||||
|
||||
uint8* fBuffer;
|
||||
size_t fAvailable;
|
||||
size_t fWriteIndex;
|
||||
uint32 fDataLeft;
|
||||
uint16 fCode;
|
||||
};
|
||||
|
||||
|
||||
inline
|
||||
CanvasMessage::CanvasMessage(StreamingRingBuffer* source,
|
||||
StreamingRingBuffer* target)
|
||||
:
|
||||
fSource(source),
|
||||
fTarget(target),
|
||||
fBuffer(NULL),
|
||||
fAvailable(0),
|
||||
fWriteIndex(0),
|
||||
fDataLeft(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
CanvasMessage::~CanvasMessage()
|
||||
{
|
||||
if (fWriteIndex > 0)
|
||||
Flush();
|
||||
free(fBuffer);
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
CanvasMessage::Start(uint16 code)
|
||||
{
|
||||
if (fWriteIndex > 0)
|
||||
Flush();
|
||||
|
||||
Add(code);
|
||||
|
||||
// uint32 sizeDummy;
|
||||
// Add(sizeDummy);
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
CanvasMessage::Flush()
|
||||
{
|
||||
if (fWriteIndex == 0)
|
||||
return B_NO_INIT;
|
||||
|
||||
// end by the multipart boundary
|
||||
static const char boundary[] = "--x\r\n\r\n";
|
||||
AddString(boundary, sizeof(boundary) - 1);
|
||||
|
||||
uint32 length = fWriteIndex;
|
||||
fAvailable += fWriteIndex;
|
||||
fWriteIndex = 0;
|
||||
|
||||
// memcpy(fBuffer + sizeof(uint16) * 2, &length, sizeof(uint32));
|
||||
return fTarget->Write(fBuffer, length);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline void
|
||||
CanvasMessage::Add(const T& value)
|
||||
{
|
||||
ssize_t done;
|
||||
|
||||
if (!_MakeSpace(sizeof(T) * 2)) // 4/3 actually
|
||||
return;
|
||||
|
||||
//memcpy(fBuffer + fWriteIndex, &value, sizeof(T));
|
||||
done = encode_base64((char *)fBuffer + fWriteIndex, (const char *)(&value),
|
||||
sizeof(T));
|
||||
fWriteIndex += done;
|
||||
fAvailable -= done;
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
CanvasMessage::AddString(const char* string, size_t length)
|
||||
{
|
||||
Add(length);
|
||||
if (length > fAvailable && !_MakeSpace(length))
|
||||
return;
|
||||
|
||||
memcpy(fBuffer + fWriteIndex, string, length);
|
||||
fWriteIndex += length;
|
||||
fAvailable -= length;
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
CanvasMessage::AddRegion(const BRegion& region)
|
||||
{
|
||||
int32 rectCount = region.CountRects();
|
||||
Add(rectCount);
|
||||
|
||||
for (int32 i = 0; i < rectCount; i++)
|
||||
Add(region.RectAt(i));
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline void
|
||||
CanvasMessage::AddList(const T* array, int32 count)
|
||||
{
|
||||
for (int32 i = 0; i < count; i++)
|
||||
Add(array[i]);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline status_t
|
||||
CanvasMessage::Read(T& value)
|
||||
{
|
||||
//TODO
|
||||
if (fDataLeft < sizeof(T))
|
||||
return B_ERROR;
|
||||
|
||||
int32 readSize = fSource->Read(&value, sizeof(T));
|
||||
if (readSize < 0)
|
||||
return readSize;
|
||||
|
||||
if (readSize != sizeof(T))
|
||||
return B_ERROR;
|
||||
|
||||
fDataLeft -= sizeof(T);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
CanvasMessage::ReadRegion(BRegion& region)
|
||||
{
|
||||
region.MakeEmpty();
|
||||
|
||||
int32 rectCount;
|
||||
Read(rectCount);
|
||||
|
||||
for (int32 i = 0; i < rectCount; i++) {
|
||||
BRect rect;
|
||||
status_t result = Read(rect);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
region.Include(rect);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline status_t
|
||||
CanvasMessage::ReadList(T* array, int32 count)
|
||||
{
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
status_t result = Read(array[i]);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
CanvasMessage::_MakeSpace(size_t size)
|
||||
{
|
||||
if (fAvailable >= size)
|
||||
return true;
|
||||
|
||||
size_t extraSize = size + 20;
|
||||
uint8 *newBuffer = (uint8*)realloc(fBuffer, fWriteIndex + extraSize);
|
||||
if (newBuffer == NULL)
|
||||
return false;
|
||||
|
||||
fAvailable = extraSize;
|
||||
fBuffer = newBuffer;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // CANVAS_MESSAGE_H
|
1117
src/servers/app/drawing/html5/HTML5DrawingEngine.cpp
Normal file
1117
src/servers/app/drawing/html5/HTML5DrawingEngine.cpp
Normal file
File diff suppressed because it is too large
Load Diff
180
src/servers/app/drawing/html5/HTML5DrawingEngine.h
Normal file
180
src/servers/app/drawing/html5/HTML5DrawingEngine.h
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* François Revol <revol@free.fr>
|
||||
*/
|
||||
#ifndef HTML5_DRAWING_ENGINE_H
|
||||
#define HTML5_DRAWING_ENGINE_H
|
||||
|
||||
#include "DrawingEngine.h"
|
||||
#include "DrawState.h"
|
||||
#include "HTML5HWInterface.h"
|
||||
#include "ServerFont.h"
|
||||
|
||||
class BPoint;
|
||||
class BRect;
|
||||
class BRegion;
|
||||
|
||||
class BitmapDrawingEngine;
|
||||
class ServerBitmap;
|
||||
|
||||
class HTML5DrawingEngine : public DrawingEngine {
|
||||
public:
|
||||
HTML5DrawingEngine(
|
||||
HTML5HWInterface* interface);
|
||||
virtual ~HTML5DrawingEngine();
|
||||
|
||||
// HWInterfaceListener interface
|
||||
virtual void FrameBufferChanged();
|
||||
|
||||
virtual void SetCopyToFrontEnabled(bool enabled);
|
||||
|
||||
// for screen shots
|
||||
virtual status_t ReadBitmap(ServerBitmap* bitmap,
|
||||
bool drawCursor, BRect bounds);
|
||||
|
||||
// clipping for all drawing functions, passing a NULL region
|
||||
// will remove any clipping (drawing allowed everywhere)
|
||||
virtual void ConstrainClippingRegion(const BRegion* region);
|
||||
|
||||
virtual void SetDrawState(const DrawState* state,
|
||||
int32 xOffset = 0, int32 yOffset = 0);
|
||||
|
||||
virtual void SetHighColor(const rgb_color& color);
|
||||
virtual void SetLowColor(const rgb_color& color);
|
||||
virtual void SetPenSize(float size);
|
||||
virtual void SetStrokeMode(cap_mode lineCap,
|
||||
join_mode joinMode, float miterLimit);
|
||||
virtual void SetPattern(const struct pattern& pattern);
|
||||
virtual void SetDrawingMode(drawing_mode mode);
|
||||
virtual void SetDrawingMode(drawing_mode mode,
|
||||
drawing_mode& oldMode);
|
||||
virtual void SetBlendingMode(source_alpha srcAlpha,
|
||||
alpha_function alphaFunc);
|
||||
virtual void SetFont(const ServerFont& font);
|
||||
virtual void SetFont(const DrawState* state);
|
||||
|
||||
// drawing functions
|
||||
virtual void InvertRect(BRect rect);
|
||||
|
||||
virtual void DrawBitmap(ServerBitmap* bitmap,
|
||||
const BRect& bitmapRect,
|
||||
const BRect& viewRect, uint32 options = 0);
|
||||
|
||||
// drawing primitives
|
||||
virtual void DrawArc(BRect rect, const float& angle,
|
||||
const float& span, bool filled);
|
||||
virtual void FillArc(BRect rect, const float& angle,
|
||||
const float& span,
|
||||
const BGradient& gradient);
|
||||
|
||||
virtual void DrawBezier(BPoint* points, bool filled);
|
||||
virtual void FillBezier(BPoint* points,
|
||||
const BGradient& gradient);
|
||||
|
||||
virtual void DrawEllipse(BRect rect, bool filled);
|
||||
virtual void FillEllipse(BRect rect,
|
||||
const BGradient& gradient);
|
||||
|
||||
virtual void DrawPolygon(BPoint* pointList, int32 numPoints,
|
||||
BRect bounds, bool filled, bool closed);
|
||||
virtual void FillPolygon(BPoint* pointList, int32 numPoints,
|
||||
BRect bounds, const BGradient& gradient,
|
||||
bool closed);
|
||||
|
||||
// these rgb_color versions are used internally by the server
|
||||
virtual void StrokePoint(const BPoint& point,
|
||||
const rgb_color& color);
|
||||
virtual void StrokeRect(BRect rect, const rgb_color &color);
|
||||
virtual void FillRect(BRect rect, const rgb_color &color);
|
||||
virtual void FillRegion(BRegion& region,
|
||||
const rgb_color& color);
|
||||
|
||||
virtual void StrokeRect(BRect rect);
|
||||
virtual void FillRect(BRect rect);
|
||||
virtual void FillRect(BRect rect, const BGradient& gradient);
|
||||
|
||||
virtual void FillRegion(BRegion& region);
|
||||
virtual void FillRegion(BRegion& region,
|
||||
const BGradient& gradient);
|
||||
|
||||
virtual void DrawRoundRect(BRect rect, float xRadius,
|
||||
float yRadius, bool filled);
|
||||
virtual void FillRoundRect(BRect rect, float xRadius,
|
||||
float yRadius, const BGradient& gradient);
|
||||
|
||||
virtual void DrawShape(const BRect& bounds,
|
||||
int32 opCount, const uint32* opList,
|
||||
int32 pointCount, const BPoint* pointList,
|
||||
bool filled,
|
||||
const BPoint& viewToScreenOffset,
|
||||
float viewScale);
|
||||
virtual void FillShape(const BRect& bounds,
|
||||
int32 opCount, const uint32* opList,
|
||||
int32 pointCount, const BPoint* pointList,
|
||||
const BGradient& gradient,
|
||||
const BPoint& viewToScreenOffset,
|
||||
float viewScale);
|
||||
|
||||
virtual void DrawTriangle(BPoint* points,
|
||||
const BRect& bounds, bool filled);
|
||||
virtual void FillTriangle(BPoint* points,
|
||||
const BRect& bounds,
|
||||
const BGradient& gradient);
|
||||
|
||||
// these versions are used by the Decorator
|
||||
virtual void StrokeLine(const BPoint& start,
|
||||
const BPoint& end, const rgb_color& color);
|
||||
virtual void StrokeLine(const BPoint& start,
|
||||
const BPoint& end);
|
||||
virtual void StrokeLineArray(int32 numlines,
|
||||
const ViewLineArrayInfo* data);
|
||||
|
||||
// returns the pen position behind the (virtually) drawn string
|
||||
virtual BPoint DrawString(const char* string, int32 length,
|
||||
const BPoint& point,
|
||||
escapement_delta* delta = NULL);
|
||||
virtual BPoint DrawString(const char* string, int32 length,
|
||||
const BPoint* offsets);
|
||||
|
||||
virtual float StringWidth(const char* string, int32 length,
|
||||
escapement_delta* delta = NULL);
|
||||
|
||||
// software rendering backend invoked by CopyRegion() for the sorted
|
||||
// individual rects
|
||||
virtual BRect CopyRect(BRect rect, int32 xOffset,
|
||||
int32 yOffset) const;
|
||||
|
||||
private:
|
||||
status_t _AddCallback();
|
||||
|
||||
static bool _DrawingEngineResult(void* cookie,
|
||||
CanvasMessage& message);
|
||||
|
||||
BRect _BuildBounds(BPoint* points, int32 pointCount);
|
||||
status_t _ExtractBitmapRegions(ServerBitmap& bitmap,
|
||||
uint32 options, const BRect& bitmapRect,
|
||||
const BRect& viewRect, double xScale,
|
||||
double yScale, BRegion& region,
|
||||
UtilityBitmap**& bitmaps);
|
||||
|
||||
HTML5HWInterface* fHWInterface;
|
||||
uint32 fToken;
|
||||
|
||||
DrawState fState;
|
||||
BRegion fClippingRegion;
|
||||
float fExtendWidth;
|
||||
|
||||
bool fCallbackAdded;
|
||||
sem_id fResultNotify;
|
||||
BPoint fDrawStringResult;
|
||||
float fStringWidthResult;
|
||||
BBitmap* fReadBitmapResult;
|
||||
|
||||
BitmapDrawingEngine* fBitmapDrawingEngine;
|
||||
};
|
||||
|
||||
#endif // HTML5_DRAWING_ENGINE_H
|
612
src/servers/app/drawing/html5/HTML5HWInterface.cpp
Normal file
612
src/servers/app/drawing/html5/HTML5HWInterface.cpp
Normal file
@ -0,0 +1,612 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* François Revol <revol@free.fr>
|
||||
*/
|
||||
|
||||
#include "HTML5HWInterface.h"
|
||||
#include "HTML5DrawingEngine.h"
|
||||
#include "CanvasEventStream.h"
|
||||
#include "CanvasMessage.h"
|
||||
|
||||
#include "WebHandler.h"
|
||||
#include "WebServer.h"
|
||||
#include "WebWorker.h"
|
||||
//#include "NetReceiver.h"
|
||||
//#include "NetSender.h"
|
||||
#include "StreamingRingBuffer.h"
|
||||
|
||||
#include "desktop.html.h"
|
||||
#include "haiku.js.h"
|
||||
|
||||
#include <Autolock.h>
|
||||
#include <NetEndpoint.h>
|
||||
|
||||
#include <new>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define TRACE(x...) debug_printf("HTML5HWInterface: "x)
|
||||
#define TRACE_ALWAYS(x...) debug_printf("HTML5HWInterface: "x)
|
||||
#define TRACE_ERROR(x...) debug_printf("HTML5HWInterface: "x)
|
||||
|
||||
|
||||
struct callback_info {
|
||||
uint32 token;
|
||||
HTML5HWInterface::CallbackFunction callback;
|
||||
void* cookie;
|
||||
};
|
||||
|
||||
|
||||
HTML5HWInterface::HTML5HWInterface(const char* target)
|
||||
:
|
||||
HWInterface(),
|
||||
fTarget(target),
|
||||
fRemoteHost(NULL),
|
||||
fRemotePort(10900),
|
||||
fIsConnected(false),
|
||||
fProtocolVersion(100),
|
||||
fConnectionSpeed(0),
|
||||
fListenPort(10901),
|
||||
fReceiveEndpoint(NULL),
|
||||
fSendBuffer(NULL),
|
||||
fReceiveBuffer(NULL),
|
||||
fServer(NULL),
|
||||
// fSender(NULL),
|
||||
// fReceiver(NULL),
|
||||
fEventThread(-1),
|
||||
fEventStream(NULL),
|
||||
fCallbackLocker("callback locker")
|
||||
{
|
||||
fDisplayMode.virtual_width = 640;
|
||||
fDisplayMode.virtual_height = 480;
|
||||
fDisplayMode.space = B_RGB32;
|
||||
|
||||
//TODO: Cleanup; parse host ??
|
||||
fRemoteHost = strdup(fTarget);
|
||||
if (strncmp(fRemoteHost, "html5:", 6) != 0) {
|
||||
fInitStatus = B_BAD_VALUE;
|
||||
return;
|
||||
}
|
||||
char *portStart = fRemoteHost + 5;//strchr(fRemoteHost + 6, ':');
|
||||
if (portStart != NULL) {
|
||||
portStart[0] = 0;
|
||||
portStart++;
|
||||
if (sscanf(portStart, "%lu", &fRemotePort) != 1) {
|
||||
fInitStatus = B_BAD_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
fListenPort = fRemotePort;
|
||||
}
|
||||
|
||||
fReceiveEndpoint = new(std::nothrow) BNetEndpoint();
|
||||
if (fReceiveEndpoint == NULL) {
|
||||
fInitStatus = B_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
fInitStatus = fReceiveEndpoint->Bind(fListenPort);
|
||||
if (fInitStatus != B_OK)
|
||||
return;
|
||||
|
||||
fSendBuffer = new(std::nothrow) StreamingRingBuffer(16 * 1024);
|
||||
if (fSendBuffer == NULL) {
|
||||
fInitStatus = B_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
fInitStatus = fSendBuffer->InitCheck();
|
||||
if (fInitStatus != B_OK)
|
||||
return;
|
||||
|
||||
fReceiveBuffer = new(std::nothrow) StreamingRingBuffer(16 * 1024);
|
||||
if (fReceiveBuffer == NULL) {
|
||||
fInitStatus = B_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
fInitStatus = fReceiveBuffer->InitCheck();
|
||||
if (fInitStatus != B_OK)
|
||||
return;
|
||||
|
||||
fServer = new(std::nothrow) WebServer(fReceiveEndpoint);
|
||||
if (fServer == NULL) {
|
||||
fInitStatus = B_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
WebHandler *handler;
|
||||
handler = new(std::nothrow) WebHandler("output", fSendBuffer);
|
||||
if (handler == NULL) {
|
||||
fInitStatus = B_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
handler->SetMultipart();
|
||||
handler->SetType("multipart/x-mixed-replace;boundary=x");
|
||||
fServer->AddHandler(handler);
|
||||
|
||||
handler = new(std::nothrow) WebHandler("input", fReceiveBuffer);
|
||||
if (handler == NULL) {
|
||||
fInitStatus = B_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
fServer->AddHandler(handler);
|
||||
|
||||
//static const char desktop_html[] = "<html><head><title>Haiku</title></head>"
|
||||
// "<body></body></html>";
|
||||
handler = new(std::nothrow) WebHandler("desktop.html",
|
||||
new(std::nothrow) BMemoryIO(desktop_html, sizeof(desktop_html) - 1));
|
||||
if (handler == NULL) {
|
||||
fInitStatus = B_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
fServer->AddHandler(handler);
|
||||
|
||||
//static const char haiku_js[] = "window.alert('plop');\n";
|
||||
handler = new(std::nothrow) WebHandler("haiku.js",
|
||||
new(std::nothrow) BMemoryIO(haiku_js, sizeof(haiku_js) - 1));
|
||||
if (handler == NULL) {
|
||||
fInitStatus = B_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
fServer->AddHandler(handler);
|
||||
|
||||
|
||||
fEventStream = new(std::nothrow) CanvasEventStream();
|
||||
if (fEventStream == NULL) {
|
||||
fInitStatus = B_NO_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
// fInitStatus = _Connect();
|
||||
// if (fInitStatus != B_OK)
|
||||
// return;
|
||||
fDisplayMode.virtual_width = 800;
|
||||
fDisplayMode.virtual_height = 600;
|
||||
|
||||
|
||||
fEventThread = spawn_thread(_EventThreadEntry, "HTML5 event thread",
|
||||
B_NORMAL_PRIORITY, this);
|
||||
if (fEventThread < 0) {
|
||||
fInitStatus = fEventThread;
|
||||
return;
|
||||
}
|
||||
|
||||
resume_thread(fEventThread);
|
||||
}
|
||||
|
||||
|
||||
HTML5HWInterface::~HTML5HWInterface()
|
||||
{
|
||||
// delete fReceiver;
|
||||
delete fReceiveBuffer;
|
||||
|
||||
delete fSendBuffer;
|
||||
// delete fSender;
|
||||
|
||||
delete fReceiveEndpoint;
|
||||
// delete fSendEndpoint;
|
||||
delete fServer;
|
||||
|
||||
delete fEventStream;
|
||||
|
||||
free(fRemoteHost);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::Initialize()
|
||||
{
|
||||
return fInitStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::Shutdown()
|
||||
{
|
||||
_Disconnect();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
DrawingEngine*
|
||||
HTML5HWInterface::CreateDrawingEngine()
|
||||
{
|
||||
return new(std::nothrow) HTML5DrawingEngine(this);
|
||||
}
|
||||
|
||||
|
||||
EventStream*
|
||||
HTML5HWInterface::CreateEventStream()
|
||||
{
|
||||
return fEventStream;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::AddCallback(uint32 token, CallbackFunction callback,
|
||||
void* cookie)
|
||||
{
|
||||
BAutolock lock(fCallbackLocker);
|
||||
int32 index = fCallbacks.BinarySearchIndexByKey(token, &_CallbackCompare);
|
||||
if (index >= 0)
|
||||
return B_NAME_IN_USE;
|
||||
|
||||
callback_info* info = new(std::nothrow) callback_info;
|
||||
if (info == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
info->token = token;
|
||||
info->callback = callback;
|
||||
info->cookie = cookie;
|
||||
|
||||
fCallbacks.AddItem(info, -index - 1);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
HTML5HWInterface::RemoveCallback(uint32 token)
|
||||
{
|
||||
BAutolock lock(fCallbackLocker);
|
||||
int32 index = fCallbacks.BinarySearchIndexByKey(token, &_CallbackCompare);
|
||||
if (index < 0)
|
||||
return false;
|
||||
|
||||
delete fCallbacks.RemoveItemAt(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
callback_info*
|
||||
HTML5HWInterface::_FindCallback(uint32 token)
|
||||
{
|
||||
BAutolock lock(fCallbackLocker);
|
||||
return fCallbacks.BinarySearchByKey(token, &_CallbackCompare);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
HTML5HWInterface::_CallbackCompare(const uint32* key,
|
||||
const callback_info* info)
|
||||
{
|
||||
if (info->token == *key)
|
||||
return 0;
|
||||
|
||||
if (info->token < *key)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
HTML5HWInterface::_EventThreadEntry(void* data)
|
||||
{
|
||||
return ((HTML5HWInterface*)data)->_EventThread();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::_EventThread()
|
||||
{
|
||||
CanvasMessage message(fReceiveBuffer, fSendBuffer);
|
||||
while (true) {
|
||||
uint16 code;
|
||||
status_t result = message.NextMessage(code);
|
||||
if (result != B_OK) {
|
||||
TRACE_ERROR("failed to read message from receiver: %s\n",
|
||||
strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
TRACE("got message code %u with %lu bytes\n", code, message.DataLeft());
|
||||
|
||||
if (code >= RP_MOUSE_MOVED && code <= RP_MODIFIERS_CHANGED) {
|
||||
// an input event, dispatch to the event stream
|
||||
if (fEventStream->EventReceived(message))
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case RP_UPDATE_DISPLAY_MODE:
|
||||
{
|
||||
// TODO: implement, we only handle it in the context of the
|
||||
// initial mode setup on connect
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
uint32 token;
|
||||
if (message.Read(token) == B_OK) {
|
||||
callback_info* info = _FindCallback(token);
|
||||
if (info != NULL && info->callback(info->cookie, message))
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE_ERROR("unhandled HTML5 event code %u\n", code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::_Connect()
|
||||
{
|
||||
#if 0
|
||||
TRACE("connecting to host \"%s\" port %lu\n", fRemoteHost, fRemotePort);
|
||||
status_t result = fSendEndpoint->Connect(fRemoteHost, (uint16)fRemotePort);
|
||||
if (result != B_OK) {
|
||||
TRACE_ERROR("failed to connect to host \"%s\" port %lu\n", fRemoteHost,
|
||||
fRemotePort);
|
||||
return result;
|
||||
}
|
||||
|
||||
CanvasMessage message(fReceiveBuffer, fSendBuffer);
|
||||
message.Start(RP_INIT_CONNECTION);
|
||||
message.Add(fListenPort);
|
||||
result = message.Flush();
|
||||
if (result != B_OK) {
|
||||
TRACE_ERROR("failed to send init connection message\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16 code;
|
||||
result = message.NextMessage(code);
|
||||
if (result != B_OK) {
|
||||
TRACE_ERROR("failed to read message from receiver: %s\n",
|
||||
strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
TRACE("code %u with %lu bytes of data\n", code, message.DataLeft());
|
||||
if (code != RP_UPDATE_DISPLAY_MODE) {
|
||||
TRACE_ERROR("invalid connection init code %u\n", code);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
int32 width, height;
|
||||
message.Read(width);
|
||||
result = message.Read(height);
|
||||
if (result != B_OK) {
|
||||
TRACE_ERROR("failed to get initial display mode\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
fDisplayMode.virtual_width = width;
|
||||
fDisplayMode.virtual_height = height;
|
||||
#endif
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HTML5HWInterface::_Disconnect()
|
||||
{
|
||||
if (fIsConnected) {
|
||||
CanvasMessage message(NULL, fSendBuffer);
|
||||
message.Start(RP_CLOSE_CONNECTION);
|
||||
message.Flush();
|
||||
fIsConnected = false;
|
||||
}
|
||||
|
||||
if (fReceiveEndpoint != NULL)
|
||||
fReceiveEndpoint->Close();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::SetMode(const display_mode& mode)
|
||||
{
|
||||
// The display mode depends on the screen resolution of the client, we
|
||||
// don't allow to change it.
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HTML5HWInterface::GetMode(display_mode* mode)
|
||||
{
|
||||
if (mode == NULL || !ReadLock())
|
||||
return;
|
||||
|
||||
*mode = fDisplayMode;
|
||||
ReadUnlock();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::GetDeviceInfo(accelerant_device_info* info)
|
||||
{
|
||||
if (!ReadLock())
|
||||
return B_ERROR;
|
||||
|
||||
info->version = fProtocolVersion;
|
||||
info->dac_speed = fConnectionSpeed;
|
||||
info->memory = 33554432; // 32MB
|
||||
snprintf(info->name, sizeof(info->name), "Haiku, Inc. HTML5HWInterface");
|
||||
snprintf(info->chipset, sizeof(info->chipset), "Haiku, Inc. Chipset");
|
||||
snprintf(info->serial_no, sizeof(info->serial_no), fTarget);
|
||||
|
||||
ReadUnlock();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::GetFrameBufferConfig(frame_buffer_config& config)
|
||||
{
|
||||
// We don't actually have a frame buffer.
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::GetModeList(display_mode** _modes, uint32* _count)
|
||||
{
|
||||
AutoReadLocker _(this);
|
||||
|
||||
display_mode* modes = new(std::nothrow) display_mode[1];
|
||||
if (modes == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
modes[0] = fDisplayMode;
|
||||
*_modes = modes;
|
||||
*_count = 1;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::GetPixelClockLimits(display_mode* mode, uint32* low,
|
||||
uint32* high)
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::GetTimingConstraints(display_timing_constraints* constraints)
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::ProposeMode(display_mode* candidate, const display_mode* low,
|
||||
const display_mode* high)
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::SetDPMSMode(uint32 state)
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
HTML5HWInterface::DPMSMode()
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
HTML5HWInterface::DPMSCapabilities()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
sem_id
|
||||
HTML5HWInterface::RetraceSemaphore()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::WaitForRetrace(bigtime_t timeout)
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HTML5HWInterface::SetCursor(ServerCursor* cursor)
|
||||
{
|
||||
HWInterface::SetCursor(cursor);
|
||||
CanvasMessage message(NULL, fSendBuffer);
|
||||
message.Start(RP_SET_CURSOR);
|
||||
message.AddCursor(Cursor().Get());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HTML5HWInterface::SetCursorVisible(bool visible)
|
||||
{
|
||||
HWInterface::SetCursorVisible(visible);
|
||||
CanvasMessage message(NULL, fSendBuffer);
|
||||
message.Start(RP_SET_CURSOR_VISIBLE);
|
||||
message.Add(visible);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HTML5HWInterface::MoveCursorTo(float x, float y)
|
||||
{
|
||||
HWInterface::MoveCursorTo(x, y);
|
||||
CanvasMessage message(NULL, fSendBuffer);
|
||||
message.Start(RP_MOVE_CURSOR_TO);
|
||||
message.Add(x);
|
||||
message.Add(y);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HTML5HWInterface::SetDragBitmap(const ServerBitmap* bitmap,
|
||||
const BPoint& offsetFromCursor)
|
||||
{
|
||||
HWInterface::SetDragBitmap(bitmap, offsetFromCursor);
|
||||
CanvasMessage message(NULL, fSendBuffer);
|
||||
message.Start(RP_SET_CURSOR);
|
||||
message.AddCursor(CursorAndDragBitmap().Get());
|
||||
}
|
||||
|
||||
|
||||
RenderingBuffer*
|
||||
HTML5HWInterface::FrontBuffer() const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
RenderingBuffer*
|
||||
HTML5HWInterface::BackBuffer() const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
HTML5HWInterface::IsDoubleBuffered() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::InvalidateRegion(BRegion& region)
|
||||
{
|
||||
CanvasMessage message(NULL, fSendBuffer);
|
||||
message.Start(RP_INVALIDATE_REGION);
|
||||
message.AddRegion(region);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::Invalidate(const BRect& frame)
|
||||
{
|
||||
CanvasMessage message(NULL, fSendBuffer);
|
||||
message.Start(RP_INVALIDATE_RECT);
|
||||
message.Add(frame);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
HTML5HWInterface::CopyBackToFront(const BRect& frame)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
131
src/servers/app/drawing/html5/HTML5HWInterface.h
Normal file
131
src/servers/app/drawing/html5/HTML5HWInterface.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* François Revol <revol@free.fr>
|
||||
*/
|
||||
#ifndef HTML5_HW_INTERFACE_H
|
||||
#define HTML5_HW_INTERFACE_H
|
||||
|
||||
#include "HWInterface.h"
|
||||
|
||||
#include <Locker.h>
|
||||
#include <ObjectList.h>
|
||||
|
||||
class BNetEndpoint;
|
||||
class StreamingRingBuffer;
|
||||
class NetSender;
|
||||
class NetReceiver;
|
||||
class CanvasEventStream;
|
||||
class CanvasMessage;
|
||||
class WebServer;
|
||||
|
||||
struct callback_info;
|
||||
|
||||
|
||||
//XXX: CanvasHWInterface ??
|
||||
class HTML5HWInterface : public HWInterface {
|
||||
public:
|
||||
HTML5HWInterface(const char* target);
|
||||
virtual ~HTML5HWInterface();
|
||||
|
||||
virtual status_t Initialize();
|
||||
virtual status_t Shutdown();
|
||||
|
||||
virtual DrawingEngine* CreateDrawingEngine();
|
||||
virtual EventStream* CreateEventStream();
|
||||
|
||||
virtual status_t SetMode(const display_mode& mode);
|
||||
virtual void GetMode(display_mode* mode);
|
||||
|
||||
virtual status_t GetDeviceInfo(accelerant_device_info* info);
|
||||
virtual status_t GetFrameBufferConfig(
|
||||
frame_buffer_config& config);
|
||||
|
||||
virtual status_t GetModeList(display_mode** _modeList,
|
||||
uint32* _count);
|
||||
virtual status_t GetPixelClockLimits(display_mode* mode,
|
||||
uint32* _low, uint32* _high);
|
||||
virtual status_t GetTimingConstraints(
|
||||
display_timing_constraints* constraints);
|
||||
virtual status_t ProposeMode(display_mode* candidate,
|
||||
const display_mode* low,
|
||||
const display_mode* high);
|
||||
|
||||
virtual sem_id RetraceSemaphore();
|
||||
virtual status_t WaitForRetrace(
|
||||
bigtime_t timeout = B_INFINITE_TIMEOUT);
|
||||
|
||||
virtual status_t SetDPMSMode(uint32 state);
|
||||
virtual uint32 DPMSMode();
|
||||
virtual uint32 DPMSCapabilities();
|
||||
|
||||
// cursor handling
|
||||
virtual void SetCursor(ServerCursor* cursor);
|
||||
virtual void SetCursorVisible(bool visible);
|
||||
virtual void MoveCursorTo(float x, float y);
|
||||
virtual void SetDragBitmap(const ServerBitmap* bitmap,
|
||||
const BPoint& offsetFormCursor);
|
||||
|
||||
// frame buffer access
|
||||
virtual RenderingBuffer* FrontBuffer() const;
|
||||
virtual RenderingBuffer* BackBuffer() const;
|
||||
virtual bool IsDoubleBuffered() const;
|
||||
|
||||
virtual status_t InvalidateRegion(BRegion& region);
|
||||
virtual status_t Invalidate(const BRect& frame);
|
||||
virtual status_t CopyBackToFront(const BRect& frame);
|
||||
|
||||
// drawing engine interface
|
||||
StreamingRingBuffer* ReceiveBuffer() { return fReceiveBuffer; }
|
||||
StreamingRingBuffer* SendBuffer() { return fSendBuffer; }
|
||||
|
||||
typedef bool (*CallbackFunction)(void* cookie, CanvasMessage& message);
|
||||
|
||||
status_t AddCallback(uint32 token,
|
||||
CallbackFunction callback,
|
||||
void* cookie);
|
||||
bool RemoveCallback(uint32 token);
|
||||
|
||||
private:
|
||||
callback_info* _FindCallback(uint32 token);
|
||||
static int _CallbackCompare(const uint32* key,
|
||||
const callback_info* info);
|
||||
|
||||
static int32 _EventThreadEntry(void* data);
|
||||
status_t _EventThread();
|
||||
|
||||
status_t _Connect();
|
||||
void _Disconnect();
|
||||
|
||||
const char* fTarget;
|
||||
char* fRemoteHost;
|
||||
uint32 fRemotePort;
|
||||
|
||||
status_t fInitStatus;
|
||||
bool fIsConnected;
|
||||
uint32 fProtocolVersion;
|
||||
uint32 fConnectionSpeed;
|
||||
display_mode fDisplayMode;
|
||||
uint16 fListenPort;
|
||||
|
||||
// BNetEndpoint* fSendEndpoint;
|
||||
BNetEndpoint* fReceiveEndpoint;
|
||||
|
||||
StreamingRingBuffer* fSendBuffer;
|
||||
StreamingRingBuffer* fReceiveBuffer;
|
||||
|
||||
WebServer* fServer;
|
||||
// NetSender* fSender;
|
||||
// NetReceiver* fReceiver;
|
||||
|
||||
thread_id fEventThread;
|
||||
CanvasEventStream* fEventStream;
|
||||
|
||||
BLocker fCallbackLocker;
|
||||
BObjectList<callback_info> fCallbacks;
|
||||
};
|
||||
|
||||
#endif // HTML5_HW_INTERFACE_H
|
32
src/servers/app/drawing/html5/Jamfile
Normal file
32
src/servers/app/drawing/html5/Jamfile
Normal file
@ -0,0 +1,32 @@
|
||||
SubDir HAIKU_TOP src servers app drawing html5 ;
|
||||
|
||||
UseLibraryHeaders agg ;
|
||||
UsePrivateHeaders app graphics interface kernel shared ;
|
||||
UsePrivateHeaders [ FDirName graphics common ] ;
|
||||
UsePrivateSystemHeaders ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src servers app ] ;
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src servers app font ] ;
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing ] ;
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter ] ;
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter drawing_modes ] ;
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter font_support ] ;
|
||||
UseHeaders $(HAIKU_FREETYPE_HEADERS) : true ;
|
||||
|
||||
StaticLibrary libashtml5.a :
|
||||
base64.cpp
|
||||
|
||||
#NetReceiver.cpp
|
||||
#NetSender.cpp
|
||||
|
||||
HTML5DrawingEngine.cpp
|
||||
CanvasEventStream.cpp
|
||||
HTML5HWInterface.cpp
|
||||
CanvasMessage.cpp
|
||||
|
||||
StreamingRingBuffer.cpp
|
||||
|
||||
WebHandler.cpp
|
||||
WebServer.cpp
|
||||
WebWorker.cpp
|
||||
;
|
75
src/servers/app/drawing/html5/NetSender.cpp
Normal file
75
src/servers/app/drawing/html5/NetSender.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
*/
|
||||
|
||||
#include "NetSender.h"
|
||||
|
||||
#include "StreamingRingBuffer.h"
|
||||
|
||||
#include <NetEndpoint.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TRACE(x...) /*debug_printf("NetSender: "x)*/
|
||||
#define TRACE_ERROR(x...) debug_printf("NetSender: "x)
|
||||
|
||||
|
||||
NetSender::NetSender(BNetEndpoint *endpoint, StreamingRingBuffer *source)
|
||||
:
|
||||
fEndpoint(endpoint),
|
||||
fSource(source),
|
||||
fSenderThread(-1),
|
||||
fStopThread(false)
|
||||
{
|
||||
fSenderThread = spawn_thread(_NetworkSenderEntry, "network sender",
|
||||
B_NORMAL_PRIORITY, this);
|
||||
resume_thread(fSenderThread);
|
||||
}
|
||||
|
||||
|
||||
NetSender::~NetSender()
|
||||
{
|
||||
fStopThread = true;
|
||||
int32 result;
|
||||
wait_for_thread(fSenderThread, &result);
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
NetSender::_NetworkSenderEntry(void *data)
|
||||
{
|
||||
return ((NetSender *)data)->_NetworkSender();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
NetSender::_NetworkSender()
|
||||
{
|
||||
while (!fStopThread) {
|
||||
uint8 buffer[4096];
|
||||
int32 readSize = fSource->Read(buffer, sizeof(buffer), true);
|
||||
if (readSize < 0) {
|
||||
TRACE_ERROR("read failed, stopping sender thread: %s\n",
|
||||
strerror(readSize));
|
||||
return readSize;
|
||||
}
|
||||
|
||||
while (readSize > 0) {
|
||||
int32 sendSize = fEndpoint->Send(buffer, readSize);
|
||||
if (sendSize < 0) {
|
||||
TRACE_ERROR("sending data failed: %s\n", strerror(sendSize));
|
||||
return sendSize;
|
||||
}
|
||||
|
||||
readSize -= sendSize;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
34
src/servers/app/drawing/html5/NetSender.h
Normal file
34
src/servers/app/drawing/html5/NetSender.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
*/
|
||||
#ifndef NET_SENDER_H
|
||||
#define NET_SENDER_H
|
||||
|
||||
#include <OS.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class BNetEndpoint;
|
||||
class StreamingRingBuffer;
|
||||
|
||||
class NetSender {
|
||||
public:
|
||||
NetSender(BNetEndpoint *endpoint,
|
||||
StreamingRingBuffer *source);
|
||||
~NetSender();
|
||||
|
||||
private:
|
||||
static int32 _NetworkSenderEntry(void *data);
|
||||
status_t _NetworkSender();
|
||||
|
||||
BNetEndpoint * fEndpoint;
|
||||
StreamingRingBuffer * fSource;
|
||||
|
||||
thread_id fSenderThread;
|
||||
bool fStopThread;
|
||||
};
|
||||
|
||||
#endif // NET_SENDER_H
|
176
src/servers/app/drawing/html5/StreamingRingBuffer.cpp
Normal file
176
src/servers/app/drawing/html5/StreamingRingBuffer.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
*/
|
||||
|
||||
#include "StreamingRingBuffer.h"
|
||||
|
||||
#include <Autolock.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TRACE(x...) /*debug_printf("StreamingRingBuffer: "x)*/
|
||||
#define TRACE_ERROR(x...) debug_printf("StreamingRingBuffer: "x)
|
||||
|
||||
|
||||
StreamingRingBuffer::StreamingRingBuffer(size_t bufferSize)
|
||||
:
|
||||
fReaderWaiting(false),
|
||||
fWriterWaiting(false),
|
||||
fReaderNotifier(-1),
|
||||
fWriterNotifier(-1),
|
||||
fReaderLocker("StreamingRingBuffer reader"),
|
||||
fWriterLocker("StreamingRingBuffer writer"),
|
||||
fDataLocker("StreamingRingBuffer data"),
|
||||
fBuffer(NULL),
|
||||
fBufferSize(bufferSize),
|
||||
fReadable(0),
|
||||
fReadPosition(0),
|
||||
fWritePosition(0)
|
||||
{
|
||||
fReaderNotifier = create_sem(0, "StreamingRingBuffer read notify");
|
||||
fWriterNotifier = create_sem(0, "StreamingRingBuffer write notify");
|
||||
|
||||
fBuffer = (uint8 *)malloc(fBufferSize);
|
||||
if (fBuffer == NULL)
|
||||
fBufferSize = 0;
|
||||
}
|
||||
|
||||
|
||||
StreamingRingBuffer::~StreamingRingBuffer()
|
||||
{
|
||||
delete_sem(fReaderNotifier);
|
||||
delete_sem(fWriterNotifier);
|
||||
free(fBuffer);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
StreamingRingBuffer::InitCheck()
|
||||
{
|
||||
if (fReaderNotifier < 0)
|
||||
return fReaderNotifier;
|
||||
if (fWriterNotifier < 0)
|
||||
return fWriterNotifier;
|
||||
if (fBuffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
StreamingRingBuffer::Read(void *buffer, size_t length, bool onlyBlockOnNoData)
|
||||
{
|
||||
BAutolock readerLock(fReaderLocker);
|
||||
if (!readerLock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
BAutolock dataLock(fDataLocker);
|
||||
if (!dataLock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
int32 readSize = 0;
|
||||
while (length > 0) {
|
||||
size_t copyLength = min_c(length, fBufferSize - fReadPosition);
|
||||
copyLength = min_c(copyLength, fReadable);
|
||||
|
||||
if (copyLength == 0) {
|
||||
if (onlyBlockOnNoData && readSize > 0)
|
||||
return readSize;
|
||||
|
||||
fReaderWaiting = true;
|
||||
dataLock.Unlock();
|
||||
|
||||
status_t result;
|
||||
do {
|
||||
TRACE("waiting in reader\n");
|
||||
result = acquire_sem(fReaderNotifier);
|
||||
TRACE("done waiting in reader with status: 0x%08lx\n", result);
|
||||
} while (result == B_INTERRUPTED);
|
||||
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if (!dataLock.Lock())
|
||||
return B_ERROR;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// support discarding input
|
||||
if (buffer != NULL) {
|
||||
memcpy(buffer, fBuffer + fReadPosition, copyLength);
|
||||
buffer = (uint8 *)buffer + copyLength;
|
||||
}
|
||||
|
||||
fReadPosition = (fReadPosition + copyLength) % fBufferSize;
|
||||
fReadable -= copyLength;
|
||||
readSize += copyLength;
|
||||
length -= copyLength;
|
||||
|
||||
if (fWriterWaiting) {
|
||||
release_sem_etc(fWriterNotifier, 1, B_DO_NOT_RESCHEDULE);
|
||||
fWriterWaiting = false;
|
||||
}
|
||||
}
|
||||
|
||||
return readSize;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
StreamingRingBuffer::Write(const void *buffer, size_t length)
|
||||
{
|
||||
BAutolock writerLock(fWriterLocker);
|
||||
if (!writerLock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
BAutolock dataLock(fDataLocker);
|
||||
if (!dataLock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
while (length > 0) {
|
||||
size_t copyLength = min_c(length, fBufferSize - fWritePosition);
|
||||
copyLength = min_c(copyLength, fBufferSize - fReadable);
|
||||
|
||||
if (copyLength == 0) {
|
||||
fWriterWaiting = true;
|
||||
dataLock.Unlock();
|
||||
|
||||
status_t result;
|
||||
do {
|
||||
TRACE("waiting in writer\n");
|
||||
result = acquire_sem(fWriterNotifier);
|
||||
TRACE("done waiting in writer with status: 0x%08lx\n", result);
|
||||
} while (result == B_INTERRUPTED);
|
||||
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if (!dataLock.Lock())
|
||||
return B_ERROR;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(fBuffer + fWritePosition, buffer, copyLength);
|
||||
fWritePosition = (fWritePosition + copyLength) % fBufferSize;
|
||||
fReadable += copyLength;
|
||||
|
||||
buffer = (uint8 *)buffer + copyLength;
|
||||
length -= copyLength;
|
||||
|
||||
if (fReaderWaiting) {
|
||||
release_sem_etc(fReaderNotifier, 1, B_DO_NOT_RESCHEDULE);
|
||||
fReaderWaiting = false;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
47
src/servers/app/drawing/html5/StreamingRingBuffer.h
Normal file
47
src/servers/app/drawing/html5/StreamingRingBuffer.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
*/
|
||||
#ifndef STREAMING_RING_BUFFER_H
|
||||
#define STREAMING_RING_BUFFER_H
|
||||
|
||||
#include <OS.h>
|
||||
#include <SupportDefs.h>
|
||||
#include <Locker.h>
|
||||
|
||||
class StreamingRingBuffer {
|
||||
public:
|
||||
StreamingRingBuffer(size_t bufferSize);
|
||||
~StreamingRingBuffer();
|
||||
|
||||
status_t InitCheck();
|
||||
|
||||
// blocking read and write
|
||||
int32 Read(void *buffer, size_t length,
|
||||
bool onlyBlockOnNoData = false);
|
||||
status_t Write(const void *buffer, size_t length);
|
||||
|
||||
private:
|
||||
bool _Lock();
|
||||
void _Unlock();
|
||||
|
||||
bool fReaderWaiting;
|
||||
bool fWriterWaiting;
|
||||
sem_id fReaderNotifier;
|
||||
sem_id fWriterNotifier;
|
||||
|
||||
BLocker fReaderLocker;
|
||||
BLocker fWriterLocker;
|
||||
BLocker fDataLocker;
|
||||
|
||||
uint8 * fBuffer;
|
||||
size_t fBufferSize;
|
||||
size_t fReadable;
|
||||
int32 fReadPosition;
|
||||
int32 fWritePosition;
|
||||
};
|
||||
|
||||
#endif // STREAMING_RING_BUFFER_H
|
85
src/servers/app/drawing/html5/WebHandler.cpp
Normal file
85
src/servers/app/drawing/html5/WebHandler.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* François Revol <revol@free.fr>
|
||||
*/
|
||||
|
||||
#include "WebHandler.h"
|
||||
|
||||
#include "StreamingRingBuffer.h"
|
||||
|
||||
#include <NetEndpoint.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TRACE(x...) debug_printf("WebHandler: "x)
|
||||
#define TRACE_ERROR(x...) debug_printf("WebHandler: "x)
|
||||
|
||||
|
||||
WebHandler::WebHandler(const char *path, BDataIO *data)
|
||||
:
|
||||
fPath(path),
|
||||
fMultipart(false),
|
||||
fType(""),
|
||||
fData(data),
|
||||
fTarget(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
WebHandler::WebHandler(const char *path, StreamingRingBuffer *target)
|
||||
:
|
||||
fPath(path),
|
||||
fMultipart(false),
|
||||
fType(""),
|
||||
fData(NULL),
|
||||
fTarget(target)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
WebHandler::~WebHandler()
|
||||
{
|
||||
delete fData;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WebHandler::HandleRequest(WebWorker *worker, BString &path)
|
||||
{
|
||||
// off_t offset = 0LL;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WebHandler::_CallbackCompare(const BString* key,
|
||||
const WebHandler* info)
|
||||
{
|
||||
int diff = strcmp(*key, info->fPath.String());
|
||||
TRACE("'%s' <> '%s' %d\n", key->String(), info->fPath.String(), diff);
|
||||
if (diff == 0)
|
||||
return 0;
|
||||
if (diff < 0)
|
||||
return -1;
|
||||
return 1;
|
||||
// return strcmp(*key, info->fPath.String());
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WebHandler::_CallbackCompare(const WebHandler* a, const WebHandler* b)
|
||||
{
|
||||
int diff = strcmp(a->fPath.String(), b->fPath.String());
|
||||
return diff;
|
||||
// return strcmp(*key, info->fPath.String());
|
||||
}
|
||||
|
||||
|
||||
|
58
src/servers/app/drawing/html5/WebHandler.h
Normal file
58
src/servers/app/drawing/html5/WebHandler.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* François Revol <revol@free.fr>
|
||||
*/
|
||||
#ifndef WEB_HANDLER_H
|
||||
#define WEB_HANDLER_H
|
||||
|
||||
#include <OS.h>
|
||||
#include <String.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class BNetEndpoint;
|
||||
class StreamingRingBuffer;
|
||||
class BDataIO;
|
||||
class WebWorker;
|
||||
|
||||
class WebHandler {
|
||||
public:
|
||||
WebHandler(const char *path,
|
||||
BDataIO *data=NULL);
|
||||
WebHandler(const char *path,
|
||||
StreamingRingBuffer *target);
|
||||
virtual ~WebHandler();
|
||||
|
||||
void SetMultipart(bool multipart=true) {
|
||||
fMultipart = true; }
|
||||
bool IsMultipart() { return fMultipart; }
|
||||
void SetType(const char *type) { fType = type; }
|
||||
|
||||
|
||||
BString & Name() { return fPath; }
|
||||
// BNetEndpoint * Endpoint() { return fEndpoint; }
|
||||
virtual status_t HandleRequest(WebWorker *worker,
|
||||
BString &path);
|
||||
|
||||
static int _CallbackCompare(const BString* key,
|
||||
const WebHandler* info);
|
||||
static int _CallbackCompare(const WebHandler* a,
|
||||
const WebHandler* b);
|
||||
|
||||
private:
|
||||
friend class WebWorker;
|
||||
BString fPath;
|
||||
|
||||
bool fMultipart;
|
||||
BString fType; // MIME
|
||||
BDataIO * fData;
|
||||
StreamingRingBuffer * fTarget;
|
||||
|
||||
thread_id fReceiverThread;
|
||||
bool fStopThread;
|
||||
};
|
||||
|
||||
#endif // WEB_HANDLER_H
|
155
src/servers/app/drawing/html5/WebServer.cpp
Normal file
155
src/servers/app/drawing/html5/WebServer.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* François Revol <revol@free.fr>
|
||||
*/
|
||||
|
||||
#include "WebHandler.h"
|
||||
#include "WebServer.h"
|
||||
#include "WebWorker.h"
|
||||
|
||||
#include "StreamingRingBuffer.h"
|
||||
|
||||
#include <NetEndpoint.h>
|
||||
#include <Autolock.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TRACE(x...) debug_printf("WebServer: "x)
|
||||
#define TRACE_ERROR(x...) debug_printf("WebServer: "x)
|
||||
|
||||
|
||||
WebServer::WebServer(BNetEndpoint *listener)
|
||||
:
|
||||
fListener(listener),
|
||||
fReceiverThread(-1),
|
||||
fStopThread(false),
|
||||
fLocker("WebServer locker")
|
||||
{
|
||||
fReceiverThread = spawn_thread(_NetworkReceiverEntry, "html5 server",
|
||||
B_NORMAL_PRIORITY, this);
|
||||
resume_thread(fReceiverThread);
|
||||
}
|
||||
|
||||
|
||||
WebServer::~WebServer()
|
||||
{
|
||||
fStopThread = true;
|
||||
|
||||
if (fListener != NULL)
|
||||
fListener->Close();
|
||||
|
||||
//int32 result;
|
||||
//wait_for_thread(fReceiverThread, &result);
|
||||
// TODO: find out why closing the endpoint doesn't notify the waiter
|
||||
|
||||
kill_thread(fReceiverThread);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WebServer::AddHandler(WebHandler *handler)
|
||||
{
|
||||
BAutolock lock(fLocker);
|
||||
fHandlers.AddItem(handler);
|
||||
}
|
||||
|
||||
int32
|
||||
WebServer::_NetworkReceiverEntry(void *data)
|
||||
{
|
||||
return ((WebServer *)data)->_NetworkReceiver();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WebServer::_NetworkReceiver()
|
||||
{
|
||||
status_t result = fListener->Listen();
|
||||
if (result != B_OK) {
|
||||
TRACE_ERROR("failed to listen on port: %s\n", strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
fHandlers.SortItems(&WebHandler::_CallbackCompare);
|
||||
|
||||
while (!fStopThread) {
|
||||
BNetEndpoint *endpoint = fListener->Accept(1000);
|
||||
if (endpoint == NULL)
|
||||
continue;
|
||||
|
||||
TRACE("new endpoint connection: %p\n", endpoint);
|
||||
while (!fStopThread) {
|
||||
int32 errorCount = 0;
|
||||
uint8 buffer[4096];
|
||||
int32 readSize = endpoint->Receive(buffer, sizeof(buffer) - 1);
|
||||
if (readSize < 0) {
|
||||
TRACE_ERROR("read failed, closing connection: %s\n",
|
||||
strerror(readSize));
|
||||
delete endpoint;
|
||||
break;
|
||||
}
|
||||
|
||||
if (readSize == 0) {
|
||||
TRACE("read 0 bytes, retrying\n");
|
||||
snooze(100 * 1000);
|
||||
errorCount++;
|
||||
if (errorCount == 5) {
|
||||
TRACE_ERROR("failed to read, assuming disconnect\n");
|
||||
delete endpoint;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
buffer[readSize] = '\0';
|
||||
|
||||
const char err404[] = "HTTP/1.1 404 Not found\r\n\r\n";
|
||||
|
||||
// XXX: HACK HACK HACK
|
||||
const char *p = (const char *)buffer;
|
||||
if (strncmp(p, "GET ", 4) == 0) {
|
||||
p += 4;
|
||||
const char *s = strchr(p, ' ');
|
||||
if (s && strncmp(s, " HTTP/", 6) == 0) {
|
||||
if (*p == '/')
|
||||
p++;
|
||||
BString path(p, s - p);
|
||||
if (p == s)
|
||||
path = "desktop.html";
|
||||
TRACE("searching handler for '%s'\n", path.String());
|
||||
WebHandler *handler = fHandlers.BinarySearchByKey(
|
||||
path, &WebHandler::_CallbackCompare);
|
||||
if (handler) {
|
||||
TRACE("found handler '%s'\n", handler->Name().String());
|
||||
WebWorker *worker =
|
||||
new (std::nothrow) WebWorker(endpoint, handler);
|
||||
if (worker) {
|
||||
fWorkers.AddItem(worker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// some error
|
||||
endpoint->Send(err404, sizeof(err404) - 1);
|
||||
delete endpoint;
|
||||
break;
|
||||
|
||||
#if 0
|
||||
status_t result = fTarget->Write(buffer, readSize);
|
||||
if (result != B_OK) {
|
||||
TRACE_ERROR("writing to ring buffer failed: %s\n",
|
||||
strerror(result));
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
47
src/servers/app/drawing/html5/WebServer.h
Normal file
47
src/servers/app/drawing/html5/WebServer.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* François Revol <revol@free.fr>
|
||||
*/
|
||||
#ifndef WEB_SERVER_H
|
||||
#define WEB_SERVER_H
|
||||
|
||||
//#include "WebWorker.h"
|
||||
|
||||
#include <Locker.h>
|
||||
#include <ObjectList.h>
|
||||
#include <OS.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class BNetEndpoint;
|
||||
class WebHandler;
|
||||
class WebWorker;
|
||||
|
||||
class WebServer {
|
||||
public:
|
||||
WebServer(BNetEndpoint *listener);
|
||||
~WebServer();
|
||||
|
||||
// BNetEndpoint * Endpoint() { return fEndpoint; }
|
||||
|
||||
void AddHandler(WebHandler *handler);
|
||||
|
||||
private:
|
||||
static int32 _NetworkReceiverEntry(void *data);
|
||||
status_t _NetworkReceiver();
|
||||
|
||||
BNetEndpoint * fListener;
|
||||
|
||||
thread_id fReceiverThread;
|
||||
bool fStopThread;
|
||||
|
||||
BLocker fLocker;
|
||||
BObjectList<WebHandler> fHandlers;
|
||||
BObjectList<WebWorker> fWorkers;
|
||||
// BNetEndpoint * fEndpoint;
|
||||
};
|
||||
|
||||
#endif // WEB_SERVER_H
|
152
src/servers/app/drawing/html5/WebWorker.cpp
Normal file
152
src/servers/app/drawing/html5/WebWorker.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* François Revol <revol@free.fr>
|
||||
*/
|
||||
|
||||
#include "WebHandler.h"
|
||||
#include "WebWorker.h"
|
||||
|
||||
#include "StreamingRingBuffer.h"
|
||||
|
||||
#include <NetEndpoint.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TRACE(x...) debug_printf("WebWorker: "x)
|
||||
#define TRACE_ERROR(x...) debug_printf("WebWorker: "x)
|
||||
|
||||
|
||||
WebWorker::WebWorker(BNetEndpoint *endpoint, WebHandler *handler)
|
||||
:
|
||||
fHandler(handler),
|
||||
fWorkThread(-1),
|
||||
fStopThread(false),
|
||||
fEndpoint(endpoint)
|
||||
{
|
||||
fWorkThread = spawn_thread(_WorkEntry, "html5 http worker",
|
||||
B_NORMAL_PRIORITY, this);
|
||||
resume_thread(fWorkThread);
|
||||
}
|
||||
|
||||
|
||||
WebWorker::~WebWorker()
|
||||
{
|
||||
fStopThread = true;
|
||||
|
||||
if (fEndpoint != NULL)
|
||||
fEndpoint->Close();
|
||||
|
||||
//int32 result;
|
||||
//wait_for_thread(fWorkThread, &result);
|
||||
// TODO: find out why closing the endpoint doesn't notify the waiter
|
||||
|
||||
kill_thread(fWorkThread);
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
WebWorker::_WorkEntry(void *data)
|
||||
{
|
||||
return ((WebWorker *)data)->_Work();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
WebWorker::_Work()
|
||||
{
|
||||
off_t pos = 0LL, contentSize = -1LL;
|
||||
int32 errorCount = 0;
|
||||
status_t result;
|
||||
TRACE("new endpoint connection: %p\n", fEndpoint);
|
||||
|
||||
BDataIO *io = fHandler->fData;
|
||||
BPositionIO *pio = dynamic_cast<BPositionIO *>(io);
|
||||
StreamingRingBuffer *rb = fHandler->fTarget;
|
||||
|
||||
if (pio)
|
||||
pio->GetSize(&contentSize);
|
||||
|
||||
BString headers("HTTP/1.1 200 OK\r\n");
|
||||
headers << "Server: app_server(Haiku)\r\n";
|
||||
headers << "Accept-Ranges: bytes\r\n";
|
||||
headers << "Connection: ";
|
||||
if (fHandler->IsMultipart())
|
||||
headers << "close";
|
||||
else
|
||||
headers << "keep-alive";
|
||||
headers << "\r\n";
|
||||
if (fHandler->fType.Length())
|
||||
headers << "Content-Type: " << fHandler->fType << "\r\n";
|
||||
if (contentSize > 0)
|
||||
headers << "Content-Length: " << contentSize << "\r\n";
|
||||
headers << "\r\n";
|
||||
|
||||
result = fEndpoint->Send(headers.String(), headers.Length());
|
||||
if (result < headers.Length()) {
|
||||
TRACE_ERROR("sending headers failed: %s\n",
|
||||
strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
// send initial multipart boundary
|
||||
// XXX: this is messy!
|
||||
if (fHandler->IsMultipart()) {
|
||||
static const char boundary[] = "--x\r\n\r\n";
|
||||
result = fEndpoint->Send(boundary, sizeof(boundary) - 1);
|
||||
if (result < (signed)sizeof(boundary) - 1) {
|
||||
TRACE_ERROR("writing to peer failed: %s\n",
|
||||
strerror(result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
while (!fStopThread) {
|
||||
uint8 buffer[4096];
|
||||
int32 readSize = 0;
|
||||
if (pio)
|
||||
readSize = pio->ReadAt(pos, buffer, sizeof(buffer));
|
||||
else if (io)
|
||||
readSize = io->Read(buffer, sizeof(buffer));
|
||||
else if (rb)
|
||||
readSize = rb->Read(buffer, sizeof(buffer));
|
||||
TRACE("readSize %ld\n", readSize);
|
||||
|
||||
if (readSize < 0) {
|
||||
TRACE_ERROR("read failed, closing connection: %s\n",
|
||||
strerror(readSize));
|
||||
return readSize;
|
||||
}
|
||||
|
||||
if (readSize == 0) {
|
||||
//XXX:should just break;
|
||||
// TRACE("read 0 bytes, retrying\n");
|
||||
snooze(100 * 1000);
|
||||
errorCount++;
|
||||
if (errorCount == 5) {
|
||||
TRACE_ERROR("failed to read, assuming disconnect\n");
|
||||
fEndpoint->Close();
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
pos += readSize;
|
||||
|
||||
errorCount = 0;
|
||||
result = fEndpoint->Send(buffer, readSize);
|
||||
TRACE("writeSize %ld\n", result);
|
||||
if (result < readSize) {
|
||||
TRACE_ERROR("writing to peer failed: %s\n",
|
||||
strerror(result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
39
src/servers/app/drawing/html5/WebWorker.h
Normal file
39
src/servers/app/drawing/html5/WebWorker.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* François Revol <revol@free.fr>
|
||||
*/
|
||||
#ifndef WEB_WORKER_H
|
||||
#define WEB_WORKER_H
|
||||
|
||||
#include <OS.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class BNetEndpoint;
|
||||
class StreamingRingBuffer;
|
||||
class WebHandler;
|
||||
|
||||
class WebWorker {
|
||||
public:
|
||||
WebWorker(BNetEndpoint *endpoint,
|
||||
WebHandler *handler);
|
||||
~WebWorker();
|
||||
|
||||
BNetEndpoint * Endpoint() { return fEndpoint; }
|
||||
|
||||
private:
|
||||
static int32 _WorkEntry(void *data);
|
||||
status_t _Work();
|
||||
|
||||
WebHandler * fHandler;
|
||||
|
||||
thread_id fWorkThread;
|
||||
bool fStopThread;
|
||||
|
||||
BNetEndpoint * fEndpoint;
|
||||
};
|
||||
|
||||
#endif // WEB_WORKER_H
|
115
src/servers/app/drawing/html5/base64.cpp
Normal file
115
src/servers/app/drawing/html5/base64.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2011, Haiku, Inc. All rights reserved.
|
||||
* Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <mail_encoding.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
static const char kBase64Alphabet[64] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'+',
|
||||
'/'
|
||||
};
|
||||
|
||||
static const char kHexAlphabet[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8','9','A','B','C','D','E','F'};
|
||||
|
||||
|
||||
ssize_t
|
||||
encode_base64(char *out, const char *in, off_t length)
|
||||
{
|
||||
uint32 concat;
|
||||
int i = 0;
|
||||
int k = 0;
|
||||
|
||||
while (i < length) {
|
||||
concat = ((in[i] & 0xff) << 16);
|
||||
|
||||
if ((i+1) < length)
|
||||
concat |= ((in[i+1] & 0xff) << 8);
|
||||
if ((i+2) < length)
|
||||
concat |= (in[i+2] & 0xff);
|
||||
|
||||
i += 3;
|
||||
|
||||
out[k++] = kBase64Alphabet[(concat >> 18) & 63];
|
||||
out[k++] = kBase64Alphabet[(concat >> 12) & 63];
|
||||
if ((i+1) < length)
|
||||
out[k++] = kBase64Alphabet[(concat >> 6) & 63];
|
||||
if ((i+2) < length)
|
||||
out[k++] = kBase64Alphabet[concat & 63];
|
||||
}
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
decode_base64(char *out, const char *in, off_t length)
|
||||
{
|
||||
uint32 concat, value;
|
||||
int lastOutLine = 0;
|
||||
int i, j;
|
||||
int outIndex = 0;
|
||||
|
||||
for (i = 0; i < length; i += 4) {
|
||||
concat = 0;
|
||||
|
||||
for (j = 0; j < 4 && (i + j) < length; j++) {
|
||||
value = in[i + j];
|
||||
|
||||
if (value == '\n' || value == '\r') {
|
||||
// jump over line breaks
|
||||
lastOutLine = outIndex;
|
||||
i++;
|
||||
j--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((value >= 'A') && (value <= 'Z'))
|
||||
value -= 'A';
|
||||
else if ((value >= 'a') && (value <= 'z'))
|
||||
value = value - 'a' + 26;
|
||||
else if ((value >= '0') && (value <= '9'))
|
||||
value = value - '0' + 52;
|
||||
else if (value == '+')
|
||||
value = 62;
|
||||
else if (value == '/')
|
||||
value = 63;
|
||||
else if (value == '=')
|
||||
break;
|
||||
else {
|
||||
// there is an invalid character in this line - we will
|
||||
// ignore the whole line and go to the next
|
||||
outIndex = lastOutLine;
|
||||
while (i < length && in[i] != '\n' && in[i] != '\r')
|
||||
i++;
|
||||
concat = 0;
|
||||
}
|
||||
|
||||
value = value << ((3-j)*6);
|
||||
|
||||
concat |= value;
|
||||
}
|
||||
|
||||
if (j > 1)
|
||||
out[outIndex++] = (concat & 0x00ff0000) >> 16;
|
||||
if (j > 2)
|
||||
out[outIndex++] = (concat & 0x0000ff00) >> 8;
|
||||
if (j > 3)
|
||||
out[outIndex++] = (concat & 0x000000ff);
|
||||
}
|
||||
|
||||
return outIndex;
|
||||
}
|
||||
|
||||
|
15
src/servers/app/drawing/html5/base64.h
Normal file
15
src/servers/app/drawing/html5/base64.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2011, Haiku, Inc. All rights reserved.
|
||||
* Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
#ifndef BASE64_H
|
||||
#define BASE64_H
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
extern ssize_t encode_base64(char *out, const char *in, off_t length);
|
||||
extern ssize_t decode_base64(char *out, const char *in, off_t length);
|
||||
|
||||
|
||||
#endif // BASE64_H
|
29
src/servers/app/drawing/html5/desktop.html
Normal file
29
src/servers/app/drawing/html5/desktop.html
Normal file
@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<!-- Haiku HTML5 desktop -->
|
||||
<!-- Loosely inspired by the Broadway GDK backend, just done differently -->
|
||||
<head>
|
||||
<title>Haiku</title>
|
||||
<meta name="robots" content="noindex, nofollow, noarchive" />
|
||||
<style type="text/css">
|
||||
<!--
|
||||
/* basic style */
|
||||
body { background-color: #336698; }
|
||||
a:link { color:orange; }
|
||||
a:visited { color:darkorange; }
|
||||
a:hover { color:pink; }
|
||||
.haiku_online_form { color: white; }
|
||||
.haiku_online_disabled { color: grey; }
|
||||
.haiku_online_out { color: white; }
|
||||
.haiku_online_debug { color: orange; }
|
||||
.haiku_online_error { color: red; font-weight: bold; }
|
||||
-->
|
||||
</style>
|
||||
<script type="text/javascript" src="/haiku.js"></script>
|
||||
<link rel="shortcut icon" href="http://haiku-os.org/sites/haiku-os.org/themes/shijin/favicon.ico" type="image/x-icon" />
|
||||
</head>
|
||||
<body onload="onPageLoad()" onunload="onPageUnload()">
|
||||
<canvas id="desktop">Your browser does not support the <canvas> element, which is required.</canvas>
|
||||
<noscript>Your browser does not support javascript or javascript is disabled.</noscript>
|
||||
<div id="log"></div>
|
||||
</body>
|
||||
</html>
|
30
src/servers/app/drawing/html5/desktop.html.h
Normal file
30
src/servers/app/drawing/html5/desktop.html.h
Normal file
@ -0,0 +1,30 @@
|
||||
static const char desktop_html[] =
|
||||
"<html>\n"
|
||||
"<!-- Haiku HTML5 desktop -->\n"
|
||||
"<!-- Loosely inspired by the Broadway GDK backend, just done differently -->\n"
|
||||
"<head>\n"
|
||||
"<title>Haiku</title>\n"
|
||||
"<meta name=\"robots\" content=\"noindex, nofollow, noarchive\" />\n"
|
||||
"<style type=\"text/css\">\n"
|
||||
"<!--\n"
|
||||
"/* basic style */\n"
|
||||
"body { background-color: #336698; }\n"
|
||||
"a:link { color:orange; }\n"
|
||||
"a:visited { color:darkorange; }\n"
|
||||
"a:hover { color:pink; }\n"
|
||||
".haiku_online_form { color: white; }\n"
|
||||
".haiku_online_disabled { color: grey; }\n"
|
||||
".haiku_online_out { color: white; }\n"
|
||||
".haiku_online_debug { color: orange; }\n"
|
||||
".haiku_online_error { color: red; font-weight: bold; }\n"
|
||||
"-->\n"
|
||||
"</style>\n"
|
||||
"<script type=\"text/javascript\" src=\"/haiku.js\"></script>\n"
|
||||
"<link rel=\"shortcut icon\" href=\"http://haiku-os.org/sites/haiku-os.org/themes/shijin/favicon.ico\" type=\"image/x-icon\" />\n"
|
||||
"</head>\n"
|
||||
"<body onload=\"onPageLoad()\" onunload=\"onPageUnload()\">\n"
|
||||
"<canvas id=\"desktop\">Your browser does not support the <canvas> element, which is required.</canvas>\n"
|
||||
"<noscript>Your browser does not support javascript or javascript is disabled.</noscript>\n"
|
||||
"<div id=\"log\"></div>\n"
|
||||
"</body>\n"
|
||||
"</html>\n";
|
100
src/servers/app/drawing/html5/haiku.js
Normal file
100
src/servers/app/drawing/html5/haiku.js
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2012, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* François Revol <revol@free.fr>
|
||||
*
|
||||
* Loosely inspired by
|
||||
* http://git.gnome.org/browse/gtk+/tree/gdk/broadway/broadway.js?h=broadway
|
||||
*/
|
||||
|
||||
var logDiv;
|
||||
var desktop; // the canvas
|
||||
|
||||
function dbg(str)
|
||||
{
|
||||
var div = document.createElement("div");
|
||||
div.className = "haiku_online_debug";
|
||||
div.appendChild(document.createTextNode(str));
|
||||
logDiv.appendChild(div);
|
||||
}
|
||||
|
||||
function err(str)
|
||||
{
|
||||
var div = document.createElement("div");
|
||||
div.className = "haiku_online_error";
|
||||
div.appendChild(document.createTextNode(str));
|
||||
logDiv.appendChild(div);
|
||||
}
|
||||
|
||||
function createXHR()
|
||||
{
|
||||
try {
|
||||
return new XMLHttpRequest();
|
||||
} catch(e) {
|
||||
err("Failed to create XHR: " + e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function onMessage(message)
|
||||
{
|
||||
dbg("onMessage: ");
|
||||
window.popup("plop");
|
||||
dbg(message.target.responseText);
|
||||
}
|
||||
|
||||
function initDesktop()
|
||||
{
|
||||
dbg("initDesktop()");
|
||||
desktop = document.getElementById("desktop");
|
||||
var xhr = createXHR();
|
||||
if (xhr) {
|
||||
if (typeof xhr.multipart != "undefined")
|
||||
xhr.multipart = true;
|
||||
else {
|
||||
err("XHR has no multipart field!");
|
||||
return;
|
||||
}
|
||||
if (typeof xhr.async != "undefined")
|
||||
xhr.async = true;
|
||||
else {
|
||||
dbg("XHR has no async field!");
|
||||
}
|
||||
dbg("multipart: " + xhr.multipart);
|
||||
xhr.open("GET", "http://127.0.0.1:8080/output", true);
|
||||
//xhr.onload = onMessage;
|
||||
xhr.onreadystatechange = function() {
|
||||
dbg("readystate changed: " + xhr.readyState);
|
||||
if (xhr.readyState != 4)
|
||||
return;
|
||||
dbg("status: " + xhr.status);
|
||||
dbg("resonseType: " + xhr.responseType);
|
||||
dbg("response: " + xhr.responseText);
|
||||
dbg("headers: " + xhr.getAllResponseHeaders());
|
||||
|
||||
}
|
||||
//xhr.responseType = "arraybuffer";
|
||||
//dbg("xhr.onload:" + xhr.onload);
|
||||
//dbg("xhr.send:" + xhr.send);
|
||||
xhr.overrideMimeType("multipart/x-mixed-replace;boundary=x");
|
||||
xhr.send(null);
|
||||
//dbg("headers: " + xhr.getAllResponseHeaders());
|
||||
} else
|
||||
err("No XHR");
|
||||
dbg("done");
|
||||
}
|
||||
|
||||
|
||||
function onPageLoad() {
|
||||
logDiv = document.getElementById("log");
|
||||
dbg("onPageLoad()");
|
||||
initDesktop();
|
||||
}
|
||||
|
||||
function onPageUnload() {
|
||||
dbg("onPageUnload()");
|
||||
}
|
||||
|
||||
|
101
src/servers/app/drawing/html5/haiku.js.h
Normal file
101
src/servers/app/drawing/html5/haiku.js.h
Normal file
@ -0,0 +1,101 @@
|
||||
static const char haiku_js[] =
|
||||
"/*\n"
|
||||
" * Copyright 2012, Haiku, Inc.\n"
|
||||
" * Distributed under the terms of the MIT License.\n"
|
||||
" *\n"
|
||||
" * Authors:\n"
|
||||
" * François Revol <revol@free.fr>\n"
|
||||
" *\n"
|
||||
" * Loosely inspired by\n"
|
||||
" * http://git.gnome.org/browse/gtk+/tree/gdk/broadway/broadway.js?h=broadway\n"
|
||||
" */\n"
|
||||
"\n"
|
||||
"var logDiv;\n"
|
||||
"var desktop; // the canvas\n"
|
||||
"\n"
|
||||
"function dbg(str)\n"
|
||||
"{\n"
|
||||
" var div = document.createElement(\"div\");\n"
|
||||
" div.className = \"haiku_online_debug\";\n"
|
||||
" div.appendChild(document.createTextNode(str));\n"
|
||||
" logDiv.appendChild(div);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"function err(str)\n"
|
||||
"{\n"
|
||||
" var div = document.createElement(\"div\");\n"
|
||||
" div.className = \"haiku_online_error\";\n"
|
||||
" div.appendChild(document.createTextNode(str));\n"
|
||||
" logDiv.appendChild(div);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"function createXHR()\n"
|
||||
"{\n"
|
||||
" try {\n"
|
||||
" return new XMLHttpRequest();\n"
|
||||
" } catch(e) {\n"
|
||||
" err(\"Failed to create XHR: \" + e);\n"
|
||||
" }\n"
|
||||
" return null;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"function onMessage(message)\n"
|
||||
"{\n"
|
||||
" dbg(\"onMessage: \");\n"
|
||||
"window.popup(\"plop\");\n"
|
||||
" dbg(message.target.responseText);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"function initDesktop()\n"
|
||||
"{\n"
|
||||
" dbg(\"initDesktop()\");\n"
|
||||
" desktop = document.getElementById(\"desktop\");\n"
|
||||
" var xhr = createXHR();\n"
|
||||
" if (xhr) {\n"
|
||||
" if (typeof xhr.multipart != \"undefined\")\n"
|
||||
" xhr.multipart = true;\n"
|
||||
" else {\n"
|
||||
" err(\"XHR has no multipart field!\");\n"
|
||||
" return;\n"
|
||||
" }\n"
|
||||
" if (typeof xhr.async != \"undefined\")\n"
|
||||
" xhr.async = true;\n"
|
||||
" else {\n"
|
||||
" dbg(\"XHR has no async field!\");\n"
|
||||
" }\n"
|
||||
" dbg(\"multipart: \" + xhr.multipart);\n"
|
||||
" xhr.open(\"GET\", \"http://127.0.0.1:8080/output\", true);\n"
|
||||
" //xhr.onload = onMessage;\n"
|
||||
" xhr.onreadystatechange = function() {\n"
|
||||
" dbg(\"readystate changed: \" + xhr.readyState);\n"
|
||||
" if (xhr.readyState != 4)\n"
|
||||
" return;\n"
|
||||
" dbg(\"status: \" + xhr.status);\n"
|
||||
" dbg(\"resonseType: \" + xhr.responseType);\n"
|
||||
" dbg(\"response: \" + xhr.responseText);\n"
|
||||
" dbg(\"headers: \" + xhr.getAllResponseHeaders());\n"
|
||||
"\n"
|
||||
" }\n"
|
||||
" //xhr.responseType = \"arraybuffer\";\n"
|
||||
" //dbg(\"xhr.onload:\" + xhr.onload);\n"
|
||||
" //dbg(\"xhr.send:\" + xhr.send);\n"
|
||||
" xhr.overrideMimeType(\"multipart/x-mixed-replace;boundary=x\");\n"
|
||||
" xhr.send(null);\n"
|
||||
" //dbg(\"headers: \" + xhr.getAllResponseHeaders());\n"
|
||||
" } else\n"
|
||||
" err(\"No XHR\");\n"
|
||||
" dbg(\"done\");\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"function onPageLoad() {\n"
|
||||
" logDiv = document.getElementById(\"log\");\n"
|
||||
" dbg(\"onPageLoad()\");\n"
|
||||
" initDesktop();\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"function onPageUnload() {\n"
|
||||
" dbg(\"onPageUnload()\");\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"\n";
|
Loading…
x
Reference in New Issue
Block a user