From b02c184829f4fcaef85cdfda4d33298e25535473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 27 Apr 2026 21:08:40 +0200 Subject: [PATCH] Add more error checking, correct caret positioning --- Common/Render/Text/draw_text_cocoa.mm | 45 +++++++++++++++++++++++++++ Common/UI/View.cpp | 6 +++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/Common/Render/Text/draw_text_cocoa.mm b/Common/Render/Text/draw_text_cocoa.mm index 91fa6c0d81..a98084112d 100644 --- a/Common/Render/Text/draw_text_cocoa.mm +++ b/Common/Render/Text/draw_text_cocoa.mm @@ -237,9 +237,23 @@ bool TextDrawerCocoa::DrawStringBitmap(std::vector &bitmapData, TextStr NSString* string = [[NSString alloc] initWithBytes:str.data() length:str.length() encoding: NSUTF8StringEncoding]; + // If UTF-8 fails, fallback to ASCII to prevent nil + if (!string) { + string = [[NSString alloc] initWithBytes:str.data() length:str.length() encoding:NSASCIIStringEncoding]; + } + // Skip if string creation failed + if (!string) { + return false; + } + NSDictionary* attributes = iter->second->attributes; NSAttributedString* as = [[NSAttributedString alloc] initWithString:string attributes:attributes]; + // Safety check for AttributedString allocation + if (!as) { + return false; + } + // Figure out how big an image we need. // We re-use MeasureString here. float w, h; @@ -267,6 +281,14 @@ bool TextDrawerCocoa::DrawStringBitmap(std::vector &bitmapData, TextStr CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast; CGContextRef ctx = CGBitmapContextCreate(bitmap, bmWidth, bmHeight, 8, bmWidth*4, space, bitmapInfo); CGColorSpaceRelease(space); + + // Safety check for CGContext creation + if (!ctx) { + WARN_LOG(Log::G3D, "Failed to create CGBitmapContext"); + delete [] bitmap; + return false; + } + // CGContextSetRGBStrokeColor(ctx, 1.0, 1.0, 1.0, 1.0); // white background CGContextSetStrokeColorWithColor(ctx, [ColorType whiteColor].CGColor); CGContextSetFillColorWithColor(ctx, [ColorType whiteColor].CGColor); @@ -277,8 +299,30 @@ bool TextDrawerCocoa::DrawStringBitmap(std::vector &bitmapData, TextStr float lineY = 0.0; for (std::string_view line : lines) { NSString *string = [[NSString alloc] initWithBytes:line.data() length:line.size() encoding: NSUTF8StringEncoding]; + + // If UTF-8 fails, fallback to ASCII to prevent nil + if (!string) { + string = [[NSString alloc] initWithBytes:line.data() length:line.size() encoding:NSASCIIStringEncoding]; + } + // Skip empty or failed strings to prevent crash + if (!string) { + continue; + } + NSAttributedString* as = [[NSAttributedString alloc] initWithString:string attributes:attributes]; + + // Safety check for AttributedString allocation + if (!as) { + continue; + } + CTLineRef ctline = CTLineCreateWithAttributedString((CFAttributedStringRef)as); + + // Core Text safety check + if (!ctline) { + continue; + } + CGFloat ascent, descent, leading; double fWidth = CTLineGetTypographicBounds(ctline, &ascent, &descent, &leading); @@ -349,6 +393,7 @@ bool TextDrawerCocoa::DrawStringBitmap(std::vector &bitmapData, TextStr _assert_msg_(false, "Bad TextDrawer format"); } + CGContextRelease(ctx); delete [] bitmap; return true; } diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index aa606ddf73..489d03868c 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -1298,13 +1298,17 @@ void TextEdit::Draw(UIContext &dc) { if (selectAtX_ >= 0) { caret_ = -1; - for (int i = 0; i <= text_.size(); i++) { + for (int i = 0; i <= text_.size(); ) { dc.MeasureText(dc.GetTheme().uiFont, 1.0f, 1.0f, textToDisplay.substr(0, i), &w, &h, ALIGN_VCENTER | ALIGN_LEFT | align_); float charX = w - scrollPos_; if (charX >= selectAtX_ - 3) { caret_ = i; break; } + if (i >= text_.size()) { + break; + } + u8_inc(text_.c_str(), &i); } if (caret_ == -1) { caret_ = (int)text_.size();