diff --git a/headers/private/interface/PicturePlayer.h b/headers/private/interface/PicturePlayer.h index 1a74b5cefe..bd714b74b5 100644 --- a/headers/private/interface/PicturePlayer.h +++ b/headers/private/interface/PicturePlayer.h @@ -14,25 +14,93 @@ #include +#include #include #include -#include + +class BAffineTransform; class BList; +class BPicture; +class BShape; namespace BPrivate { + +struct picture_player_callbacks { + void (*move_pen_by)(void* userData, const BPoint& where); + void (*stroke_line)(void* userData, const BPoint& start, const BPoint& end); + void (*draw_rect)(void* userData, const BRect& rect, bool fill); + void (*draw_round_rect)(void* userData, const BRect& rect, + const BPoint& radii, bool fill); + void (*draw_bezier)(void* userData, size_t numControlPoints, + const BPoint controlPoints[], bool fill); + void (*draw_arc)(void* userData, const BPoint& center, const BPoint& radii, + float startTheta, float arcTheta, bool fill); + void (*draw_ellipse)(void* userData, const BRect& rect, bool fill); + void (*draw_polygon)(void* userData, size_t numPoints, + const BPoint points[], bool isClosed, bool fill); + void (*draw_shape)(void* userData, const BShape& shape, bool fill); + void (*draw_string)(void* userData, const char* string, size_t length, + float spaceEscapement, float nonSpaceEscapement); + void (*draw_pixels)(void* userData, const BRect& source, + const BRect& destination, uint32 width, uint32 height, + size_t bytesPerRow, color_space pixelFormat, uint32 flags, + const void* data, size_t length); + void (*draw_picture)(void* userData, const BPoint& where, int32 token); + void (*set_clipping_rects)(void* userData, size_t numRects, + const BRect rects[]); + void (*clip_to_picture)(void* userData, const BPicture& picture, + const BPoint& where, bool clipToInverse); + void (*push_state)(void* userData); + void (*pop_state)(void* userData); + void (*enter_state_change)(void* userData); + void (*exit_state_change)(void* userData); + void (*enter_font_state)(void* userData); + void (*exit_font_state)(void* userData); + void (*set_origin)(void* userData, const BPoint& origin); + void (*set_pen_location)(void* userData, const BPoint& location); + void (*set_drawing_mode)(void* userData, drawing_mode mode); + void (*set_line_mode)(void* userData, cap_mode capMode, join_mode joinMode, + float miterLimit); + void (*set_pen_size)(void* userData, float size); + void (*set_fore_color)(void* userData, const rgb_color& color); + void (*set_back_color)(void* userData, const rgb_color& color); + void (*set_stipple_pattern)(void* userData, const pattern& patter); + void (*set_scale)(void* userData, float scale); + void (*set_font_family)(void* userData, const char* familyName, + size_t length); + void (*set_font_style)(void* userData, const char* styleName, + size_t length); + void (*set_font_spacing)(void* userData, uint8 spacing); + void (*set_font_size)(void* userData, float size); + void (*set_font_rotation)(void* userData, float rotation); + void (*set_font_encoding)(void* userData, uint8 encoding); + void (*set_font_flags)(void* userData, uint32 flags); + void (*set_font_shear)(void* userData, float shear); + void (*set_font_face)(void* userData, uint16 face); + void (*set_blending_mode)(void* userData, source_alpha alphaSourceMode, + alpha_function alphaFunctionMode); + void (*set_transform)(void* userData, const BAffineTransform& transform); +}; + + class PicturePlayer { public: PicturePlayer(); - PicturePlayer(const void *data, size_t size, BList *pictures); + PicturePlayer(const void* data, size_t size, BList* pictures); virtual ~PicturePlayer(); - status_t Play(void **callBackTable, int32 tableEntries, - void *userData); + status_t Play(void** callbacks, int32 tableEntries, + void* userData); + status_t Play(const picture_player_callbacks& callbacks, + size_t callbacksSize, void* userData); private: + status_t _Play(const picture_player_callbacks& callbacks, void* userData, + const void* data, size_t length, uint16 parentOp); + const void* fData; size_t fSize; BList* fPictures; diff --git a/src/kits/interface/PicturePlayer.cpp b/src/kits/interface/PicturePlayer.cpp index f337bc1896..4b32428a4a 100644 --- a/src/kits/interface/PicturePlayer.cpp +++ b/src/kits/interface/PicturePlayer.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -23,30 +24,10 @@ using BPrivate::PicturePlayer; -typedef void (*fnc)(void*); -typedef void (*fnc_BPoint)(void*, BPoint); -typedef void (*fnc_BPointBPoint)(void*, BPoint, BPoint); -typedef void (*fnc_BRect)(void*, BRect); -typedef void (*fnc_BRectBPoint)(void*, BRect, BPoint); -typedef void (*fnc_PBPoint)(void*, const BPoint*); -typedef void (*fnc_i)(void*, int32); -typedef void (*fnc_iPBPointb)(void*, int32, const BPoint*, bool); -typedef void (*fnc_iPBPoint)(void*, int32, const BPoint*); -typedef void (*fnc_Pc)(void*, const char*); -typedef void (*fnc_Pcff)(void*, const char*, float, float); -typedef void (*fnc_BPointBPointff)(void*, BPoint, BPoint, float, float); -typedef void (*fnc_s)(void*, int16); -typedef void (*fnc_ssf)(void*, int16, int16, float); -typedef void (*fnc_f)(void*, float); -typedef void (*fnc_Color)(void*, rgb_color); -typedef void (*fnc_Pattern)(void*, pattern); -typedef void (*fnc_ss)(void *, int16, int16); -typedef void (*fnc_PBRecti)(void*, const BRect*, uint32); -typedef void (*fnc_DrawPixels)(void *, BRect, BRect, int32, int32, int32, - int32, int32, const void *); -typedef void (*fnc_DrawPicture)(void *, BPoint, int32); -typedef void (*fnc_BShape)(void*, BShape*); -typedef void (*fnc_BAffineTransform)(void*, BAffineTransform); +struct adapter_context { + void* user_data; + void** function_table; +}; static void @@ -55,6 +36,421 @@ nop() } +static void +move_pen_by(void* _context, const BPoint& delta) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, BPoint))context->function_table[1])(context->user_data, + delta); +} + + +static void +stroke_line(void* _context, const BPoint& start, const BPoint& end) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, BPoint, BPoint))context->function_table[2])( + context->user_data, start, end); +} + + +static void +draw_rect(void* _context, const BRect& rect, bool fill) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, BRect))context->function_table[fill ? 4 : 3])( + context->user_data, rect); +} + + +static void +draw_round_rect(void* _context, const BRect& rect, const BPoint& radii, + bool fill) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, BRect, BPoint))context->function_table[fill ? 6 : 5])( + context->user_data, rect, radii); +} + + +static void +draw_bezier(void* _context, size_t numPoints, const BPoint _points[], bool fill) +{ + adapter_context* context = reinterpret_cast(_context); + if (numPoints != 4) + return; + + BPoint points[4] = { _points[0], _points[1], _points[2], _points[3] }; + ((void (*)(void*, BPoint*))context->function_table[fill ? 8 : 7])( + context->user_data, points); +} + + +static void +draw_arc(void* _context, const BPoint& center, const BPoint& radii, + float startTheta, float arcTheta, bool fill) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, BPoint, BPoint, float, float)) + context->function_table[fill ? 10 : 9])(context->user_data, center, + radii, startTheta, arcTheta); +} + + +static void +draw_ellipse(void* _context, const BRect& rect, bool fill) +{ + adapter_context* context = reinterpret_cast(_context); + BPoint radii((rect.Width() + 1) / 2.0f, (rect.Height() + 1) / 2.0f); + BPoint center = rect.LeftTop() + radii; + ((void (*)(void*, BPoint, BPoint)) + context->function_table[fill ? 12 : 11])(context->user_data, center, + radii); +} + + +static void +draw_polygon(void* _context, size_t numPoints, const BPoint _points[], + bool isClosed, bool fill) +{ + adapter_context* context = reinterpret_cast(_context); + + // This is rather ugly but works for such a trivial class. + const size_t kMaxStackCount = 200; + char stackData[kMaxStackCount * sizeof(BPoint)]; + BPoint* points = (BPoint*)stackData; + if (numPoints > kMaxStackCount) { + points = (BPoint*)malloc(numPoints * sizeof(BPoint)); + if (points == NULL) + return; + } + + memcpy(points, _points, numPoints * sizeof(BPoint)); + + ((void (*)(void*, int32, BPoint*, bool)) + context->function_table[fill ? 14 : 13])(context->user_data, numPoints, + points, isClosed); + + if (numPoints > kMaxStackCount) + free(points); +} + + +static void +draw_shape(void* _context, const BShape& shape, bool fill) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, BShape))context->function_table[fill ? 16 : 15])( + context->user_data, shape); +} + + +static void +draw_string(void* _context, const char* _string, size_t length, + float deltaSpace, float deltaNonSpace) +{ + adapter_context* context = reinterpret_cast(_context); + char* string = strndup(_string, length); + + ((void (*)(void*, char*, float, float)) + context->function_table[17])(context->user_data, string, deltaSpace, + deltaNonSpace); + + free(string); +} + + +static void +draw_pixels(void* _context, const BRect& src, const BRect& dest, uint32 width, + uint32 height, size_t bytesPerRow, color_space pixelFormat, uint32 options, + const void* _data, size_t length) +{ + adapter_context* context = reinterpret_cast(_context); + void* data = malloc(length); + if (data == NULL) + return; + + memcpy(data, _data, length); + + ((void (*)(void*, BRect, BRect, int32, int32, int32, int32, int32, void*)) + context->function_table[18])(context->user_data, src, dest, width, + height, bytesPerRow, pixelFormat, options, data); + + free(data); +} + + +static void +draw_picture(void* _context, const BPoint& where, int32 token) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, BPoint, int32))context->function_table[19])( + context->user_data, where, token); +} + + +static void +set_clipping_rects(void* _context, size_t numRects, const BRect _rects[]) +{ + adapter_context* context = reinterpret_cast(_context); + + // This is rather ugly but works for such a trivial class. + const size_t kMaxStackCount = 100; + char stackData[kMaxStackCount * sizeof(BRect)]; + BRect* rects = (BRect*)stackData; + if (numRects > kMaxStackCount) { + rects = (BRect*)malloc(numRects * sizeof(BRect)); + if (rects == NULL) + return; + } + + memcpy(rects, _rects, numRects * sizeof(BRect)); + + ((void (*)(void*, BRect*, uint32))context->function_table[20])( + context->user_data, rects, numRects); + + if (numRects > kMaxStackCount) + free(rects); +} + + +static void +clip_to_picture(void* context, const BPicture& picture, const BPoint& origin, + bool clipToInverse) +{ +} + + +static void +push_state(void* _context) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*))context->function_table[22])(context->user_data); +} + + +static void +pop_state(void* _context) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*))context->function_table[23])(context->user_data); +} + + +static void +enter_state_change(void* _context) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*))context->function_table[24])(context->user_data); +} + + +static void +exit_state_change(void* _context) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*))context->function_table[25])(context->user_data); +} + + +static void +enter_font_state(void* _context) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*))context->function_table[26])(context->user_data); +} + + +static void +exit_font_state(void* _context) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*))context->function_table[27])(context->user_data); +} + + +static void +set_origin(void* _context, const BPoint& origin) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, BPoint))context->function_table[28])(context->user_data, + origin); +} + + +static void +set_pen_location(void* _context, const BPoint& penLocation) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, BPoint))context->function_table[29])(context->user_data, + penLocation); +} + + +static void +set_drawing_mode(void* _context, drawing_mode mode) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, drawing_mode))context->function_table[30])( + context->user_data, mode); +} + + +static void +set_line_mode(void* _context, cap_mode capMode, join_mode joinMode, + float miterLimit) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, cap_mode, join_mode, float))context->function_table[31])( + context->user_data, capMode, joinMode, miterLimit); +} + + +static void +set_pen_size(void* _context, float size) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, float))context->function_table[32])(context->user_data, + size); +} + + +static void +set_fore_color(void* _context, const rgb_color& color) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, rgb_color))context->function_table[33])( + context->user_data, color); +} + + +static void +set_back_color(void* _context, const rgb_color& color) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, rgb_color))context->function_table[34])( + context->user_data, color); +} + + +static void +set_stipple_pattern(void* _context, const pattern& stipplePattern) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, pattern))context->function_table[35])(context->user_data, + stipplePattern); +} + + +static void +set_scale(void* _context, float scale) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, float))context->function_table[36])(context->user_data, + scale); +} + + +static void +set_font_family(void* _context, const char* _family, size_t length) +{ + adapter_context* context = reinterpret_cast(_context); + char* family = strndup(_family, length); + + ((void (*)(void*, char*))context->function_table[37])(context->user_data, + family); + + free(family); +} + + +static void +set_font_style(void* _context, const char* _style, size_t length) +{ + adapter_context* context = reinterpret_cast(_context); + char* style = strndup(_style, length); + + ((void (*)(void*, char*))context->function_table[38])(context->user_data, + style); + + free(style); +} + + +static void +set_font_spacing(void* _context, uint8 spacing) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, int32))context->function_table[39])(context->user_data, + spacing); +} + + +static void +set_font_size(void* _context, float size) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, float))context->function_table[40])(context->user_data, + size); +} + + +static void +set_font_rotation(void* _context, float rotation) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, float))context->function_table[41])(context->user_data, + rotation); +} + + +static void +set_font_encoding(void* _context, uint8 encoding) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, int32))context->function_table[42])(context->user_data, + encoding); +} + + +static void +set_font_flags(void* _context, uint32 flags) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, int32))context->function_table[43])(context->user_data, + flags); +} + + +static void +set_font_shear(void* _context, float shear) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, float))context->function_table[44])(context->user_data, + shear); +} + + +static void +set_font_face(void* _context, uint16 face) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, int32))context->function_table[46])(context->user_data, + face); +} + + +static void +set_blending_mode(void* _context, source_alpha alphaSrcMode, + alpha_function alphaFncMode) +{ + adapter_context* context = reinterpret_cast(_context); + ((void (*)(void*, source_alpha, alpha_function)) + context->function_table[47])(context->user_data, alphaSrcMode, + alphaFncMode); +} + + #if DEBUG > 1 static const char * PictureOpToString(int op) @@ -132,241 +528,403 @@ PicturePlayer::~PicturePlayer() status_t -PicturePlayer::Play(void **callBackTable, int32 tableEntries, void *userData) +PicturePlayer::Play(void** callBackTable, int32 tableEntries, void* userData) { + const BPrivate::picture_player_callbacks kAdapterCallbacks = { + 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 + }; + // We don't check if the functions in the table are NULL, but we // check the tableEntries to see if the table is big enough. // If an application supplies the wrong size or an invalid pointer, // it's its own fault. + + // If the caller supplied a function table smaller than needed, + // we use our dummy table, and copy the supported ops from the supplied one. + void *dummyTable[kOpsTableSize]; + + adapter_context adapterContext; + adapterContext.user_data = userData; + adapterContext.function_table = callBackTable; + + if ((size_t)tableEntries < kOpsTableSize) { + memcpy(dummyTable, callBackTable, tableEntries * sizeof(void*)); + for (size_t i = (size_t)tableEntries; i < kOpsTableSize; i++) + dummyTable[i] = (void*)nop; + + adapterContext.function_table = dummyTable; + } + + return _Play(kAdapterCallbacks, &adapterContext, fData, fSize, 0); +} + + +status_t +PicturePlayer::Play(const picture_player_callbacks& callbacks, + size_t callbacksSize, void* userData) +{ + return _Play(callbacks, userData, fData, fSize, 0); +} + + +class DataReader { +public: + DataReader(const void* buffer, size_t length) + : + fBuffer((const uint8*)buffer), + fRemaining(length) + { + } + + size_t + Remaining() const + { + return fRemaining; + } + + template + bool + Get(const T*& typed, size_t count = 1) + { + if (fRemaining < sizeof(T) * count) + return false; + + typed = reinterpret_cast(fBuffer); + fRemaining -= sizeof(T) * count; + fBuffer += sizeof(T) * count; + return true; + } + + template + bool + GetRemaining(const T*& buffer, size_t& size) + { + if (fRemaining == 0) + return false; + + buffer = reinterpret_cast(fBuffer); + size = fRemaining; + fRemaining = 0; + return true; + } + +private: + const uint8* fBuffer; + size_t fRemaining; +}; + + +struct picture_data_entry_header { + uint16 op; + uint32 size; +} _PACKED; + + +status_t +PicturePlayer::_Play(const picture_player_callbacks& callbacks, void* userData, + const void* buffer, size_t length, uint16 parentOp) +{ #if DEBUG - FILE *file = fopen("/var/log/PicturePlayer.log", "a"); - fprintf(file, "Start rendering BPicture...\n"); + printf("Start rendering %sBPicture...\n", parentOp != 0 ? "sub " : ""); bigtime_t startTime = system_time(); int32 numOps = 0; #endif - // If the caller supplied a function table smaller than needed, - // we use our dummy table, and copy the supported ops from the supplied one. - void **functionTable = callBackTable; - void *dummyTable[kOpsTableSize] = { - (void *)nop, (void *)nop, (void *)nop, (void *)nop, - (void *)nop, (void *)nop, (void *)nop, (void *)nop, - (void *)nop, (void *)nop, (void *)nop, (void *)nop, - (void *)nop, (void *)nop, (void *)nop, (void *)nop, - (void *)nop, (void *)nop, (void *)nop, (void *)nop, - (void *)nop, (void *)nop, (void *)nop, (void *)nop, - (void *)nop, (void *)nop, (void *)nop, (void *)nop, - (void *)nop, (void *)nop, (void *)nop, (void *)nop, - (void *)nop, (void *)nop, (void *)nop, (void *)nop, - (void *)nop, (void *)nop, (void *)nop, (void *)nop, - (void *)nop, (void *)nop, (void *)nop, (void *)nop, - (void *)nop, (void *)nop, (void *)nop, (void *)nop - }; - if ((uint32)tableEntries < kOpsTableSize) { -#if DEBUG - fprintf(file, "PicturePlayer: A smaller than needed function table was supplied.\n"); -#endif - functionTable = dummyTable; - memcpy(functionTable, callBackTable, tableEntries * sizeof(void *)); - } + DataReader pictureReader(buffer, length); - const char *data = reinterpret_cast(fData); - size_t pos = 0; + while (pictureReader.Remaining() > 0) { + const picture_data_entry_header* header; + const uint8* opData; + if (!pictureReader.Get(header) + || !pictureReader.Get(opData, header->size)) { + return B_BAD_DATA; + } - int32 fontStateBlockSize = -1; - int32 stateBlockSize = -1; + DataReader reader(opData, header->size); - while ((pos + 6) <= fSize) { - int16 op = *reinterpret_cast(data); - int32 size = *reinterpret_cast(data + 2); - pos += 6; - data += 6; + // Disallow ops that don't fit the parent. + switch (parentOp) { + case 0: + // No parent op, no restrictions. + break; - if (pos + size > fSize) - debugger("PicturePlayer::Play: buffer overrun\n"); + case B_PIC_ENTER_STATE_CHANGE: + if (header->op <= B_PIC_ENTER_STATE_CHANGE + || header->op > B_PIC_SET_TRANSFORM) { + return B_BAD_DATA; + } + break; + + case B_PIC_ENTER_FONT_STATE: + if (header->op < B_PIC_SET_FONT_FAMILY + || header->op > B_PIC_SET_FONT_FACE) { + return B_BAD_DATA; + } + break; + + default: + return B_BAD_DATA; + } #if DEBUG > 1 bigtime_t startOpTime = system_time(); - fprintf(file, "Op %s ", PictureOpToString(op)); + printf("Op %s ", PictureOpToString(header->op)); #endif - switch (op) { + switch (header->op) { case B_PIC_MOVE_PEN_BY: { - ((fnc_BPoint)functionTable[1])(userData, - *reinterpret_cast(data)); /* where */ + const BPoint* where; + if (callbacks.move_pen_by == NULL || !reader.Get(where)) + break; + + callbacks.move_pen_by(userData, *where); break; } case B_PIC_STROKE_LINE: { - ((fnc_BPointBPoint)functionTable[2])(userData, - *reinterpret_cast(data), /* start */ - *reinterpret_cast(data + sizeof(BPoint))); /* end */ + const BPoint* start; + const BPoint* end; + if (callbacks.stroke_line == NULL || !reader.Get(start) + || !reader.Get(end)) { + break; + } + + callbacks.stroke_line(userData, *start, *end); break; } case B_PIC_STROKE_RECT: - { - ((fnc_BRect)functionTable[3])(userData, - *reinterpret_cast(data)); /* rect */ - break; - } - case B_PIC_FILL_RECT: { - ((fnc_BRect)functionTable[4])(userData, - *reinterpret_cast(data)); /* rect */ + const BRect* rect; + if (callbacks.draw_rect == NULL || !reader.Get(rect)) + break; + + callbacks.draw_rect(userData, *rect, + header->op == B_PIC_FILL_RECT); break; } case B_PIC_STROKE_ROUND_RECT: - { - ((fnc_BRectBPoint)functionTable[5])(userData, - *reinterpret_cast(data), /* rect */ - *reinterpret_cast(data + sizeof(BRect))); /* radii */ - break; - } - case B_PIC_FILL_ROUND_RECT: { - ((fnc_BRectBPoint)functionTable[6])(userData, - *reinterpret_cast(data), /* rect */ - *reinterpret_cast(data + sizeof(BRect))); /* radii */ + const BRect* rect; + const BPoint* radii; + if (callbacks.draw_round_rect == NULL || !reader.Get(rect) + || !reader.Get(radii)) { + break; + } + + callbacks.draw_round_rect(userData, *rect, *radii, + header->op == B_PIC_FILL_ROUND_RECT); break; } case B_PIC_STROKE_BEZIER: - { - ((fnc_PBPoint)functionTable[7])(userData, - reinterpret_cast(data)); - break; - } - case B_PIC_FILL_BEZIER: { - ((fnc_PBPoint)functionTable[8])(userData, - reinterpret_cast(data)); + const size_t kNumControlPoints = 4; + const BPoint* controlPoints; + if (callbacks.draw_bezier == NULL + || !reader.Get(controlPoints, kNumControlPoints)) { + break; + } + + callbacks.draw_bezier(userData, kNumControlPoints, + controlPoints, header->op == B_PIC_FILL_BEZIER); break; } case B_PIC_STROKE_ARC: - { - ((fnc_BPointBPointff)functionTable[9])(userData, - *reinterpret_cast(data), /* center */ - *reinterpret_cast(data + sizeof(BPoint)), /* radii */ - *reinterpret_cast(data + 2 * sizeof(BPoint)), /* startTheta */ - *reinterpret_cast(data + 2 * sizeof(BPoint) + sizeof(float))); /* arcTheta */ - break; - } - case B_PIC_FILL_ARC: { - ((fnc_BPointBPointff)functionTable[10])(userData, - *reinterpret_cast(data), /* center */ - *reinterpret_cast(data + sizeof(BPoint)), /* radii */ - *reinterpret_cast(data + 2 * sizeof(BPoint)), /* startTheta */ - *reinterpret_cast(data + 2 * sizeof(BPoint) + sizeof(float))); /* arcTheta */ + const BPoint* center; + const BPoint* radii; + const float* startTheta; + const float* arcTheta; + if (callbacks.draw_arc == NULL || !reader.Get(center) + || !reader.Get(radii) || !reader.Get(startTheta) + || !reader.Get(arcTheta)) { + break; + } + + callbacks.draw_arc(userData, *center, *radii, *startTheta, + *arcTheta, header->op == B_PIC_FILL_ARC); break; } case B_PIC_STROKE_ELLIPSE: - { - const BRect *rect = reinterpret_cast(data); - BPoint radii((rect->Width() + 1) / 2.0f, (rect->Height() + 1) / 2.0f); - BPoint center = rect->LeftTop() + radii; - ((fnc_BPointBPoint)functionTable[11])(userData, center, radii); - break; - } - case B_PIC_FILL_ELLIPSE: { - const BRect *rect = reinterpret_cast(data); - BPoint radii((rect->Width() + 1) / 2.0f, (rect->Height() + 1) / 2.0f); - BPoint center = rect->LeftTop() + radii; - ((fnc_BPointBPoint)functionTable[12])(userData, center, radii); + const BRect* rect; + if (callbacks.draw_ellipse == NULL || !reader.Get(rect)) + break; + + callbacks.draw_ellipse(userData, *rect, + header->op == B_PIC_FILL_ELLIPSE); break; } case B_PIC_STROKE_POLYGON: - { - int32 numPoints = *reinterpret_cast(data); - ((fnc_iPBPointb)functionTable[13])(userData, - numPoints, - reinterpret_cast(data + sizeof(int32)), /* points */ - *reinterpret_cast(data + sizeof(int32) + numPoints * sizeof(BPoint))); /* is-closed */ - break; - } - case B_PIC_FILL_POLYGON: { - ((fnc_iPBPoint)functionTable[14])(userData, - *reinterpret_cast(data), /* numPoints */ - reinterpret_cast(data + sizeof(int32))); /* points */ + const uint32* numPoints; + const BPoint* points; + if (callbacks.draw_polygon == NULL || !reader.Get(numPoints) + || !reader.Get(points, *numPoints)) { + break; + } + + bool isClosed = true; + const bool* closedPointer; + if (header->op != B_PIC_FILL_POLYGON) { + if (!reader.Get(closedPointer)) + break; + + isClosed = *closedPointer; + } + + callbacks.draw_polygon(userData, *numPoints, points, isClosed, + header->op == B_PIC_FILL_POLYGON); break; } case B_PIC_STROKE_SHAPE: case B_PIC_FILL_SHAPE: { - const bool stroke = (op == B_PIC_STROKE_SHAPE); - int32 opCount = *reinterpret_cast(data); - int32 ptCount = *reinterpret_cast(data + sizeof(int32)); - const uint32 *opList = reinterpret_cast(data + 2 * sizeof(int32)); - const BPoint *ptList = reinterpret_cast(data + 2 * sizeof(int32) + opCount * sizeof(uint32)); + const uint32* opCount; + const uint32* pointCount; + const uint32* opList; + const BPoint* pointList; + if (callbacks.draw_shape == NULL || !reader.Get(opCount) + || !reader.Get(pointCount) || !reader.Get(opList, *opCount) + || !reader.Get(pointList, *pointCount)) { + break; + } // TODO: remove BShape data copying BShape shape; - shape.SetData(opCount, ptCount, opList, ptList); + shape.SetData(*opCount, *pointCount, opList, pointList); - const int32 tableIndex = stroke ? 15 : 16; - ((fnc_BShape)functionTable[tableIndex])(userData, &shape); + callbacks.draw_shape(userData, shape, + header->op == B_PIC_FILL_SHAPE); break; } case B_PIC_DRAW_STRING: { - ((fnc_Pcff)functionTable[17])(userData, - reinterpret_cast(data + 2 * sizeof(float)), /* string */ - *reinterpret_cast(data), /* escapement.space */ - *reinterpret_cast(data + sizeof(float))); /* escapement.nonspace */ + const float* escapementSpace; + const float* escapementNonSpace; + const char* string; + size_t length; + if (callbacks.draw_string == NULL + || !reader.Get(escapementSpace) + || !reader.Get(escapementNonSpace) + || !reader.GetRemaining(string, length)) { + break; + } + + callbacks.draw_string(userData, string, length, + *escapementSpace, *escapementNonSpace); break; } case B_PIC_DRAW_PIXELS: { - ((fnc_DrawPixels)functionTable[18])(userData, - *reinterpret_cast(data), /* src */ - *reinterpret_cast(data + 1 * sizeof(BRect)), /* dst */ - *reinterpret_cast(data + 2 * sizeof(BRect)), /* width */ - *reinterpret_cast(data + 2 * sizeof(BRect) + 1 * sizeof(int32)), /* height */ - *reinterpret_cast(data + 2 * sizeof(BRect) + 2 * sizeof(int32)), /* bytesPerRow */ - *reinterpret_cast(data + 2 * sizeof(BRect) + 3 * sizeof(int32)), /* pixelFormat */ - *reinterpret_cast(data + 2 * sizeof(BRect) + 4 * sizeof(int32)), /* flags */ - reinterpret_cast(data + 2 * sizeof(BRect) + 5 * sizeof(int32))); /* data */ + const BRect* sourceRect; + const BRect* destinationRect; + const uint32* width; + const uint32* height; + const uint32* bytesPerRow; + const uint32* colorSpace; + const uint32* flags; + const void* data; + size_t length; + if (callbacks.draw_pixels == NULL || !reader.Get(sourceRect) + || !reader.Get(destinationRect) || !reader.Get(width) + || !reader.Get(height) || !reader.Get(bytesPerRow) + || !reader.Get(colorSpace) || !reader.Get(flags) + || !reader.GetRemaining(data, length)) { + break; + } + + callbacks.draw_pixels(userData, *sourceRect, *destinationRect, + *width, *height, *bytesPerRow, (color_space)*colorSpace, + *flags, data, length); break; } case B_PIC_DRAW_PICTURE: { - ((fnc_DrawPicture)functionTable[19])(userData, - *reinterpret_cast(data), - *reinterpret_cast(data + sizeof(BPoint))); + const BPoint* where; + const int32* token; + if (callbacks.draw_picture == NULL || !reader.Get(where) + || !reader.Get(token)) { + break; + } + + callbacks.draw_picture(userData, *where, *token); break; } case B_PIC_SET_CLIPPING_RECTS: { - // TODO: Not sure if it's compatible with R5's BPicture version - const uint32 numRects = *reinterpret_cast(data); - const BRect *rects = reinterpret_cast(data + sizeof(uint32)); - ((fnc_PBRecti)functionTable[20])(userData, rects, numRects); + const uint32* numRects; + const BRect* rects; + if (callbacks.set_clipping_rects == NULL + || !reader.Get(numRects) || !reader.Get(rects, *numRects)) { + break; + } + callbacks.set_clipping_rects(userData, *numRects, rects); break; } case B_PIC_CLEAR_CLIPPING_RECTS: { - ((fnc_PBRecti)functionTable[20])(userData, NULL, 0); + if (callbacks.set_clipping_rects == NULL) + break; + + callbacks.set_clipping_rects(userData, 0, NULL); break; } @@ -378,170 +936,270 @@ PicturePlayer::Play(void **callBackTable, int32 tableEntries, void *userData) case B_PIC_PUSH_STATE: { - ((fnc)functionTable[22])(userData); + if (callbacks.push_state == NULL) + break; + + callbacks.push_state(userData); break; } case B_PIC_POP_STATE: { - ((fnc)functionTable[23])(userData); + if (callbacks.pop_state == NULL) + break; + + callbacks.pop_state(userData); break; } case B_PIC_ENTER_STATE_CHANGE: - { - ((fnc)functionTable[24])(userData); - stateBlockSize = size; - break; - } - case B_PIC_ENTER_FONT_STATE: { - ((fnc)functionTable[26])(userData); - fontStateBlockSize = size; + const void* data; + size_t length; + if (!reader.GetRemaining(data, length)) + break; + + if (header->op == B_PIC_ENTER_STATE_CHANGE) { + if (callbacks.enter_state_change != NULL) + callbacks.enter_state_change(userData); + } else if (callbacks.enter_font_state != NULL) + callbacks.enter_font_state(userData); + + status_t result = _Play(callbacks, userData, data, length, + header->op); + if (result != B_OK) + return result; + + if (header->op == B_PIC_ENTER_STATE_CHANGE) { + if (callbacks.exit_state_change != NULL) + callbacks.exit_state_change(userData); + } else if (callbacks.exit_font_state != NULL) + callbacks.exit_font_state(userData); + break; } case B_PIC_SET_ORIGIN: { - ((fnc_BPoint)functionTable[28])(userData, - *reinterpret_cast(data)); /* origin */ + const BPoint* origin; + if (callbacks.set_origin == NULL || !reader.Get(origin)) + break; + + callbacks.set_origin(userData, *origin); break; } case B_PIC_SET_PEN_LOCATION: { - ((fnc_BPoint)functionTable[29])(userData, - *reinterpret_cast(data)); /* location */ + const BPoint* location; + if (callbacks.set_pen_location == NULL || !reader.Get(location)) + break; + + callbacks.set_pen_location(userData, *location); break; } case B_PIC_SET_DRAWING_MODE: { - ((fnc_s)functionTable[30])(userData, - *reinterpret_cast(data)); /* mode */ + const uint16* mode; + if (callbacks.set_drawing_mode == NULL || !reader.Get(mode)) + break; + + callbacks.set_drawing_mode(userData, (drawing_mode)*mode); break; } case B_PIC_SET_LINE_MODE: { - ((fnc_ssf)functionTable[31])(userData, - *reinterpret_cast(data), /* cap-mode */ - *reinterpret_cast(data + 1 * sizeof(int16)), /* join-mode */ - *reinterpret_cast(data + 2 * sizeof(int16))); /* miter-limit */ + const uint16* capMode; + const uint16* joinMode; + const float* miterLimit; + if (callbacks.set_line_mode == NULL || !reader.Get(capMode) + || !reader.Get(joinMode) || !reader.Get(miterLimit)) { + break; + } + + callbacks.set_line_mode(userData, (cap_mode)*capMode, + (join_mode)*joinMode, *miterLimit); break; } case B_PIC_SET_PEN_SIZE: { - ((fnc_f)functionTable[32])(userData, - *reinterpret_cast(data)); /* size */ + const float* penSize; + if (callbacks.set_pen_size == NULL || !reader.Get(penSize)) + break; + + callbacks.set_pen_size(userData, *penSize); break; } case B_PIC_SET_FORE_COLOR: { - ((fnc_Color)functionTable[33])(userData, - *reinterpret_cast(data)); /* color */ + const rgb_color* color; + if (callbacks.set_fore_color == NULL || !reader.Get(color)) + break; + + callbacks.set_fore_color(userData, *color); break; } case B_PIC_SET_BACK_COLOR: { - ((fnc_Color)functionTable[34])(userData, - *reinterpret_cast(data)); /* color */ + const rgb_color* color; + if (callbacks.set_back_color == NULL || !reader.Get(color)) + break; + + callbacks.set_back_color(userData, *color); break; } case B_PIC_SET_STIPLE_PATTERN: { - ((fnc_Pattern)functionTable[35])(userData, - *reinterpret_cast(data)); /* pattern */ + const pattern* stipplePattern; + if (callbacks.set_stipple_pattern == NULL + || !reader.Get(stipplePattern)) { + break; + } + + callbacks.set_stipple_pattern(userData, *stipplePattern); break; } case B_PIC_SET_SCALE: { - ((fnc_f)functionTable[36])(userData, - *reinterpret_cast(data)); /* scale */ + const float* scale; + if (callbacks.set_scale == NULL || !reader.Get(scale)) + break; + + callbacks.set_scale(userData, *scale); break; } case B_PIC_SET_FONT_FAMILY: { - ((fnc_Pc)functionTable[37])(userData, - reinterpret_cast(data)); /* string */ + const char* family; + size_t length; + if (callbacks.set_font_family == NULL + || !reader.GetRemaining(family, length)) { + break; + } + + callbacks.set_font_family(userData, family, length); break; } case B_PIC_SET_FONT_STYLE: { - ((fnc_Pc)functionTable[38])(userData, - reinterpret_cast(data)); /* string */ + const char* style; + size_t length; + if (callbacks.set_font_style == NULL + || !reader.GetRemaining(style, length)) { + break; + } + + callbacks.set_font_style(userData, style, length); break; } case B_PIC_SET_FONT_SPACING: { - ((fnc_i)functionTable[39])(userData, - *reinterpret_cast(data)); /* spacing */ + const uint32* spacing; + if (callbacks.set_font_spacing == NULL || !reader.Get(spacing)) + break; + + callbacks.set_font_spacing(userData, *spacing); break; } case B_PIC_SET_FONT_SIZE: { - ((fnc_f)functionTable[40])(userData, - *reinterpret_cast(data)); /* size */ + const float* size; + if (callbacks.set_font_size == NULL || !reader.Get(size)) + break; + + callbacks.set_font_size(userData, *size); break; } case B_PIC_SET_FONT_ROTATE: { - ((fnc_f)functionTable[41])(userData, - *reinterpret_cast(data)); /* rotation */ + const float* rotation; + if (callbacks.set_font_rotation == NULL + || !reader.Get(rotation)) { + break; + } + + callbacks.set_font_rotation(userData, *rotation); break; } case B_PIC_SET_FONT_ENCODING: { - ((fnc_i)functionTable[42])(userData, - *reinterpret_cast(data)); /* encoding */ + const uint32* encoding; + if (callbacks.set_font_encoding == NULL + || !reader.Get(encoding)) { + break; + } + + callbacks.set_font_encoding(userData, *encoding); break; } case B_PIC_SET_FONT_FLAGS: { - ((fnc_i)functionTable[43])(userData, - *reinterpret_cast(data)); /* flags */ + const uint32* flags; + if (callbacks.set_font_flags == NULL || !reader.Get(flags)) + break; + + callbacks.set_font_flags(userData, *flags); break; } case B_PIC_SET_FONT_SHEAR: { - ((fnc_f)functionTable[44])(userData, - *reinterpret_cast(data)); /* shear */ + const float* shear; + if (callbacks.set_font_shear == NULL || !reader.Get(shear)) + break; + + callbacks.set_font_shear(userData, *shear); break; } case B_PIC_SET_FONT_FACE: { - ((fnc_i)functionTable[46])(userData, - *reinterpret_cast(data)); /* flags */ + const uint32* face; + if (callbacks.set_font_face == NULL || !reader.Get(face)) + break; + + callbacks.set_font_face(userData, *face); break; } case B_PIC_SET_BLENDING_MODE: { - ((fnc_ss)functionTable[47])(userData, - *reinterpret_cast(data), /* alphaSrcMode */ - *reinterpret_cast(data + sizeof(int16))); /* alphaFncMode */ + const uint16* alphaSourceMode; + const uint16* alphaFunctionMode; + if (callbacks.set_blending_mode == NULL + || !reader.Get(alphaSourceMode) + || !reader.Get(alphaFunctionMode)) { + break; + } + + callbacks.set_blending_mode(userData, + (source_alpha)*alphaSourceMode, + (alpha_function)*alphaFunctionMode); break; } case B_PIC_SET_TRANSFORM: { - ((fnc_BAffineTransform)functionTable[48])(userData, - *reinterpret_cast(data)); + const BAffineTransform* transform; + if (callbacks.set_transform == NULL || !reader.Get(transform)) + break; + + callbacks.set_transform(userData, *transform); break; } @@ -549,42 +1207,18 @@ PicturePlayer::Play(void **callBackTable, int32 tableEntries, void *userData) break; } - // Skip the already handled block unless it's one of these two, - // since they can contain other nested ops. - if (op != B_PIC_ENTER_STATE_CHANGE && op != B_PIC_ENTER_FONT_STATE) { - pos += size; - data += size; - if (stateBlockSize > 0) - stateBlockSize -= size + 6; - if (fontStateBlockSize > 0) - fontStateBlockSize -= size + 6; - } - - // call the exit_state_change hook if needed - if (stateBlockSize == 0) { - ((fnc)functionTable[25])(userData); - stateBlockSize = -1; - } - - // call the exit_font_state hook if needed - if (fontStateBlockSize == 0) { - ((fnc)functionTable[27])(userData); - fontStateBlockSize = -1; - } #if DEBUG numOps++; #if DEBUG > 1 - fprintf(file, "executed in %" B_PRId64 " usecs\n", system_time() + printf("executed in %" B_PRId64 " usecs\n", system_time() - startOpTime); #endif #endif - // TODO: what if too much was read, should we return B_ERROR? } #if DEBUG - fprintf(file, "Done! %" B_PRId32 " ops, rendering completed in %" - B_PRId64 " usecs.\n", numOps, system_time() - startTime); - fclose(file); + printf("Done! %" B_PRId32 " ops, rendering completed in %" B_PRId64 + " usecs.\n", numOps, system_time() - startTime); #endif return B_OK; }