* Copyright 2001-2019, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marc Flerackers (mflerackers@androme.be)
* Stefano Ceccherini (stefano.ceccherini@gmail.com)
* Marcus Overhagen <marcus@overhagen.de>
* Julian Harnath <julian.harnath@rwth-aachen.de>
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "ServerPicture.h"
#include <new>
#include <stdio.h>
#include <stack>
#include "AlphaMask.h"
#include "DrawingEngine.h"
#include "DrawState.h"
#include "GlobalFontManager.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)
{
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)
{
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();
}
BPoint screenOffset = fCanvas->CurrentState()->PenLocation();
frame.OffsetBy(screenOffset);
const SimpleTransform transform = fCanvas->PenToScreenTransform();
transform.Apply(&screenOffset);
transform.Apply(&frame);
if (fGradient != NULL) {
fCanvas->GetDrawingEngine()->DrawShape(frame, opCount, opList,
ptCount, ptList, filled, *fGradient, screenOffset, fCanvas->Scale());
} else {
fCanvas->GetDrawingEngine()->DrawShape(frame, opCount, opList,
ptCount, ptList, filled, screenOffset, fCanvas->Scale());
}
delete[] opList;
delete[] ptList;
}
}
class CanvasCallbacks: public BPrivate::PicturePlayerCallbacks {
public:
CanvasCallbacks(Canvas* const canvas);
virtual void MovePenBy(const BPoint& where);
virtual void StrokeLine(const BPoint& start, const BPoint& end);
virtual void DrawRect(const BRect& rect, bool fill);
virtual void DrawRoundRect(const BRect& rect, const BPoint& radii, bool fill);
virtual void DrawBezier(const BPoint controlPoints[4], bool fill);
virtual void DrawArc(const BPoint& center, const BPoint& radii, float startTheta,
float arcTheta, bool fill);
virtual void DrawEllipse(const BRect& rect, bool fill);
virtual void DrawPolygon(size_t numPoints, const BPoint points[], bool isClosed, bool fill);
virtual void DrawShape(const BShape& shape, bool fill);
virtual void DrawString(const char* string, size_t length, float spaceEscapement,
float nonSpaceEscapement);
virtual void DrawPixels(const BRect& source, const BRect& destination, uint32 width,
uint32 height, size_t bytesPerRow, color_space pixelFormat, uint32 flags, const void* data,
size_t length);
virtual void DrawPicture(const BPoint& where, int32 token);
virtual void SetClippingRects(size_t numRects, const clipping_rect rects[]);
virtual void ClipToPicture(int32 token, const BPoint& where, bool clipToInverse);
virtual void PushState();
virtual void PopState();
virtual void EnterStateChange();
virtual void ExitStateChange();
virtual void EnterFontState();
virtual void ExitFontState();
virtual void SetOrigin(const BPoint& origin);
virtual void SetPenLocation(const BPoint& location);
virtual void SetDrawingMode(drawing_mode mode);
virtual void SetLineMode(cap_mode capMode, join_mode joinMode, float miterLimit);
virtual void SetPenSize(float size);
virtual void SetForeColor(const rgb_color& color);
virtual void SetBackColor(const rgb_color& color);
virtual void SetStipplePattern(const pattern& patter);
virtual void SetScale(float scale);
virtual void SetFontFamily(const char* familyName, size_t length);
virtual void SetFontStyle(const char* styleName, size_t length);
virtual void SetFontSpacing(uint8 spacing);
virtual void SetFontSize(float size);
virtual void SetFontRotation(float rotation);
virtual void SetFontEncoding(uint8 encoding);
virtual void SetFontFlags(uint32 flags);
virtual void SetFontShear(float shear);
virtual void SetFontFace(uint16 face);
virtual void SetBlendingMode(source_alpha alphaSourceMode, alpha_function alphaFunctionMode);
virtual void SetTransform(const BAffineTransform& transform);
virtual void TranslateBy(double x, double y);
virtual void ScaleBy(double x, double y);
virtual void RotateBy(double angleRadians);
virtual void BlendLayer(Layer* layer);
virtual void ClipToRect(const BRect& rect, bool inverse);
virtual void ClipToShape(int32 opCount, const uint32 opList[], int32 ptCount,
const BPoint ptList[], bool inverse);
virtual void DrawStringLocations(const char* string, size_t length, const BPoint locations[],
size_t locationCount);
virtual void DrawRectGradient(const BRect& rect, BGradient& gradient, bool fill);
virtual void DrawRoundRectGradient(const BRect& rect, const BPoint& radii, BGradient& gradient,
bool fill);
virtual void DrawBezierGradient(const BPoint controlPoints[4], BGradient& gradient, bool fill);
virtual void DrawArcGradient(const BPoint& center, const BPoint& radii, float startTheta,
float arcTheta, BGradient& gradient, bool fill);
virtual void DrawEllipseGradient(const BRect& rect, BGradient& gradient, bool fill);
virtual void DrawPolygonGradient(size_t numPoints, const BPoint points[], bool isClosed,
BGradient& gradient, bool fill);
virtual void DrawShapeGradient(const BShape& shape, BGradient& gradient, bool fill);
virtual void SetFillRule(int32 fillRule);
virtual void StrokeLineGradient(const BPoint& start, const BPoint& end, BGradient& gradient);
private:
Canvas* const fCanvas;
};
CanvasCallbacks::CanvasCallbacks(Canvas* const canvas)
:
fCanvas(canvas)
{
}
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);
}
void
CanvasCallbacks::MovePenBy(const BPoint& delta)
{
fCanvas->CurrentState()->SetPenLocation(
fCanvas->CurrentState()->PenLocation() + delta);
}
void
CanvasCallbacks::StrokeLine(const BPoint& _start, const BPoint& _end)
{
BPoint start = _start;
BPoint end = _end;
const SimpleTransform transform = fCanvas->PenToScreenTransform();
transform.Apply(&start);
transform.Apply(&end);
fCanvas->GetDrawingEngine()->StrokeLine(start, end);
fCanvas->CurrentState()->SetPenLocation(_end);
}
void
CanvasCallbacks::DrawRect(const BRect& _rect, bool fill)
{
BRect rect = _rect;
fCanvas->PenToScreenTransform().Apply(&rect);
if (fill)
fCanvas->GetDrawingEngine()->FillRect(rect);
else
fCanvas->GetDrawingEngine()->StrokeRect(rect);
}
void
CanvasCallbacks::DrawRoundRect(const BRect& _rect, const BPoint& radii,
bool fill)
{
BRect rect = _rect;
fCanvas->PenToScreenTransform().Apply(&rect);
float scale = fCanvas->CurrentState()->CombinedScale();
fCanvas->GetDrawingEngine()->DrawRoundRect(rect, radii.x * scale,
radii.y * scale, fill);
}
void
CanvasCallbacks::DrawBezier(const BPoint viewPoints[4], bool fill)
{
const size_t kNumPoints = 4;
BPoint points[kNumPoints];
fCanvas->PenToScreenTransform().Apply(points, viewPoints, kNumPoints);
fCanvas->GetDrawingEngine()->DrawBezier(points, fill);
}
void
CanvasCallbacks::DrawArc(const BPoint& center, const BPoint& radii,
float startTheta, float arcTheta, bool fill)
{
BRect rect(center.x - radii.x, center.y - radii.y,
center.x + radii.x - 1, center.y + radii.y - 1);
fCanvas->PenToScreenTransform().Apply(&rect);
fCanvas->GetDrawingEngine()->DrawArc(rect, startTheta, arcTheta, fill);
}
void
CanvasCallbacks::DrawEllipse(const BRect& _rect, bool fill)
{
BRect rect = _rect;
fCanvas->PenToScreenTransform().Apply(&rect);
fCanvas->GetDrawingEngine()->DrawEllipse(rect, fill);
}
void
CanvasCallbacks::DrawPolygon(size_t numPoints, const BPoint viewPoints[],
bool isClosed, bool fill)
{
if (numPoints == 0)
return;
BStackOrHeapArray<BPoint, 200> points(numPoints);
if (!points.IsValid())
return;
fCanvas->PenToScreenTransform().Apply(points, viewPoints, numPoints);
BRect polyFrame;
get_polygon_frame(points, numPoints, &polyFrame);
fCanvas->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame,
fill, isClosed && numPoints > 2);
}
void
CanvasCallbacks::DrawShape(const BShape& shape, bool fill)
{
ShapePainter drawShape(fCanvas, NULL);
drawShape.Iterate(&shape);
drawShape.Draw(shape.Bounds(), fill);
}
void
CanvasCallbacks::DrawRectGradient(const BRect& _rect, BGradient& gradient, bool fill)
{
BRect rect = _rect;
const SimpleTransform transform =
fCanvas->PenToScreenTransform();
transform.Apply(&rect);
transform.Apply(&gradient);
fCanvas->GetDrawingEngine()->FillRect(rect, gradient);
}
void
CanvasCallbacks::DrawRoundRectGradient(const BRect& _rect, const BPoint& radii, BGradient& gradient,
bool fill)
{
BRect rect = _rect;
const SimpleTransform transform =
fCanvas->PenToScreenTransform();
transform.Apply(&rect);
transform.Apply(&gradient);
float scale = fCanvas->CurrentState()->CombinedScale();
fCanvas->GetDrawingEngine()->DrawRoundRect(rect, radii.x * scale,
radii.y * scale, fill, gradient);
}
void
CanvasCallbacks::DrawBezierGradient(const BPoint viewPoints[4], BGradient& gradient, bool fill)
{
const size_t kNumPoints = 4;
BPoint points[kNumPoints];
const SimpleTransform transform =
fCanvas->PenToScreenTransform();
transform.Apply(points, viewPoints, kNumPoints);
transform.Apply(&gradient);
fCanvas->GetDrawingEngine()->DrawBezier(points, fill, gradient);
}
void
CanvasCallbacks::DrawArcGradient(const BPoint& center, const BPoint& radii,
float startTheta, float arcTheta, BGradient& gradient, bool fill)
{
BRect rect(center.x - radii.x, center.y - radii.y,
center.x + radii.x - 1, center.y + radii.y - 1);
const SimpleTransform transform =
fCanvas->PenToScreenTransform();
transform.Apply(&rect);
transform.Apply(&gradient);
fCanvas->GetDrawingEngine()->DrawArc(rect, startTheta, arcTheta, fill, gradient);
}
void
CanvasCallbacks::DrawEllipseGradient(const BRect& _rect, BGradient& gradient, bool fill)
{
BRect rect = _rect;
const SimpleTransform transform =
fCanvas->PenToScreenTransform();
transform.Apply(&rect);
transform.Apply(&gradient);
fCanvas->GetDrawingEngine()->DrawEllipse(rect, fill, gradient);
}
void
CanvasCallbacks::DrawPolygonGradient(size_t numPoints, const BPoint viewPoints[],
bool isClosed, BGradient& gradient, bool fill)
{
if (numPoints == 0)
return;
BStackOrHeapArray<BPoint, 200> points(numPoints);
if (!points.IsValid())
return;
const SimpleTransform transform =
fCanvas->PenToScreenTransform();
transform.Apply(points, viewPoints, numPoints);
transform.Apply(&gradient);
BRect polyFrame;
get_polygon_frame(points, numPoints, &polyFrame);
fCanvas->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame,
isClosed && numPoints > 2, fill, gradient);
}
void
CanvasCallbacks::DrawShapeGradient(const BShape& shape, BGradient& gradient, bool fill)
{
ShapePainter drawShape(fCanvas, &gradient);
drawShape.Iterate(&shape);
drawShape.Draw(shape.Bounds(), fill);
}
void
CanvasCallbacks::StrokeLineGradient(const BPoint& _start, const BPoint& _end,
BGradient& gradient)
{
BPoint start = _start;
BPoint end = _end;
const SimpleTransform transform = fCanvas->PenToScreenTransform();
transform.Apply(&start);
transform.Apply(&end);
fCanvas->GetDrawingEngine()->StrokeLine(start, end, gradient);
fCanvas->CurrentState()->SetPenLocation(_end);
}
void
CanvasCallbacks::DrawString(const char* string, size_t length, float deltaSpace,
float deltaNonSpace)
{
BPoint location = fCanvas->CurrentState()->PenLocation();
escapement_delta delta = { deltaSpace, deltaNonSpace };
fCanvas->PenToScreenTransform().Apply(&location);
location = fCanvas->GetDrawingEngine()->DrawString(string, length,
location, &delta);
fCanvas->PenToScreenTransform().Apply(&location);
fCanvas->CurrentState()->SetPenLocation(location);
}
void
CanvasCallbacks::DrawStringLocations(const char* string, size_t length,
const BPoint* _locations, size_t locationsCount)
{
BStackOrHeapArray<BPoint, 200> locations(locationsCount);
if (!locations.IsValid())
return;
const SimpleTransform transform = fCanvas->PenToScreenTransform();
for (size_t i = 0; i < locationsCount; i++) {
locations[i] = _locations[i];
transform.Apply(&locations[i]);
}
BPoint location = fCanvas->GetDrawingEngine()->DrawString(string, length,
locations);
fCanvas->PenToScreenTransform().Apply(&location);
fCanvas->CurrentState()->SetPenLocation(location);
}
void
CanvasCallbacks::DrawPixels(const BRect& src, const BRect& _dest, uint32 width,
uint32 height, size_t bytesPerRow, color_space pixelFormat, uint32 options,
const void* data, size_t length)
{
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;
fCanvas->PenToScreenTransform().Apply(&dest);
fCanvas->GetDrawingEngine()->DrawBitmap(&bitmap, src, dest, options);
}
void
CanvasCallbacks::DrawPicture(const BPoint& where, int32 token)
{
BReference<ServerPicture> picture(fCanvas->GetPicture(token), true);
if (picture != NULL) {
fCanvas->PushState();
fCanvas->SetDrawingOrigin(where);
fCanvas->PushState();
picture->Play(fCanvas);
fCanvas->PopState();
fCanvas->PopState();
}
}
void
CanvasCallbacks::SetClippingRects(size_t numRects, const clipping_rect rects[])
{
if (numRects == 0)
fCanvas->SetUserClipping(NULL);
else {
BRegion region;
for (uint32 c = 0; c < numRects; c++)
region.Include(rects[c]);
fCanvas->SetUserClipping(®ion);
}
fCanvas->UpdateCurrentDrawingRegion();
}
void
CanvasCallbacks::ClipToPicture(int32 pictureToken, const BPoint& where,
bool clipToInverse)
{
BReference<ServerPicture> picture(fCanvas->GetPicture(pictureToken), true);
if (picture == NULL)
return;
BReference<AlphaMask> mask(new(std::nothrow) PictureAlphaMask(fCanvas->GetAlphaMask(),
picture, *fCanvas->CurrentState(), where, clipToInverse), true);
fCanvas->SetAlphaMask(mask);
fCanvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
fCanvas->Bounds());
fCanvas->ResyncDrawState();
}
void
CanvasCallbacks::PushState()
{
fCanvas->PushState();
}
void
CanvasCallbacks::PopState()
{
fCanvas->PopState();
BPoint p(0, 0);
fCanvas->PenToScreenTransform().Apply(&p);
fCanvas->GetDrawingEngine()->SetDrawState(fCanvas->CurrentState(),
(int32)p.x, (int32)p.y);
}
void
CanvasCallbacks::EnterStateChange()
{
}
void
CanvasCallbacks::ExitStateChange()
{
fCanvas->ResyncDrawState();
}
void
CanvasCallbacks::EnterFontState()
{
}
void
CanvasCallbacks::ExitFontState()
{
fCanvas->GetDrawingEngine()->SetFont(fCanvas->CurrentState()->Font());
}
void
CanvasCallbacks::SetOrigin(const BPoint& pt)
{
fCanvas->CurrentState()->SetOrigin(pt);
}
void
CanvasCallbacks::SetPenLocation(const BPoint& pt)
{
fCanvas->CurrentState()->SetPenLocation(pt);
}
void
CanvasCallbacks::SetDrawingMode(drawing_mode mode)
{
if (fCanvas->CurrentState()->SetDrawingMode(mode))
fCanvas->GetDrawingEngine()->SetDrawingMode(mode);
}
void
CanvasCallbacks::SetLineMode(cap_mode capMode, join_mode joinMode,
float miterLimit)
{
DrawState* state = fCanvas->CurrentState();
state->SetLineCapMode(capMode);
state->SetLineJoinMode(joinMode);
state->SetMiterLimit(miterLimit);
fCanvas->GetDrawingEngine()->SetStrokeMode(capMode, joinMode, miterLimit);
}
void
CanvasCallbacks::SetPenSize(float size)
{
fCanvas->CurrentState()->SetPenSize(size);
fCanvas->GetDrawingEngine()->SetPenSize(
fCanvas->CurrentState()->PenSize());
}
void
CanvasCallbacks::SetForeColor(const rgb_color& color)
{
fCanvas->CurrentState()->SetHighColor(color);
fCanvas->GetDrawingEngine()->SetHighColor(color);
}
void
CanvasCallbacks::SetBackColor(const rgb_color& color)
{
fCanvas->CurrentState()->SetLowColor(color);
fCanvas->GetDrawingEngine()->SetLowColor(color);
}
void
CanvasCallbacks::SetStipplePattern(const pattern& pattern)
{
fCanvas->CurrentState()->SetPattern(Pattern(pattern));
fCanvas->GetDrawingEngine()->SetPattern(pattern);
}
void
CanvasCallbacks::SetScale(float scale)
{
fCanvas->CurrentState()->SetScale(scale);
fCanvas->ResyncDrawState();
}
void
CanvasCallbacks::SetFontFamily(const char* _family, size_t length)
{
BString family(_family, length);
gFontManager->Lock();
FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0);
ServerFont font;
font.SetStyle(fontStyle);
gFontManager->Unlock();
fCanvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
}
void
CanvasCallbacks::SetFontStyle(const char* _style, size_t length)
{
BString style(_style, length);
ServerFont font(fCanvas->CurrentState()->Font());
gFontManager->Lock();
FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style);
font.SetStyle(fontStyle);
gFontManager->Unlock();
fCanvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE);
}
void
CanvasCallbacks::SetFontSpacing(uint8 spacing)
{
ServerFont font;
font.SetSpacing(spacing);
fCanvas->CurrentState()->SetFont(font, B_FONT_SPACING);
}
void
CanvasCallbacks::SetFontSize(float size)
{
ServerFont font;
font.SetSize(size);
fCanvas->CurrentState()->SetFont(font, B_FONT_SIZE);
}
void
CanvasCallbacks::SetFontRotation(float rotation)
{
ServerFont font;
font.SetRotation(rotation);
fCanvas->CurrentState()->SetFont(font, B_FONT_ROTATION);
}
void
CanvasCallbacks::SetFontEncoding(uint8 encoding)
{
ServerFont font;
font.SetEncoding(encoding);
fCanvas->CurrentState()->SetFont(font, B_FONT_ENCODING);
}
void
CanvasCallbacks::SetFontFlags(uint32 flags)
{
ServerFont font;
font.SetFlags(flags);
fCanvas->CurrentState()->SetFont(font, B_FONT_FLAGS);
}
void
CanvasCallbacks::SetFontShear(float shear)
{
ServerFont font;
font.SetShear(shear);
fCanvas->CurrentState()->SetFont(font, B_FONT_SHEAR);
}
void
CanvasCallbacks::SetFontFace(uint16 face)
{
ServerFont font;
font.SetFace(face);
fCanvas->CurrentState()->SetFont(font, B_FONT_FACE);
}
void
CanvasCallbacks::SetBlendingMode(source_alpha alphaSrcMode,
alpha_function alphaFncMode)
{
fCanvas->CurrentState()->SetBlendingMode(alphaSrcMode, alphaFncMode);
}
void
CanvasCallbacks::SetFillRule(int32 fillRule)
{
fCanvas->CurrentState()->SetFillRule(fillRule);
fCanvas->GetDrawingEngine()->SetFillRule(fillRule);
}
void
CanvasCallbacks::SetTransform(const BAffineTransform& transform)
{
BPoint leftTop(0, 0);
fCanvas->PenToScreenTransform().Apply(&leftTop);
fCanvas->CurrentState()->SetTransform(transform);
fCanvas->GetDrawingEngine()->SetTransform(
fCanvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
}
void
CanvasCallbacks::TranslateBy(double x, double y)
{
BPoint leftTop(0, 0);
fCanvas->PenToScreenTransform().Apply(&leftTop);
BAffineTransform transform = fCanvas->CurrentState()->Transform();
transform.PreTranslateBy(x, y);
fCanvas->CurrentState()->SetTransform(transform);
fCanvas->GetDrawingEngine()->SetTransform(
fCanvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
}
void
CanvasCallbacks::ScaleBy(double x, double y)
{
BPoint leftTop(0, 0);
fCanvas->PenToScreenTransform().Apply(&leftTop);
BAffineTransform transform = fCanvas->CurrentState()->Transform();
transform.PreScaleBy(x, y);
fCanvas->CurrentState()->SetTransform(transform);
fCanvas->GetDrawingEngine()->SetTransform(
fCanvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
}
void
CanvasCallbacks::RotateBy(double angleRadians)
{
BPoint leftTop(0, 0);
fCanvas->PenToScreenTransform().Apply(&leftTop);
BAffineTransform transform = fCanvas->CurrentState()->Transform();
transform.PreRotateBy(angleRadians);
fCanvas->CurrentState()->SetTransform(transform);
fCanvas->GetDrawingEngine()->SetTransform(
fCanvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y);
}
void
CanvasCallbacks::BlendLayer(Layer* layer)
{
fCanvas->BlendLayer(layer);
}
void
CanvasCallbacks::ClipToRect(const BRect& rect, bool inverse)
{
bool needDrawStateUpdate = fCanvas->ClipToRect(rect, inverse);
if (needDrawStateUpdate) {
fCanvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
fCanvas->Bounds());
fCanvas->ResyncDrawState();
}
fCanvas->UpdateCurrentDrawingRegion();
}
void
CanvasCallbacks::ClipToShape(int32 opCount, const uint32 opList[],
int32 ptCount, const BPoint ptList[], bool inverse)
{
shape_data shapeData;
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);
fCanvas->ClipToShape(&shapeData, inverse);
fCanvas->CurrentState()->GetAlphaMask()->SetCanvasGeometry(BPoint(0, 0),
fCanvas->Bounds());
fCanvas->ResyncDrawState();
free(shapeData.opList);
free(shapeData.ptList);
}
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;
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)
{
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());
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) {
}
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)
{
BMallocIO* mallocIO = dynamic_cast<BMallocIO*>(fData.Get());
if (mallocIO == NULL)
return;
CanvasCallbacks callbacks(target);
BPrivate::PicturePlayer player(mallocIO->Buffer(),
mallocIO->BufferLength(), PictureList::Private(fPictures.Get()).AsBList());
player.Play(callbacks);
}
*/
void
ServerPicture::PushPicture(ServerPicture* picture)
{
if (fPushed != NULL)
debugger("already pushed a picture");
fPushed.SetTo(picture, false);
}
*/
ServerPicture*
ServerPicture::PopPicture()
{
return fPushed.Detach();
}
void
ServerPicture::AppendPicture(ServerPicture* picture)
{
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;
}