Fix nested markup conversion to NSAttributedString wxMarkupToAttrStringBase implementation of markup parsing failed to correctly apply nested attributes: in e.g. <i><b>foo</b></i>, only the outer attribute was in effect. This was due to applying - and overwriting - attributes to a span in OnAttrEnd(), which is called first for the inner span, and then for the outer one, overwriting all inner changes. Instead, apply the currently effective attributes to text in OnText(), similarly to how wxMarkupParserRenderOutput does it. As a side effect, this also eliminates the need to apply default font to the entire range first. See #25864. (cherry picked from commit ca05aee2f8134dcae53aecd1a952d2a57f51b223)
Avoid using already destroyed timers in wxOSX Check that the timer is still valid before using the associated object. This is necessary because already queued timer events are still delivered, even if wxTimer is destroyed. See #25871. (cherry picked from commit f25aec1b38bf208a34e0aabefae5e05ca265ecd3)
... | ... | @@ -293,6 +293,8 @@ wxOSX: |
293 | 293 | - Fix memory leak in wxColour::Set() (#25569).
|
294 | 294 | - Fix regression with configure build under macOS < 12 (#25675).
|
295 | 295 | - Fix build under macOS 26 Tahoe (#25798).
|
296 | +- Fix nested markup attributes handling (Václav Slavík, #25864).
|
|
297 | +- Fix possible use of already destroyed wxTimers (Federico Perini, #25871).
|
|
296 | 298 | |
297 | 299 | |
298 | 300 | 3.2.8.1: (released 2025-05-25)
|
... | ... | @@ -37,12 +37,6 @@ protected: |
37 | 37 | |
38 | 38 | [m_attrString beginEditing];
|
39 | 39 | |
40 | - // First thing we do is change the default string font: as mentioned in
|
|
41 | - // Apple documentation, attributed strings use "Helvetica 12" font by
|
|
42 | - // default which is different from the system "Lucida Grande" font. So
|
|
43 | - // we need to explicitly change the font for the entire string.
|
|
44 | - ApplyFont(font, NSMakeRange(0, [m_attrString length]));
|
|
45 | - |
|
46 | 40 | // Now translate the markup tags to corresponding attributes.
|
47 | 41 | wxMarkupParser parser(*this);
|
48 | 42 | parser.Parse(markup);
|
... | ... | @@ -56,27 +50,6 @@ protected: |
56 | 50 | [m_attrString release];
|
57 | 51 | }
|
58 | 52 | |
59 | - void ApplyFont(const wxFont& font, const NSRange& range)
|
|
60 | - {
|
|
61 | - [m_attrString addAttribute:NSFontAttributeName
|
|
62 | - value:font.OSXGetNSFont()
|
|
63 | - range:range];
|
|
64 | - |
|
65 | - if ( font.GetStrikethrough() )
|
|
66 | - {
|
|
67 | - [m_attrString addAttribute:NSStrikethroughStyleAttributeName
|
|
68 | - value:@(NSUnderlineStyleSingle)
|
|
69 | - range:range];
|
|
70 | - }
|
|
71 | - |
|
72 | - if ( font.GetUnderlined() )
|
|
73 | - {
|
|
74 | - [m_attrString addAttribute:NSUnderlineStyleAttributeName
|
|
75 | - value:@(NSUnderlineStyleSingle)
|
|
76 | - range:range];
|
|
77 | - }
|
|
78 | - }
|
|
79 | - |
|
80 | 53 | // prepare text chunk for display, e.g. strip mnemonics from it
|
81 | 54 | virtual wxString PrepareText(const wxString& text) = 0;
|
82 | 55 | |
... | ... | @@ -89,53 +62,42 @@ public: |
89 | 62 | return m_attrString;
|
90 | 63 | }
|
91 | 64 | |
92 | - |
|
93 | 65 | // Implement base class pure virtual methods to process markup tags.
|
94 | 66 | virtual void OnText(const wxString& text)
|
95 | 67 | {
|
96 | - m_pos += PrepareText(text).length();
|
|
97 | - }
|
|
68 | + const Attr& attr = GetAttr();
|
|
98 | 69 | |
99 | - virtual void OnAttrStart(const Attr& WXUNUSED(attr))
|
|
100 | - {
|
|
101 | - // Just remember the starting position of the range, we can't really
|
|
102 | - // set the attribute until we find the end of it.
|
|
103 | - m_rangeStarts.push(m_pos);
|
|
104 | - }
|
|
70 | + NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
105 | 71 | |
106 | - virtual void OnAttrEnd(const Attr& attr)
|
|
107 | - {
|
|
108 | - unsigned start = m_rangeStarts.top();
|
|
109 | - m_rangeStarts.pop();
|
|
110 | - |
|
111 | - const NSRange range = NSMakeRange(start, m_pos - start);
|
|
112 | - |
|
113 | - ApplyFont(attr.font, range);
|
|
114 | - |
|
115 | - if ( attr.foreground.IsOk() )
|
|
116 | - {
|
|
117 | - [m_attrString addAttribute:NSForegroundColorAttributeName
|
|
118 | - value:attr.foreground.OSXGetNSColor()
|
|
119 | - range:range];
|
|
120 | - }
|
|
121 | - |
|
122 | - if ( attr.background.IsOk() )
|
|
123 | - {
|
|
124 | - [m_attrString addAttribute:NSBackgroundColorAttributeName
|
|
125 | - value:attr.background.OSXGetNSColor()
|
|
126 | - range:range];
|
|
127 | - }
|
|
72 | + dict[NSFontAttributeName] = attr.effectiveFont.OSXGetNSFont();
|
|
73 | + if ( attr.effectiveFont.GetStrikethrough() )
|
|
74 | + dict[NSStrikethroughStyleAttributeName] = @(NSUnderlineStyleSingle);
|
|
75 | + if ( attr.effectiveFont.GetUnderlined() )
|
|
76 | + dict[NSUnderlineStyleAttributeName] = @(NSUnderlineStyleSingle);
|
|
77 | + |
|
78 | + if ( attr.effectiveForeground.IsOk() )
|
|
79 | + dict[NSForegroundColorAttributeName] = attr.effectiveForeground.OSXGetNSColor();
|
|
80 | + |
|
81 | + if ( attr.effectiveBackground.IsOk() )
|
|
82 | + dict[NSBackgroundColorAttributeName] = attr.effectiveBackground.OSXGetNSColor();
|
|
83 | + |
|
84 | + const unsigned len = PrepareText(text).length();
|
|
85 | + |
|
86 | + [m_attrString addAttributes:dict range:NSMakeRange(m_pos, len)];
|
|
87 | + |
|
88 | + m_pos += len;
|
|
128 | 89 | }
|
129 | 90 | |
91 | + virtual void OnAttrStart(const Attr& WXUNUSED(attr)) {}
|
|
92 | + |
|
93 | + virtual void OnAttrEnd(const Attr& WXUNUSED(attr)) {}
|
|
94 | + |
|
130 | 95 | private:
|
131 | 96 | // The attributed string we're building.
|
132 | 97 | NSMutableAttributedString *m_attrString;
|
133 | 98 | |
134 | 99 | // The current position in the output string.
|
135 | 100 | unsigned m_pos;
|
136 | - |
|
137 | - // The positions of starting ranges.
|
|
138 | - wxStack<unsigned> m_rangeStarts;
|
|
139 | 101 | };
|
140 | 102 | |
141 | 103 |
... | ... | @@ -25,11 +25,17 @@ struct wxOSXTimerInfo |
25 | 25 | CFRunLoopTimerRef m_timerRef;
|
26 | 26 | };
|
27 | 27 | |
28 | -void wxProcessTimer(CFRunLoopTimerRef WXUNUSED(theTimer), void *data)
|
|
28 | +void wxProcessTimer(CFRunLoopTimerRef theTimer, void *data)
|
|
29 | 29 | {
|
30 | 30 | if ( data == NULL )
|
31 | 31 | return;
|
32 | 32 | |
33 | + // CFRunLoop can fire timer callbacks after CFRunLoopTimerInvalidate()
|
|
34 | + // has been called (e.g., if the callback was already queued when Stop() was called).
|
|
35 | + // Verify the timer is still valid before proceeding to avoid crashes.
|
|
36 | + if ( !CFRunLoopTimerIsValid(theTimer) )
|
|
37 | + return;
|
|
38 | + |
|
33 | 39 | wxOSXTimerImpl* timer = (wxOSXTimerImpl*)data;
|
34 | 40 | |
35 | 41 | if ( timer->IsOneShot() )
|
—
View it on GitLab.
You're receiving this email because of your account on gitlab.com. Manage all notifications · Help