[Git][wxwidgets/wxwidgets][3.2-2025-10-backports] 2 commits: Fix nested markup conversion to NSAttributedString

1 view
Skip to first unread message

Vadim Zeitlin (@_VZ_)

unread,
Oct 10, 2025, 4:10:13 AM (12 days ago) Oct 10
to wx-commi...@googlegroups.com

Vadim Zeitlin pushed to branch 3.2-2025-10-backports at wxWidgets / wxWidgets

Commits:

  • 46cfa36c
    by Václav Slavík at 2025-10-07T15:03:19+02:00
    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)
    
  • f2cff7f4
    by Federico Perini at 2025-10-10T10:07:11+02:00
    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)
    

3 changed files:

Changes:

  • docs/changes.txt
    ... ... @@ -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)
    

  • include/wx/osx/cocoa/private/markuptoattr.h
    ... ... @@ -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
     
    

  • src/osx/core/timer.cpp
    ... ... @@ -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() )
    

Reply all
Reply to author
Forward
0 new messages