haiku/src/servers/app/PicturePlayer.cpp

510 lines
12 KiB
C++
Raw Normal View History

//------------------------------------------------------------------------------
// Copyright (c) 2001-2002, Haiku, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: PicturePlayer.cpp
// Author: Marc Flerackers (mflerackers@androme.be)
// DarkWyrm <bpmagic@columbus.rr.com>
// Description: Server class to interpret and play BPicture data. Based on
// Marc Flerackers' TPicture class
//------------------------------------------------------------------------------
#include "PicturePlayer.h"
#include "PictureProtocol.h"
#include "Utils.h"
#include "DisplayDriver.h"
#include <ServerBitmap.h>
#include <stdio.h>
PicturePlayer::PicturePlayer(DisplayDriver *d,void *data, int32 size)
: fData(data, size)
{
fdriver=d;
stipplepat=0xFFFFFFFFFFFFFFFFLL;
clipreg=NULL;
}
PicturePlayer::~PicturePlayer()
{
if(clipreg)
delete clipreg;
}
int16 PicturePlayer::GetOp()
{
int16 data;
fData.Read(&data, sizeof(int16));
return data;
}
bool PicturePlayer::GetBool()
{
bool data;
fData.Read(&data, sizeof(bool));
return data;
}
int16 PicturePlayer::GetInt16()
{
int16 data;
fData.Read(&data, sizeof(int16));
return data;
}
int32 PicturePlayer::GetInt32()
{
int32 data;
fData.Read(&data, sizeof(int32));
return data;
}
float PicturePlayer::GetFloat()
{
float data;
fData.Read(&data, sizeof(float));
return data;
}
BPoint PicturePlayer::GetCoord()
{
BPoint data;
fData.Read(&data, sizeof(BPoint));
return data;
}
BRect PicturePlayer::GetRect()
{
BRect data;
fData.Read(&data, sizeof(BRect));
return data;
}
rgb_color PicturePlayer::GetColor()
{
rgb_color data;
fData.Read(&data, sizeof(rgb_color));
return data;
}
void PicturePlayer::GetData(void *data, int32 size)
{
fData.Read(data, size);
}
status_t PicturePlayer::Play(int32 tableEntries,void *userData, LayerData *d)
{
if(!userData || !d)
return B_ERROR;
int16 op;
int32 size=fData.Seek(0,SEEK_END);
fData.Seek(0,SEEK_SET);
off_t pos;
fldata=*d;
while (fData.Position() < size)
{
op = GetOp();
size = GetInt32();
pos = fData.Position();
switch (op)
{
case B_PIC_MOVE_PEN_BY:
{
BPoint where = GetCoord();
fldata.penlocation.x+=where.x;
fldata.penlocation.y+=where.y;
break;
}
case B_PIC_STROKE_LINE:
{
BPoint start = GetCoord();
BPoint end = GetCoord();
fdriver->StrokeLine(start,end,&fldata);
break;
}
case B_PIC_STROKE_RECT:
{
BRect rect = GetRect();
fdriver->StrokeRect(rect,&fldata);
break;
}
case B_PIC_FILL_RECT:
{
BRect rect = GetRect();
fdriver->FillRect(rect,&fldata);
break;
}
case B_PIC_STROKE_ROUND_RECT:
{
BRect rect = GetRect();
BPoint radii = GetCoord();
fdriver->StrokeRoundRect(rect,radii.x,radii.y,&fldata);
break;
}
case B_PIC_FILL_ROUND_RECT:
{
BRect rect = GetRect();
BPoint radii = GetCoord();
fdriver->FillRoundRect(rect,radii.x,radii.y,&fldata);
break;
}
case B_PIC_STROKE_BEZIER:
{
BPoint control[4];
GetData(control, sizeof(control));
fdriver->StrokeBezier(control,&fldata);
break;
}
case B_PIC_FILL_BEZIER:
{
BPoint control[4];
GetData(control, sizeof(control));
fdriver->FillBezier(control,&fldata);
break;
}
case B_PIC_STROKE_POLYGON:
{
int32 numPoints = GetInt32();
BPoint *points = new BPoint[numPoints];
GetData(points, numPoints * sizeof(BPoint));
bool isClosed = GetBool();
fdriver->StrokePolygon(points,numPoints,CalculatePolygonBounds(points,numPoints),&fldata,isClosed);
delete points;
break;
}
case B_PIC_FILL_POLYGON:
{
int32 numPoints = GetInt32();
BPoint *points = new BPoint[numPoints];
GetData(points, numPoints * sizeof(BPoint));
fdriver->FillPolygon(points,numPoints,CalculatePolygonBounds(points,numPoints),&fldata);
delete points;
break;
}
case B_PIC_STROKE_SHAPE:
case B_PIC_FILL_SHAPE:
break;
case B_PIC_DRAW_STRING:
{
int32 len = GetInt32();
char *string = new char[len + 1];
GetData(string, len);
string[len] = '\0';
float deltax = GetFloat();
float deltay = GetFloat();
// TODO: The deltas given are escapements. They seem to be called deltax and deltay
// despite the fact that they are space and non-space escapements. Find out which is which when possible.
// My best guess is that deltax corresponds to escapement_delta.nonspace.
fldata.edelta.nonspace=deltax;
fldata.edelta.space=deltay;
fdriver->DrawString(string,len,fldata.penlocation,&fldata);
delete string;
break;
}
case B_PIC_DRAW_PIXELS:
{
// Equivalent of DrawBitmap().
// Normally, we wouldn't explicitly play around with ServerBitmap's buffer memory, but
// we don't want the overhead of going through the pool allocator for a quick bitmap.
BRect src = GetRect();
BRect dest = GetRect();
int32 width = GetInt32();
int32 height = GetInt32();
int32 bytesPerRow = GetInt32();
int32 pixelFormat = GetInt32();
int32 flags = GetInt32();
ServerBitmap sbmp(BRect(0,0,width-1,height-1), (color_space)pixelFormat, flags, bytesPerRow);
sbmp._AllocateBuffer();
GetData(sbmp.Bits(), size - (fData.Position() - pos));
fdriver->DrawBitmap(&sbmp,src,dest,&fldata);
sbmp._FreeBuffer();
break;
}
case B_PIC_DRAW_PICTURE:
{
// TODO: Implement
printf("DEBUG: PicturePlayer::Play(): B_PIC_DRAW_PICTURE unimplemented!\n");
break;
}
case B_PIC_STROKE_ARC:
{
BPoint center = GetCoord();
BPoint radii = GetCoord();
float startTheta = GetFloat();
float arcTheta = GetFloat();
fdriver->StrokeArc(BRect(center.x-radii.x,center.y-radii.y,center.x+radii.x,
center.y+radii.y),startTheta, arcTheta, &fldata);
break;
}
case B_PIC_FILL_ARC:
{
BPoint center = GetCoord();
BPoint radii = GetCoord();
float startTheta = GetFloat();
float arcTheta = GetFloat();
fdriver->FillArc(BRect(center.x-radii.x,center.y-radii.y,center.x+radii.x,
center.y+radii.y),startTheta, arcTheta, &fldata);
break;
}
case B_PIC_STROKE_ELLIPSE:
{
BRect rect = GetRect();
BPoint center;
BPoint radii((rect.Width() + 1) / 2.0f, (rect.Height() + 1) / 2.0f);
center = rect.LeftTop() + radii;
fdriver->StrokeEllipse(rect,&fldata);
break;
}
case B_PIC_FILL_ELLIPSE:
{
BRect rect = GetRect();
BPoint center;
BPoint radii((rect.Width() + 1) / 2.0f, (rect.Height() + 1) / 2.0f);
center = rect.LeftTop() + radii;
fdriver->FillEllipse(rect,&fldata);
break;
}
case B_PIC_ENTER_STATE_CHANGE:
{
// This simply signals that only state stuff will follow until
// B_PIC_EXIT_STATE_CHANGE is encountered. This doesn't affect us AFAIK,
// so we'll do absolutely nothing.
break;
}
case B_PIC_CLIP_TO_PICTURE:
{
//TODO: Implement
break;
}
case B_PIC_PUSH_STATE:
{
//TODO: Implement
break;
}
case B_PIC_POP_STATE:
{
//TODO: Implement
break;
}
case B_PIC_SET_CLIPPING_RECTS:
{
// TODO: Find out how the data will be stored and implement
break;
}
case B_PIC_CLEAR_CLIPPING_RECTS:
{
SetClippingRegion(NULL, 0);
break;
}
case B_PIC_SET_ORIGIN:
{
BPoint pt = GetCoord();
forigin=pt;
break;
}
case B_PIC_SET_PEN_LOCATION:
{
BPoint pt = GetCoord();
fldata.penlocation=pt;
break;
}
case B_PIC_SET_DRAWING_MODE:
{
int16 mode = GetInt16();
fldata.draw_mode=(drawing_mode)mode;
break;
}
case B_PIC_SET_LINE_MODE:
{
GetData(&fldata.lineCap,sizeof(cap_mode));
GetData(&fldata.lineJoin,sizeof(join_mode));
fldata.miterLimit = GetFloat();
break;
}
case B_PIC_SET_PEN_SIZE:
{
float size = GetFloat();
fldata.pensize=size;
break;
}
case B_PIC_SET_SCALE:
{
float scale = GetFloat();
fldata.scale=scale;
break;
}
case B_PIC_SET_FORE_COLOR:
{
rgb_color color = GetColor();
fldata.highcolor=color;
break;
}
case B_PIC_SET_BACK_COLOR:
{
rgb_color color = GetColor();
fldata.lowcolor=color;
break;
}
case B_PIC_SET_STIPLE_PATTERN:
{
pattern p;
GetData(&p, sizeof(p));
stipplepat=*((uint64*)p.data);
break;
}
case B_PIC_ENTER_FONT_STATE:
{
// We don't really care about this call, so do nothing
break;
}
case B_PIC_SET_BLENDING_MODE:
{
int16 alphaSrcMode = GetInt16();
int16 alphaFncMode = GetInt16();
fldata.alphaSrcMode = (source_alpha)alphaSrcMode;
fldata.alphaFncMode = (alpha_function)alphaFncMode;
break;
}
case B_PIC_SET_FONT_FAMILY:
{
//TODO: Implement
/* int32 len = GetInt32();
char *string = new char[len + 1];
GetData(string, len);
string[len] = '\0';
((fnc_Pc)callBackTable[37])(userData, string);
delete string;
*/ break;
}
case B_PIC_SET_FONT_STYLE:
{
//TODO: Implement
/* int32 len = GetInt32();
char *string = new char[len + 1];
GetData(string, len);
string[len] = '\0';
((fnc_Pc)callBackTable[38])(userData, string);
delete string;
*/ break;
}
case B_PIC_SET_FONT_SPACING:
{
fldata.font.SetSpacing(GetInt32());
break;
}
case B_PIC_SET_FONT_ENCODING:
{
fldata.font.SetEncoding(GetInt32());
break;
}
case B_PIC_SET_FONT_FLAGS:
{
fldata.font.SetFlags(GetInt32());
break;
}
case B_PIC_SET_FONT_SIZE:
{
fldata.font.SetSize(GetFloat());
break;
}
case B_PIC_SET_FONT_ROTATE:
{
fldata.font.SetRotation(GetFloat());
break;
}
case B_PIC_SET_FONT_SHEAR:
{
fldata.font.SetShear(GetFloat());
break;
}
case B_PIC_SET_FONT_FACE:
{
fldata.font.SetFace(GetInt32());
break;
}
default:
break;
}
// If we didn't read enough bytes, skip them. This is not a error
// since the instructions can change over time.
if (fData.Position() - pos < size)
fData.Seek(size - (fData.Position() - pos), SEEK_CUR);
}
return B_OK;
}
void PicturePlayer::SetClippingRegion(BRect *rects, int32 numrects)
{
// Sets the player's clipping region to the union of the rectangles passed to it.
// Passing NULL or 0 rectangles to the function empties the clipping region. The clipping
// region is also emptied if there is no union of all rectangles passed to the function.
if(!rects || numrects)
{
delete clipreg;
clipreg=NULL;
return;
}
if(!clipreg)
clipreg=new BRegion();
else
clipreg->MakeEmpty();
*clipreg=rects[0];
BRegion temp;
for(int32 i=1; i<numrects; i++)
{
temp=rects[i];
clipreg->IntersectWith(&temp);
}
if(clipreg->CountRects()==0)
{
delete clipreg;
clipreg=NULL;
}
}