diff options
| author | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2026-10-15 14:46:34 +0200 |
|---|---|---|
| committer | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2026-10-15 14:46:34 +0200 |
| commit | 909ef3c352e947517b3cab6ecdb8c64ea9677705 (patch) | |
| tree | 87ecc10f874345882e3137268cfe6408dbab895f | |
| parent | 6ddc3fb585a106d37b35356e12e02761a39f9aa2 (diff) | |
svg process_elt new_sub_path cmd, rename text_run cmd to text
| -rw-r--r-- | docker-compose.build.yml | 2 | ||||
| -rw-r--r-- | gunit_tests/context.cpp | 6 | ||||
| -rw-r--r-- | gunit_tests/pathDraw.cpp | 62 | ||||
| -rw-r--r-- | gunit_tests/textDraw.cpp | 47 | ||||
| -rw-r--r-- | include/vkvg.h | 14 | ||||
| -rw-r--r-- | samples/tests/circles.cpp | 17 | ||||
| -rw-r--r-- | samples/tests/gradient.cpp | 72 | ||||
| -rw-r--r-- | src/array.h | 10 | ||||
| -rw-r--r-- | src/svg/svg-parse.c | 10 | ||||
| -rw-r--r-- | src/vkvg_context.c | 54 | ||||
| -rw-r--r-- | src/vkvg_context_internal.c | 2 | ||||
| -rw-r--r-- | src/vkvg_device_internal.h | 27 | ||||
| -rw-r--r-- | src/vkvg_fonts.c | 10 | ||||
| -rw-r--r-- | src/vkvg_fonts.h | 4 | ||||
| -rw-r--r-- | tests/data/text.svg | 4 | ||||
| -rw-r--r-- | tests/fonts/allfont.c | 66 | ||||
| -rw-r--r-- | tests/fonts/fontquery.c | 8 | ||||
| -rw-r--r-- | tests/text.c | 63 |
18 files changed, 356 insertions, 122 deletions
diff --git a/docker-compose.build.yml b/docker-compose.build.yml index 4afe72c..9ab4731 100644 --- a/docker-compose.build.yml +++ b/docker-compose.build.yml @@ -25,7 +25,7 @@ services: image: debian-c-builder:trixie environment: - DISTRO=debian - - BUILD_DOC=off + - BUILD_DOC=on deploy: resources: limits: diff --git a/gunit_tests/context.cpp b/gunit_tests/context.cpp index 4b3a438..9f68a6b 100644 --- a/gunit_tests/context.cpp +++ b/gunit_tests/context.cpp @@ -170,11 +170,11 @@ TEST_F(ContextTest, CtxDrawBasicNullContext) { EXPECT_NO_FATAL_FAILURE(vkvg_text_extents(ctx, NULL, NULL)); EXPECT_NO_FATAL_FAILURE(vkvg_font_extents(ctx, NULL)); - vkvg_text_run_create(ctx, NULL); - vkvg_text_run_create_with_length(ctx, NULL, 10); + vkvg_text_create(ctx, NULL); + vkvg_text_create_with_length(ctx, NULL, 10); // vkvg_text_run_destroy(NULL); - vkvg_text_run_render(ctx, NULL); + vkvg_text_render(ctx, NULL); } diff --git a/gunit_tests/pathDraw.cpp b/gunit_tests/pathDraw.cpp index 8399ddf..9f37ee7 100644 --- a/gunit_tests/pathDraw.cpp +++ b/gunit_tests/pathDraw.cpp @@ -117,24 +117,64 @@ TEST_F(PathDrawTest, CircleFillStrokeScaleDown10) { compareWithRefImage(); } -TEST_F(PathDrawTest, curved_rect) { +TEST_F(PathDrawTest, CircleCurve) { VkvgContext ctx = vkvg_create(surf); vkvg_set_source_rgb(ctx, 0.8,0.8,0.8); vkvg_paint(ctx); + vkvg_scale(ctx,0.1,0.1); + vkvg_set_source_rgb(ctx, 0.5, 0.5, 1); + vkvg_arc(ctx, 1280, 1280, 1000, 0, M_PI * 2); + vkvg_fill_preserve(ctx); + vkvg_set_source_rgb(ctx, 0, 0, 0); + vkvg_set_line_width(ctx, 100); + vkvg_stroke(ctx); vkvg_destroy(ctx); + compareWithRefImage(); } -TEST_F(PathDrawTest, CircleCurve) { +TEST_F(PathDrawTest, CircleLargerStrokeThanR0) { VkvgContext ctx = vkvg_create(surf); vkvg_set_source_rgb(ctx, 0.8,0.8,0.8); vkvg_paint(ctx); - vkvg_scale(ctx,0.1,0.1); - vkvg_set_source_rgb(ctx, 0.5, 0.5, 1); - vkvg_arc(ctx, 1280, 1280, 1000, 0, M_PI * 2); + + vkvg_set_source_rgb(ctx, 0, 0, 1); + vkvg_arc(ctx, 128, 128, 50.f, 0, M_PI * 1.5f); vkvg_fill_preserve(ctx); - vkvg_set_source_rgb(ctx, 0, 0, 0); - vkvg_set_line_width(ctx, 100); + vkvg_set_source_rgba(ctx, 0, 1, 0, 0.3f); + vkvg_set_line_width(ctx, 150); + vkvg_stroke(ctx); + + vkvg_destroy(ctx); + + compareWithRefImage(); +} +TEST_F(PathDrawTest, CircleLargerStrokeThanR1) { + VkvgContext ctx = vkvg_create(surf); + vkvg_set_source_rgb(ctx, 0.8,0.8,0.8); + vkvg_paint(ctx); + + vkvg_set_source_rgb(ctx, 0, 0, 1); + vkvg_arc(ctx, 128, 128, 10.f, 0, M_PI * 1.5f); + vkvg_fill_preserve(ctx); + vkvg_set_source_rgba(ctx, 0, 1, 0, 0.3f); + vkvg_set_line_width(ctx, 150); + vkvg_stroke(ctx); + + vkvg_destroy(ctx); + + compareWithRefImage(); +} +TEST_F(PathDrawTest, CircleLargerStrokeThanR2) { + VkvgContext ctx = vkvg_create(surf); + vkvg_set_source_rgb(ctx, 0.8,0.8,0.8); + vkvg_paint(ctx); + + vkvg_set_source_rgb(ctx, 0, 0, 1); + vkvg_arc(ctx, 128, 128, 01.f, 0, M_PI * 1.5f); + vkvg_fill_preserve(ctx); + vkvg_set_source_rgba(ctx, 0, 1, 0, 0.3f); + vkvg_set_line_width(ctx, 150); vkvg_stroke(ctx); vkvg_destroy(ctx); @@ -292,3 +332,11 @@ TEST_F(PathDrawTest, curve3) { compareWithRefImage(); } +TEST_F(PathDrawTest, curved_rect) { + VkvgContext ctx = vkvg_create(surf); + vkvg_set_source_rgb(ctx, 0.8,0.8,0.8); + vkvg_paint(ctx); + + vkvg_destroy(ctx); + compareWithRefImage(); +}
\ No newline at end of file diff --git a/gunit_tests/textDraw.cpp b/gunit_tests/textDraw.cpp index 8e40294..25b43a9 100644 --- a/gunit_tests/textDraw.cpp +++ b/gunit_tests/textDraw.cpp @@ -6,7 +6,7 @@ class TextDrawTest : public DrawTestBase { protected: void SetUp() override { - surf = vkvg_surface_create(dev, 512, 512); + surf = vkvg_surface_create(dev, 512, 512); } void TearDown() override { @@ -14,6 +14,19 @@ class TextDrawTest : public DrawTestBase { } }; TEST_F(TextDrawTest, References) { + VkvgFont font = vkvg_font_create(dev, "sans", 12); + EXPECT_EQ(VKVG_STATUS_SUCCESS, vkvg_font_status(font)); + vkvg_font_destroy(font); + + font = vkvg_font_create(dev, "Sans", 12); + EXPECT_EQ(VKVG_STATUS_SUCCESS, vkvg_font_status(font)); + vkvg_font_destroy(font); + + font = vkvg_font_create(dev, "noto sans jp", 12); + EXPECT_EQ(VKVG_STATUS_SUCCESS, vkvg_font_status(font)); + vkvg_font_destroy(font); + + /*EXPECT_EQ(VKVG_STATUS_NULL_POINTER, vkvg_font_status(NULL)); EXPECT_EQ(0, vkvg_pattern_get_reference_count(NULL)); EXPECT_NO_FATAL_FAILURE(vkvg_pattern_reference(NULL)); @@ -38,10 +51,40 @@ TEST_F(TextDrawTest, References) { vkvg_pattern_destroy(pat);*/ } -TEST_F(TextDrawTest, PaintImgPattern) { +TEST_F(TextDrawTest, ShowText) { VkvgContext ctx = vkvg_create(surf); + vkvg_paint(ctx); + VkvgFont font = vkvg_font_create(dev, "sans", 30); + vkvg_set_font(ctx, font); + vkvg_font_extents_t fe = {0}; + vkvg_font_extents(ctx, &fe); + vkvg_set_source_rgb(ctx,1,1,1); + float penY = fe.ascent; + vkvg_move_to(ctx, 40, penY); + vkvg_show_text(ctx, "Galvanized by the quartz, the white rabbit just jumped on the red fox for the sake of the crows"); + penY += fe.height; + + vkvg_font_destroy(font); + + font = vkvg_font_create(dev, "noto sans jp", 30); + vkvg_set_font(ctx, font); + vkvg_move_to(ctx, 40, penY); + vkvg_show_text(ctx, "Galvanized by the quartz, The white rabbit just jumped on the red fox for the sake of the crows"); + vkvg_font_extents(ctx, &fe); + penY += fe.height; + + vkvg_move_to(ctx, 40, penY); + vkvg_show_text(ctx, "いろはにほへと ちりぬるを わかよたれそ つねならむ"); + vkvg_font_extents(ctx, &fe); + penY += fe.height; + vkvg_set_text_direction(ctx, VKVG_VERTICAL); + vkvg_move_to(ctx, 20, 60); + vkvg_show_text(ctx, "石英に刺激され、白ウサギはカラスたちのために、赤ギツネの上に飛び乗った。"); + + vkvg_destroy(ctx); compareWithRefImage(); } + diff --git a/include/vkvg.h b/include/vkvg.h index 1ca2522..c457060 100644 --- a/include/vkvg.h +++ b/include/vkvg.h @@ -1780,7 +1780,7 @@ vkvg_public void vkvg_font_extents(VkvgContext ctx, vkvg_font_extents_t* extents * @param text Null terminated utf8 string. * @return VkvgText */ -vkvg_public VkvgText vkvg_text_run_create(VkvgContext ctx, const char* text); +vkvg_public VkvgText vkvg_text_create(VkvgContext ctx, const char* text); /** * @brief Create a new text run for a non null terminated string. * @@ -1789,40 +1789,40 @@ vkvg_public VkvgText vkvg_text_run_create(VkvgContext ctx, const char* text); * @param length glyphs count, not to be confused with byte length. * @return VkvgText */ -vkvg_public VkvgText vkvg_text_run_create_with_length(VkvgContext ctx, const char* text, uint32_t length); +vkvg_public VkvgText vkvg_text_create_with_length(VkvgContext ctx, const char* text, uint32_t length); /** * @brief Release resources holded by the text run. * * @param VkvgtextRun A valid VkvgText pointer. */ -vkvg_public void vkvg_text_run_destroy(VkvgText textRun); +vkvg_public void vkvg_text_destroy(VkvgText textRun); /** * @brief * * @param ctx a valid vkvg @ref context * @param textRun */ -vkvg_public void vkvg_text_run_render(VkvgContext ctx, VkvgText textRun); +vkvg_public void vkvg_text_render(VkvgContext ctx, VkvgText textRun); /** * @brief * * @param textRun * @param extents */ -vkvg_public void vkvg_text_run_get_extents(VkvgText textRun, vkvg_text_extents_t* extents); +vkvg_public void vkvg_text_get_extents(VkvgText textRun, vkvg_text_extents_t* extents); /** * @brief Get glyph count of text run. * * @return glyph count */ -vkvg_public uint32_t vkvg_text_run_get_glyph_count(VkvgText textRun); +vkvg_public uint32_t vkvg_text_get_glyph_count(VkvgText textRun); /** * @brief Get glyph position at the provided index * @param textRun A valid @ref VkvgText * @param index index of the glyph to get position for. * @return the glyph structure with position and glyph index. */ -vkvg_public vkvg_glyph_info_t vkvg_text_run_get_glyph_position(VkvgText textRun, uint32_t index); +vkvg_public vkvg_glyph_info_t vkvg_text_get_glyph_position(VkvgText textRun, uint32_t index); /** @}*/ /** diff --git a/samples/tests/circles.cpp b/samples/tests/circles.cpp index a302ec8..a03963f 100644 --- a/samples/tests/circles.cpp +++ b/samples/tests/circles.cpp @@ -44,3 +44,20 @@ TEST(circles_sizes) { vkvg_destroy(ctx); } +TEST(circles_stroke_larger_than_r) { + VkvgContext ctx = vkvg_create(test->surf); + vkvg_clear(ctx); + + vkvg_set_source_rgb(ctx, 1, 0, 0); + + vkvg_arc(ctx, test->app->width / 2, test->app->height / 2, 1.f, 0, M_PIF * 1.5f); + vkvg_fill_preserve(ctx); + + vkvg_set_source_rgba(ctx, 0, 1, 0, 0.3f); + vkvg_set_line_width(ctx, 300); + vkvg_stroke(ctx); + + vkvg_destroy(ctx); + + vkvg_destroy(ctx); +}
\ No newline at end of file diff --git a/samples/tests/gradient.cpp b/samples/tests/gradient.cpp index 37379b3..90a55c1 100644 --- a/samples/tests/gradient.cpp +++ b/samples/tests/gradient.cpp @@ -8,6 +8,67 @@ VkvgPattern create_grad(VkvgContext ctx, float x) { return pat; } + +void draw_gradient1(VkvgContext cr) +{ + VkvgPattern pat1; + pat1 = vkvg_pattern_create_linear(0.0, 0.0, 350.0, 350.0); + + double j; + int count = 1; + for ( j = 0.1; j < 1; j += 0.1 ) { + if (( count % 2 )) { + vkvg_pattern_add_color_stop(pat1, j, 0, 0, 0, 1); + } else { + vkvg_pattern_add_color_stop(pat1, j, 1, 0, 0, 1); + } + count++; + } + + vkvg_rectangle(cr, 20, 20, 300, 100); + vkvg_set_source(cr, pat1); + vkvg_fill(cr); + + vkvg_pattern_destroy(pat1); +} +void draw_gradient2(VkvgContext cr) +{ + VkvgPattern pat2; + pat2 = vkvg_pattern_create_linear(0.0, 0.0, 350.0, 0.0); + + double i; + int count = 1; + for ( i = 0.05; i < 0.95; i += 0.075 ) { + if (( count % 2 )) { + vkvg_pattern_add_color_stop(pat2, i, 0, 0, 0, 1); + } else { + vkvg_pattern_add_color_stop(pat2, i, 0, 0, 1, 1); + } + count++; + } + + vkvg_rectangle(cr, 20, 140, 300, 100); + vkvg_set_source(cr, pat2); + vkvg_fill(cr); + + vkvg_pattern_destroy(pat2); +} +void draw_gradient3(VkvgContext cr) +{ + VkvgPattern pat3; + pat3 = vkvg_pattern_create_linear(20.0, 260.0, 20.0, 360.0); + + vkvg_pattern_add_color_stop(pat3, 0.1, 0, 0, 0, 1); + vkvg_pattern_add_color_stop(pat3, 0.5, 1, 1, 0, 1); + vkvg_pattern_add_color_stop(pat3, 0.9, 0, 0, 0, 1); + + vkvg_rectangle(cr, 20, 260, 300, 100); + vkvg_set_source(cr, pat3); + vkvg_fill(cr); + + vkvg_pattern_destroy(pat3); +} + TEST(gradient_paint) { VkvgContext ctx = vkvg_create(test->surf); vkvg_clear(ctx); @@ -172,3 +233,14 @@ TEST(gradient_radial) { vkvg_destroy(ctx); } + +TEST(gradient_cairo) { + VkvgContext ctx = vkvg_create(test->surf); + vkvg_set_source_rgb(ctx, 0.7f, 0.7f, 0.7f); + vkvg_paint(ctx); + + draw_gradient1(ctx); + draw_gradient2(ctx); + draw_gradient3(ctx); + vkvg_destroy(ctx); +}
\ No newline at end of file diff --git a/src/array.h b/src/array.h index fc3a8ce..041d05f 100644 --- a/src/array.h +++ b/src/array.h @@ -31,10 +31,12 @@ static type* array_last_##type (array_##type* arr) { \ return &arr->elements[arr->count - 1]; \ } \ static void array_destroy_##type (array_##type* arr) { \ - free(arr->elements); \ - arr->elements = NULL; \ - arr->count = 0; \ - arr->size = 0; \ + if (arr && arr->size > 0) { \ + free(arr->elements); \ + arr->elements = NULL; \ + arr->count = 0; \ + arr->size = 0; \ + } \ } #define ARRAY_DEL_ELT(type) \ static void array_del_##type (array_##type* arr, type elt) { \ diff --git a/src/svg/svg-parse.c b/src/svg/svg-parse.c index 9761050..90b019f 100644 --- a/src/svg/svg-parse.c +++ b/src/svg/svg-parse.c @@ -1459,6 +1459,7 @@ void draw(svg_context *svg, SvgPresentationAttributes *const attribs) { } } void process_element(svg_context *const svg, SvgPresentationAttributes *const attribs, void *elt, bool use) { + vkvg_new_sub_path(svg->ctx); if (!(svg->inDefs || !attribs->visibility)) { LOG("process element: %.*s \n", (int)svg->elt_len, svg->elt); switch (_get_element_type(elt)) { @@ -1673,17 +1674,16 @@ void draw_text(SVG_COMMON_SIG, svg_text_coords* coords, const uint8_t *buff, con else len = buff_end - buff; - tr = vkvg_text_run_create_with_length(svg->ctx, (char*)buff, len); - vkvg_text_run_render(svg->ctx, tr); - charI += vkvg_text_run_get_glyph_count(tr); - vkvg_text_run_destroy(tr); + tr = vkvg_text_create_with_length(svg->ctx, (char*)buff, len); + vkvg_text_render(svg->ctx, tr); + charI += vkvg_text_get_glyph_count(tr); + vkvg_text_destroy(tr); buff += len; } coords->charIndex = charI; } - void process_innerText(SVG_COMMON_SIG, const uint8_t *innerText, size_t txt_len) { if (!parentData) return; diff --git a/src/vkvg_context.c b/src/vkvg_context.c index 0c49c8d..16e31d5 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -1238,7 +1238,16 @@ void vkvg_set_text_direction(vkvg_context* ctx, vkvg_direction_t direction) { RECORD(ctx, VKVG_CMD_SET_TEXT_DIRECTION, size); ctx->textDirection = direction; } - +void vkvg_text_extents(VkvgContext ctx, const char* text, vkvg_text_extents_t* extents) { + if (vkvg_status(ctx)) + return; + _font_cache_text_extents(ctx, text, -1, extents); +} +void vkvg_font_extents(VkvgContext ctx, vkvg_font_extents_t* extents) { + if (vkvg_status(ctx) || vkvg_font_status(ctx->currentFont)) + return; + _font_cache_font_extents(ctx->currentFont, extents); +} void vkvg_show_text(VkvgContext ctx, const char* text) { if (vkvg_status(ctx) || vkvg_font_status(ctx->currentFont)) return; @@ -1249,23 +1258,33 @@ void vkvg_show_text(VkvgContext ctx, const char* text) { //_flush_undrawn_vertices (ctx); } -VkvgText vkvg_text_run_create(VkvgContext ctx, const char* text) { +VkvgText vkvg_text_create(VkvgContext ctx, const char* text) { if (vkvg_status(ctx) || vkvg_font_status(ctx->currentFont)) return NULL; VkvgText tr = (vkvg_text_run_t*)calloc(1, sizeof(vkvg_text_run_t)); - text_run_init(ctx->currentFont, ctx->textDirection, text, -1, tr); + if (!tr) { + LOGE("vkvg_text_create error, no memory\n"); + return NULL; + } + text_run_init(tr, ctx->currentFont, ctx->textDirection, text, -1); return tr; } -VkvgText vkvg_text_run_create_with_length(VkvgContext ctx, const char* text, uint32_t length) { +VkvgText vkvg_text_create_with_length(VkvgContext ctx, const char* text, uint32_t length) { if (vkvg_status(ctx) || vkvg_font_status(ctx->currentFont)) return NULL; VkvgText tr = (vkvg_text_run_t*)calloc(1, sizeof(vkvg_text_run_t)); - text_run_init(ctx->currentFont, ctx->textDirection, text, length, tr); + if (!tr) { + LOGE("vkvg_text_create error, no memory\n"); + return NULL; + } + text_run_init(tr, ctx->currentFont, ctx->textDirection, text, length); return tr; } -uint32_t vkvg_text_run_get_glyph_count(VkvgText textRun) { return textRun ? textRun->glyph_count : 0; } -vkvg_glyph_info_t vkvg_text_run_get_glyph_position(VkvgText textRun, uint32_t index) { - if (index >= textRun->glyph_count) { +uint32_t vkvg_text_get_glyph_count(VkvgText textRun) { + return textRun ? textRun->glyph_count : 0; +} +vkvg_glyph_info_t vkvg_text_get_glyph_position(VkvgText textRun, uint32_t index) { + if (!textRun || index >= textRun->glyph_count) { return (vkvg_glyph_info_t){0}; } #if VKVG_USE_HARFBUZZ @@ -1275,28 +1294,19 @@ vkvg_glyph_info_t vkvg_text_run_get_glyph_position(VkvgText textRun, uint32_t in return textRun->glyphs[index]; #endif } -void vkvg_text_run_destroy(VkvgText textRun) { +void vkvg_text_destroy(VkvgText textRun) { if (!textRun) return; text_run_term(textRun); free(textRun); } -void vkvg_text_run_render(VkvgContext ctx, VkvgText textRun) { +void vkvg_text_render(VkvgContext ctx, VkvgText textRun) { if (vkvg_status(ctx) || !textRun) return; - text_run_render(ctx, textRun); + text_run_render(textRun, ctx); } -void vkvg_text_run_get_extents(VkvgText textRun, vkvg_text_extents_t* extents) { *extents = textRun->extents; } - -void vkvg_text_extents(VkvgContext ctx, const char* text, vkvg_text_extents_t* extents) { - if (vkvg_status(ctx)) - return; - _font_cache_text_extents(ctx, text, -1, extents); -} -void vkvg_font_extents(VkvgContext ctx, vkvg_font_extents_t* extents) { - if (vkvg_status(ctx) || vkvg_font_status(ctx->currentFont)) - return; - _font_cache_font_extents(ctx->currentFont, extents); +void vkvg_text_get_extents(VkvgText textRun, vkvg_text_extents_t* extents) { + *extents = textRun->extents; } void vkvg_save(VkvgContext ctx) { diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c index 2d2a600..47f274b 100644 --- a/src/vkvg_context_internal.c +++ b/src/vkvg_context_internal.c @@ -1273,7 +1273,7 @@ void _draw_segment(VkvgContext ctx, stroke_context_t* str, dash_context_t* dc, b else _build_vb_step(ctx, str, isCurve); str->iL = str->cp++; - if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) { + if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) {//TODO:should unit test that case Vertex v0 = ctx->vertexCache[ctx->curVertOffset + str->firstIdx]; Vertex v1 = ctx->vertexCache[ctx->curVertOffset + str->firstIdx + 1]; _emit_draw_cmd_undrawn_vertices(ctx); diff --git a/src/vkvg_device_internal.h b/src/vkvg_device_internal.h index 5dced18..a436cd9 100644 --- a/src/vkvg_device_internal.h +++ b/src/vkvg_device_internal.h @@ -72,22 +72,21 @@ typedef struct _vkvg_device_t { VkFormat stencilFormat; /**< Supported vulkan image format for stencil */ VkImageAspectFlags stencilAspectFlag; /**< stencil only or depth stencil, could be solved by VK_KHR_separate_depth_stencil_layouts*/ - VkFormat pngStagFormat; /**< Supported vulkan image format png write staging img */ - VkImageTiling pngStagTiling; /**< tiling for the blit operation */ + VkFormat pngStagFormat; /**< Supported vulkan image format png write staging img */ + VkImageTiling pngStagTiling; /**< tiling for the blit operation */ - mtx_t mutex; /**< protect device access (queue, cahes, ...)from ctxs in separate threads */ - bool threadAware; /**< if true, mutex is created and guard device queue and caches access */ - VkhQueue gQueue; /**< Vulkan Queue with Graphic flag */ + mtx_t mutex; /**< protect device access (queue, cahes, ...)from ctxs in separate threads */ + bool threadAware; /**< if true, mutex is created and guard device queue and caches access */ + VkhQueue gQueue; /**< Vulkan Queue with Graphic flag */ - VkRenderPass renderPass; /**< Vulkan render pass, common for all surfaces */ - VkRenderPass - renderPass_ClearStencil; /**< Vulkan render pass for first draw with context, stencil has to be cleared */ - VkRenderPass renderPass_ClearAll; /**< Vulkan render pass for new surface, clear all attacments*/ + VkRenderPass renderPass; /**< Vulkan render pass, common for all surfaces */ + VkRenderPass renderPass_ClearStencil; /**< Vulkan render pass for first draw with context, stencil has to be cleared */ + VkRenderPass renderPass_ClearAll; /**< Vulkan render pass for new surface, clear all attacments*/ uint32_t references; /**< Reference count, prevent destroying device if still in use */ VkCommandPool cmdPool; /**< Global command pool for processing on surfaces without context */ VkCommandBuffer cmd; /**< Global command buffer */ - VkFence fence; /**< this fence is kept signaled when idle, wait and reset are called before each recording. */ + VkFence fence; /**< this fence is kept signaled when idle, wait and reset are called before each recording. */ VkPipeline pipe_OVER; /**< default operator */ VkPipeline pipe_SUB; @@ -107,11 +106,11 @@ typedef struct _vkvg_device_t { VkhDevice vkhDev; /**< old VkhDev created during vulkan context creation by @ref vkvg_device_create. */ - VkhImage emptyImg; /**< prevent unbound descriptor to trigger Validation error 61 */ - VkSampleCountFlags samples; /**< samples count common to all surfaces */ - bool deferredResolve; /**< if true, resolve only on context destruction and set as source */ + VkhImage emptyImg; /**< prevent unbound descriptor to trigger Validation error 61 */ + VkSampleCountFlags samples; /**< samples count common to all surfaces */ + bool deferredResolve; /**< if true, resolve only on context destruction and set as source */ - _font_cache_t* fontCache; /**< Store everything relative to common font caching system */ + _font_cache_t* fontCache; /**< Store everything relative to common font caching system */ VkvgContext lastCtx; /**< last element of double linked list of context, used to trigger font caching system update on all contexts*/ diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c index 8098a28..7d7c356 100644 --- a/src/vkvg_fonts.c +++ b/src/vkvg_fonts.c @@ -802,7 +802,7 @@ void _font_cache_text_extents(VkvgContext ctx, const char* text, int length, vkv } vkvg_text_run_t tr = {0}; - text_run_init(ctx->currentFont, ctx->textDirection, text, length, &tr); + text_run_init(&tr, ctx->currentFont, ctx->textDirection, text, length); if (ctx->status) return; @@ -814,18 +814,18 @@ void _font_cache_text_extents(VkvgContext ctx, const char* text, int length, vkv // text is expected as utf8 encoded void _font_cache_show_text(VkvgContext ctx, const char* text) { vkvg_text_run_t tr = {0}; - text_run_init(ctx->currentFont, ctx->textDirection, text, -1, &tr); + text_run_init(&tr, ctx->currentFont, ctx->textDirection, text, -1); if (ctx->status) return; - text_run_render(ctx, &tr); + text_run_render(&tr, ctx); text_run_term(&tr); //_show_texture(ctx); return; } // if length is < 0, text must be null terminated, else it contains glyph count -void text_run_init(VkvgFont font, vkvg_direction_t textDirection, const char* text, int length, VkvgText textRun) { +void text_run_init(VkvgText textRun, VkvgFont font, vkvg_direction_t textDirection, const char* text, int length) { textRun->font = font; textRun->textDirection = textDirection; vkvg_font_reference (textRun->font); @@ -897,7 +897,7 @@ void text_run_term(VkvgText textRun) { vkvg_font_destroy(textRun->font); } -void text_run_render(VkvgContext ctx, VkvgText tr) { +void text_run_render(VkvgText tr, VkvgContext ctx) { unsigned int glyph_count; #ifdef VKVG_USE_HARFBUZZ hb_glyph_info_t* glyph_info = hb_buffer_get_glyph_infos(tr->hbBuf, &glyph_count); diff --git a/src/vkvg_fonts.h b/src/vkvg_fonts.h index 09a57d0..66f8612 100644 --- a/src/vkvg_fonts.h +++ b/src/vkvg_fonts.h @@ -312,7 +312,7 @@ void _font_cache_text_extents(VkvgContext ctx, const char* text, int length, vkv void _font_cache_font_extents(VkvgFont font, vkvg_font_extents_t* extents); void _font_cache_update_context_descset(VkvgContext ctx); -void text_run_init(VkvgFont font, vkvg_direction_t textDirection, const char* text, int length, VkvgText textRun); +void text_run_init(VkvgText textRun, VkvgFont font, vkvg_direction_t textDirection, const char* text, int length); void text_run_term(VkvgText textRun); -void text_run_render(VkvgContext ctx, VkvgText tr); // Draw text run +void text_run_render(VkvgText tr, VkvgContext ctx); // Draw text run #endif diff --git a/tests/data/text.svg b/tests/data/text.svg index 91c2505..0be89d8 100644 --- a/tests/data/text.svg +++ b/tests/data/text.svg @@ -1,4 +1,4 @@ -<svg xmlns="http://w3.org" width="800" height="600" viewBox="0 0 800 600"> +<svg width="800" height="600" viewBox="0 0 800 600"> <!-- Visual grid lines for debugging alignments --> <g stroke="#e0e0e0" stroke-width="1"> <line x1="50" y1="0" x2="50" y2="600" /> @@ -21,7 +21,7 @@ <!-- TEST 1: Comma/Space Separators & List Exhaustion --> <!-- 'S' at 50, 'P' at 100, 'A' at 150, 'C' at 200. 'E' and 'S' should rely on default font advances. --> - <text x="50, 100 150,200" y="100" font-family="sans-serif" font-size="24" fill="black"> + <text x="50, 100 150,200" y="100" font-family="sans" font-size="52" fill="black"> SPACES </text> diff --git a/tests/fonts/allfont.c b/tests/fonts/allfont.c index 00eb19d..4e79fa3 100644 --- a/tests/fonts/allfont.c +++ b/tests/fonts/allfont.c @@ -31,7 +31,6 @@ typedef struct { // A localized library of pan-unicode text variations static const LocaleSample script_samples[] = { - { "en", "The quick brown fox jumps over the lazy dog." }, // Latin Fallback { "ja", "いろはにほへと ちりぬるを わかよたれそ つねならむ" }, // Japanese Hiragana { "zh", "天地玄黃,宇宙洪荒。日月盈昃,辰宿列張。" }, // Chinese Hanzi { "ko", "다람쥐 쳇바퀴에 타고파" }, // Korean Hangul @@ -42,14 +41,16 @@ static const LocaleSample script_samples[] = { { "el", "διαφυλάξτε γενικά τη ζωή σας από τον φόβο" }, // Greek { "th", "เป็นมนุษย์สุดประเสริฐเลิIศคุณค่า" }, // Thai { "hy", "Ֆիզիկոս Մկրտիչը օճառաջուր ցողելով բժշկում է գնդապետ Հայկի փքված ձախ թևը։" }, // Armenian + { "pa", "ਘੁਮਿਆਰ ਨੇ ਮਿੱਟੀ ਚੁੱਕ ਕੇ ਇੱਕ ਬਹੁਤ ਹੀ ਸੁੰਦਰ ਘੜਾ ਬਣਾਇਆ।" }, // Punjabi (Gurmukhi script) + { "te", "కచ్ఛపము మందగమనముతో చెరువు వైపు వెళుతోంది." }, // Telugu (Telugu script) + { "ta", "தமிழ் மொழி உலகினில் மிக தொன்மையான மற்றும் அழகான மொழியாகும்." }, // Tamil (Tamil script) + { "ber-ma", "ⵎⴰⵕⵕⴰ ⵉⵎᏓⵏⵏ ⴷⴳ ⵓⵍⵉⴼ ⴷ ⵉⵣⵔⴼⴰⵏ ⴷ ⵍⵃⵇⵇ ⵜⵜⵍⴰⵍⴰⵏ ⴷ ⵉⵍⴻⵍⵍⵉⵢⵏ." }, // Moroccan Berber (Tifinagh script) + { "en", "The quick brown fox jumps over the lazy dog." }, // Latin Fallback { "agr", "Agatjai juuk tusha numpanum ijuaku jintanum pujawai" }, // Aguaruna (Latin script variation) //{ "aa", "Afari fanta asat darih doro dahanik xisbisa" }, // Afar (Latin script variation) { "bem", "Abantu bonse bafyalwa abalubuka no kulingana mu mucinshi" }, // Bemba (Bantu Latin script) - { "pa", "ਘੁਮਿਆਰ ਨੇ ਮਿੱਟੀ ਚੁੱਕ ਕੇ ਇੱਕ ਬਹੁਤ ਹੀ ਸੁੰਦਰ ਘੜਾ ਬਣਾਇਆ।" }, // Punjabi (Gurmukhi script) - { "te", "కచ్ఛపము మందగమనముతో చెరువు వైపు వెళుతోంది." }, // Telugu (Telugu script) { "km", "ខ្យល់បក់បោកបបួលបក្សីហើរទៅកាន់ព្រៃព្រឹក្សាដ៏ស្ងប់ស្ងាត់។" }, // Khmer (Khmer script) { "lo", "ນົກກາງແກບິນຂ້າມທົ່ງນາທີ່ກວ້າງໃຫຍ່ໄພສານຢ່າງສະຫງ່າງາມ." }, // Lao (Lao script) - { "ta", "தமிழ் மொழி உலகினில் மிக தொன்மையான மற்றும் அழகான மொழியாகும்." }, // Tamil (Tamil script) { "or", "ଋଷିମାନେ ଅରଣ୍ୟ ମଧ୍ୟରେ ଧ୍ୟାନ କରି ଶାନ୍ତି ଲାଭ କରନ୍ତି।" }, // Odia/Oriya (Odia script) { "ml", "ഭൂമിയിലെ എല്ലാ മനുഷ്യരും തുല്യ അവകാശങ്ങളോടെ ജനിക്കുന്നു." }, // Malayalam (Malayalam script) { "as", "শৰৎকালৰ স্নিগ্ধ জোনাক ৰাতি আকাশখন বৰ ধুনীয়া দেখায়।" }, // Assamese (Bengali-Assamese script) @@ -63,7 +64,6 @@ static const LocaleSample script_samples[] = { { "mnw", "မန်ဝံသဂမၠိုၚ် က္တဵုဒှ်ကၠုၚ် နကဵုဂုဏ်သိက္ခာ ညဳသၟဟ်ဂမၠိုၚ်။" }, // Mon (Mon-Burmese script) { "ii", "ꊿꊪꉼꆹꊪꊪꊿꐊꐥꌋꅍꐛꐹꂿꆪꄮꄯꉼꆹꄮꄯꂿꆪꊨꏦꍏꆪꐥꌋꅍꐛꐹꏦꍏꅪꏦꍏꅪꐨꏦꍏꄮꄯꅪ" }, // Nuosu / Liangshan Yi (Yi syllabary) { "chr", "ᏂᎦᏛ ᎠᏂᏰᎸᎢ ᎤᏂᎲᏓ ᏂᎨᏒᎾ ᎤᎾᏕᎲᎩ ᎢᏳᏍᏗᏉ ᎨᏒ ᎦᎸᏉᏗᏳ" }, // Cherokee (Cherokee syllabary) - { "ber-ma", "ⵎⴰⵕⵕⴰ ⵉⵎᏓⵏⵏ ⴷⴳ ⵓⵍⵉⴼ ⴷ ⵉⵣⵔⴼⴰⵏ ⴷ ⵍⵃⵇⵇ ⵜⵜⵍⴰⵍⴰⵏ ⴷ ⵉⵍⴻⵍⵍⵉⵢⵏ." }, // Moroccan Berber (Tifinagh script) { "ab", "Дарбанზаалак ауаҩы дшоуп ихы ақәgenericуи иҳаgenericти." }, // Abkhaz (Cyrillic variation) { "syr", "ܟܠ ܒܪܢܫܐ ܡܬܝܠܕ ܚܐܪܐ ܘܫܘܝܐ ܒܐܝܩܪܐ ܘܒܙܕܩܐ." }, // Syriac (Syriac script, right-to-left) { "iu", "ᐃᓅᔪᓕᒫᑦ ᐊᓂᖅᑎᕆᔪᓕᒫᑦ ᐃᓅᕗᑦ ᐃᓱᒪᕐᓱᕐᖢᑎᒃ ᐊᒻᒪ ᐊᔾᔨᒌᒃᑐᒥᒃ" }, // Inuktitut (Canadian Aboriginal Syllabics) @@ -71,27 +71,6 @@ static const LocaleSample script_samples[] = { { "mn-cn", "Хүн бүр төрөхDiscussion эрх чөлөөтэй, нэр төр, эрхийн хувьд адилхан." }, // Mongolian - Inner Mongolia (Cyrillic fallback) }; -bool try_get_sample_by_fc_lang(const char* fc_lang, char* str) { - const char* sample = NULL; - if (fc_lang) { - for (int i = 0; i < 37; i++) { - if (!strncmp(fc_lang, script_samples[i].lang_code, strlen(script_samples[i].lang_code)) && - strlen(script_samples[i].lang_code) == strlen(fc_lang)) { - sample = script_samples[i].sample_text; - - break; - } - } - if (!sample) { - sample = script_samples[0].sample_text; - return false; - } - } - - strncpy(str, sample, strlen(sample)+1); - return true; -} - #ifdef VKVG_USE_FREETYPE void convert_utf16be_to_utf8(const FT_Byte* src, FT_UInt src_len, char* dest, FT_UInt dest_max_len) { FT_UInt d_idx = 0; @@ -146,6 +125,7 @@ bool try_get_sample_string(FcPattern* font_entry, FT_Face face, char* str) { } FcLangSet* langset = NULL; FcChar8* lang = NULL; + const char* sample = NULL; if (FcPatternGetLangSet(font_entry, FC_LANG, 0, &langset) == FcResultMatch) { FcStrSet *lang_set = FcLangSetGetLangs(langset); if (!lang_set) @@ -155,13 +135,23 @@ bool try_get_sample_string(FcPattern* font_entry, FT_Face face, char* str) { FcStrListDone(lang_list); return false; } - - while ((lang = FcStrListNext(lang_list))) { - if (!lang) - continue; - if (try_get_sample_by_fc_lang((char*)lang, str)) - printf("sample found for %s\n", lang); + for (int i = 0; i < 37; i++) { + while ((lang = FcStrListNext(lang_list))) { + if (!lang) + continue; + if (!strncmp((char*)lang, script_samples[i].lang_code, strlen(script_samples[i].lang_code)) && + strlen(script_samples[i].lang_code) == strlen((char*)lang)) { + sample = (char*)script_samples[i].sample_text; + break; + } + } + if (sample) + break; + FcStrListFirst(lang_list); } + if (!sample) + sample = (char*)script_samples[14].sample_text; + strncpy(str, sample, strlen(sample)+1); FcStrListDone(lang_list); FcStrSetDestroy(lang_set); @@ -234,9 +224,9 @@ void draw(VkvgSurface surfFont) { vkvg_font_extents_t fe = {0}; vkvg_font_extents(ctx, &fe); - VkvgText tr = vkvg_text_run_create(ctx, tmp); + VkvgText tr = vkvg_text_create(ctx, tmp); vkvg_text_extents_t extents = {0}; - vkvg_text_run_get_extents(tr, &extents); + vkvg_text_get_extents(tr, &extents); vkvg_rectangle(ctx, penX, penY - fe.ascent, extents.width, extents.height); vkvg_set_line_width(ctx, 1); vkvg_set_source_rgba(ctx,0.5f,0.5f,1, 0.7f); @@ -249,11 +239,11 @@ void draw(VkvgSurface surfFont) { vkvg_move_to (ctx, penX, penY); vkvg_set_source_rgb(ctx,1,1,1); - vkvg_text_run_render(ctx,tr); + vkvg_text_render(ctx,tr); vkvg_flush(ctx); - penY += fe.height; + penY += fe.height * 1.5f; if (vkvg_font_status(font)) { printf("Font in error %s\n", file_path); @@ -264,7 +254,7 @@ void draw(VkvgSurface surfFont) { } vkvg_font_destroy(font); - vkvg_text_run_destroy(tr); + vkvg_text_destroy(tr); if (penY > test_height - 100) break; @@ -350,7 +340,7 @@ int main(int argc, char* argv[]) { e->gQFamIdx, 0, false };//, TESTS_DATA_ROOT "/fonts"}; device = vkvg_device_create(&info); - vkvg_device_set_dpy(device, 140,140); + vkvg_device_set_dpy(device, 96,96); surf = vkvg_surface_create(device, test_width, test_height); VkvgSurface surfFont = vkvg_surface_create(device, test_width, test_height); diff --git a/tests/fonts/fontquery.c b/tests/fonts/fontquery.c index bf979ab..c4ab1f9 100644 --- a/tests/fonts/fontquery.c +++ b/tests/fonts/fontquery.c @@ -298,9 +298,9 @@ void draw(VkvgSurface surfFont) { vkvg_font_extents_t fe = {0}; vkvg_font_extents(ctx, &fe); - VkvgText tr = vkvg_text_run_create(ctx, txtBuffCopy); + VkvgText tr = vkvg_text_create(ctx, txtBuffCopy); vkvg_text_extents_t extents = {0}; - vkvg_text_run_get_extents(tr, &extents); + vkvg_text_get_extents(tr, &extents); vkvg_rectangle(ctx, penX, penY - fe.ascent, extents.width, extents.height); vkvg_set_line_width(ctx, 1); vkvg_set_source_rgba(ctx,0.5f,0.5f,1, 0.7f); @@ -313,7 +313,7 @@ void draw(VkvgSurface surfFont) { vkvg_move_to (ctx, penX, penY); vkvg_set_source_rgb(ctx,1,1,1); - vkvg_text_run_render(ctx,tr); + vkvg_text_render(ctx,tr); penX = 50; penY = 150; @@ -371,7 +371,7 @@ void draw(VkvgSurface surfFont) { vkvg_fill(ctx);*/ vkvg_flush(ctx); - vkvg_text_run_destroy(tr); + vkvg_text_destroy(tr); vkvg_font_destroy(f); } else { for (int i = curFontStartIdx; i < font_database->nfont; i++) { diff --git a/tests/text.c b/tests/text.c index 4d3e948..6e131ce 100644 --- a/tests/text.c +++ b/tests/text.c @@ -1,6 +1,7 @@ #include "test.h" static const char* txt = "The quick brown fox jumps over the lazy dog"; +static const char* txt2 = "いろはにほへと ちりぬるを わかよたれそ つねならむ"; void print(VkvgContext ctx, float penY, uint32_t size) { vkvg_set_font_size(ctx, size); @@ -193,12 +194,62 @@ void simple_text() { vkvg_paint(ctx); vkvg_set_source_rgb(ctx, 1, 1, 1); - vkvg_load_font_from_path(ctx, "data/DancingScript-Regular.ttf", "dancing"); + VkvgFont mono = vkvg_font_create(device, "mono", 12); + VkvgFont norm = vkvg_font_create_from_file(device, "data/Proto-Sinaitic15.ttf", 0, 24); + vkvg_set_font (ctx, mono); + vkvg_move_to(ctx, 20, 50); + vkvg_show_text(ctx, "hwhy"); + + vkvg_move_to(ctx, 100, 50); + vkvg_show_text(ctx, "efgh"); + + vkvg_move_to(ctx, 180, 50); + vkvg_show_text(ctx, "ijkl"); + + vkvg_set_font (ctx, norm); + vkvg_move_to(ctx, 20, 100); + vkvg_show_text(ctx, "ABCD"); + + /*vkvg_load_font_from_path(ctx, "data/DancingScript-Regular.ttf", "dancing"); print_boxed(ctx, "abcdefghijklmnopqrstuvwxyz", 20, 60, 20); print_boxed(ctx, "ABC", 20, 160, 60); vkvg_select_font_face(ctx, "mono"); print_boxed(ctx, "This is a test string!", 20, 250, 20); - print_boxed(ctx, "ANOTHER ONE TO CHECK..", 20, 350, 20); + print_boxed(ctx, "ANOTHER ONE TO CHECK..", 20, 350, 20);*/ + + vkvg_flush(ctx); + + vkvg_font_destroy(mono); + /*vkvg_font_destroy(norm);*/ + vkvg_destroy(ctx); +} +void variable_text() { + VkvgContext ctx = vkvg_create(surf); + vkvg_paint(ctx); + vkvg_set_source_rgb(ctx, 1, 1, 1); + + VkvgFont noto = vkvg_font_create(device, "Noto Sans JP:fontvariations=wght=150", 30); + + vkvg_set_font (ctx, noto); + vkvg_move_to(ctx, 20, 50); + vkvg_show_text(ctx, txt2); + + vkvg_font_destroy(noto); + + noto = vkvg_font_create(device, "Noto Sans JP:fontvariations=wght=900", 30); + vkvg_set_font (ctx, noto); + vkvg_move_to(ctx, 20, 150); + vkvg_show_text(ctx, txt2); + + vkvg_font_destroy(noto); + + noto = vkvg_font_create(device, "Cantarell:fontvariations=wght=900", 30); + vkvg_set_font (ctx, noto); + vkvg_move_to(ctx, 20, 200); + vkvg_show_text(ctx, txt); + + vkvg_font_destroy(noto); + vkvg_destroy(ctx); } @@ -266,15 +317,17 @@ void proto_sinaitic() { } int main(int argc, char* argv[]) { no_test_size = true; - PERFORM_TEST(simple_text, argc, argv); - PERFORM_TEST(font_file_path, argc, argv); + vkh_log_level = VKVG_LOG_INFO; + //PERFORM_TEST(simple_text, argc, argv); + PERFORM_TEST(variable_text, argc, argv); + /*PERFORM_TEST(font_file_path, argc, argv); PERFORM_TEST(single_font_and_size, argc, argv); PERFORM_TEST(random_size, argc, argv); PERFORM_TEST(random_font_and_size, argc, argv); PERFORM_TEST(test, argc, argv); PERFORM_TEST(test1, argc, argv); PERFORM_TEST(test2, argc, argv); - PERFORM_TEST(proto_sinaitic, argc, argv); + PERFORM_TEST(proto_sinaitic, argc, argv);*/ return 0; } |