diff --git a/.cproject b/.cproject index cf11c93..a760ba8 100644 --- a/.cproject +++ b/.cproject @@ -89,9 +89,6 @@ - - - @@ -145,9 +142,6 @@ - - - @@ -185,6 +179,7 @@ + @@ -204,7 +199,11 @@ + + + + @@ -240,8 +239,77 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -286,4 +354,4 @@ - \ No newline at end of file + diff --git a/CHANGELOG b/CHANGELOG index 8dac056..53f10e2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,13 @@ * RECENT CHANGES ******************************************************************************* +=== 1.0.14 === +* Improved code base by using PVS Studio static code analyzer. +* Improved text rendering for Windows platform. +* Significant improvements related to rectangle area clipping for Windows platform. +* Several improvements against grabbing events for Windows. +* Updated module versions in dependencies. + === 1.0.13 === * Updated build scripts. * Updated module versions in dependencies. diff --git a/include/lsp-plug.in/ws/version.h b/include/lsp-plug.in/ws/version.h index ad94e6e..cfeb3e5 100644 --- a/include/lsp-plug.in/ws/version.h +++ b/include/lsp-plug.in/ws/version.h @@ -24,7 +24,7 @@ #define LSP_WS_LIB_MAJOR 1 #define LSP_WS_LIB_MINOR 0 -#define LSP_WS_LIB_MICRO 13 +#define LSP_WS_LIB_MICRO 14 #if defined(LSP_WS_LIB_PUBLISHER) #define LSP_WS_LIB_PUBLIC LSP_EXPORT_MODIFIER diff --git a/include/private/win/WinDDSurface.h b/include/private/win/WinDDSurface.h index 091ff70..9b441ac 100644 --- a/include/private/win/WinDDSurface.h +++ b/include/private/win/WinDDSurface.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2020 Linux Studio Plugins Project - * (C) 2020 Vladimir Sadovnikov + * Copyright (C) 2023 Linux Studio Plugins Project + * (C) 2023 Vladimir Sadovnikov * * This file is part of lsp-ws-lib * Created on: 5 июл. 2022 г. @@ -89,8 +89,8 @@ namespace lsp void draw_negative_arc(ID2D1Brush *brush, float x0, float y0, float x1, float y1, float x2, float y2); void draw_polygon(ID2D1Brush *brush, const float *x, const float *y, size_t n, float width); - bool try_out_text(IDWriteFontCollection *fc, IDWriteFontFamily *ff, const WCHAR *family, const Font &f, const Color &color, float x, float y, const WCHAR *text, size_t length); - bool try_out_text_relative(IDWriteFontCollection *fc, IDWriteFontFamily *ff, const WCHAR *family, const Font &f, const Color &color, float x, float y, float dx, float dy, const WCHAR *text, size_t length); + bool try_out_text(IDWriteFontCollection *fc, IDWriteFontFamily *ff, const WCHAR *family, const Font &f, const Color &color, float x, float y, const lsp_wchar_t *text, size_t length); + bool try_out_text_relative(IDWriteFontCollection *fc, IDWriteFontFamily *ff, const WCHAR *family, const Font &f, const Color &color, float x, float y, float dx, float dy, const lsp_wchar_t *text, size_t length); public: virtual IDisplay *display() override; diff --git a/include/private/win/WinDisplay.h b/include/private/win/WinDisplay.h index 5883c8a..0d9d3ee 100644 --- a/include/private/win/WinDisplay.h +++ b/include/private/win/WinDisplay.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2020 Linux Studio Plugins Project - * (C) 2020 Vladimir Sadovnikov + * Copyright (C) 2023 Linux Studio Plugins Project + * (C) 2023 Vladimir Sadovnikov * * This file is part of lsp-ws-lib * Created on: 1 июл. 2022 г. @@ -39,6 +39,8 @@ #include #include +#include + //----------------------------------------------------------------------------- // Some specific definitions #ifndef WM_MOUSEHWHEEL @@ -102,6 +104,7 @@ namespace lsp ATOM hClipClass; // Window class for the clipboard LSPString sDflFontFamily; // Default font family name MSG sPendingMessage; // Currently pending message + MSG sLastMouseMove; // Last mouse move message HCURSOR vCursors[__MP_COUNT]; // Cursor handles (cached) lltl::darray vMonitors; // Monitor information font_cache_t vFontCache; // Font cache @@ -115,6 +118,7 @@ namespace lsp WinWindow *pDragWindow; // Window which is currently acting in Drag&Drop action ipc::Thread *pPingThread; // Pinger thread volatile timestamp_t nLastIdleCall; // The time of last idle call + volatile atomic_t nIdlePending; // Number of idle requests pending LSPString sWindowClassName; // Window class name LSPString sClipboardClassName; // Clipboard window class name @@ -126,12 +130,15 @@ namespace lsp IDWriteTextLayout *create_text_layout(const Font &f, const WCHAR *fname, IDWriteFontCollection *fc, IDWriteFontFamily *ff, const WCHAR *string, size_t length); IDWriteFontFamily *get_font_family(const Font &f, LSPString *name, font_t **custom); bool get_font_metrics(const Font &f, IDWriteFontFamily *ff, DWRITE_FONT_METRICS *metrics); + IDWriteFont *get_font(const Font &f, IDWriteFontFamily *ff); + IDWriteFontFace *get_font_face(const Font &f, IDWriteFontFamily *ff); static void drop_font_cache(font_cache_t *cache); bool create_font_cache(); void drop_font(font_t *f); static font_t *alloc_font(const char *name); font_t *get_custom_font_collection(const char *name); - bool try_get_text_parameters(const Font &f, const WCHAR *fname, IDWriteFontCollection *fc, IDWriteFontFamily *ff, text_parameters_t *tp, const WCHAR *text, ssize_t length); + bool try_get_text_parameters(const Font &f, const WCHAR *fname, IDWriteFontCollection *fc, IDWriteFontFamily *ff, text_parameters_t *tp, const UINT32 *text, size_t length); + win::glyph_run_t *make_glyph_run(const Font &f, IDWriteFontFace *face, const DWRITE_FONT_METRICS *fm, const UINT32 *text, size_t length); status_t install_windows_hooks(); status_t uninstall_windows_hooks(); diff --git a/include/private/win/fonts.h b/include/private/win/fonts.h index 8d5931f..6b29ae8 100644 --- a/include/private/win/fonts.h +++ b/include/private/win/fonts.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2020 Linux Studio Plugins Project - * (C) 2020 Vladimir Sadovnikov + * Copyright (C) 2023 Linux Studio Plugins Project + * (C) 2023 Vladimir Sadovnikov * * This file is part of lsp-ws-lib * Created on: 13 июл. 2022 г. @@ -28,7 +28,10 @@ #include #include +#include #include +#include +#include #include @@ -45,6 +48,12 @@ namespace lsp class WinFontFileEnumerator; class WinFontCollectionLoader; + typedef struct glyph_run_t + { + const DWRITE_GLYPH_RUN *run; + const DWRITE_GLYPH_METRICS *metrics; + } glyph_run_t; + /** * Custom implementation of IDWriteFontFileStream interface for collections * of fonts embedded in the application as resources. The font collection @@ -146,6 +155,13 @@ namespace lsp IDWriteFontFileEnumerator **fontFileEnumerator) override; }; + void calc_text_metrics( + const Font &f, + text_parameters_t *tp, + const DWRITE_FONT_METRICS *fm, + const DWRITE_GLYPH_METRICS *metrics, + size_t length); + } /* namespace win */ } /* namespace ws */ } /* namespace lsp */ diff --git a/modules.mk b/modules.mk index dbcc205..a5d75ba 100644 --- a/modules.mk +++ b/modules.mk @@ -20,49 +20,49 @@ #------------------------------------------------------------------------------ # Variables that describe source code dependencies -LSP_COMMON_LIB_VERSION := 1.0.30 +LSP_COMMON_LIB_VERSION := 1.0.31 LSP_COMMON_LIB_NAME := lsp-common-lib LSP_COMMON_LIB_TYPE := src LSP_COMMON_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_COMMON_LIB_NAME).git LSP_COMMON_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_COMMON_LIB_NAME).git -LSP_DSP_LIB_VERSION := 1.0.14 +LSP_DSP_LIB_VERSION := 1.0.15 LSP_DSP_LIB_NAME := lsp-dsp-lib LSP_DSP_LIB_TYPE := src LSP_DSP_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_DSP_LIB_NAME).git LSP_DSP_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_DSP_LIB_NAME).git -LSP_LLTL_LIB_VERSION := 1.0.13 +LSP_LLTL_LIB_VERSION := 1.0.14 LSP_LLTL_LIB_NAME := lsp-lltl-lib LSP_LLTL_LIB_TYPE := src LSP_LLTL_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_LLTL_LIB_NAME).git LSP_LLTL_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_LLTL_LIB_NAME).git -LSP_R3D_BASE_LIB_VERSION := 1.0.13 +LSP_R3D_BASE_LIB_VERSION := 1.0.14 LSP_R3D_BASE_LIB_NAME := lsp-r3d-base-lib LSP_R3D_BASE_LIB_TYPE := src LSP_R3D_BASE_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_R3D_BASE_LIB_NAME).git LSP_R3D_BASE_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_R3D_BASE_LIB_NAME).git -LSP_R3D_GLX_LIB_VERSION := 1.0.13 +LSP_R3D_GLX_LIB_VERSION := 1.0.14 LSP_R3D_GLX_LIB_NAME := lsp-r3d-glx-lib LSP_R3D_GLX_LIB_TYPE := src LSP_R3D_GLX_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_R3D_GLX_LIB_NAME).git LSP_R3D_GLX_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_R3D_GLX_LIB_NAME).git -LSP_R3D_IFACE_VERSION := 1.0.13 +LSP_R3D_IFACE_VERSION := 1.0.14 LSP_R3D_IFACE_NAME := lsp-r3d-iface LSP_R3D_IFACE_TYPE := src LSP_R3D_IFACE_URL_RO := https://github.com/lsp-plugins/$(LSP_R3D_IFACE_NAME).git LSP_R3D_IFACE_URL_RW := git@github.com:lsp-plugins/$(LSP_R3D_IFACE_NAME).git -LSP_R3D_WGL_LIB_VERSION := 1.0.8 +LSP_R3D_WGL_LIB_VERSION := 1.0.9 LSP_R3D_WGL_LIB_NAME := lsp-r3d-wgl-lib LSP_R3D_WGL_LIB_TYPE := src LSP_R3D_WGL_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_R3D_WGL_LIB_NAME).git LSP_R3D_WGL_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_R3D_WGL_LIB_NAME).git -LSP_RUNTIME_LIB_VERSION := 1.0.16 +LSP_RUNTIME_LIB_VERSION := 1.0.17 LSP_RUNTIME_LIB_NAME := lsp-runtime-lib LSP_RUNTIME_LIB_TYPE := src LSP_RUNTIME_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_RUNTIME_LIB_NAME).git diff --git a/project.mk b/project.mk index ca3a60a..9744aca 100644 --- a/project.mk +++ b/project.mk @@ -23,5 +23,5 @@ ARTIFACT_ID = LSP_WS_LIB ARTIFACT_NAME = lsp-ws-lib ARTIFACT_DESC = LSP window subsystem core library ARTIFACT_HEADERS = lsp-plug.in -ARTIFACT_VERSION = 1.0.13 +ARTIFACT_VERSION = 1.0.14 diff --git a/src/main/IDataSource.cpp b/src/main/IDataSource.cpp index db75540..e10022e 100644 --- a/src/main/IDataSource.cpp +++ b/src/main/IDataSource.cpp @@ -36,14 +36,17 @@ namespace lsp ++n; vMimes = reinterpret_cast(::malloc(sizeof(char *) * (n+1))); - for (size_t i=0; i<(n+1); ++i) - vMimes[i] = NULL; - - for (size_t i=0, j=0; i last)) return false; - else if (first == last) + + if (first == last) { - tp->x_bearing = 0; - tp->y_bearing = 0; - tp->width = 0; - tp->height = 0; - tp->x_advance = 0; - tp->y_advance = 0; + if (tp != NULL) + { + tp->x_bearing = 0; + tp->y_bearing = 0; + tp->width = 0; + tp->height = 0; + tp->x_advance = 0; + tp->y_advance = 0; + } + return true; } diff --git a/src/main/freetype/GlyphCache.cpp b/src/main/freetype/GlyphCache.cpp index b9abf57..507f0af 100644 --- a/src/main/freetype/GlyphCache.cpp +++ b/src/main/freetype/GlyphCache.cpp @@ -141,11 +141,10 @@ namespace lsp // Cleanup all data nSize = 0; nCap = 0; - if (vBins != NULL) - { - free(vBins); - vBins = NULL; - } + + // Cleanup bins + free(vBins); + vBins = NULL; return root; } diff --git a/src/main/freetype/face.cpp b/src/main/freetype/face.cpp index dec52e0..5c1468b 100644 --- a/src/main/freetype/face.cpp +++ b/src/main/freetype/face.cpp @@ -182,6 +182,8 @@ namespace lsp FT_Error error; // Reference the freetype face + if (src == NULL) + return NULL; if ((error = FT_Reference_Face(src->ft_face)) != FT_Err_Ok) return NULL; lsp_finally { diff --git a/src/main/win/WinDDSurface.cpp b/src/main/win/WinDDSurface.cpp index 230c9f1..419939f 100644 --- a/src/main/win/WinDDSurface.cpp +++ b/src/main/win/WinDDSurface.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2020 Linux Studio Plugins Project - * (C) 2020 Vladimir Sadovnikov + * Copyright (C) 2023 Linux Studio Plugins Project + * (C) 2023 Vladimir Sadovnikov * * This file is part of lsp-ws-lib * Created on: 5 июл. 2022 г. @@ -63,7 +63,7 @@ namespace lsp size_t WinDDShared::Release() { - size_t count = nReferences--; + size_t count = --nReferences; if (count == 0) delete this; return count; @@ -179,7 +179,7 @@ namespace lsp prop.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; // D2D1_ALPHA_MODE_STRAIGHT; prop.dpiX = dpi_x; prop.dpiY = dpi_y; - prop.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE; + prop.usage = D2D1_RENDER_TARGET_USAGE_NONE; prop.minLevel = D2D1_FEATURE_LEVEL_DEFAULT; hwndProp.hwnd = pShared->hWindow; @@ -1218,17 +1218,9 @@ namespace lsp if (bad_state()) return; - // Create the clipping layer - ID2D1Layer *layer = NULL; - HRESULT hr = pDC->CreateLayer(NULL, &layer); - if ((FAILED(hr)) || (layer == NULL)) - return; - lsp_finally{ safe_release(layer); }; - - // Apply the layer - pDC->PushLayer( - D2D1::LayerParameters(D2D1::RectF(x, y, x+w, y+h)), - layer); + pDC->PushAxisAlignedClip( + D2D1::RectF(x, y, x+w, y+h), + D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); #ifdef LSP_DEBUG ++ nClipping; @@ -1249,7 +1241,7 @@ namespace lsp -- nClipping; #endif /* LSP_DEBUG */ - pDC->PopLayer(); + pDC->PopAxisAlignedClip(); } IDisplay *WinDDSurface::display() @@ -1273,7 +1265,7 @@ namespace lsp &desiredSize, &desiredPixelSize, &pixelFormat, - D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE, // options + D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, // options &dc); if (FAILED(hr)) return NULL; @@ -1307,7 +1299,7 @@ namespace lsp &desiredSize, &desiredPixelSize, &pixelFormat, - D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE, + D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, &dc); if (FAILED(hr)) return NULL; @@ -1489,13 +1481,23 @@ namespace lsp out_text(f, color, x, y, &tmp, 0, tmp.length()); } - bool WinDDSurface::try_out_text(IDWriteFontCollection *fc, IDWriteFontFamily *ff, const WCHAR *family, const Font &f, const Color &color, float x, float y, const WCHAR *text, size_t length) + bool WinDDSurface::try_out_text(IDWriteFontCollection *fc, IDWriteFontFamily *ff, const WCHAR *family, const Font &f, const Color &color, float x, float y, const lsp_wchar_t *text, size_t length) { - // Create text layout - IDWriteTextLayout *tl = pShared->pDisplay->create_text_layout(f, family, fc, ff, text, length); - if (tl == NULL) + // Get font face + IDWriteFontFace *face = pShared->pDisplay->get_font_face(f, ff); + if (face == NULL) return false; - lsp_finally{ safe_release(tl); }; + lsp_finally { safe_release(face); }; + + // Obtain font metrics + DWRITE_FONT_METRICS fm; + face->GetMetrics(&fm); + + // Create glyph run + win::glyph_run_t *run = pShared->pDisplay->make_glyph_run(f, face, &fm, text, length); + if (run == NULL) + return false; + lsp_finally { free(run); }; // Create brush ID2D1SolidColorBrush *brush = NULL; @@ -1517,11 +1519,33 @@ namespace lsp default: break; } - pDC->DrawTextLayout( - D2D1::Point2F(x, y), - tl, + + pDC->DrawGlyphRun( + D2D1_POINT_2F{x, y}, + run->run, brush, - D2D1_DRAW_TEXT_OPTIONS_NONE); + DWRITE_MEASURING_MODE_NATURAL); + + if (f.is_underline()) + { + ws::text_parameters_t tp; + calc_text_metrics(f, &tp, &fm, run->metrics, length); + + float scale = f.size() / float(fm.designUnitsPerEm); + float k = f.bold() ? 0.6f : 0.5f; + float ypos = y - fm.underlinePosition * scale; + float thick = k * fm.underlineThickness * scale; + + pDC->FillRectangle( + D2D1_RECT_F { + x, + ypos - thick, + x + tp.Width, + ypos + thick + }, + brush); + } + pDC->SetTextAntialiasMode(antialias); return true; @@ -1531,10 +1555,11 @@ namespace lsp { if (bad_state()) return; - const WCHAR *pText = (text != NULL) ? reinterpret_cast(text->get_utf16(first, last)) : NULL; - if (pText == NULL) + if ((first < 0) || (last < 0) || (first >= last)) return; - size_t length = text->range_length(first, last); + + size_t range = text->range_length(first, last); + const lsp_wchar_t *data = text->characters(); // Obtain the font family LSPString family_name; @@ -1544,12 +1569,12 @@ namespace lsp if (custom != NULL) { - if (try_out_text(custom->collection, custom->family, custom->wname, f, color, x, y, pText, length)) + if (try_out_text(custom->collection, custom->family, custom->wname, f, color, x, y, &data[first], range)) return; } if (ff != NULL) { - if (try_out_text(NULL, ff, family_name.get_utf16(), f, color, x, y, pText, length)) + if (try_out_text(NULL, ff, family_name.get_utf16(), f, color, x, y, &data[first], range)) return; } } @@ -1568,18 +1593,22 @@ namespace lsp return out_text_relative(f, color, x, y, dx, dy, &tmp, 0, tmp.length()); } - bool WinDDSurface::try_out_text_relative(IDWriteFontCollection *fc, IDWriteFontFamily *ff, const WCHAR *family, const Font &f, const Color &color, float x, float y, float dx, float dy, const WCHAR *text, size_t length) + bool WinDDSurface::try_out_text_relative(IDWriteFontCollection *fc, IDWriteFontFamily *ff, const WCHAR *family, const Font &f, const Color &color, float x, float y, float dx, float dy, const lsp_wchar_t *text, size_t length) { + IDWriteFontFace *face = pShared->pDisplay->get_font_face(f, ff); + if (face == NULL) + return false; + lsp_finally { safe_release(face); }; + // Obtain font metrics DWRITE_FONT_METRICS fm; - if (!pShared->pDisplay->get_font_metrics(f, ff, &fm)) - return false; + face->GetMetrics(&fm); - // Create text layout - IDWriteTextLayout *tl = pShared->pDisplay->create_text_layout(f, family, fc, ff, text, length); - if (tl == NULL) + // Create glyph run + win::glyph_run_t *run = pShared->pDisplay->make_glyph_run(f, face, &fm, text, length); + if (run == NULL) return false; - lsp_finally{ safe_release(tl); }; + lsp_finally { free(run); }; // Create brush ID2D1SolidColorBrush *brush = NULL; @@ -1587,19 +1616,6 @@ namespace lsp return false; lsp_finally{ safe_release(brush); }; - // Get text layout metrics and font metrics - DWRITE_TEXT_METRICS tm; - tl->GetMetrics(&tm); - - // Compute the text position - float ratio = f.size() / float(fm.designUnitsPerEm); - float height = (fm.ascent + fm.descent + fm.lineGap) * ratio; - float xbearing = (f.italic()) ? sinf(0.033f * M_PI) * height : 0.0f; - float r_w = tm.width; - float r_h = fm.capHeight * ratio; - float fx = x - xbearing - r_w * 0.5f + (r_w + 4.0f) * 0.5f * dx; - float fy = y + r_h * 0.5f - (r_h + 4.0f) * 0.5f * dy; - // Draw the text D2D1_TEXT_ANTIALIAS_MODE antialias = pDC->GetTextAntialiasMode(); switch (f.antialias()) @@ -1615,11 +1631,37 @@ namespace lsp break; } - pDC->DrawTextLayout( - D2D1::Point2F(fx, fy), - tl, + ws::text_parameters_t tp; + calc_text_metrics(f, &tp, &fm, run->metrics, length); + + float r_w = tp.Width; + float r_h = tp.Height; + float fx = x - tp.XBearing - r_w * 0.5f + (r_w + 4.0f) * 0.5f * dx; + float fy = y + r_h * 0.5f - (r_h + 4.0f) * 0.5f * dy; + + pDC->DrawGlyphRun( + D2D1_POINT_2F{fx, fy}, + run->run, brush, - D2D1_DRAW_TEXT_OPTIONS_NONE); + DWRITE_MEASURING_MODE_NATURAL); + + if (f.is_underline()) + { + float scale = f.size() / float(fm.designUnitsPerEm); + float k = f.bold() ? 0.6f : 0.5f; + float ypos = fy - fm.underlinePosition * scale; + float thick = k * fm.underlineThickness * scale; + + pDC->FillRectangle( + D2D1_RECT_F { + fx, + ypos - thick, + fx + tp.Width, + ypos + thick + }, + brush); + } + pDC->SetTextAntialiasMode(antialias); return true; @@ -1629,10 +1671,11 @@ namespace lsp { if (bad_state()) return; - const WCHAR *pText = (text != NULL) ? reinterpret_cast(text->get_utf16(first, last)) : NULL; - if (pText == NULL) + if ((first < 0) || (last < 0) || (first >= last)) return; - size_t length = text->range_length(first, last); + + size_t range = text->range_length(first, last); + const lsp_wchar_t *data = text->characters(); // Obtain the font family LSPString family_name; @@ -1643,12 +1686,12 @@ namespace lsp if (custom != NULL) { - if (try_out_text_relative(custom->collection, custom->family, custom->wname, f, color, x, y, dx, dy, pText, length)) + if (try_out_text_relative(custom->collection, custom->family, custom->wname, f, color, x, y, dx, dy, &data[first], range)) return; } if (ff != NULL) { - if (try_out_text_relative(NULL, ff, family_name.get_utf16(), f, color, x, y, dx, dy, pText, length)) + if (try_out_text_relative(NULL, ff, family_name.get_utf16(), f, color, x, y, dx, dy, &data[first], range)) return; } } diff --git a/src/main/win/WinDisplay.cpp b/src/main/win/WinDisplay.cpp index e29c738..ecda5d3 100644 --- a/src/main/win/WinDisplay.cpp +++ b/src/main/win/WinDisplay.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2020 Linux Studio Plugins Project - * (C) 2020 Vladimir Sadovnikov + * Copyright (C) 2023 Linux Studio Plugins Project + * (C) 2023 Vladimir Sadovnikov * * This file is part of lsp-ws-lib * Created on: 1 июл. 2022 г. @@ -23,6 +23,7 @@ #ifdef PLATFORM_WINDOWS +#include #include #include #include @@ -83,6 +84,9 @@ namespace lsp bzero(&sPendingMessage, sizeof(sPendingMessage)); sPendingMessage.message = WM_NULL; + bzero(&sLastMouseMove, sizeof(sLastMouseMove)); + sLastMouseMove.message = WM_NULL; + for (size_t i=0; i<__MP_COUNT; ++i) vCursors[i] = NULL; @@ -92,6 +96,7 @@ namespace lsp pDragWindow = NULL; pPingThread = NULL; nLastIdleCall = 0; + nIdlePending = 0; } WinDisplay::~WinDisplay() @@ -285,9 +290,11 @@ namespace lsp while (!ipc::Thread::is_cancelled()) { // Post message if there was no idle loop for a long time - timestamp_t ts = system::get_time_millis(); - if (ts >= (self->nLastIdleCall + self->idle_interval())) + if (self->nIdlePending < 2) + { + atomic_add(&self->nIdlePending, 1); PostMessageW(self->hClipWnd, WM_USER, 0, 0); + } ipc::Thread::sleep(20); } @@ -324,6 +331,16 @@ namespace lsp } } + // Check spurious WM_MOUSEMOVE message + if (uMsg == WM_MOUSEMOVE) + { + MSG *mouse = &self->sLastMouseMove; + if ((mouse->wParam == wParam) && (mouse->lParam == lParam)) + return 0; + mouse->wParam = wParam; + mouse->lParam = lParam; + } + // // Debug // switch (uMsg) // { @@ -378,6 +395,8 @@ namespace lsp // Here we perform a check that there is some message in the queue if (!PeekMessageW(&sPendingMessage, NULL, 0, 0, PM_REMOVE)) { + sPendingMessage.message = WM_NULL; + UINT_PTR timerId = SetTimer(NULL, 0, wtime, NULL); BOOL res = GetMessageW(&sPendingMessage, NULL, 0, 0); KillTimer(NULL, timerId); @@ -415,16 +434,14 @@ namespace lsp { TranslateMessage(&sPendingMessage); DispatchMessageW(&sPendingMessage); + sPendingMessage.message = WM_NULL; } if ((limit++) >= 0x20) break; } while (PeekMessageW(&sPendingMessage, NULL, 0, 0, PM_REMOVE)); - // At this moment, we don't have any pending messages for processing - sPendingMessage.message = WM_NULL; - // Process all pending tasks - status_t res = process_pending_tasks(ts); + status_t res = process_pending_tasks(ts); nLastIdleCall = ts; return res; @@ -662,6 +679,7 @@ namespace lsp font_t *f = vCustomFonts.get(name); if (f != NULL) return STATUS_ALREADY_EXISTS; + if ((f = alloc_font(name)) == NULL) return STATUS_NO_MEM; lsp_finally{ drop_font(f); }; @@ -673,19 +691,19 @@ namespace lsp return status_t(-length); // Create file loader - f->file = new WinFontFileLoader(&os); + f->file = safe_acquire(new WinFontFileLoader(&os)); if (f->file == NULL) return STATUS_NO_MEM; - f->file->AddRef(); + hr = pDWriteFactory->RegisterFontFileLoader(f->file); if (FAILED(hr)) return STATUS_UNKNOWN_ERR; // Create collection loader - f->loader = new WinFontCollectionLoader(); + f->loader = safe_acquire(new WinFontCollectionLoader()); if (f->loader == NULL) return STATUS_NO_MEM; - f->loader->AddRef(); + hr = pDWriteFactory->RegisterFontCollectionLoader(f->loader); if (FAILED(hr)) return STATUS_UNKNOWN_ERR; @@ -699,6 +717,7 @@ namespace lsp UINT32 count = f->collection->GetFontFamilyCount(); if (count <= 0) return STATUS_UNKNOWN_ERR; + f->collection->GetFontFamily(0, &f->family); if ((FAILED(hr)) || (f->family == NULL)) return STATUS_UNKNOWN_ERR; @@ -708,6 +727,7 @@ namespace lsp hr = f->family->GetFamilyNames(&names); if ((FAILED(hr)) || (names == NULL)) return STATUS_UNKNOWN_ERR; + lsp_finally{ safe_release(names); }; // Enumerate all possible font family names @@ -728,6 +748,7 @@ namespace lsp // The font has been found, add it to registry and exit if (!vCustomFonts.create(name, f)) return STATUS_UNKNOWN_ERR; + #ifdef LSP_TRACE LSPString out; out.set_utf16(f->wname); @@ -1063,13 +1084,9 @@ namespace lsp { HRESULT hr; - // Obtain the system locale - const WCHAR *wLocale = _wsetlocale(LC_ALL, NULL); - if (wLocale == NULL) - wLocale = L"en-us"; - // Create text format IDWriteTextFormat *tf = NULL; + hr = pDWriteFactory->CreateTextFormat( fname, // Font family name fc, // Font collection (NULL sets it to use the system font collection) @@ -1077,7 +1094,7 @@ namespace lsp (f.italic()) ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, f.size(), - wLocale, + L"", &tf); if ((FAILED(hr)) || (tf == NULL)) { @@ -1092,7 +1109,7 @@ namespace lsp DWRITE_FONT_STYLE_OBLIQUE, DWRITE_FONT_STRETCH_NORMAL, f.size(), - wLocale, + L"", &tf); if ((FAILED(hr)) || (tf == NULL)) return NULL; @@ -1136,30 +1153,49 @@ namespace lsp } } - bool WinDisplay::get_font_metrics(const Font &f, IDWriteFontFamily *ff, DWRITE_FONT_METRICS *metrics) + IDWriteFont *WinDisplay::get_font(const Font &f, IDWriteFontFamily *ff) { - HRESULT hr; - - // Find the matching font DWRITE_FONT_WEIGHT fWeight = (f.bold()) ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_REGULAR; DWRITE_FONT_STYLE fStyle = (f.italic()) ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; DWRITE_FONT_STRETCH fStretch= DWRITE_FONT_STRETCH_NORMAL; - IDWriteFont* font = NULL; - hr = ff->GetFirstMatchingFont(fWeight, fStretch, fStyle, &font); + + HRESULT hr = ff->GetFirstMatchingFont(fWeight, fStretch, fStyle, &font); if ((FAILED(hr)) || (font == NULL)) { if (!f.italic()) - return false; + return NULL; hr = ff->GetFirstMatchingFont(fWeight, fStretch, DWRITE_FONT_STYLE_OBLIQUE, &font); if ((FAILED(hr)) || (font == NULL)) - return false; + return NULL; } - lsp_finally{ safe_release(font); }; + + return font; + } + + IDWriteFontFace *WinDisplay::get_font_face(const Font &f, IDWriteFontFamily *ff) + { + // Find the matching font + IDWriteFont* font = get_font(f, ff); + if (font == NULL) + return NULL; + lsp_finally { safe_release(font); }; + + IDWriteFontFace *face = NULL; + HRESULT hr = font->CreateFontFace(&face); + return ((FAILED(hr)) || (face == NULL)) ? NULL : face; + } + + bool WinDisplay::get_font_metrics(const Font &f, IDWriteFontFamily *ff, DWRITE_FONT_METRICS *metrics) + { + // Find the matching font + IDWriteFont* font = get_font(f, ff); + if (font == NULL) + return false; + lsp_finally { safe_release(font); }; // Get font metrics font->GetMetrics(metrics); - return true; } @@ -1195,15 +1231,55 @@ namespace lsp IDWriteFontCollection *fc, IDWriteFontFamily *ff, text_parameters_t *tp, - const WCHAR *text, - ssize_t length) + const UINT32 *text, + size_t length) { + HRESULT hr; + if (length <= 0) + { + tp->Width = 0; + tp->Height = 0; + tp->XAdvance = 0; + tp->YAdvance = 0; + tp->XBearing = 0; + tp->YBearing = 0; + return true; + } + + // Get font face + IDWriteFontFace *face = get_font_face(f, ff); + if (face == NULL) + return false; + lsp_finally { safe_release(face); }; + + // Get glyph indices + UINT16 *glyphIndices = static_cast(malloc(length * sizeof(UINT16))); + if (glyphIndices == NULL) + return false; + lsp_finally { free(glyphIndices); }; + + hr = face->GetGlyphIndices(text, length, glyphIndices); + if (FAILED(hr)) + return false; + + // Get glyph metrics + DWRITE_GLYPH_METRICS *glyphMetrics = static_cast(malloc(length * sizeof(DWRITE_GLYPH_METRICS))); + if (glyphMetrics == NULL) + return false; + lsp_finally { free(glyphMetrics); }; + + hr = face->GetDesignGlyphMetrics(glyphIndices, length, glyphMetrics, FALSE); + if (FAILED(hr)) + return false; + // Obtain font metrics DWRITE_FONT_METRICS fm; - if (!get_font_metrics(f, ff, &fm)) - return false; + face->GetMetrics(&fm); - // Create text layout + // Compute the text metrics + calc_text_metrics(f, tp, &fm, glyphMetrics, length); + +/* // Create text layout IDWriteTextLayout *tl = create_text_layout(f, fname, fc, ff, text, length); if (tl == NULL) return false; @@ -1211,7 +1287,9 @@ namespace lsp // Get text layout metrics and font metrics DWRITE_TEXT_METRICS tm; - tl->GetMetrics(&tm); + HRESULT hr = tl->GetMetrics(&tm); + if (FAILED(hr)) + return false; float ratio = f.size() / float(fm.designUnitsPerEm); tp->Width = tm.widthIncludingTrailingWhitespace; @@ -1219,17 +1297,92 @@ namespace lsp tp->XAdvance = tm.widthIncludingTrailingWhitespace; tp->YAdvance = tp->Height; tp->XBearing = (f.italic()) ? sinf(0.033f * M_PI) * tp->Height : 0.0f; - tp->YBearing = - fm.capHeight * ratio; + tp->YBearing = - fm.capHeight * ratio;*/ return true; } + win::glyph_run_t *WinDisplay::make_glyph_run(const Font &f, IDWriteFontFace *face, const DWRITE_FONT_METRICS *fm, const UINT32 *text, size_t length) + { + HRESULT hr; + + // Allocate glyph run and supplementary data structures + size_t szof_res = align_size(sizeof(glyph_run_t), DEFAULT_ALIGN); + size_t szof_run = align_size(sizeof(DWRITE_GLYPH_RUN), DEFAULT_ALIGN); + size_t szof_indices = align_size(sizeof(UINT16) * length, DEFAULT_ALIGN); + size_t szof_advances= align_size(sizeof(FLOAT) * length, DEFAULT_ALIGN); + size_t szof_offsets = align_size(sizeof(DWRITE_GLYPH_OFFSET) * length, DEFAULT_ALIGN); + size_t szof_metrics = align_size(sizeof(DWRITE_GLYPH_METRICS) * length, DEFAULT_ALIGN); + size_t to_alloc = + szof_res + + szof_run + + szof_indices + + szof_advances + + szof_offsets + + szof_metrics; + + uint8_t *ptr = static_cast(malloc(to_alloc)); + if (ptr == NULL) + return NULL; + + win::glyph_run_t *res = reinterpret_cast(ptr); + ptr += szof_res; + DWRITE_GLYPH_RUN *run = reinterpret_cast(ptr); + ptr += szof_run; + UINT16 *glyphIndices = reinterpret_cast(ptr); + ptr += szof_indices; + FLOAT *glyphAdvances = reinterpret_cast(ptr); + ptr += szof_advances; + DWRITE_GLYPH_OFFSET *glyphOffsets = reinterpret_cast(ptr); + ptr += szof_offsets; + DWRITE_GLYPH_METRICS *glyphMetrics = reinterpret_cast(ptr); + + run->fontFace = face; + run->fontEmSize = f.size(); + run->glyphCount = length; + run->glyphIndices = glyphIndices; + run->glyphAdvances = glyphAdvances; + run->glyphOffsets = glyphOffsets; + run->isSideways = FALSE; + run->bidiLevel = 0; + + res->run = run; + res->metrics = glyphMetrics; + + lsp_finally { + if (res != NULL) + free(res); + }; + + // Fill glyph run + hr = face->GetGlyphIndices(text, length, glyphIndices); + if (FAILED(hr)) + return NULL; + + // Obtain glyph metrics + hr = face->GetDesignGlyphMetrics(glyphIndices, length, glyphMetrics, FALSE); + if (FAILED(hr)) + return NULL; + + const float ratio = run->fontEmSize / fm->designUnitsPerEm; + for (size_t i = 0; i(text->get_utf16(first, last)) : NULL; - if (pText == NULL) + if ((first < 0) || (last < 0) || (last < first)) return false; - size_t range = text->range_length(first, last); + + size_t range = text->range_length(first, last); + const lsp_wchar_t *data = text->characters(); // Obtain the font family LSPString family_name; @@ -1240,9 +1393,9 @@ namespace lsp // Process custom font first bool found = false; if (custom != NULL) - found = try_get_text_parameters(f, custom->wname, custom->collection, custom->family, tp, pText, range); + found = try_get_text_parameters(f, custom->wname, custom->collection, custom->family, tp, &data[first], range); if ((!found) && (ff != NULL)) - found = try_get_text_parameters(f, family_name.get_utf16(), NULL, ff, tp, pText, range); + found = try_get_text_parameters(f, family_name.get_utf16(), NULL, ff, tp, &data[first], range); return found; } @@ -1332,6 +1485,8 @@ namespace lsp if (!vGrab[group].add(wnd)) return STATUS_NO_MEM; + lsp_trace("Added HWND=%p to grab group %d", wnd->win_handle(), int(group)); + // Obtain a grab if necessary if (count > 0) return STATUS_OK; @@ -1350,7 +1505,10 @@ namespace lsp { lltl::parray &g = vGrab[i]; if (g.premove(wnd)) + { + lsp_trace("Removed HWND=%p from grab group %d", wnd->win_handle(), int(i)); found = true; + } count += g.size(); } @@ -1608,17 +1766,18 @@ namespace lsp * @param pt The x- and y-coordinates of the cursor, in per-monitor-aware screen coordinates. */ POINT pt = mou->pt; - RECT rect; if (!ScreenToClient(wnd->hWindow, &pt)) continue; - if (!GetClientRect(wnd->hWindow, &rect)) - continue; - // Skip events that are inside of client area of the window. Process them as usual. - if ((pt.x >= rect.left) && (pt.x <= rect.right) && - (pt.y >= rect.top) && (pt.y <= rect.bottom)) - continue; +// // Skip events that are inside of client area of the window. Process them as usual. +// RECT rect; +// if (!GetClientRect(wnd->hWindow, &rect)) +// continue; +// if ((pt.x >= rect.left) && (pt.x <= rect.right) && +// (pt.y >= rect.top) && (pt.y <= rect.bottom)) +// continue; + // Send the message lParam = MAKELONG(pt.x, pt.y); PostMessageW(wnd->hWindow, uMsg, wParam, lParam); } @@ -1833,6 +1992,7 @@ namespace lsp { ws::timestamp_t ts = system::get_time_millis(); dpy->process_pending_tasks(ts); + atomic_add(&dpy->nIdlePending, -1); return 0; } default: @@ -2231,7 +2391,10 @@ namespace lsp void WinDisplay::task_queue_changed() { if (hClipWnd != NULL) + { + atomic_add(&nIdlePending, 1); PostMessageW(hClipWnd, WM_USER, 0, 0); + } } } /* namespace win */ diff --git a/src/main/win/WinWindow.cpp b/src/main/win/WinWindow.cpp index 0d15088..c69f7c7 100644 --- a/src/main/win/WinWindow.cpp +++ b/src/main/win/WinWindow.cpp @@ -612,16 +612,34 @@ namespace lsp if ((hTransientFor == NULL) || (hTransientFor == HWND_TOP)) break; - HWND hPrev = GetTopWindow(GetDesktopWindow()); +// WCHAR caption[256]; +// LSPString tmp; +// +// lsp_trace("Order for hWnd = %p, hTransientFor = %p:", hWindow, hTransientFor); +// HWND hIter = GetWindow(hWindow, GW_HWNDFIRST); +// while (hIter != NULL) +// { +// caption[0] = 0; +// GetWindowTextW(hIter, caption, sizeof(caption)/sizeof(WCHAR)); +// tmp.set_utf16(caption); +// lsp_trace(" hWnd=%p (%s)", hIter, tmp.get_native()); +// +// hIter = GetWindow(hIter, GW_HWNDNEXT); +// } + + HWND hPrev = GetWindow(hWindow, GW_HWNDFIRST); +// lsp_trace("hPrev = %p", hPrev); while (hPrev != NULL) { HWND hCurr = GetWindow(hPrev, GW_HWNDNEXT); +// lsp_trace("hCurr = %p", hCurr); // We are already at the top? if (hCurr == hWindow) break; if (hCurr == hTransientFor) { +// lsp_trace("overriding hwndInsertAfter with %p", hPrev); WINDOWPOS *p = reinterpret_cast(lParam); p->hwndInsertAfter = hPrev; p->flags &= ~SWP_NOZORDER; diff --git a/src/main/win/fonts.cpp b/src/main/win/fonts.cpp index 167d1ef..c1c8163 100644 --- a/src/main/win/fonts.cpp +++ b/src/main/win/fonts.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2020 Linux Studio Plugins Project - * (C) 2020 Vladimir Sadovnikov + * Copyright (C) 2023 Linux Studio Plugins Project + * (C) 2023 Vladimir Sadovnikov * * This file is part of lsp-ws-lib * Created on: 13 июл. 2022 г. @@ -25,6 +25,7 @@ #include #include +#include #include @@ -230,6 +231,47 @@ namespace lsp return S_OK; } + //----------------------------------------------------------------- + void calc_text_metrics( + const Font &f, + text_parameters_t *tp, + const DWRITE_FONT_METRICS *fm, + const DWRITE_GLYPH_METRICS *metrics, + size_t length) + { + if (length <= 0) + { + tp->Width = 0.0f; + tp->Height = 0.0f; + tp->XAdvance = 0.0f; + tp->YAdvance = 0.0f; + tp->XBearing = 0.0f; + tp->YBearing = 0.0f; + return; + } + + // Compute the text metrics + const DWRITE_GLYPH_METRICS *glyph = &metrics[0]; + const float ratio = f.size() / float(fm->designUnitsPerEm); + + ssize_t x_bearing = floorf(glyph->leftSideBearing * ratio); + ssize_t x = ceilf(glyph->advanceWidth * ratio); + + for (size_t i = 1; iadvanceWidth * ratio); + } + + // Output text metrics + tp->Width = x - x_bearing; + tp->Height = ceilf((fm->ascent + fm->descent + fm->lineGap) * ratio); + tp->XAdvance = x; + tp->YAdvance = tp->Height; + tp->XBearing = x_bearing + ceilf((f.italic()) ? sinf(0.033f * M_PI) * tp->Height : 0.0f); + tp->YBearing = ceilf( - fm->capHeight * ratio); + } + } /* namespace win */ } /* namespace ws */ } /* namespace lsp */ diff --git a/src/main/x11/X11Display.cpp b/src/main/x11/X11Display.cpp index 84305af..f066ddc 100644 --- a/src/main/x11/X11Display.cpp +++ b/src/main/x11/X11Display.cpp @@ -163,6 +163,8 @@ namespace lsp for (size_t i=0; i<__MP_COUNT; ++i) vCursors[i] = None; + bzero(&sAtoms, sizeof(sAtoms)); + sTranslateReq.hSrcW = None; sTranslateReq.hDstW = None; sTranslateReq.bSuccess = false; @@ -929,9 +931,7 @@ namespace lsp if ((task->cb_send.hProperty == ev->atom) && (task->cb_send.hRequestor == ev->window)) { - status_t result = handle_property_notify(&task->cb_send, ev); - if (task->result == STATUS_OK) - task->result = result; + task->result = update_status(task->result, handle_property_notify(&task->cb_send, ev)); } break; default: @@ -2130,7 +2130,7 @@ namespace lsp // Test for support of XDnD protocol status_t res = read_property(child, sAtoms.X11_XdndAware, sAtoms.X11_XA_ATOM, &data, &size, &xtype); lsp_trace("xDndAware res=%d, xtype=%d, size=%d", int(res), int(xtype), int(size)); - if ((res != STATUS_OK) || (xtype == None) || (size < 1) || (data[0] < 1)) + if ((res != STATUS_OK) || (xtype == None) || (size < 1) || (data == NULL) || (data[0] < 1)) { lsp_trace("Window %lx does not support XDnD Protocol", long(child)); parent = child; @@ -2346,8 +2346,6 @@ namespace lsp Atom type; size_t bytes; - uint8_t *data = NULL; - drop_mime_types(&vDndMimeTypes); // Find target window @@ -2367,11 +2365,7 @@ namespace lsp { // Create task if ((task = sAsync.add()) == NULL) - { - if (data != NULL) - ::free(data); return STATUS_NO_MEM; - } lsp_trace("Created new XDnD proxy task"); @@ -2388,9 +2382,6 @@ namespace lsp dnd->enter[1] = ev->data.l[2]; dnd->enter[2] = ev->data.l[3]; dnd->enter[3] = ev->data.l[4]; - - if (data != NULL) - ::free(data); } return STATUS_OK; @@ -2400,6 +2391,7 @@ namespace lsp if (ev->data.l[1] & 1) { // Fetch all MIME types as additional property + uint8_t *data = NULL; status_t res = read_property(ev->data.l[0], sAtoms.X11_XdndTypeList, sAtoms.X11_XA_ATOM, &data, &bytes, &type); @@ -2408,11 +2400,12 @@ namespace lsp lsp_trace("Could not read proprty XdndTypeList"); return res; } - else if (type != sAtoms.X11_XA_ATOM) + else if ((data == NULL) || (type != sAtoms.X11_XA_ATOM)) { lsp_trace("Could proprty XdndTypeList is not of XA_ATOM type"); return STATUS_BAD_TYPE; } + lsp_finally { free(data); }; // Decode MIME types uint32_t *atoms = reinterpret_cast(data); @@ -3638,8 +3631,8 @@ namespace lsp ev->data.l[1] = 1 | ((r != NULL) ? (1 << 1) : 0); if (r != NULL) { - ev->data.l[2] = (x << 16) | y; - ev->data.l[3] = (r->nWidth << 16) | r->nHeight; + ev->data.l[2] = (long(x) << 16) | long(y); + ev->data.l[3] = (long(r->nWidth) << 16) | long(r->nHeight); } else { diff --git a/src/main/x11/X11Window.cpp b/src/main/x11/X11Window.cpp index 7603a31..930833f 100644 --- a/src/main/x11/X11Window.cpp +++ b/src/main/x11/X11Window.cpp @@ -65,6 +65,13 @@ namespace lsp nScreen = screen; pSurface = NULL; enBorderStyle = BS_SIZEABLE; + + sMotif.flags = 0; + sMotif.functions = 0; + sMotif.decorations = 0; + sMotif.input_mode = 0; + sMotif.status = 0; + nActions = WA_SINGLE; nFlags = 0; enPointer = MP_DEFAULT; @@ -824,8 +831,7 @@ namespace lsp } // Enable constraints back - if (result == STATUS_OK) - result = do_update_constraints(false); + result = do_update_constraints(false); pX11Display->flush(); return result; diff --git a/src/main/x11/decode.cpp b/src/main/x11/decode.cpp index ca2d2a5..045e579 100644 --- a/src/main/x11/decode.cpp +++ b/src/main/x11/decode.cpp @@ -1025,7 +1025,7 @@ namespace lsp { if ((code >= 0x20) && (code <= 0x7e)) return code; - else if ((code >= 0xa0) && (code <= 0x00ff)) + else if (code >= 0xa0) return code; } else if (code & 0xff000000) diff --git a/src/test/mtest/display/font2.cpp b/src/test/mtest/display/font2.cpp index 144f976..09d6280 100644 --- a/src/test/mtest/display/font2.cpp +++ b/src/test/mtest/display/font2.cpp @@ -74,7 +74,7 @@ MTEST_BEGIN("ws.display", font2) s->get_font_parameters(f, &fp); s->get_text_parameters(f, &tp1, "Text"); - s->get_text_parameters(f, &tp2, " Text"); + s->get_text_parameters(f, &tp2, " Текст"); // Text bar 1 c.alpha(0.0f); @@ -121,7 +121,7 @@ MTEST_BEGIN("ws.display", font2) // Output text c.set_rgb24(0x000000); c.alpha(0.25f); - s->out_text(f, c, x, y, " Text"); + s->out_text(f, c, x, y, " Текст"); } s->end();