-
Notifications
You must be signed in to change notification settings - Fork 688
UI fixes #1798
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UI fixes #1798
Changes from 22 commits
16e1cf3
2d03032
2901162
2093703
5835b18
2ec0498
0206aac
f79bfbb
4354753
8edd379
822a794
1a7a91d
805f1c4
f45dec9
75b205a
1918449
fabcdee
d443e0f
cc151ee
0dd4172
45e9db0
827a492
daecc1b
aef28b7
d1fa2c9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,20 +5,31 @@ | |||||||||||||||||||||||||||||
| #include <WeaselUI.h> | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| using namespace weasel; | ||||||||||||||||||||||||||||||
| #define STYLEORWEIGHT (L":[^:]*[^a-f0-9:]+[^:]*") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| vector<wstring> ws_split(const wstring& in, const wstring& delim) { | ||||||||||||||||||||||||||||||
| static vector<wstring> ws_split(const wstring& in, const wstring& delim) { | ||||||||||||||||||||||||||||||
| // Optimization for simple character delimiters to avoid regex overhead | ||||||||||||||||||||||||||||||
| if (delim.find_first_of(L"\\^$.|?*+()[]{}") == wstring::npos && | ||||||||||||||||||||||||||||||
| delim.length() > 0) { | ||||||||||||||||||||||||||||||
| vector<wstring> result; | ||||||||||||||||||||||||||||||
| size_t start = 0; | ||||||||||||||||||||||||||||||
| size_t end = in.find(delim); | ||||||||||||||||||||||||||||||
| while (end != wstring::npos) { | ||||||||||||||||||||||||||||||
| result.push_back(in.substr(start, end - start)); | ||||||||||||||||||||||||||||||
| start = end + delim.length(); | ||||||||||||||||||||||||||||||
| end = in.find(delim, start); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| result.push_back(in.substr(start)); | ||||||||||||||||||||||||||||||
| return result; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| std::wregex re{delim}; | ||||||||||||||||||||||||||||||
| return vector<wstring>{ | ||||||||||||||||||||||||||||||
| std::wsregex_token_iterator(in.begin(), in.end(), re, -1), | ||||||||||||||||||||||||||||||
| std::wsregex_token_iterator()}; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| DirectWriteResources::DirectWriteResources(weasel::UIStyle& style, | ||||||||||||||||||||||||||||||
| UINT dpi = 96) | ||||||||||||||||||||||||||||||
| : _style(style), | ||||||||||||||||||||||||||||||
| dpiScaleFontPoint(0), | ||||||||||||||||||||||||||||||
| dpiScaleLayout(0), | ||||||||||||||||||||||||||||||
| DirectWriteResources::DirectWriteResources() | ||||||||||||||||||||||||||||||
| : dpiScaleFontPoint(1.0f), | ||||||||||||||||||||||||||||||
| dpiScaleLayout(1.0f), | ||||||||||||||||||||||||||||||
| pD2d1Factory(NULL), | ||||||||||||||||||||||||||||||
| pDWFactory(NULL), | ||||||||||||||||||||||||||||||
| pRenderTarget(NULL), | ||||||||||||||||||||||||||||||
|
|
@@ -28,84 +39,96 @@ DirectWriteResources::DirectWriteResources(weasel::UIStyle& style, | |||||||||||||||||||||||||||||
| pTextFormat(NULL), | ||||||||||||||||||||||||||||||
| pLabelTextFormat(NULL), | ||||||||||||||||||||||||||||||
| pCommentTextFormat(NULL) { | ||||||||||||||||||||||||||||||
| D2D1_TEXT_ANTIALIAS_MODE mode = | ||||||||||||||||||||||||||||||
| _style.antialias_mode <= 3 | ||||||||||||||||||||||||||||||
| ? (D2D1_TEXT_ANTIALIAS_MODE)(_style.antialias_mode) | ||||||||||||||||||||||||||||||
| : D2D1_TEXT_ANTIALIAS_MODE_FORCE_DWORD; // prepare d2d1 resources | ||||||||||||||||||||||||||||||
| // create factory | ||||||||||||||||||||||||||||||
| // prepare d2d1 resources create factory | ||||||||||||||||||||||||||||||
| HR(::D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, | ||||||||||||||||||||||||||||||
| pD2d1Factory.ReleaseAndGetAddressOf())); | ||||||||||||||||||||||||||||||
| // create IDWriteFactory | ||||||||||||||||||||||||||||||
| HR(DWriteCreateFactory( | ||||||||||||||||||||||||||||||
| DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), | ||||||||||||||||||||||||||||||
| reinterpret_cast<IUnknown**>(pDWFactory.ReleaseAndGetAddressOf()))); | ||||||||||||||||||||||||||||||
| /* ID2D1HwndRenderTarget */ | ||||||||||||||||||||||||||||||
| const D2D1_PIXEL_FORMAT format = D2D1::PixelFormat( | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| DirectWriteResources::~DirectWriteResources() { | ||||||||||||||||||||||||||||||
| _textFormatCache.clear(); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| HRESULT DirectWriteResources::EnsureRenderTarget(int antialiasMode) { | ||||||||||||||||||||||||||||||
| if (pRenderTarget) | ||||||||||||||||||||||||||||||
| return S_OK; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| static const D2D1_PIXEL_FORMAT format = D2D1::PixelFormat( | ||||||||||||||||||||||||||||||
| DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED); | ||||||||||||||||||||||||||||||
| const D2D1_RENDER_TARGET_PROPERTIES properties = | ||||||||||||||||||||||||||||||
| static const D2D1_RENDER_TARGET_PROPERTIES properties = | ||||||||||||||||||||||||||||||
| D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, format); | ||||||||||||||||||||||||||||||
| HR(pD2d1Factory->CreateDCRenderTarget(&properties, &pRenderTarget)); | ||||||||||||||||||||||||||||||
| pRenderTarget->SetTextAntialiasMode(mode); | ||||||||||||||||||||||||||||||
| pRenderTarget->SetTextAntialiasMode((D2D1_TEXT_ANTIALIAS_MODE)antialiasMode); | ||||||||||||||||||||||||||||||
| pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); | ||||||||||||||||||||||||||||||
| HR(pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), | ||||||||||||||||||||||||||||||
| pBrush.ReleaseAndGetAddressOf())); | ||||||||||||||||||||||||||||||
|
fxliang marked this conversation as resolved.
|
||||||||||||||||||||||||||||||
| // get the dpi information | ||||||||||||||||||||||||||||||
| dpiScaleFontPoint = dpiScaleLayout = (float)dpi; | ||||||||||||||||||||||||||||||
| dpiScaleFontPoint /= 72.0f; | ||||||||||||||||||||||||||||||
| dpiScaleLayout /= 96.0f; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| InitResources(style, dpi); | ||||||||||||||||||||||||||||||
| return S_OK; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| DirectWriteResources::~DirectWriteResources() {} | ||||||||||||||||||||||||||||||
| void DirectWriteResources::ResetRenderTarget() { | ||||||||||||||||||||||||||||||
| pRenderTarget.Reset(); | ||||||||||||||||||||||||||||||
| pBrush.Reset(); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| HRESULT DirectWriteResources::InitResources(const wstring& label_font_face, | ||||||||||||||||||||||||||||||
| HRESULT DirectWriteResources::InitResources(const UIStyle& style, | ||||||||||||||||||||||||||||||
| const int& label_font_point, | ||||||||||||||||||||||||||||||
| const wstring& font_face, | ||||||||||||||||||||||||||||||
| const int& font_point, | ||||||||||||||||||||||||||||||
| const wstring& comment_font_face, | ||||||||||||||||||||||||||||||
| const int& comment_font_point, | ||||||||||||||||||||||||||||||
| const bool& vertical_text) { | ||||||||||||||||||||||||||||||
| const int& comment_font_point) { | ||||||||||||||||||||||||||||||
| // prepare d2d1 resources | ||||||||||||||||||||||||||||||
| DWRITE_WORD_WRAPPING wrapping = | ||||||||||||||||||||||||||||||
| ((_style.max_width == 0 && | ||||||||||||||||||||||||||||||
| _style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT) || | ||||||||||||||||||||||||||||||
| (_style.max_height == 0 && | ||||||||||||||||||||||||||||||
| _style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT)) | ||||||||||||||||||||||||||||||
| const bool vertical_text = style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT; | ||||||||||||||||||||||||||||||
| const DWRITE_WORD_WRAPPING wrapping = | ||||||||||||||||||||||||||||||
| ((style.max_width == 0 && | ||||||||||||||||||||||||||||||
| style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT) || | ||||||||||||||||||||||||||||||
| (style.max_height == 0 && | ||||||||||||||||||||||||||||||
| style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT)) | ||||||||||||||||||||||||||||||
| ? DWRITE_WORD_WRAPPING_NO_WRAP | ||||||||||||||||||||||||||||||
| : DWRITE_WORD_WRAPPING_WHOLE_WORD; | ||||||||||||||||||||||||||||||
| DWRITE_WORD_WRAPPING wrapping_preedit = | ||||||||||||||||||||||||||||||
| ((_style.max_width == 0 && | ||||||||||||||||||||||||||||||
| _style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT) || | ||||||||||||||||||||||||||||||
| (_style.max_height == 0 && | ||||||||||||||||||||||||||||||
| _style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT)) | ||||||||||||||||||||||||||||||
| const DWRITE_WORD_WRAPPING wrapping_preedit = | ||||||||||||||||||||||||||||||
| ((style.max_width == 0 && | ||||||||||||||||||||||||||||||
| style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT) || | ||||||||||||||||||||||||||||||
| (style.max_height == 0 && | ||||||||||||||||||||||||||||||
| style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT)) | ||||||||||||||||||||||||||||||
| ? DWRITE_WORD_WRAPPING_NO_WRAP | ||||||||||||||||||||||||||||||
| : DWRITE_WORD_WRAPPING_CHARACTER; | ||||||||||||||||||||||||||||||
| DWRITE_FLOW_DIRECTION flow = _style.vertical_text_left_to_right | ||||||||||||||||||||||||||||||
| ? DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT | ||||||||||||||||||||||||||||||
| : DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT; | ||||||||||||||||||||||||||||||
| const DWRITE_FLOW_DIRECTION flow = style.vertical_text_left_to_right | ||||||||||||||||||||||||||||||
| ? DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT | ||||||||||||||||||||||||||||||
| : DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // set main font a invalid font name, to make every font range customizable | ||||||||||||||||||||||||||||||
| const wstring _mainFontFace = L"_InvalidFontName_"; | ||||||||||||||||||||||||||||||
| static const wstring _mainFontFace = L"_InvalidFontName_"; | ||||||||||||||||||||||||||||||
| DWRITE_FONT_WEIGHT fontWeight = DWRITE_FONT_WEIGHT_NORMAL; | ||||||||||||||||||||||||||||||
| DWRITE_FONT_STYLE fontStyle = DWRITE_FONT_STYLE_NORMAL; | ||||||||||||||||||||||||||||||
| // convert percentage to float | ||||||||||||||||||||||||||||||
| float linespacing = dpiScaleFontPoint * ((float)_style.linespacing / 100.0f); | ||||||||||||||||||||||||||||||
| float baseline = dpiScaleFontPoint * ((float)_style.baseline / 100.0f); | ||||||||||||||||||||||||||||||
| if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) | ||||||||||||||||||||||||||||||
| float linespacing = dpiScaleFontPoint * ((float)style.linespacing / 100.0f); | ||||||||||||||||||||||||||||||
| float baseline = dpiScaleFontPoint * ((float)style.baseline / 100.0f); | ||||||||||||||||||||||||||||||
| if (style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) | ||||||||||||||||||||||||||||||
| baseline = linespacing / 2; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| auto init_font = [&](const wstring& fontface, int fontpoint, | ||||||||||||||||||||||||||||||
| ComPtr<IDWriteTextFormat1>& _pTextFormat, | ||||||||||||||||||||||||||||||
| DWRITE_WORD_WRAPPING wrap) { | ||||||||||||||||||||||||||||||
| const wstring key = fontface + L"|" + std::to_wstring(fontpoint) + L"|" + | ||||||||||||||||||||||||||||||
| (vertical_text ? L"1" : L"0") + L"|" + | ||||||||||||||||||||||||||||||
| std::to_wstring((int)wrap) + L"|" + | ||||||||||||||||||||||||||||||
| std::to_wstring(style.linespacing) + L"|" + | ||||||||||||||||||||||||||||||
| std::to_wstring(style.baseline) + L"|" + | ||||||||||||||||||||||||||||||
| std::to_wstring(dpiScaleFontPoint); | ||||||||||||||||||||||||||||||
|
Comment on lines
+118
to
+123
|
||||||||||||||||||||||||||||||
| const wstring key = fontface + L"|" + std::to_wstring(fontpoint) + L"|" + | |
| (vertical_text ? L"1" : L"0") + L"|" + | |
| std::to_wstring((int)wrap) + L"|" + | |
| std::to_wstring(style.linespacing) + L"|" + | |
| std::to_wstring(style.baseline) + L"|" + | |
| std::to_wstring(dpiScaleFontPoint); | |
| // Use a quantized integer representation of dpiScaleFontPoint in the cache key | |
| const int dpiScaleKey = static_cast<int>(dpiScaleFontPoint * 1000.0f + 0.5f); | |
| const wstring key = fontface + L"|" + std::to_wstring(fontpoint) + L"|" + | |
| (vertical_text ? L"1" : L"0") + L"|" + | |
| std::to_wstring((int)wrap) + L"|" + | |
| std::to_wstring(style.linespacing) + L"|" + | |
| std::to_wstring(style.baseline) + L"|" + | |
| std::to_wstring(dpiScaleKey); |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the lambda init_font, if CreateTextFormat or subsequent operations fail, _pTextFormat may remain NULL but the function continues execution. The cache insertion at line 160 would then cache a NULL ComPtr, which could cause issues on subsequent accesses. Consider checking if _pTextFormat is valid before caching it, or return an error status from the lambda to handle failures properly.
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The static regex patterns (styleOrWeightRegex, patWeight, patStyle) are compiled once and reused, which is good for performance. However, in multi-threaded scenarios, regex operations might have thread-safety concerns depending on the standard library implementation. Since DirectWriteResources can be accessed from UI code which might be called from different contexts, verify that the regex usage here is thread-safe or add appropriate synchronization if needed.
Uh oh!
There was an error while loading. Please reload this page.