diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index 8202b8019..3cf9ba9f0 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -1,7 +1,7 @@ // // Windows-specific code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2024 by Bill Spitzak and others. +// Copyright 1998-2026 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -1510,7 +1510,22 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar static char buffer[1024]; if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { wchar_t u = (wchar_t)wParam; - Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); + // Windows emoji palette triggered with Windows + dot sends 2 or more WM_CHAR messages: + // the 2 components of a surrogate pair, or variation selectors, or zero-width joiner, + // or emoji modifiers FITZPATRICK or extra Unicode points. + if (u >= 0xD800 && u <= 0xDFFF) { // handle the 2 components of a surrogate pair + static wchar_t surrogate_pair[2]; + if (IS_HIGH_SURROGATE(u)) { + surrogate_pair[0] = u; // memorize the 1st member of the pair + Fl::e_length = 0; + return 0; // and wait for next WM_CHAR message that will give the 2nd member + } else { + surrogate_pair[1] = u; // memorize the 2nd member of the pair + Fl::e_length = fl_utf8fromwc(buffer, 1024, surrogate_pair, 2); // transform to UTF-8 + } + } else { + Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); // process regular Unicode point + } buffer[Fl::e_length] = 0; } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { if (state & FL_NUM_LOCK) { diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx index daf12d5d7..1ca3a5b29 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx @@ -1,7 +1,7 @@ // // Windows font utilities for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2025 by Bill Spitzak and others. +// Copyright 1998-2026 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -366,6 +366,27 @@ Fl_Fontsize Fl_GDI_Graphics_Driver::size_unscaled() { } double Fl_GDI_Graphics_Driver::width_unscaled(const char* c, int n) { + if (n == 0) return 0; + int len1 = fl_utf8len1(*c); + if (n > len1 && len1 > 0) { // a text with several codepoints: compute its typographical width + int wn = fl_utf8toUtf16(c, n, wstr, wstr_len); + if (wn >= wstr_len) { + wstr = (unsigned short*) realloc(wstr, sizeof(unsigned short) * (wn + 1)); + wstr_len = wn + 1; + wn = fl_utf8toUtf16(c, n, wstr, wstr_len); + } + HDC gc2 = gc_; + HWND hWnd; + if (!gc2) { + hWnd = Fl::first_window() ? fl_xid(Fl::first_window()) : NULL; + gc2 = GetDC(hWnd); + } + SelectObject(gc2, ((Fl_GDI_Font_Descriptor*)font_descriptor())->fid); + SIZE s; + GetTextExtentPoint32W(gc2, (WCHAR*)wstr, wn, &s); + if (gc2 && gc2 != gc_) ReleaseDC(hWnd, gc2); + return (double)s.cx; + } int i = 0; if (!font_descriptor()) return -1.0; double w = 0.0; diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx index 7b2085c23..a277010e3 100644 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx @@ -1,7 +1,7 @@ // // MacOS font selection routines for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2018 by Bill Spitzak and others. +// Copyright 1998-2026 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -300,6 +300,21 @@ void Fl_Quartz_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) { } double Fl_Quartz_Graphics_Driver::width(const char* txt, int n) { + if (n == 0) return 0; + int len1 = fl_utf8len1(*txt); + if (len1 > 0 && n > len1) { // a text with several codepoints: compute its typographical width + CFStringRef str = CFStringCreateWithBytes(NULL, (const UInt8*)txt, n, kCFStringEncodingUTF8, false); + if (str) { + CFDictionarySetValue(attributes, kCTFontAttributeName, valid_font_descriptor()->fontref); + CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str, attributes); + CFRelease(str); + CTLineRef ctline = CTLineCreateWithAttributedString(mastr); + CFRelease(mastr); + double d = CTLineGetTypographicBounds(ctline, NULL, NULL, NULL); + CFRelease(ctline); + return d; + } + } int wc_len = n; UniChar *uniStr = mac_Utf8_to_Utf16(txt, n, &wc_len); return width(uniStr, wc_len);