Author: stippi Date: 2010-03-15 14:59:14 +0100 (Mon, 15 Mar 2010) New Revision: 35865 Changeset: http://dev.haiku-os.org/changeset/35865/haiku Added: haiku/trunk/src/tests/servers/app/draw_string_offsets/ haiku/trunk/src/tests/servers/app/draw_string_offsets/Jamfile haiku/trunk/src/tests/servers/app/draw_string_offsets/main.cpp Modified: haiku/trunk/headers/os/interface/View.h haiku/trunk/headers/private/app/ServerProtocol.h haiku/trunk/src/kits/interface/View.cpp haiku/trunk/src/servers/app/GlyphLayoutEngine.h haiku/trunk/src/servers/app/ServerWindow.cpp haiku/trunk/src/servers/app/drawing/DrawingEngine.cpp haiku/trunk/src/servers/app/drawing/DrawingEngine.h haiku/trunk/src/servers/app/drawing/Painter/AGGTextRenderer.cpp haiku/trunk/src/servers/app/drawing/Painter/AGGTextRenderer.h haiku/trunk/src/servers/app/drawing/Painter/Painter.cpp haiku/trunk/src/servers/app/drawing/Painter/Painter.h haiku/trunk/src/tests/servers/app/Jamfile Log: * Extended the BView drawing API by a DrawString() version that takes an array of locations, one for each glyph. * Added a test for the new functionality. Modified: haiku/trunk/headers/os/interface/View.h =================================================================== --- haiku/trunk/headers/os/interface/View.h 2010-03-15 11:19:21 UTC (rev 35864) +++ haiku/trunk/headers/os/interface/View.h 2010-03-15 13:59:14 UTC (rev 35865) @@ -423,16 +423,18 @@ void DrawChar(char aChar); void DrawChar(char aChar, BPoint location); - void DrawString(const char* aString, + void DrawString(const char* string, escapement_delta* delta = NULL); - void DrawString(const char* aString, + void DrawString(const char* string, BPoint location, escapement_delta* delta = NULL); - void DrawString(const char* aString, int32 length, + void DrawString(const char* string, int32 length, escapement_delta* delta = NULL); - void DrawString(const char* aString, int32 length, + void DrawString(const char* string, int32 length, BPoint location, escapement_delta* delta = 0L); + void DrawString(const char* string, int32 length, + const BPoint* locations); virtual void SetFont(const BFont* font, uint32 mask = B_FONT_ALL); Modified: haiku/trunk/headers/private/app/ServerProtocol.h =================================================================== --- haiku/trunk/headers/private/app/ServerProtocol.h 2010-03-15 11:19:21 UTC (rev 35864) +++ haiku/trunk/headers/private/app/ServerProtocol.h 2010-03-15 13:59:14 UTC (rev 35865) @@ -254,6 +254,7 @@ AS_DRAW_STRING, AS_DRAW_STRING_WITH_DELTA, + AS_DRAW_STRING_WITH_OFFSETS, AS_SYNC, Modified: haiku/trunk/src/kits/interface/View.cpp =================================================================== --- haiku/trunk/src/kits/interface/View.cpp 2010-03-15 11:19:21 UTC (rev 35864) +++ haiku/trunk/src/kits/interface/View.cpp 2010-03-15 13:59:14 UTC (rev 35865) @@ -45,6 +45,7 @@ #include <String.h> #include <Window.h> +#include <utf8_functions.h> #include <AppMisc.h> #include <AppServerLink.h> #include <binary_compatibility/Interface.h> @@ -59,7 +60,6 @@ #include <TokenSpace.h> #include <ViewPrivate.h> - using std::nothrow; //#define DEBUG_BVIEW @@ -2571,6 +2571,29 @@ void +BView::DrawString(const char* string, int32 length, const BPoint* locations) +{ + if (fOwner == NULL || string == NULL || length < 1 || locations == NULL) + return; + + _CheckLockAndSwitchCurrent(); + + fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_OFFSETS); + + int32 glyphCount = UTF8CountChars(string, length); + fOwner->fLink->Attach<int32>(length); + fOwner->fLink->Attach<int32>(glyphCount); + fOwner->fLink->Attach(string, length); + fOwner->fLink->Attach(locations, glyphCount * sizeof(BPoint)); + + _FlushIfNotInTransaction(); + + // this modifies our pen location, so we invalidate the flag. + fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; +} + + +void BView::StrokeEllipse(BPoint center, float xRadius, float yRadius, ::pattern pattern) { Modified: haiku/trunk/src/servers/app/GlyphLayoutEngine.h =================================================================== --- haiku/trunk/src/servers/app/GlyphLayoutEngine.h 2010-03-15 11:19:21 UTC (rev 35864) +++ haiku/trunk/src/servers/app/GlyphLayoutEngine.h 2010-03-15 13:59:14 UTC (rev 35865) @@ -64,6 +64,7 @@ const escapement_delta* delta = NULL, bool kerning = true, uint8 spacing = B_BITMAP_SPACING, + const BPoint* offsets = NULL, FontCacheReference* cacheReference = NULL); static bool IsWhiteSpace(uint32 glyphCode); @@ -101,7 +102,7 @@ const ServerFont& font, const char* utf8String, int32 length, const escapement_delta* delta, bool kerning, uint8 spacing, - FontCacheReference* cacheReference) + const BPoint* offsets, FontCacheReference* cacheReference) { // TODO: implement spacing modes @@ -136,6 +137,10 @@ double x = 0.0; double y = 0.0; + if (offsets) { + x = offsets[0].x; + y = offsets[0].y; + } double advanceX = 0.0; double advanceY = 0.0; @@ -146,6 +151,24 @@ const char* start = utf8String; while ((charCode = UTF8ToCharCode(&utf8String))) { + if (offsets) { + // Use direct glyph locations instead of calculating them + // from the advance values + x = offsets[index].x; + y = offsets[index].y; + } else { +// TODO: Currently disabled, because it works much too slow (doesn't seem +// to be properly cached in FreeType.) +// if (kerning) +// entry->GetKerning(lastCharCode, charCode, &advanceX, &advanceY); + + x += advanceX; + y += advanceY; + + if (delta) + x += IsWhiteSpace(charCode) ? delta->space : delta->nonspace; + } + const GlyphCache* glyph = entry->Glyph(charCode); if (glyph == NULL) { fprintf(stderr, "failed to load glyph for 0x%04lx (%c)\n", charCode, @@ -155,17 +178,6 @@ continue; } -// TODO: Currently disabled, because it works much too slow (doesn't seem -// to be properly cached in FreeType.) -// if (kerning) -// entry->GetKerning(lastCharCode, charCode, &advanceX, &advanceY); - - x += advanceX; - y += advanceY; - - if (delta) - x += IsWhiteSpace(charCode) ? delta->space : delta->nonspace; - if (!consumer.ConsumeGlyph(index, charCode, glyph, entry, x, y)) { advanceX = 0; advanceY = 0; Modified: haiku/trunk/src/servers/app/ServerWindow.cpp =================================================================== --- haiku/trunk/src/servers/app/ServerWindow.cpp 2010-03-15 11:19:21 UTC (rev 35864) +++ haiku/trunk/src/servers/app/ServerWindow.cpp 2010-03-15 13:59:14 UTC (rev 35865) @@ -49,8 +49,10 @@ #include <WindowPrivate.h> #include "clipping.h" +#include "utf8_functions.h" #include "AppServer.h" +#include "AutoDeleter.h" #include "Desktop.h" #include "DirectWindowInfo.h" #include "DrawingEngine.h" @@ -2674,8 +2676,10 @@ case AS_DRAW_STRING_WITH_DELTA: { ViewDrawStringInfo info; - if (link.Read<ViewDrawStringInfo>(&info) != B_OK) + if (link.Read<ViewDrawStringInfo>(&info) != B_OK + || info.stringLength <= 0) { break; + } const ssize_t kMaxStackStringSize = 4096; char stackString[kMaxStackStringSize]; @@ -2716,7 +2720,64 @@ free(string); break; } + case AS_DRAW_STRING_WITH_OFFSETS: + { + int32 stringLength; + if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0) + break; + int32 glyphCount; + if (link.Read<int32>(&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, if nothing else, it's important + // for the DTRACE call below... + string[stringLength] = '\0'; + + DTRACE(("ServerWindow %s: Message AS_DRAW_STRING_WITH_OFFSETS, View: %s " + "-> %s\n", Title(), fCurrentView->Name(), string)); + + for (int32 i = 0; i < stringLength; i++) + fCurrentView->ConvertToScreenForDrawing(&locations[i]); + + BPoint penLocation = drawingEngine->DrawString(string, + stringLength, locations); + + fCurrentView->ConvertFromScreenForDrawing(&penLocation); + fCurrentView->CurrentState()->SetPenLocation(penLocation); + + break; + } + case AS_VIEW_DRAW_PICTURE: { int32 token; Modified: haiku/trunk/src/servers/app/drawing/DrawingEngine.cpp =================================================================== --- haiku/trunk/src/servers/app/drawing/DrawingEngine.cpp 2010-03-15 11:19:21 UTC (rev 35864) +++ haiku/trunk/src/servers/app/drawing/DrawingEngine.cpp 2010-03-15 13:59:14 UTC (rev 35865) @@ -1343,6 +1343,37 @@ } +BPoint +DrawingEngine::DrawString(const char* string, int32 length, + const BPoint* offsets) +{ + ASSERT_PARALLEL_LOCKED(); + + // use a FontCacheRefernece to speed up the second pass of + // drawing the string + FontCacheReference cacheReference; + + BPoint penLocation; + BRect b = fPainter->BoundingBox(string, length, offsets, &penLocation, + &cacheReference); + // stop here if we're supposed to render outside of the clipping + b = fPainter->ClipRect(b); + if (b.IsValid()) { +//printf("bounding box '%s': %lld µs\n", string, system_time() - now); + AutoFloatingOverlaysHider _(fGraphicsCard, b); + +//now = system_time(); + BRect touched = fPainter->DrawString(string, length, offsets, + &cacheReference); +//printf("drawing string: %lld µs\n", system_time() - now); + + _CopyToFront(touched); + } + + return penLocation; +} + + float DrawingEngine::StringWidth(const char* string, int32 length, escapement_delta* delta) Modified: haiku/trunk/src/servers/app/drawing/DrawingEngine.h =================================================================== --- haiku/trunk/src/servers/app/drawing/DrawingEngine.h 2010-03-15 11:19:21 UTC (rev 35864) +++ haiku/trunk/src/servers/app/drawing/DrawingEngine.h 2010-03-15 13:59:14 UTC (rev 35865) @@ -166,6 +166,8 @@ virtual BPoint DrawString(const char* string, int32 length, const BPoint& pt, escapement_delta* delta = NULL); + virtual BPoint DrawString(const char* string, int32 length, + const BPoint* offsets); float StringWidth(const char* string, int32 length, escapement_delta* delta = NULL); Modified: haiku/trunk/src/servers/app/drawing/Painter/AGGTextRenderer.cpp =================================================================== --- haiku/trunk/src/servers/app/drawing/Painter/AGGTextRenderer.cpp 2010-03-15 11:19:21 UTC (rev 35864) +++ haiku/trunk/src/servers/app/drawing/Painter/AGGTextRenderer.cpp 2010-03-15 13:59:14 UTC (rev 35865) @@ -304,7 +304,7 @@ AGGTextRenderer& fRenderer; }; -// RenderString + BRect AGGTextRenderer::RenderString(const char* string, uint32 length, const BPoint& baseLine, const BRect& clippingFrame, bool dryRun, @@ -335,7 +335,41 @@ transform, transformOffset, nextCharPos, *this); GlyphLayoutEngine::LayoutGlyphs(renderer, fFont, string, length, delta, - fKerning, B_BITMAP_SPACING, cacheReference); + fKerning, B_BITMAP_SPACING, NULL, cacheReference); return transform.TransformBounds(renderer.Bounds()); } + + +BRect +AGGTextRenderer::RenderString(const char* string, uint32 length, + const BPoint* offsets, const BRect& clippingFrame, bool dryRun, + BPoint* nextCharPos, FontCacheReference* cacheReference) +{ +//printf("RenderString(\"%s\", length: %ld, dry: %d)\n", string, length, dryRun); + + Transformable transform(fEmbeddedTransformation); + + fCurves.approximation_scale(transform.scale()); + + // use a transformation behind the curves + // (only if glyph->data_type == agg::glyph_data_outline) + // in the pipeline for the rasterizer + FontCacheEntry::TransformedOutline + transformedOutline(fCurves, transform); + FontCacheEntry::TransformedContourOutline + transformedContourOutline(fContour, transform); + + // for when we bypass the transformation pipeline + BPoint transformOffset(0.0, 0.0); + transform.Transform(&transformOffset); + + StringRenderer renderer(clippingFrame, dryRun, + transformedOutline, transformedContourOutline, + transform, transformOffset, nextCharPos, *this); + + GlyphLayoutEngine::LayoutGlyphs(renderer, fFont, string, length, NULL, + fKerning, B_BITMAP_SPACING, offsets, cacheReference); + + return transform.TransformBounds(renderer.Bounds()); +} Modified: haiku/trunk/src/servers/app/drawing/Painter/AGGTextRenderer.h =================================================================== --- haiku/trunk/src/servers/app/drawing/Painter/AGGTextRenderer.h 2010-03-15 11:19:21 UTC (rev 35864) +++ haiku/trunk/src/servers/app/drawing/Painter/AGGTextRenderer.h 2010-03-15 13:59:14 UTC (rev 35865) @@ -54,6 +54,12 @@ const escapement_delta* delta, FontCacheReference* cacheReference); + BRect RenderString(const char* utf8String, + uint32 length, const BPoint* offsets, + const BRect& clippingFrame, bool dryRun, + BPoint* nextCharPos, + FontCacheReference* cacheReference); + private: class StringRenderer; Modified: haiku/trunk/src/servers/app/drawing/Painter/Painter.cpp =================================================================== --- haiku/trunk/src/servers/app/drawing/Painter/Painter.cpp 2010-03-15 11:19:21 UTC (rev 35864) +++ haiku/trunk/src/servers/app/drawing/Painter/Painter.cpp 2010-03-15 13:59:14 UTC (rev 35865) @@ -1418,7 +1418,7 @@ baseLine.y = roundf(baseLine.y); } - BRect bounds(0.0, 0.0, -1.0, -1.0); + BRect bounds; // text is not rendered with patterns, but we need to // make sure that the previous pattern is restored @@ -1435,6 +1435,32 @@ } +// DrawString +BRect +Painter::DrawString(const char* utf8String, uint32 length, + const BPoint* offsets, FontCacheReference* cacheReference) +{ + CHECK_CLIPPING + + // TODO: Round offsets to device pixel grid if !fSubpixelPrecise? + + BRect bounds; + + // text is not rendered with patterns, but we need to + // make sure that the previous pattern is restored + pattern oldPattern = *fPatternHandler.GetR5Pattern(); + SetPattern(B_SOLID_HIGH, true); + + bounds = fTextRenderer.RenderString(utf8String, length, + offsets, fClippingRegion->Frame(), false, NULL, + cacheReference); + + SetPattern(oldPattern); + + return _Clipped(bounds); +} + + // BoundingBox BRect Painter::BoundingBox(const char* utf8String, uint32 length, BPoint baseLine, @@ -1452,6 +1478,20 @@ } +// BoundingBox +BRect +Painter::BoundingBox(const char* utf8String, uint32 length, + const BPoint* offsets, BPoint* penLocation, + FontCacheReference* cacheReference) const +{ + // TODO: Round offsets to device pixel grid if !fSubpixelPrecise? + + static BRect dummy; + return fTextRenderer.RenderString(utf8String, length, + offsets, dummy, true, penLocation, cacheReference); +} + + // StringWidth float Painter::StringWidth(const char* utf8String, uint32 length, Modified: haiku/trunk/src/servers/app/drawing/Painter/Painter.h =================================================================== --- haiku/trunk/src/servers/app/drawing/Painter/Painter.h 2010-03-15 11:19:21 UTC (rev 35864) +++ haiku/trunk/src/servers/app/drawing/Painter/Painter.h 2010-03-15 13:59:14 UTC (rev 35865) @@ -200,6 +200,9 @@ uint32 length, BPoint baseLine, const escapement_delta* delta, FontCacheReference* cacheReference = NULL); + BRect DrawString(const char* utf8String, + uint32 length, const BPoint* offsets, + FontCacheReference* cacheReference = NULL); BRect BoundingBox(const char* utf8String, uint32 length, BPoint baseLine, @@ -207,6 +210,11 @@ const escapement_delta* delta, FontCacheReference* cacheReference = NULL) const; + BRect BoundingBox(const char* utf8String, + uint32 length, const BPoint* offsets, + BPoint* penLocation, + FontCacheReference* cacheReference + = NULL) const; float StringWidth(const char* utf8String, uint32 length, Modified: haiku/trunk/src/tests/servers/app/Jamfile =================================================================== --- haiku/trunk/src/tests/servers/app/Jamfile 2010-03-15 11:19:21 UTC (rev 35864) +++ haiku/trunk/src/tests/servers/app/Jamfile 2010-03-15 13:59:14 UTC (rev 35865) @@ -173,6 +173,7 @@ SubInclude HAIKU_TOP src tests servers app cursor_test ; SubInclude HAIKU_TOP src tests servers app desktop_window ; SubInclude HAIKU_TOP src tests servers app draw_after_children ; +SubInclude HAIKU_TOP src tests servers app draw_string_offsets ; SubInclude HAIKU_TOP src tests servers app drawing_debugger ; SubInclude HAIKU_TOP src tests servers app drawing_modes ; SubInclude HAIKU_TOP src tests servers app event_mask ; Added: haiku/trunk/src/tests/servers/app/draw_string_offsets/Jamfile =================================================================== --- haiku/trunk/src/tests/servers/app/draw_string_offsets/Jamfile (rev 0) +++ haiku/trunk/src/tests/servers/app/draw_string_offsets/Jamfile 2010-03-15 13:59:14 UTC (rev 35865) @@ -0,0 +1,17 @@ +SubDir HAIKU_TOP src tests servers app draw_string_offsets ; + +SetSubDirSupportedPlatformsBeOSCompatible ; +AddSubDirSupportedPlatforms libbe_test ; + +UseHeaders [ FDirName os app ] ; +UseHeaders [ FDirName os interface ] ; + +SimpleTest DrawStringOffsets : + main.cpp + : be $(TARGET_LIBSUPC++) + ; + +if ( $(TARGET_PLATFORM) = libbe_test ) { + HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR) : DrawStringOffsets + : tests!apps ; +} Added: haiku/trunk/src/tests/servers/app/draw_string_offsets/main.cpp =================================================================== --- haiku/trunk/src/tests/servers/app/draw_string_offsets/main.cpp (rev 0) +++ haiku/trunk/src/tests/servers/app/draw_string_offsets/main.cpp 2010-03-15 13:59:14 UTC (rev 35865) @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <string.h> + +#include <Application.h> +#include <Message.h> +#include <Shape.h> +#include <View.h> +#include <Window.h> + + +static const char* kAppSignature = "application/x.vnd-Haiku.DrawStringOffsets"; + + +class TestView : public BView { +public: + TestView(BRect frame, const char* name, + uint32 resizeFlags, uint32 flags); + + virtual void Draw(BRect updateRect); +}; + + +TestView::TestView(BRect frame, const char* name, uint32 resizeFlags, + uint32 flags) + : + BView(frame, name, resizeFlags, flags) +{ +} + + +void +TestView::Draw(BRect updateRect) +{ + BPoint offsets[5]; + offsets[0].x = 10; + offsets[0].y = 10; + offsets[1].x = 15; + offsets[1].y = 10; + offsets[2].x = 20; + offsets[2].y = 18; + offsets[3].x = 23; + offsets[3].y = 12; + offsets[4].x = 30; + offsets[4].y = 10; + + DrawString("Hello", strlen("Hello"), offsets); +} + + +// #pragma mark - + + +int +main(int argc, char** argv) +{ + BApplication app(kAppSignature); + + BWindow* window = new BWindow(BRect(50.0, 50.0, 300.0, 250.0), + "DrawString() with offsets", B_TITLED_WINDOW, + B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE); + + BView* view = new TestView(window->Bounds(), "test", B_FOLLOW_ALL, + B_WILL_DRAW); + window->AddChild(view); + + window->Show(); + + app.Run(); + return 0; +}