Change-Id: Ia2b7a719fd398e78cc3b11d4f7b02cb81179f65f Reviewed-on: https://review.haiku-os.org/c/haiku/+/3488 Reviewed-by: Jérôme Duval <[email protected]>
1404 lines
32 KiB
C++
1404 lines
32 KiB
C++
/*
|
|
* Copyright 2001-2019, Haiku.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Authors:
|
|
* Marc Flerackers ([email protected])
|
|
* Stefano Ceccherini ([email protected])
|
|
* Marcus Overhagen <[email protected]>
|
|
* Julian Harnath <[email protected]>
|
|
* Stephan Aßmus <[email protected]>
|
|
*/
|
|
|
|
#include "ServerPicture.h"
|
|
|
|
#include <new>
|
|
#include <stdio.h>
|
|
#include <stack>
|
|
|
|
#include "AlphaMask.h"
|
|
#include "DrawingEngine.h"
|
|
#include "DrawState.h"
|
|
#include "FontManager.h"
|
|
#include "Layer.h"
|
|
#include "ServerApp.h"
|
|
#include "ServerBitmap.h"
|
|
#include "ServerFont.h"
|
|
#include "ServerTokenSpace.h"
|
|
#include "View.h"
|
|
#include "Window.h"
|
|
|
|
#include <LinkReceiver.h>
|
|
#include <OffsetFile.h>
|
|
#include <ObjectListPrivate.h>
|
|
#include <PicturePlayer.h>
|
|
#include <PictureProtocol.h>
|
|
#include <PortLink.h>
|
|
#include <ServerProtocol.h>
|
|
#include <ShapePrivate.h>
|
|
#include <StackOrHeapArray.h>
|
|
|
|
#include <Bitmap.h>
|
|
#include <Debug.h>
|
|
#include <List.h>
|
|
#include <Shape.h>
|
|
|
|
|
|
using std::stack;
|
|
|
|
|
|
class ShapePainter : public BShapeIterator {
|
|
public:
|
|
ShapePainter(Canvas* canvas, BGradient* gradient);
|
|
virtual ~ShapePainter();
|
|
|
|
status_t Iterate(const BShape* shape);
|
|
|
|
virtual status_t IterateMoveTo(BPoint* point);
|
|
virtual status_t IterateLineTo(int32 lineCount, BPoint* linePts);
|
|
virtual status_t IterateBezierTo(int32 bezierCount, BPoint* bezierPts);
|
|
virtual status_t IterateClose();
|
|
virtual status_t IterateArcTo(float& rx, float& ry,
|
|
float& angle, bool largeArc, bool counterClockWise, BPoint& point);
|
|
|
|
void Draw(BRect frame, bool filled);
|
|
|
|
private:
|
|
Canvas* fCanvas;
|
|
BGradient* fGradient;
|
|
stack<uint32> fOpStack;
|
|
stack<BPoint> fPtStack;
|
|
};
|
|
|
|
|
|
ShapePainter::ShapePainter(Canvas* canvas, BGradient* gradient)
|
|
:
|
|
fCanvas(canvas),
|
|
fGradient(gradient)
|
|
{
|
|
}
|
|
|
|
|
|
ShapePainter::~ShapePainter()
|
|
{
|
|
}
|
|
|
|
|
|
status_t
|
|
ShapePainter::Iterate(const BShape* shape)
|
|
{
|
|
// this class doesn't modify the shape data
|
|
return BShapeIterator::Iterate(const_cast<BShape*>(shape));
|
|
}
|
|
|
|
|
|
status_t
|
|
ShapePainter::IterateMoveTo(BPoint* point)
|
|
{
|
|
try {
|
|
fOpStack.push(OP_MOVETO);
|
|
fPtStack.push(*point);
|
|
} catch (std::bad_alloc&) {
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
ShapePainter::IterateLineTo(int32 lineCount, BPoint* linePts)
|
|
{
|
|
try {
|
|
fOpStack.push(OP_LINETO | lineCount);
|
|
for (int32 i = 0; i < lineCount; i++)
|
|
fPtStack.push(linePts[i]);
|
|
} catch (std::bad_alloc&) {
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
ShapePainter::IterateBezierTo(int32 bezierCount, BPoint* bezierPts)
|
|
{
|
|
bezierCount *= 3;
|
|
try {
|
|
fOpStack.push(OP_BEZIERTO | bezierCount);
|
|
for (int32 i = 0; i < bezierCount; i++)
|
|
fPtStack.push(bezierPts[i]);
|
|
} catch (std::bad_alloc&) {
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
ShapePainter::IterateArcTo(float& rx, float& ry,
|
|
float& angle, bool largeArc, bool counterClockWise, BPoint& point)
|
|
{
|
|
uint32 op;
|
|
if (largeArc) {
|
|
if (counterClockWise)
|
|
op = OP_LARGE_ARC_TO_CCW;
|
|
else
|
|
op = OP_LARGE_ARC_TO_CW;
|
|
} else {
|
|
if (counterClockWise)
|
|
op = OP_SMALL_ARC_TO_CCW;
|
|
else
|
|
op = OP_SMALL_ARC_TO_CW;
|
|
}
|
|
|
|
try {
|
|
fOpStack.push(op | 3);
|
|
fPtStack.push(BPoint(rx, ry));
|
|
fPtStack.push(BPoint(angle, 0));
|
|
fPtStack.push(point);
|
|
} catch (std::bad_alloc&) {
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
ShapePainter::IterateClose()
|
|
{
|
|
try {
|
|
fOpStack.push(OP_CLOSE);
|
|
} catch (std::bad_alloc&) {
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
void
|
|
ShapePainter::Draw(BRect frame, bool filled)
|
|
{
|
|
// We're going to draw the currently iterated shape.
|
|
// TODO: This can be more efficient by skipping the conversion.
|
|
int32 opCount = fOpStack.size();
|
|
int32 ptCount = fPtStack.size();
|
|
|
|
if (opCount > 0 && ptCount > 0) {
|
|
int32 i;
|
|
uint32* opList = new(std::nothrow) uint32[opCount];
|
|
if (opList == NULL)
|
|
return;
|
|
|
|
BPoint* ptList = new(std::nothrow) BPoint[ptCount];
|
|
if (ptList == NULL) {
|
|
delete[] opList;
|
|
return;
|
|
}
|
|
|
|
for (i = opCount - 1; i >= 0; i--) {
|
|
opList[i] = fOpStack.top();
|
|
fOpStack.pop();
|
|
}
|
|
|
|
for (i = ptCount - 1; i >= 0; i--) {
|
|
ptList[i] = fPtStack.top();
|
|
fPtStack.pop();
|
|
}
|
|
|
|
// this might seem a bit weird, but under R5, the shapes
|
|
// are always offset by the current pen location
|
|
BPoint screenOffset = fCanvas->CurrentState()->PenLocation();
|
|
frame.OffsetBy(screenOffset);
|
|
|
|
const SimpleTransform transform = fCanvas->PenToScreenTransform();
|
|
transform.Apply(&screenOffset);
|
|
transform.Apply(&frame);
|
|
|
|
/* stroked gradients are not yet supported */
|
|
if (fGradient != NULL && filled) {
|
|
fCanvas->GetDrawingEngine()->FillShape(frame, opCount, opList,
|
|
ptCount, ptList, *fGradient, screenOffset, fCanvas->Scale());
|
|
} else {
|
|
fCanvas->GetDrawingEngine()->DrawShape(frame, opCount, opList,
|
|
ptCount, ptList, filled, screenOffset, fCanvas->Scale());
|
|
}
|
|
|
|
delete[] opList;
|
|
delete[] ptList;
|
|
}
|
|
}
|
|
|
|
|
|
// #pragma mark - drawing functions
|
|
|
|
|
|
static void
|
|
get_polygon_frame(const BPoint* points, uint32 numPoints, BRect* _frame)
|
|
{
|
|
ASSERT(numPoints > 0);
|
|
|
|
float left = points->x;
|
|
float top = points->y;
|
|
float right = left;
|
|
float bottom = top;
|
|
|
|
points++;
|
|
numPoints--;
|
|
|
|
while (numPoints--) {
|
|
if (points->x < left)
|
|
left = points->x;
|
|
if (points->x > right)
|
|
right = points->x;
|
|
if (points->y < top)
|
|
top = points->y;
|
|
if (points->y > bottom)
|
|
bottom = points->y;
|
|
points++;
|
|
}
|
|
|
|
_frame->Set(left, top, right, bottom);
|
|
}
|
|
|
|
|
|
static void
|
|
move_pen_by(void* _canvas, const BPoint& delta)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->CurrentState()->SetPenLocation(
|
|
canvas->CurrentState()->PenLocation() + delta);
|
|
}
|
|
|
|
|
|
static void
|
|
stroke_line(void* _canvas, const BPoint& _start, const BPoint& _end)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
BPoint start = _start;
|
|
BPoint end = _end;
|
|
|
|
const SimpleTransform transform = canvas->PenToScreenTransform();
|
|
transform.Apply(&start);
|
|
transform.Apply(&end);
|
|
canvas->GetDrawingEngine()->StrokeLine(start, end);
|
|
|
|
canvas->CurrentState()->SetPenLocation(_end);
|
|
// the DrawingEngine/Painter does not need to be updated, since this
|
|
// effects only the view->screen coord conversion, which is handled
|
|
// by the view only
|
|
}
|
|
|
|
|
|
static void
|
|
draw_rect(void* _canvas, const BRect& _rect, bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
BRect rect = _rect;
|
|
|
|
canvas->PenToScreenTransform().Apply(&rect);
|
|
if (fill)
|
|
canvas->GetDrawingEngine()->FillRect(rect);
|
|
else
|
|
canvas->GetDrawingEngine()->StrokeRect(rect);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_round_rect(void* _canvas, const BRect& _rect, const BPoint& radii,
|
|
bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
BRect rect = _rect;
|
|
|
|
canvas->PenToScreenTransform().Apply(&rect);
|
|
float scale = canvas->CurrentState()->CombinedScale();
|
|
canvas->GetDrawingEngine()->DrawRoundRect(rect, radii.x * scale,
|
|
radii.y * scale, fill);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_bezier(void* _canvas, size_t numPoints, const BPoint viewPoints[],
|
|
bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
const size_t kSupportedPoints = 4;
|
|
if (numPoints != kSupportedPoints)
|
|
return;
|
|
|
|
BPoint points[kSupportedPoints];
|
|
canvas->PenToScreenTransform().Apply(points, viewPoints, kSupportedPoints);
|
|
canvas->GetDrawingEngine()->DrawBezier(points, fill);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_arc(void* _canvas, const BPoint& center, const BPoint& radii,
|
|
float startTheta, float arcTheta, bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
BRect rect(center.x - radii.x, center.y - radii.y,
|
|
center.x + radii.x - 1, center.y + radii.y - 1);
|
|
canvas->PenToScreenTransform().Apply(&rect);
|
|
canvas->GetDrawingEngine()->DrawArc(rect, startTheta, arcTheta, fill);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_ellipse(void* _canvas, const BRect& _rect, bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
BRect rect = _rect;
|
|
canvas->PenToScreenTransform().Apply(&rect);
|
|
canvas->GetDrawingEngine()->DrawEllipse(rect, fill);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_polygon(void* _canvas, size_t numPoints, const BPoint viewPoints[],
|
|
bool isClosed, bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
if (numPoints == 0)
|
|
return;
|
|
|
|
BStackOrHeapArray<BPoint, 200> points(numPoints);
|
|
if (!points.IsValid())
|
|
return;
|
|
|
|
canvas->PenToScreenTransform().Apply(points, viewPoints, numPoints);
|
|
|
|
BRect polyFrame;
|
|
get_polygon_frame(points, numPoints, &polyFrame);
|
|
|
|
canvas->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame,
|
|
fill, isClosed && numPoints > 2);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_shape(void* _canvas, const BShape& shape, bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
ShapePainter drawShape(canvas, NULL);
|
|
|
|
drawShape.Iterate(&shape);
|
|
drawShape.Draw(shape.Bounds(), fill);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_rect_gradient(void* _canvas, const BRect& _rect, BGradient& gradient, bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
BRect rect = _rect;
|
|
|
|
const SimpleTransform transform =
|
|
canvas->PenToScreenTransform();
|
|
transform.Apply(&rect);
|
|
transform.Apply(&gradient);
|
|
|
|
canvas->GetDrawingEngine()->FillRect(rect, gradient);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_round_rect_gradient(void* _canvas, const BRect& _rect, const BPoint& radii, BGradient& gradient,
|
|
bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
BRect rect = _rect;
|
|
|
|
const SimpleTransform transform =
|
|
canvas->PenToScreenTransform();
|
|
transform.Apply(&rect);
|
|
transform.Apply(&gradient);
|
|
float scale = canvas->CurrentState()->CombinedScale();
|
|
canvas->GetDrawingEngine()->FillRoundRect(rect, radii.x * scale,
|
|
radii.y * scale, gradient);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_bezier_gradient(void* _canvas, size_t numPoints, const BPoint viewPoints[], BGradient& gradient,
|
|
bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
const size_t kSupportedPoints = 4;
|
|
if (numPoints != kSupportedPoints)
|
|
return;
|
|
|
|
BPoint points[kSupportedPoints];
|
|
const SimpleTransform transform =
|
|
canvas->PenToScreenTransform();
|
|
transform.Apply(points, viewPoints, kSupportedPoints);
|
|
transform.Apply(&gradient);
|
|
canvas->GetDrawingEngine()->FillBezier(points, gradient);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_arc_gradient(void* _canvas, const BPoint& center, const BPoint& radii,
|
|
float startTheta, float arcTheta, BGradient& gradient, bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
BRect rect(center.x - radii.x, center.y - radii.y,
|
|
center.x + radii.x - 1, center.y + radii.y - 1);
|
|
const SimpleTransform transform =
|
|
canvas->PenToScreenTransform();
|
|
transform.Apply(&rect);
|
|
transform.Apply(&gradient);
|
|
canvas->GetDrawingEngine()->FillArc(rect, startTheta, arcTheta, gradient);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_ellipse_gradient(void* _canvas, const BRect& _rect, BGradient& gradient, bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
BRect rect = _rect;
|
|
|
|
const SimpleTransform transform =
|
|
canvas->PenToScreenTransform();
|
|
transform.Apply(&rect);
|
|
transform.Apply(&gradient);
|
|
canvas->GetDrawingEngine()->FillEllipse(rect, gradient);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_polygon_gradient(void* _canvas, size_t numPoints, const BPoint viewPoints[],
|
|
bool isClosed, BGradient& gradient, bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
if (numPoints == 0)
|
|
return;
|
|
|
|
BStackOrHeapArray<BPoint, 200> points(numPoints);
|
|
if (!points.IsValid())
|
|
return;
|
|
|
|
const SimpleTransform transform =
|
|
canvas->PenToScreenTransform();
|
|
transform.Apply(points, viewPoints, numPoints);
|
|
transform.Apply(&gradient);
|
|
|
|
BRect polyFrame;
|
|
get_polygon_frame(points, numPoints, &polyFrame);
|
|
|
|
canvas->GetDrawingEngine()->FillPolygon(points, numPoints, polyFrame,
|
|
gradient, isClosed && numPoints > 2);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_shape_gradient(void* _canvas, const BShape& shape, BGradient& gradient, bool fill)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
ShapePainter drawShape(canvas, &gradient);
|
|
|
|
drawShape.Iterate(&shape);
|
|
drawShape.Draw(shape.Bounds(), fill);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_string(void* _canvas, const char* string, size_t length, float deltaSpace,
|
|
float deltaNonSpace)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
// NOTE: the picture data was recorded with a "set pen location"
|
|
// command inserted before the "draw string" command, so we can
|
|
// use PenLocation()
|
|
BPoint location = canvas->CurrentState()->PenLocation();
|
|
|
|
escapement_delta delta = { deltaSpace, deltaNonSpace };
|
|
canvas->PenToScreenTransform().Apply(&location);
|
|
location = canvas->GetDrawingEngine()->DrawString(string, length,
|
|
location, &delta);
|
|
|
|
canvas->PenToScreenTransform().Apply(&location);
|
|
canvas->CurrentState()->SetPenLocation(location);
|
|
// the DrawingEngine/Painter does not need to be updated, since this
|
|
// effects only the view->screen coord conversion, which is handled
|
|
// by the view only
|
|
}
|
|
|
|
|
|
static void
|
|
draw_string_locations(void* _canvas, const char* string, size_t length,
|
|
const BPoint* _locations, size_t locationsCount)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
BStackOrHeapArray<BPoint, 200> locations(locationsCount);
|
|
if (!locations.IsValid())
|
|
return;
|
|
|
|
const SimpleTransform transform = canvas->PenToScreenTransform();
|
|
for (size_t i = 0; i < locationsCount; i++) {
|
|
locations[i] = _locations[i];
|
|
transform.Apply(&locations[i]);
|
|
}
|
|
|
|
BPoint location = canvas->GetDrawingEngine()->DrawString(string, length,
|
|
locations);
|
|
|
|
canvas->PenToScreenTransform().Apply(&location);
|
|
canvas->CurrentState()->SetPenLocation(location);
|
|
// the DrawingEngine/Painter does not need to be updated, since this
|
|
// effects only the view->screen coord conversion, which is handled
|
|
// by the view only
|
|
}
|
|
|
|
|
|
static void
|
|
draw_pixels(void* _canvas, const BRect& src, const BRect& _dest, uint32 width,
|
|
uint32 height, size_t bytesPerRow, color_space pixelFormat, uint32 options,
|
|
const void* data, size_t length)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
UtilityBitmap bitmap(BRect(0, 0, width - 1, height - 1),
|
|
(color_space)pixelFormat, 0, bytesPerRow);
|
|
|
|
if (!bitmap.IsValid())
|
|
return;
|
|
|
|
memcpy(bitmap.Bits(), data, std::min(height * bytesPerRow, length));
|
|
|
|
BRect dest = _dest;
|
|
canvas->PenToScreenTransform().Apply(&dest);
|
|
canvas->GetDrawingEngine()->DrawBitmap(&bitmap, src, dest, options);
|
|
}
|
|
|
|
|
|
static void
|
|
draw_picture(void* _canvas, const BPoint& where, int32 token)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
BReference<ServerPicture> picture(canvas->GetPicture(token), true);
|
|
if (picture != NULL) {
|
|
canvas->PushState();
|
|
canvas->SetDrawingOrigin(where);
|
|
|
|
canvas->PushState();
|
|
picture->Play(canvas);
|
|
canvas->PopState();
|
|
|
|
canvas->PopState();
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
set_clipping_rects(void* _canvas, size_t numRects, const BRect rects[])
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
if (numRects == 0)
|
|
canvas->SetUserClipping(NULL);
|
|
else {
|
|
// TODO: This might be too slow, we should copy the rects
|
|
// directly to BRegion's internal data
|
|
BRegion region;
|
|
for (uint32 c = 0; c < numRects; c++)
|
|
region.Include(rects[c]);
|
|
canvas->SetUserClipping(®ion);
|
|
}
|
|
canvas->UpdateCurrentDrawingRegion();
|
|
}
|
|
|
|
|
|
static void
|
|
clip_to_picture(void* _canvas, int32 pictureToken, const BPoint& where,
|
|
bool clipToInverse)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
BReference<ServerPicture> picture(canvas->GetPicture(pictureToken), true);
|
|
if (picture == NULL)
|
|
return;
|
|
BReference<AlphaMask> mask(new(std::nothrow) PictureAlphaMask(canvas->GetAlphaMask(),
|
|
picture, *canvas->CurrentState(), where, clipToInverse), true);
|
|
canvas->SetAlphaMask(mask);
|
|
canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
|
|
canvas->Bounds());
|
|
canvas->ResyncDrawState();
|
|
}
|
|
|
|
|
|
static void
|
|
push_state(void* _canvas)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->PushState();
|
|
}
|
|
|
|
|
|
static void
|
|
pop_state(void* _canvas)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->PopState();
|
|
|
|
BPoint p(0, 0);
|
|
canvas->PenToScreenTransform().Apply(&p);
|
|
canvas->GetDrawingEngine()->SetDrawState(canvas->CurrentState(),
|
|
(int32)p.x, (int32)p.y);
|
|
}
|
|
|
|
|
|
// TODO: Be smart and actually take advantage of these methods:
|
|
// only apply state changes when they are called
|
|
static void
|
|
enter_state_change(void* _canvas)
|
|
{
|
|
}
|
|
|
|
|
|
static void
|
|
exit_state_change(void* _canvas)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->ResyncDrawState();
|
|
}
|
|
|
|
|
|
static void
|
|
enter_font_state(void* _canvas)
|
|
{
|
|
}
|
|
|
|
|
|
static void
|
|
exit_font_state(void* _canvas)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->GetDrawingEngine()->SetFont(canvas->CurrentState()->Font());
|
|
}
|
|
|
|
|
|
static void
|
|
set_origin(void* _canvas, const BPoint& pt)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->CurrentState()->SetOrigin(pt);
|
|
}
|
|
|
|
|
|
static void
|
|
set_pen_location(void* _canvas, const BPoint& pt)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->CurrentState()->SetPenLocation(pt);
|
|
// the DrawingEngine/Painter does not need to be updated, since this
|
|
// effects only the view->screen coord conversion, which is handled
|
|
// by the view only
|
|
}
|
|
|
|
|
|
static void
|
|
set_drawing_mode(void* _canvas, drawing_mode mode)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
if (canvas->CurrentState()->SetDrawingMode(mode))
|
|
canvas->GetDrawingEngine()->SetDrawingMode(mode);
|
|
}
|
|
|
|
|
|
static void
|
|
set_line_mode(void* _canvas, cap_mode capMode, join_mode joinMode,
|
|
float miterLimit)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
DrawState* state = canvas->CurrentState();
|
|
state->SetLineCapMode(capMode);
|
|
state->SetLineJoinMode(joinMode);
|
|
state->SetMiterLimit(miterLimit);
|
|
canvas->GetDrawingEngine()->SetStrokeMode(capMode, joinMode, miterLimit);
|
|
}
|
|
|
|
|
|
static void
|
|
set_pen_size(void* _canvas, float size)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->CurrentState()->SetPenSize(size);
|
|
canvas->GetDrawingEngine()->SetPenSize(
|
|
canvas->CurrentState()->PenSize());
|
|
// DrawState::PenSize() returns the scaled pen size, so we
|
|
// need to use that value to set the drawing engine pen size.
|
|
}
|
|
|
|
|
|
static void
|
|
set_fore_color(void* _canvas, const rgb_color& color)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->CurrentState()->SetHighColor(color);
|
|
canvas->GetDrawingEngine()->SetHighColor(color);
|
|
}
|
|
|
|
|
|
static void
|
|
set_back_color(void* _canvas, const rgb_color& color)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->CurrentState()->SetLowColor(color);
|
|
canvas->GetDrawingEngine()->SetLowColor(color);
|
|
}
|
|
|
|
|
|
static void
|
|
set_stipple_pattern(void* _canvas, const pattern& pattern)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->CurrentState()->SetPattern(Pattern(pattern));
|
|
canvas->GetDrawingEngine()->SetPattern(pattern);
|
|
}
|
|
|
|
|
|
static void
|
|
set_scale(void* _canvas, float scale)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->CurrentState()->SetScale(scale);
|
|
canvas->ResyncDrawState();
|
|
|
|
// Update the drawing engine draw state, since some stuff
|
|
// (for example the pen size) needs to be recalculated.
|
|
}
|
|
|
|
|
|
static void
|
|
set_font_family(void* _canvas, const char* _family, size_t length)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
BString family(_family, length);
|
|
|
|
FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0);
|
|
ServerFont font;
|
|
font.SetStyle(fontStyle);
|
|
canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
|
|
}
|
|
|
|
|
|
static void
|
|
set_font_style(void* _canvas, const char* _style, size_t length)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
BString style(_style, length);
|
|
|
|
ServerFont font(canvas->CurrentState()->Font());
|
|
|
|
FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style);
|
|
|
|
font.SetStyle(fontStyle);
|
|
canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
|
|
}
|
|
|
|
|
|
static void
|
|
set_font_spacing(void* _canvas, uint8 spacing)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
ServerFont font;
|
|
font.SetSpacing(spacing);
|
|
canvas->CurrentState()->SetFont(font, B_FONT_SPACING);
|
|
}
|
|
|
|
|
|
static void
|
|
set_font_size(void* _canvas, float size)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
ServerFont font;
|
|
font.SetSize(size);
|
|
canvas->CurrentState()->SetFont(font, B_FONT_SIZE);
|
|
}
|
|
|
|
|
|
static void
|
|
set_font_rotation(void* _canvas, float rotation)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
ServerFont font;
|
|
font.SetRotation(rotation);
|
|
canvas->CurrentState()->SetFont(font, B_FONT_ROTATION);
|
|
}
|
|
|
|
|
|
static void
|
|
set_font_encoding(void* _canvas, uint8 encoding)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
ServerFont font;
|
|
font.SetEncoding(encoding);
|
|
canvas->CurrentState()->SetFont(font, B_FONT_ENCODING);
|
|
}
|
|
|
|
|
|
static void
|
|
set_font_flags(void* _canvas, uint32 flags)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
ServerFont font;
|
|
font.SetFlags(flags);
|
|
canvas->CurrentState()->SetFont(font, B_FONT_FLAGS);
|
|
}
|
|
|
|
|
|
static void
|
|
set_font_shear(void* _canvas, float shear)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
ServerFont font;
|
|
font.SetShear(shear);
|
|
canvas->CurrentState()->SetFont(font, B_FONT_SHEAR);
|
|
}
|
|
|
|
|
|
static void
|
|
set_font_face(void* _canvas, uint16 face)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
ServerFont font;
|
|
font.SetFace(face);
|
|
canvas->CurrentState()->SetFont(font, B_FONT_FACE);
|
|
}
|
|
|
|
|
|
static void
|
|
set_blending_mode(void* _canvas, source_alpha alphaSrcMode,
|
|
alpha_function alphaFncMode)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->CurrentState()->SetBlendingMode(alphaSrcMode, alphaFncMode);
|
|
}
|
|
|
|
|
|
static void
|
|
set_fill_rule(void* _canvas, int32 fillRule)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->CurrentState()->SetFillRule(fillRule);
|
|
canvas->GetDrawingEngine()->SetFillRule(fillRule);
|
|
}
|
|
|
|
|
|
static void
|
|
set_transform(void* _canvas, const BAffineTransform& transform)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
BPoint leftTop(0, 0);
|
|
canvas->PenToScreenTransform().Apply(&leftTop);
|
|
|
|
canvas->CurrentState()->SetTransform(transform);
|
|
canvas->GetDrawingEngine()->SetTransform(
|
|
canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
|
|
}
|
|
|
|
|
|
static void
|
|
translate_by(void* _canvas, double x, double y)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
BPoint leftTop(0, 0);
|
|
canvas->PenToScreenTransform().Apply(&leftTop);
|
|
|
|
BAffineTransform transform = canvas->CurrentState()->Transform();
|
|
transform.PreTranslateBy(x, y);
|
|
canvas->CurrentState()->SetTransform(transform);
|
|
canvas->GetDrawingEngine()->SetTransform(
|
|
canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
|
|
}
|
|
|
|
|
|
static void
|
|
scale_by(void* _canvas, double x, double y)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
BPoint leftTop(0, 0);
|
|
canvas->PenToScreenTransform().Apply(&leftTop);
|
|
|
|
BAffineTransform transform = canvas->CurrentState()->Transform();
|
|
transform.PreScaleBy(x, y);
|
|
canvas->CurrentState()->SetTransform(transform);
|
|
canvas->GetDrawingEngine()->SetTransform(
|
|
canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
|
|
}
|
|
|
|
|
|
static void
|
|
rotate_by(void* _canvas, double angleRadians)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
|
|
BPoint leftTop(0, 0);
|
|
canvas->PenToScreenTransform().Apply(&leftTop);
|
|
|
|
BAffineTransform transform = canvas->CurrentState()->Transform();
|
|
transform.PreRotateBy(angleRadians);
|
|
canvas->CurrentState()->SetTransform(transform);
|
|
canvas->GetDrawingEngine()->SetTransform(
|
|
canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
|
|
}
|
|
|
|
|
|
static void
|
|
blend_layer(void* _canvas, Layer* layer)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
canvas->BlendLayer(layer);
|
|
}
|
|
|
|
|
|
static void
|
|
clip_to_rect(void* _canvas, const BRect& rect, bool inverse)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
bool needDrawStateUpdate = canvas->ClipToRect(rect, inverse);
|
|
if (needDrawStateUpdate) {
|
|
canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
|
|
canvas->Bounds());
|
|
canvas->ResyncDrawState();
|
|
}
|
|
canvas->UpdateCurrentDrawingRegion();
|
|
}
|
|
|
|
|
|
static void
|
|
clip_to_shape(void* _canvas, int32 opCount, const uint32 opList[],
|
|
int32 ptCount, const BPoint ptList[], bool inverse)
|
|
{
|
|
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
|
|
shape_data shapeData;
|
|
|
|
// TODO: avoid copies
|
|
shapeData.opList = (uint32*)malloc(opCount * sizeof(uint32));
|
|
memcpy(shapeData.opList, opList, opCount * sizeof(uint32));
|
|
shapeData.ptList = (BPoint*)malloc(ptCount * sizeof(BPoint));
|
|
memcpy((void*)shapeData.ptList, ptList, ptCount * sizeof(BPoint));
|
|
|
|
shapeData.opCount = opCount;
|
|
shapeData.opSize = opCount * sizeof(uint32);
|
|
shapeData.ptCount = ptCount;
|
|
shapeData.ptSize = ptCount * sizeof(BPoint);
|
|
|
|
canvas->ClipToShape(&shapeData, inverse);
|
|
canvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
|
|
canvas->Bounds());
|
|
canvas->ResyncDrawState();
|
|
|
|
free(shapeData.opList);
|
|
free(shapeData.ptList);
|
|
}
|
|
|
|
|
|
static const BPrivate::picture_player_callbacks kPicturePlayerCallbacks = {
|
|
move_pen_by,
|
|
stroke_line,
|
|
draw_rect,
|
|
draw_round_rect,
|
|
draw_bezier,
|
|
draw_arc,
|
|
draw_ellipse,
|
|
draw_polygon,
|
|
draw_shape,
|
|
draw_string,
|
|
draw_pixels,
|
|
draw_picture,
|
|
set_clipping_rects,
|
|
clip_to_picture,
|
|
push_state,
|
|
pop_state,
|
|
enter_state_change,
|
|
exit_state_change,
|
|
enter_font_state,
|
|
exit_font_state,
|
|
set_origin,
|
|
set_pen_location,
|
|
set_drawing_mode,
|
|
set_line_mode,
|
|
set_pen_size,
|
|
set_fore_color,
|
|
set_back_color,
|
|
set_stipple_pattern,
|
|
set_scale,
|
|
set_font_family,
|
|
set_font_style,
|
|
set_font_spacing,
|
|
set_font_size,
|
|
set_font_rotation,
|
|
set_font_encoding,
|
|
set_font_flags,
|
|
set_font_shear,
|
|
set_font_face,
|
|
set_blending_mode,
|
|
set_transform,
|
|
translate_by,
|
|
scale_by,
|
|
rotate_by,
|
|
blend_layer,
|
|
clip_to_rect,
|
|
clip_to_shape,
|
|
draw_string_locations,
|
|
draw_rect_gradient,
|
|
draw_round_rect_gradient,
|
|
draw_bezier_gradient,
|
|
draw_arc_gradient,
|
|
draw_ellipse_gradient,
|
|
draw_polygon_gradient,
|
|
draw_shape_gradient,
|
|
set_fill_rule
|
|
};
|
|
|
|
|
|
// #pragma mark - ServerPicture
|
|
|
|
|
|
ServerPicture::ServerPicture()
|
|
:
|
|
fFile(NULL),
|
|
fOwner(NULL)
|
|
{
|
|
fToken = gTokenSpace.NewToken(kPictureToken, this);
|
|
fData.SetTo(new(std::nothrow) BMallocIO());
|
|
|
|
PictureDataWriter::SetTo(fData.Get());
|
|
}
|
|
|
|
|
|
ServerPicture::ServerPicture(const ServerPicture& picture)
|
|
:
|
|
fFile(NULL),
|
|
fData(NULL),
|
|
fOwner(NULL)
|
|
{
|
|
fToken = gTokenSpace.NewToken(kPictureToken, this);
|
|
|
|
BMallocIO* mallocIO = new(std::nothrow) BMallocIO();
|
|
if (mallocIO == NULL)
|
|
return;
|
|
|
|
fData.SetTo(mallocIO);
|
|
|
|
const off_t size = picture.DataLength();
|
|
if (mallocIO->SetSize(size) < B_OK)
|
|
return;
|
|
|
|
picture.fData->ReadAt(0, const_cast<void*>(mallocIO->Buffer()),
|
|
size);
|
|
|
|
PictureDataWriter::SetTo(fData.Get());
|
|
}
|
|
|
|
|
|
ServerPicture::ServerPicture(const char* fileName, int32 offset)
|
|
:
|
|
fFile(NULL),
|
|
fData(NULL),
|
|
fOwner(NULL)
|
|
{
|
|
fToken = gTokenSpace.NewToken(kPictureToken, this);
|
|
|
|
fFile.SetTo(new(std::nothrow) BFile(fileName, B_READ_WRITE));
|
|
if (!fFile.IsSet())
|
|
return;
|
|
|
|
BPrivate::Storage::OffsetFile* offsetFile
|
|
= new(std::nothrow) BPrivate::Storage::OffsetFile(fFile.Get(), offset);
|
|
if (offsetFile == NULL || offsetFile->InitCheck() != B_OK) {
|
|
delete offsetFile;
|
|
return;
|
|
}
|
|
|
|
fData.SetTo(offsetFile);
|
|
|
|
PictureDataWriter::SetTo(fData.Get());
|
|
}
|
|
|
|
|
|
ServerPicture::~ServerPicture()
|
|
{
|
|
ASSERT(fOwner == NULL);
|
|
|
|
gTokenSpace.RemoveToken(fToken);
|
|
|
|
if (fPictures.IsSet()) {
|
|
for (int32 i = fPictures->CountItems(); i-- > 0;) {
|
|
ServerPicture* picture = fPictures->ItemAt(i);
|
|
picture->SetOwner(NULL);
|
|
picture->ReleaseReference();
|
|
}
|
|
}
|
|
|
|
if (fPushed != NULL)
|
|
fPushed->SetOwner(NULL);
|
|
}
|
|
|
|
|
|
bool
|
|
ServerPicture::SetOwner(ServerApp* owner)
|
|
{
|
|
if (owner == fOwner)
|
|
return true;
|
|
|
|
// Acquire an extra reference, since calling RemovePicture()
|
|
// May remove the last reference and then we will self-destruct right then.
|
|
// Setting fOwner to NULL would access free'd memory. If owner is another
|
|
// ServerApp, it's expected to already have a reference of course.
|
|
BReference<ServerPicture> _(this);
|
|
|
|
if (fOwner != NULL)
|
|
fOwner->RemovePicture(this);
|
|
|
|
fOwner = NULL;
|
|
if (owner == NULL)
|
|
return true;
|
|
|
|
if (!owner->AddPicture(this))
|
|
return false;
|
|
|
|
fOwner = owner;
|
|
return true;
|
|
}
|
|
|
|
|
|
void
|
|
ServerPicture::EnterStateChange()
|
|
{
|
|
BeginOp(B_PIC_ENTER_STATE_CHANGE);
|
|
}
|
|
|
|
|
|
void
|
|
ServerPicture::ExitStateChange()
|
|
{
|
|
EndOp();
|
|
}
|
|
|
|
|
|
void
|
|
ServerPicture::SyncState(Canvas* canvas)
|
|
{
|
|
// TODO: Finish this
|
|
EnterStateChange();
|
|
|
|
WriteSetOrigin(canvas->CurrentState()->Origin());
|
|
WriteSetPenLocation(canvas->CurrentState()->PenLocation());
|
|
WriteSetPenSize(canvas->CurrentState()->UnscaledPenSize());
|
|
WriteSetScale(canvas->CurrentState()->Scale());
|
|
WriteSetLineMode(canvas->CurrentState()->LineCapMode(),
|
|
canvas->CurrentState()->LineJoinMode(),
|
|
canvas->CurrentState()->MiterLimit());
|
|
//WriteSetPattern(*canvas->CurrentState()->GetPattern().GetInt8());
|
|
WriteSetDrawingMode(canvas->CurrentState()->GetDrawingMode());
|
|
|
|
WriteSetHighColor(canvas->CurrentState()->HighColor());
|
|
WriteSetLowColor(canvas->CurrentState()->LowColor());
|
|
|
|
ExitStateChange();
|
|
}
|
|
|
|
|
|
void
|
|
ServerPicture::WriteFontState(const ServerFont& font, uint16 mask)
|
|
{
|
|
BeginOp(B_PIC_ENTER_FONT_STATE);
|
|
|
|
if (mask & B_FONT_FAMILY_AND_STYLE) {
|
|
WriteSetFontFamily(font.Family());
|
|
WriteSetFontStyle(font.Style());
|
|
}
|
|
|
|
if (mask & B_FONT_SIZE) {
|
|
WriteSetFontSize(font.Size());
|
|
}
|
|
|
|
if (mask & B_FONT_SHEAR) {
|
|
WriteSetFontShear(font.Shear());
|
|
}
|
|
|
|
if (mask & B_FONT_ROTATION) {
|
|
WriteSetFontRotation(font.Rotation());
|
|
}
|
|
|
|
if (mask & B_FONT_FALSE_BOLD_WIDTH) {
|
|
// TODO: Implement
|
|
// WriteSetFalseBoldWidth(font.FalseBoldWidth());
|
|
}
|
|
|
|
if (mask & B_FONT_SPACING) {
|
|
WriteSetFontSpacing(font.Spacing());
|
|
}
|
|
|
|
if (mask & B_FONT_ENCODING) {
|
|
WriteSetFontEncoding(font.Encoding());
|
|
}
|
|
|
|
if (mask & B_FONT_FACE) {
|
|
WriteSetFontFace(font.Face());
|
|
}
|
|
|
|
if (mask & B_FONT_FLAGS) {
|
|
WriteSetFontFlags(font.Flags());
|
|
}
|
|
|
|
EndOp();
|
|
}
|
|
|
|
|
|
void
|
|
ServerPicture::Play(Canvas* target)
|
|
{
|
|
// TODO: for now: then change PicturePlayer
|
|
// to accept a BPositionIO object
|
|
BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(fData.Get());
|
|
if (mallocIO == NULL)
|
|
return;
|
|
|
|
BPrivate::PicturePlayer player(mallocIO->Buffer(),
|
|
mallocIO->BufferLength(), PictureList::Private(fPictures.Get()).AsBList());
|
|
player.Play(kPicturePlayerCallbacks, sizeof(kPicturePlayerCallbacks),
|
|
target);
|
|
}
|
|
|
|
|
|
/*! Acquires a reference to the pushed picture.
|
|
*/
|
|
void
|
|
ServerPicture::PushPicture(ServerPicture* picture)
|
|
{
|
|
if (fPushed != NULL)
|
|
debugger("already pushed a picture");
|
|
|
|
fPushed.SetTo(picture, false);
|
|
}
|
|
|
|
|
|
/*! Returns a reference with the popped picture.
|
|
*/
|
|
ServerPicture*
|
|
ServerPicture::PopPicture()
|
|
{
|
|
return fPushed.Detach();
|
|
}
|
|
|
|
|
|
void
|
|
ServerPicture::AppendPicture(ServerPicture* picture)
|
|
{
|
|
// A pushed picture is the same as an appended one
|
|
PushPicture(picture);
|
|
}
|
|
|
|
|
|
bool
|
|
ServerPicture::NestPicture(ServerPicture* picture)
|
|
{
|
|
if (!fPictures.IsSet())
|
|
fPictures.SetTo(new(std::nothrow) PictureList);
|
|
|
|
if (!fPictures.IsSet() || !fPictures->AddItem(picture))
|
|
return false;
|
|
|
|
picture->AcquireReference();
|
|
return true;
|
|
}
|
|
|
|
|
|
off_t
|
|
ServerPicture::DataLength() const
|
|
{
|
|
if (!fData.IsSet())
|
|
return 0;
|
|
off_t size;
|
|
fData->GetSize(&size);
|
|
return size;
|
|
}
|
|
|
|
|
|
status_t
|
|
ServerPicture::ImportData(BPrivate::LinkReceiver& link)
|
|
{
|
|
int32 size = 0;
|
|
link.Read<int32>(&size);
|
|
|
|
off_t oldPosition = fData->Position();
|
|
fData->Seek(0, SEEK_SET);
|
|
|
|
status_t status = B_NO_MEMORY;
|
|
char* buffer = new(std::nothrow) char[size];
|
|
if (buffer) {
|
|
status = B_OK;
|
|
ssize_t read = link.Read(buffer, size);
|
|
if (read < B_OK || fData->Write(buffer, size) < B_OK)
|
|
status = B_ERROR;
|
|
delete [] buffer;
|
|
}
|
|
|
|
fData->Seek(oldPosition, SEEK_SET);
|
|
return status;
|
|
}
|
|
|
|
|
|
status_t
|
|
ServerPicture::ExportData(BPrivate::PortLink& link)
|
|
{
|
|
link.StartMessage(B_OK);
|
|
|
|
off_t oldPosition = fData->Position();
|
|
fData->Seek(0, SEEK_SET);
|
|
|
|
int32 subPicturesCount = 0;
|
|
if (fPictures.IsSet())
|
|
subPicturesCount = fPictures->CountItems();
|
|
link.Attach<int32>(subPicturesCount);
|
|
if (subPicturesCount > 0) {
|
|
for (int32 i = 0; i < subPicturesCount; i++) {
|
|
ServerPicture* subPicture = fPictures->ItemAt(i);
|
|
link.Attach<int32>(subPicture->Token());
|
|
}
|
|
}
|
|
|
|
off_t size = 0;
|
|
fData->GetSize(&size);
|
|
link.Attach<int32>((int32)size);
|
|
|
|
status_t status = B_NO_MEMORY;
|
|
char* buffer = new(std::nothrow) char[size];
|
|
if (buffer) {
|
|
status = B_OK;
|
|
ssize_t read = fData->Read(buffer, size);
|
|
if (read < B_OK || link.Attach(buffer, read) < B_OK)
|
|
status = B_ERROR;
|
|
delete [] buffer;
|
|
}
|
|
|
|
if (status != B_OK) {
|
|
link.CancelMessage();
|
|
link.StartMessage(B_ERROR);
|
|
}
|
|
|
|
fData->Seek(oldPosition, SEEK_SET);
|
|
return status;
|
|
}
|