/* * Copyright 2001-2018, Haiku Inc. * 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) * Stephan Aßmus */ /** PicturePlayer is used to play picture data. */ #include #include #include #include #include #include #include #include #include #include #include using BPrivate::PicturePlayer; struct adapter_context { void* user_data; void** function_table; }; static void 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); BStackOrHeapArray points(numPoints); if (!points.IsValid()) return; memcpy((void*)points, _points, numPoints * sizeof(BPoint)); ((void (*)(void*, int32, BPoint*, bool)) context->function_table[fill ? 14 : 13])(context->user_data, numPoints, points, isClosed); } 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. BStackOrHeapArray rects(numRects); if (!rects.IsValid()) return; memcpy((void*)rects, _rects, numRects * sizeof(BRect)); ((void (*)(void*, BRect*, uint32))context->function_table[20])( context->user_data, rects, numRects); } static void clip_to_picture(void* _context, int32 token, const BPoint& origin, bool clipToInverse) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, int32, BPoint, bool))context->function_table[21])( context->user_data, token, origin, 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); } static void set_transform(void* _context, const BAffineTransform& transform) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, const BAffineTransform&)) context->function_table[48])(context->user_data, transform); } static void translate_by(void* _context, double x, double y) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, double, double)) context->function_table[49])(context->user_data, x, y); } static void scale_by(void* _context, double x, double y) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, double, double)) context->function_table[50])(context->user_data, x, y); } static void rotate_by(void* _context, double angleRadians) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, double)) context->function_table[51])(context->user_data, angleRadians); } static void blend_layer(void* _context, Layer* layer) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, Layer*)) context->function_table[52])(context->user_data, layer); } static void clip_to_rect(void* _context, const BRect& rect, bool inverse) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, const BRect&, bool)) context->function_table[53])(context->user_data, rect, inverse); } static void clip_to_shape(void* _context, int32 opCount, const uint32 opList[], int32 ptCount, const BPoint ptList[], bool inverse) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, int32, const uint32*, int32, const BPoint*, bool)) context->function_table[54])(context->user_data, opCount, opList, ptCount, ptList, inverse); } static void draw_string_locations(void* _context, const char* _string, size_t length, const BPoint* locations, size_t locationCount) { adapter_context* context = reinterpret_cast(_context); char* string = strndup(_string, length); ((void (*)(void*, char*, const BPoint*, size_t)) context->function_table[55])(context->user_data, string, locations, locationCount); free(string); } static void draw_rect_gradient(void* _context, const BRect& rect, BGradient& gradient, bool fill) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, BRect, BGradient&))context->function_table[fill ? 56 : 57])( context->user_data, rect, gradient); } static void draw_round_rect_gradient(void* _context, const BRect& rect, const BPoint& radii, BGradient& gradient, bool fill) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, BRect, BPoint, BGradient&))context->function_table[fill ? 58 : 59])( context->user_data, rect, radii, gradient); } static void draw_bezier_gradient(void* _context, size_t numPoints, const BPoint _points[], BGradient& gradient, 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*, BGradient&))context->function_table[fill ? 60 : 61])( context->user_data, points, gradient); } static void draw_arc_gradient(void* _context, const BPoint& center, const BPoint& radii, float startTheta, float arcTheta, BGradient& gradient, bool fill) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, BPoint, BPoint, float, float, BGradient&)) context->function_table[fill ? 62 : 63])(context->user_data, center, radii, startTheta, arcTheta, gradient); } static void draw_ellipse_gradient(void* _context, const BRect& rect, BGradient& gradient, 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, BGradient&)) context->function_table[fill ? 64 : 65])(context->user_data, center, radii, gradient); } static void draw_polygon_gradient(void* _context, size_t numPoints, const BPoint _points[], bool isClosed, BGradient& gradient, bool fill) { adapter_context* context = reinterpret_cast(_context); BStackOrHeapArray points(numPoints); if (!points.IsValid()) return; memcpy((void*)points, _points, numPoints * sizeof(BPoint)); ((void (*)(void*, int32, BPoint*, bool, BGradient&)) context->function_table[fill ? 66 : 67])(context->user_data, numPoints, points, isClosed, gradient); } static void draw_shape_gradient(void* _context, const BShape& shape, BGradient& gradient, bool fill) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, BShape, BGradient&))context->function_table[fill ? 68 : 69])( context->user_data, shape, gradient); } static void set_fill_rule(void* _context, int32 fillRule) { adapter_context* context = reinterpret_cast(_context); ((void (*)(void*, int32))context->function_table[70])( context->user_data, fillRule); } #if DEBUG > 1 static const char * PictureOpToString(int op) { #define RETURN_STRING(x) case x: return #x switch(op) { RETURN_STRING(B_PIC_MOVE_PEN_BY); RETURN_STRING(B_PIC_STROKE_LINE); RETURN_STRING(B_PIC_STROKE_RECT); RETURN_STRING(B_PIC_FILL_RECT); RETURN_STRING(B_PIC_STROKE_ROUND_RECT); RETURN_STRING(B_PIC_FILL_ROUND_RECT); RETURN_STRING(B_PIC_STROKE_BEZIER); RETURN_STRING(B_PIC_FILL_BEZIER); RETURN_STRING(B_PIC_STROKE_POLYGON); RETURN_STRING(B_PIC_FILL_POLYGON); RETURN_STRING(B_PIC_STROKE_SHAPE); RETURN_STRING(B_PIC_FILL_SHAPE); RETURN_STRING(B_PIC_DRAW_STRING); RETURN_STRING(B_PIC_DRAW_STRING_LOCATIONS); RETURN_STRING(B_PIC_DRAW_PIXELS); RETURN_STRING(B_PIC_DRAW_PICTURE); RETURN_STRING(B_PIC_STROKE_ARC); RETURN_STRING(B_PIC_FILL_ARC); RETURN_STRING(B_PIC_STROKE_ELLIPSE); RETURN_STRING(B_PIC_FILL_ELLIPSE); RETURN_STRING(B_PIC_STROKE_RECT_GRADIENT); RETURN_STRING(B_PIC_FILL_RECT_GRADIENT); RETURN_STRING(B_PIC_STROKE_ROUND_RECT_GRADIENT); RETURN_STRING(B_PIC_FILL_ROUND_RECT_GRADIENT); RETURN_STRING(B_PIC_STROKE_BEZIER_GRADIENT); RETURN_STRING(B_PIC_FILL_BEZIER_GRADIENT); RETURN_STRING(B_PIC_STROKE_POLYGON_GRADIENT); RETURN_STRING(B_PIC_FILL_POLYGON_GRADIENT); RETURN_STRING(B_PIC_STROKE_SHAPE_GRADIENT); RETURN_STRING(B_PIC_FILL_SHAPE_GRADIENT); RETURN_STRING(B_PIC_STROKE_ARC_GRADIENT); RETURN_STRING(B_PIC_FILL_ARC_GRADIENT); RETURN_STRING(B_PIC_STROKE_ELLIPSE_GRADIENT); RETURN_STRING(B_PIC_FILL_ELLIPSE_GRADIENT); RETURN_STRING(B_PIC_ENTER_STATE_CHANGE); RETURN_STRING(B_PIC_SET_CLIPPING_RECTS); RETURN_STRING(B_PIC_CLIP_TO_PICTURE); RETURN_STRING(B_PIC_PUSH_STATE); RETURN_STRING(B_PIC_POP_STATE); RETURN_STRING(B_PIC_CLEAR_CLIPPING_RECTS); RETURN_STRING(B_PIC_CLIP_TO_RECT); RETURN_STRING(B_PIC_CLIP_TO_SHAPE); RETURN_STRING(B_PIC_SET_ORIGIN); RETURN_STRING(B_PIC_SET_PEN_LOCATION); RETURN_STRING(B_PIC_SET_DRAWING_MODE); RETURN_STRING(B_PIC_SET_LINE_MODE); RETURN_STRING(B_PIC_SET_PEN_SIZE); RETURN_STRING(B_PIC_SET_SCALE); RETURN_STRING(B_PIC_SET_TRANSFORM); RETURN_STRING(B_PIC_SET_FORE_COLOR); RETURN_STRING(B_PIC_SET_BACK_COLOR); RETURN_STRING(B_PIC_SET_STIPLE_PATTERN); RETURN_STRING(B_PIC_ENTER_FONT_STATE); RETURN_STRING(B_PIC_SET_BLENDING_MODE); RETURN_STRING(B_PIC_SET_FILL_RULE); RETURN_STRING(B_PIC_SET_FONT_FAMILY); RETURN_STRING(B_PIC_SET_FONT_STYLE); RETURN_STRING(B_PIC_SET_FONT_SPACING); RETURN_STRING(B_PIC_SET_FONT_ENCODING); RETURN_STRING(B_PIC_SET_FONT_FLAGS); RETURN_STRING(B_PIC_SET_FONT_SIZE); RETURN_STRING(B_PIC_SET_FONT_ROTATE); RETURN_STRING(B_PIC_SET_FONT_SHEAR); RETURN_STRING(B_PIC_SET_FONT_BPP); RETURN_STRING(B_PIC_SET_FONT_FACE); RETURN_STRING(B_PIC_AFFINE_TRANSLATE); RETURN_STRING(B_PIC_AFFINE_SCALE); RETURN_STRING(B_PIC_AFFINE_ROTATE); RETURN_STRING(B_PIC_BLEND_LAYER); default: return "Unknown op"; } #undef RETURN_STRING } #endif PicturePlayer::PicturePlayer(const void *data, size_t size, BList *pictures) : fData(data), fSize(size), fPictures(pictures) { } PicturePlayer::~PicturePlayer() { } status_t 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, 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 }; // 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; } bool GetGradient(BGradient*& gradient) { BMemoryIO stream(fBuffer, fRemaining); printf("fRemaining: %ld\n", fRemaining); if (BGradient::Unflatten(gradient, &stream) != B_OK) { printf("BGradient::Unflatten(_gradient, &stream) != B_OK\n"); return false; } fRemaining -= stream.Position(); fBuffer += stream.Position(); 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 printf("Start rendering %sBPicture...\n", parentOp != 0 ? "sub " : ""); bigtime_t startTime = system_time(); int32 numOps = 0; #endif DataReader pictureReader(buffer, length); while (pictureReader.Remaining() > 0) { const picture_data_entry_header* header; const uint8* opData = NULL; if (!pictureReader.Get(header) || !pictureReader.Get(opData, header->size)) { return B_BAD_DATA; } DataReader reader(opData, header->size); // Disallow ops that don't fit the parent. switch (parentOp) { case 0: // No parent op, no restrictions. break; 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(); printf("Op %s ", PictureOpToString(header->op)); #endif switch (header->op) { case B_PIC_MOVE_PEN_BY: { 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: { 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: case B_PIC_FILL_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: case B_PIC_FILL_ROUND_RECT: { 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: case B_PIC_FILL_BEZIER: { 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: case B_PIC_FILL_ARC: { 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: case B_PIC_FILL_ELLIPSE: { 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: case B_PIC_FILL_POLYGON: { 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 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, *pointCount, opList, pointList); callbacks.draw_shape(userData, shape, header->op == B_PIC_FILL_SHAPE); break; } case B_PIC_STROKE_RECT_GRADIENT: case B_PIC_FILL_RECT_GRADIENT: { const BRect* rect; BGradient* gradient; if (callbacks.draw_rect_gradient == NULL || !reader.Get(rect) || !reader.GetGradient(gradient)) break; ObjectDeleter gradientDeleter(gradient); callbacks.draw_rect_gradient(userData, *rect, *gradient, header->op == B_PIC_FILL_RECT_GRADIENT); break; } case B_PIC_STROKE_ROUND_RECT_GRADIENT: case B_PIC_FILL_ROUND_RECT_GRADIENT: { const BRect* rect; const BPoint* radii; BGradient* gradient; if (callbacks.draw_round_rect_gradient == NULL || !reader.Get(rect) || !reader.Get(radii) || !reader.GetGradient(gradient)) { break; } ObjectDeleter gradientDeleter(gradient); callbacks.draw_round_rect_gradient(userData, *rect, *radii, *gradient, header->op == B_PIC_FILL_ROUND_RECT_GRADIENT); break; } case B_PIC_STROKE_BEZIER_GRADIENT: case B_PIC_FILL_BEZIER_GRADIENT: { const size_t kNumControlPoints = 4; const BPoint* controlPoints; BGradient* gradient; if (callbacks.draw_bezier_gradient == NULL || !reader.Get(controlPoints, kNumControlPoints) || !reader.GetGradient(gradient)) { break; } ObjectDeleter gradientDeleter(gradient); callbacks.draw_bezier_gradient(userData, kNumControlPoints, controlPoints, *gradient, header->op == B_PIC_FILL_BEZIER_GRADIENT); break; } case B_PIC_STROKE_POLYGON_GRADIENT: case B_PIC_FILL_POLYGON_GRADIENT: { const uint32* numPoints; const BPoint* points; BGradient* gradient; if (callbacks.draw_polygon_gradient == NULL || !reader.Get(numPoints) || !reader.Get(points, *numPoints)) { break; } bool isClosed = true; const bool* closedPointer; if (header->op != B_PIC_FILL_POLYGON_GRADIENT) { if (!reader.Get(closedPointer)) break; isClosed = *closedPointer; } if (!reader.GetGradient(gradient)) break; ObjectDeleter gradientDeleter(gradient); callbacks.draw_polygon_gradient(userData, *numPoints, points, isClosed, *gradient, header->op == B_PIC_FILL_POLYGON_GRADIENT); break; } case B_PIC_STROKE_SHAPE_GRADIENT: case B_PIC_FILL_SHAPE_GRADIENT: { const uint32* opCount; const uint32* pointCount; const uint32* opList; const BPoint* pointList; BGradient* gradient; if (callbacks.draw_shape_gradient == NULL || !reader.Get(opCount) || !reader.Get(pointCount) || !reader.Get(opList, *opCount) || !reader.Get(pointList, *pointCount) || !reader.GetGradient(gradient)) { break; } ObjectDeleter gradientDeleter(gradient); // TODO: remove BShape data copying BShape shape; shape.SetData(*opCount, *pointCount, opList, pointList); callbacks.draw_shape_gradient(userData, shape, *gradient, header->op == B_PIC_FILL_SHAPE_GRADIENT); break; } case B_PIC_STROKE_ARC_GRADIENT: case B_PIC_FILL_ARC_GRADIENT: { const BPoint* center; const BPoint* radii; const float* startTheta; const float* arcTheta; BGradient* gradient; if (callbacks.draw_arc_gradient == NULL || !reader.Get(center) || !reader.Get(radii) || !reader.Get(startTheta) || !reader.Get(arcTheta) || !reader.GetGradient(gradient)) { break; } ObjectDeleter gradientDeleter(gradient); callbacks.draw_arc_gradient(userData, *center, *radii, *startTheta, *arcTheta, *gradient, header->op == B_PIC_FILL_ARC_GRADIENT); break; } case B_PIC_STROKE_ELLIPSE_GRADIENT: case B_PIC_FILL_ELLIPSE_GRADIENT: { const BRect* rect; BGradient* gradient; if (callbacks.draw_ellipse_gradient == NULL || !reader.Get(rect) || !reader.GetGradient(gradient)) break; ObjectDeleter gradientDeleter(gradient); callbacks.draw_ellipse_gradient(userData, *rect, *gradient, header->op == B_PIC_FILL_ELLIPSE_GRADIENT); break; } case B_PIC_DRAW_STRING: { 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_STRING_LOCATIONS: { const uint32* pointCount; const BPoint* pointList; const char* string; size_t length; if (callbacks.draw_string_locations == NULL || !reader.Get(pointCount) || !reader.Get(pointList, *pointCount) || !reader.GetRemaining(string, length)) { break; } callbacks.draw_string_locations(userData, string, length, pointList, *pointCount); break; } case B_PIC_DRAW_PIXELS: { 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: { 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: { 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: { if (callbacks.set_clipping_rects == NULL) break; callbacks.set_clipping_rects(userData, 0, NULL); break; } case B_PIC_CLIP_TO_PICTURE: { const int32* token; const BPoint* where; const bool* inverse; if (callbacks.clip_to_picture == NULL || !reader.Get(token) || !reader.Get(where) || !reader.Get(inverse)) break; callbacks.clip_to_picture(userData, *token, *where, *inverse); break; } case B_PIC_PUSH_STATE: { if (callbacks.push_state == NULL) break; callbacks.push_state(userData); break; } case B_PIC_POP_STATE: { if (callbacks.pop_state == NULL) break; callbacks.pop_state(userData); break; } case B_PIC_ENTER_STATE_CHANGE: case B_PIC_ENTER_FONT_STATE: { 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: { const BPoint* origin; if (callbacks.set_origin == NULL || !reader.Get(origin)) break; callbacks.set_origin(userData, *origin); break; } case B_PIC_SET_PEN_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: { 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: { 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: { 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: { 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: { 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: { 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: { const float* scale; if (callbacks.set_scale == NULL || !reader.Get(scale)) break; callbacks.set_scale(userData, *scale); break; } case B_PIC_SET_FONT_FAMILY: { 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: { 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: { 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: { 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: { 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: { 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: { 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: { 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: { 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: { 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_FILL_RULE: { const uint32* fillRule; if (callbacks.set_fill_rule == NULL || !reader.Get(fillRule)) { break; } callbacks.set_fill_rule(userData, *fillRule); break; } case B_PIC_SET_TRANSFORM: { const BAffineTransform* transform; if (callbacks.set_transform == NULL || !reader.Get(transform)) break; callbacks.set_transform(userData, *transform); break; } case B_PIC_AFFINE_TRANSLATE: { const double* x; const double* y; if (callbacks.translate_by == NULL || !reader.Get(x) || !reader.Get(y)) { break; } callbacks.translate_by(userData, *x, *y); break; } case B_PIC_AFFINE_SCALE: { const double* x; const double* y; if (callbacks.scale_by == NULL || !reader.Get(x) || !reader.Get(y)) { break; } callbacks.scale_by(userData, *x, *y); break; } case B_PIC_AFFINE_ROTATE: { const double* angleRadians; if (callbacks.rotate_by == NULL || !reader.Get(angleRadians)) break; callbacks.rotate_by(userData, *angleRadians); break; } case B_PIC_BLEND_LAYER: { Layer* const* layer; if (callbacks.blend_layer == NULL || !reader.Get(layer)) break; callbacks.blend_layer(userData, *layer); break; } case B_PIC_CLIP_TO_RECT: { const bool* inverse; const BRect* rect; if (callbacks.clip_to_rect == NULL || !reader.Get(inverse) || !reader.Get(rect)) { break; } callbacks.clip_to_rect(userData, *rect, *inverse); break; } case B_PIC_CLIP_TO_SHAPE: { const bool* inverse; const uint32* opCount; const uint32* pointCount; const uint32* opList; const BPoint* pointList; if (callbacks.clip_to_shape == NULL || !reader.Get(inverse) || !reader.Get(opCount) || !reader.Get(pointCount) || !reader.Get(opList, *opCount) || !reader.Get(pointList, *pointCount)) { break; } callbacks.clip_to_shape(userData, *opCount, opList, *pointCount, pointList, *inverse); break; } default: break; } #if DEBUG numOps++; #if DEBUG > 1 printf("executed in %" B_PRId64 " usecs\n", system_time() - startOpTime); #endif #endif } #if DEBUG printf("Done! %" B_PRId32 " ops, rendering completed in %" B_PRId64 " usecs.\n", numOps, system_time() - startTime); #endif return B_OK; }