diff --git a/headers/private/interface/PictureDataWriter.h b/headers/private/interface/PictureDataWriter.h index 6018ed9f47..af5f7e3c76 100644 --- a/headers/private/interface/PictureDataWriter.h +++ b/headers/private/interface/PictureDataWriter.h @@ -1,10 +1,11 @@ /* - * Copyright 2006-2015 Haiku, Inc. All rights reserved. + * Copyright 2006-2018 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Stefano Ceccherini, burton666@libero.it * Julian Harnath, + * Stephan Aßmus */ #ifndef _PICTURE_DATA_WRITER_H #define _PICTURE_DATA_WRITER_H @@ -84,6 +85,9 @@ public: status_t WriteDrawString(const BPoint& where, const char* string, const int32& length, const escapement_delta& delta); + status_t WriteDrawString(const char* string, + int32 length, const BPoint* locations, + int32 locationCount); status_t WriteDrawShape(const int32& opCount, const void* opList, const int32& ptCount, const void* ptList, const bool& fill); diff --git a/headers/private/interface/PicturePlayer.h b/headers/private/interface/PicturePlayer.h index 1a2e92b272..72e4b50a78 100644 --- a/headers/private/interface/PicturePlayer.h +++ b/headers/private/interface/PicturePlayer.h @@ -1,11 +1,12 @@ /* - * Copyright 2001-2007, Haiku Inc. + * 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 */ #ifndef _PICTURE_PLAYER_H #define _PICTURE_PLAYER_H @@ -91,6 +92,8 @@ struct picture_player_callbacks { void (*clip_to_rect)(void* userData, const BRect& rect, bool inverse); void (*clip_to_shape)(void* userData, int32 opCount, const uint32 opList[], int32 ptCount, const BPoint ptList[], bool inverse); + void (*draw_string_locations)(void* userData, const char* string, + size_t length, const BPoint locations[], size_t locationCount); }; diff --git a/headers/private/interface/PictureProtocol.h b/headers/private/interface/PictureProtocol.h index b226b52dfe..8775ef1958 100644 --- a/headers/private/interface/PictureProtocol.h +++ b/headers/private/interface/PictureProtocol.h @@ -22,6 +22,7 @@ enum { B_PIC_FILL_ARC = 0x0114, B_PIC_STROKE_ELLIPSE = 0x0115, B_PIC_FILL_ELLIPSE = 0x0116, + B_PIC_DRAW_STRING_LOCATIONS = 0x0117, B_PIC_ENTER_STATE_CHANGE = 0x0200, B_PIC_SET_CLIPPING_RECTS = 0x0201, @@ -61,7 +62,7 @@ enum { }; -const static uint32 kOpsTableSize = 50; +const static uint32 kOpsTableSize = 51; #endif diff --git a/src/kits/interface/PictureDataWriter.cpp b/src/kits/interface/PictureDataWriter.cpp index f37fe8ff5b..0f66f5942f 100644 --- a/src/kits/interface/PictureDataWriter.cpp +++ b/src/kits/interface/PictureDataWriter.cpp @@ -1,10 +1,11 @@ /* - * Copyright 2006-2015 Haiku, Inc. All rights reserved. + * Copyright 2006-2018 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Stefano Ceccherini, stefano.ceccherini@gmail.com * Julian Harnath, + * Stephan Aßmus */ #include @@ -478,6 +479,27 @@ PictureDataWriter::WriteDrawString(const BPoint& where, const char* string, } +status_t +PictureDataWriter::WriteDrawString(const char* string, + int32 length, const BPoint* locations, int32 locationCount) +{ + try { + BeginOp(B_PIC_DRAW_STRING_LOCATIONS); + Write(locationCount); + for (int32 i = 0; i < locationCount; i++) { + Write(locations[i]); + } + WriteData(string, length); + Write(0); + EndOp(); + } catch (status_t& status) { + return status; + } + + return B_OK; +} + + status_t PictureDataWriter::WriteDrawShape(const int32& opCount, const void* opList, const int32& ptCount, const void* ptList, const bool& fill) diff --git a/src/kits/interface/PicturePlayer.cpp b/src/kits/interface/PicturePlayer.cpp index 4cbc85fd3b..2abeba8f28 100644 --- a/src/kits/interface/PicturePlayer.cpp +++ b/src/kits/interface/PicturePlayer.cpp @@ -1,11 +1,12 @@ /* - * Copyright 2001-2007, Haiku Inc. + * 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. */ @@ -454,6 +455,87 @@ set_blending_mode(void* _context, source_alpha alphaSrcMode, } +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); +} + + + #if DEBUG > 1 static const char * PictureOpToString(int op) @@ -474,6 +556,7 @@ PictureOpToString(int op) 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); @@ -510,6 +593,13 @@ PictureOpToString(int op) 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 @@ -572,7 +662,15 @@ PicturePlayer::Play(void** callBackTable, int32 tableEntries, void* userData) set_font_flags, set_font_shear, set_font_face, - set_blending_mode + set_blending_mode, + set_transform, + translate_by, + scale_by, + rotate_by, + blend_layer, + clip_to_rect, + clip_to_shape, + draw_string_locations }; // We don't check if the functions in the table are NULL, but we @@ -871,6 +969,24 @@ PicturePlayer::_Play(const picture_player_callbacks& callbacks, void* userData, 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; diff --git a/src/servers/app/ServerPicture.cpp b/src/servers/app/ServerPicture.cpp index 316340afbd..b6bd20f769 100644 --- a/src/servers/app/ServerPicture.cpp +++ b/src/servers/app/ServerPicture.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2015, Haiku. + * Copyright 2001-2019, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -7,6 +7,7 @@ * Stefano Ceccherini (stefano.ceccherini@gmail.com) * Marcus Overhagen * Julian Harnath + * Stephan Aßmus */ #include "ServerPicture.h" @@ -411,6 +412,23 @@ draw_string(void* _canvas, const char* string, size_t length, float deltaSpace, } +static void +draw_string_locations(void* _canvas, const char* string, size_t length, + const BPoint* locations, size_t locationsCount) +{ + Canvas* const canvas = reinterpret_cast(_canvas); + + BPoint location = canvas->GetDrawingEngine()->DrawString(string, length, + locations); + + canvas->PenToScreenTransform().Apply(&location); + canvas->CurrentState()->SetPenLocation(location); + // the DrawingEngine/Painter does not need to be updated, since this + // effects only the view->screen coord conversion, which is handled + // by the view only +} + + static void draw_pixels(void* _canvas, const BRect& src, const BRect& _dest, uint32 width, uint32 height, size_t bytesPerRow, color_space pixelFormat, uint32 options, @@ -881,7 +899,8 @@ static const BPrivate::picture_player_callbacks kPicturePlayerCallbacks = { rotate_by, blend_layer, clip_to_rect, - clip_to_shape + clip_to_shape, + draw_string_locations }; @@ -1046,68 +1065,46 @@ ServerPicture::SyncState(View* view) void -ServerPicture::SetFontFromLink(BPrivate::LinkReceiver& link) +ServerPicture::WriteFontState(const ServerFont& font, uint16 mask) { BeginOp(B_PIC_ENTER_FONT_STATE); - uint16 mask; - link.Read(&mask); - if (mask & B_FONT_FAMILY_AND_STYLE) { - uint32 fontID; - link.Read(&fontID); - ServerFont font; - font.SetFamilyAndStyle(fontID); WriteSetFontFamily(font.Family()); WriteSetFontStyle(font.Style()); } if (mask & B_FONT_SIZE) { - float size; - link.Read(&size); - WriteSetFontSize(size); + WriteSetFontSize(font.Size()); } if (mask & B_FONT_SHEAR) { - float shear; - link.Read(&shear); - WriteSetFontShear(shear); + WriteSetFontShear(font.Shear()); } if (mask & B_FONT_ROTATION) { - float rotation; - link.Read(&rotation); - WriteSetFontRotation(rotation); + WriteSetFontRotation(font.Rotation()); } if (mask & B_FONT_FALSE_BOLD_WIDTH) { - float falseBoldWidth; - link.Read(&falseBoldWidth); - //SetFalseBoldWidth(falseBoldWidth); + // TODO: Implement +// WriteSetFalseBoldWidth(font.FalseBoldWidth()); } if (mask & B_FONT_SPACING) { - uint8 spacing; - link.Read(&spacing); - WriteSetFontSpacing(spacing); + WriteSetFontSpacing(font.Spacing()); } if (mask & B_FONT_ENCODING) { - uint8 encoding; - link.Read((uint8*)&encoding); - WriteSetFontEncoding(encoding); + WriteSetFontEncoding(font.Encoding()); } if (mask & B_FONT_FACE) { - uint16 face; - link.Read(&face); - WriteSetFontFace(face); + WriteSetFontFace(font.Face()); } if (mask & B_FONT_FLAGS) { - uint32 flags; - link.Read(&flags); - WriteSetFontFlags(flags); + WriteSetFontFlags(font.Flags()); } EndOp(); diff --git a/src/servers/app/ServerPicture.h b/src/servers/app/ServerPicture.h index d44d2a5282..603b8d777c 100644 --- a/src/servers/app/ServerPicture.h +++ b/src/servers/app/ServerPicture.h @@ -1,11 +1,12 @@ /* - * Copyright 2001-2015, Haiku. + * Copyright 2001-2019, Haiku. * Distributed under the terms of the MIT License. * * Authors: * DarkWyrm * Stefano Ceccherini * Julian Harnath + * Stephan Aßmus */ #ifndef SERVER_PICTURE_H #define SERVER_PICTURE_H @@ -21,6 +22,7 @@ class BFile; class Canvas; class ServerApp; +class ServerFont; class View; namespace BPrivate { @@ -48,7 +50,8 @@ public: void ExitStateChange(); void SyncState(View* view); - void SetFontFromLink(BPrivate::LinkReceiver& link); + void WriteFontState(const ServerFont& font, + uint16 mask); void Play(Canvas* target); diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index fbfd7454a8..fcc0f9a24b 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2015, Haiku. + * Copyright 2001-2019, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -3284,6 +3284,7 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) fCurrentView->CurrentState()->SetPenLocation(location); break; } + case AS_VIEW_SET_PEN_SIZE: { float penSize; @@ -3332,6 +3333,9 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) break; picture->WriteSetTransform(transform); + + fCurrentView->CurrentState()->SetTransform(transform); + _UpdateDrawState(fCurrentView); break; } @@ -3342,6 +3346,12 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) link.Read(&y); picture->WriteTranslateBy(x, y); + + BAffineTransform current = + fCurrentView->CurrentState()->Transform(); + current.PreTranslateBy(x, y); + fCurrentView->CurrentState()->SetTransform(current); + _UpdateDrawState(fCurrentView); break; } @@ -3352,6 +3362,12 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) link.Read(&y); picture->WriteScaleBy(x, y); + + BAffineTransform current = + fCurrentView->CurrentState()->Transform(); + current.PreScaleBy(x, y); + fCurrentView->CurrentState()->SetTransform(current); + _UpdateDrawState(fCurrentView); break; } @@ -3361,6 +3377,12 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) link.Read(&angleRadians); picture->WriteRotateBy(angleRadians); + + BAffineTransform current = + fCurrentView->CurrentState()->Transform(); + current.PreRotateBy(angleRadians); + fCurrentView->CurrentState()->SetTransform(current); + _UpdateDrawState(fCurrentView); break; } @@ -3375,7 +3397,11 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) case AS_VIEW_SET_FONT_STATE: { - picture->SetFontFromLink(link); + uint16 mask = fCurrentView->CurrentState()->ReadFontFromLink(link); + fWindow->GetDrawingEngine()->SetFont( + fCurrentView->CurrentState()); + + picture->WriteFontState(fCurrentView->CurrentState()->Font(), mask); break; } @@ -3498,6 +3524,12 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) link.Read(&info); picture->WriteStrokeLine(info.startPoint, info.endPoint); + + BPoint penPos = info.endPoint; + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); + transform.Apply(&info.endPoint); + fCurrentView->CurrentState()->SetPenLocation(penPos); break; } @@ -3585,10 +3617,78 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) picture->WriteDrawString(info.location, string, info.stringLength, info.delta); + // We need to update the pen location + fCurrentView->PenToScreenTransform().Apply(&info.location); + BPoint penLocation = fWindow->GetDrawingEngine()->DrawStringDry( + string, info.stringLength, info.location, &info.delta); + + fCurrentView->ScreenToPenTransform().Apply(&penLocation); + fCurrentView->CurrentState()->SetPenLocation(penLocation); + free(string); break; } + case AS_DRAW_STRING_WITH_OFFSETS: + { + int32 stringLength; + if (link.Read(&stringLength) != B_OK || stringLength <= 0) + break; + + int32 glyphCount; + if (link.Read(&glyphCount) != B_OK || glyphCount <= 0) + break; + + const ssize_t kMaxStackStringSize = 512; + char stackString[kMaxStackStringSize]; + char* string = stackString; + BPoint stackLocations[kMaxStackStringSize]; + BPoint* locations = stackLocations; + MemoryDeleter stringDeleter; + MemoryDeleter locationsDeleter; + if (stringLength >= kMaxStackStringSize) { + // NOTE: Careful, the + 1 is for termination! + string = (char*)malloc((stringLength + 1 + 63) / 64 * 64); + if (string == NULL) + break; + stringDeleter.SetTo(string); + } + if (glyphCount > kMaxStackStringSize) { + locations = (BPoint*)malloc( + ((glyphCount * sizeof(BPoint)) + 63) / 64 * 64); + if (locations == NULL) + break; + locationsDeleter.SetTo(locations); + } + + if (link.Read(string, stringLength) != B_OK) + break; + // Count UTF8 glyphs and make sure we have enough locations + if ((int32)UTF8CountChars(string, stringLength) > glyphCount) + break; + if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK) + break; + // Terminate the string + string[stringLength] = '\0'; + + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); + for (int32 i = 0; i < glyphCount; i++) + transform.Apply(&locations[i]); + + picture->WriteDrawString(string, stringLength, locations, + glyphCount); + + // Update pen location + BPoint penLocation = fWindow->GetDrawingEngine()->DrawStringDry( + string, stringLength, locations); + + fCurrentView->ScreenToPenTransform().Apply(&penLocation); + fCurrentView->CurrentState()->SetPenLocation(penLocation); + + break; + } + case AS_STROKE_SHAPE: case AS_FILL_SHAPE: {