From unknown Wed Jun 18 23:16:38 2025 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Mailer: MIME-tools 5.509 (Entity 5.509) Content-Type: text/plain; charset=utf-8 From: bug#51411 <51411@debbugs.gnu.org> To: bug#51411 <51411@debbugs.gnu.org> Subject: Status: NS port cleanups Reply-To: bug#51411 <51411@debbugs.gnu.org> Date: Thu, 19 Jun 2025 06:16:38 +0000 retitle 51411 NS port cleanups reassign 51411 emacs submitter 51411 Po Lu severity 51411 normal tag 51411 patch thanks From debbugs-submit-bounces@debbugs.gnu.org Tue Oct 26 07:42:07 2021 Received: (at submit) by debbugs.gnu.org; 26 Oct 2021 11:42:07 +0000 Received: from localhost ([127.0.0.1]:45292 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfKqB-0004Z7-MZ for submit@debbugs.gnu.org; Tue, 26 Oct 2021 07:42:07 -0400 Received: from lists.gnu.org ([209.51.188.17]:55034) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfKq6-0004Ya-TH for submit@debbugs.gnu.org; Tue, 26 Oct 2021 07:42:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40048) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mfKq3-0001bL-Sy for bug-gnu-emacs@gnu.org; Tue, 26 Oct 2021 07:41:56 -0400 Received: from sonic312-23.consmr.mail.ne1.yahoo.com ([66.163.191.204]:45808) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mfKpt-0005OU-1a for bug-gnu-emacs@gnu.org; Tue, 26 Oct 2021 07:41:55 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635248502; bh=SOmd+rNkBzAHuQLbcwBhcs2MIp72OoqjYw5gDCc/y8I=; h=From:To:Subject:Date:References:From:Subject:Reply-To; b=I1PkczhBDfoi3kwanXELjcCZUgmgBgmBM/cTRNOvOLb0NQMcdH1XSGoWaDYDgI2gzsZPhk25aMFchC6L2cwMsajrLdcSSVddggSBKcnPj/BT6s9IJTZ4H76/X6EESVH0HMfFlRMSbK5lBODSCfcIyqY5p9T6vOLzAAIZuYcL9/YyCQsa0HCRY16kHxj+CyYSh1jPZRGcboBPqxSK0AYqv/VIUdOF2EeHkpl+67gNL4qOqthPjIH1WX5Dg5ULhrIuDJy+VrQDW1Cw60U4cU+LnKRcjG7O/7DSIvgSLws01/sq49gaUSyXf+vDMQsP6JFkwlTUknndUElGACa4nYbVDw== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635248502; bh=dSkbc9JZQFjnqpf6v/3dylWx0aok1ScHT+Q32NdPw7u=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=NnhzHFo90PQKX+0SPJCYeELgaGWkQfEl/7o6S6wS8YHXwLBEgh66CINnJlVUCEit0ev35qx/V/FMOLEckvfRLYX0Ti9OWDlubcZJY7cS1FeMviUNxh5rBqDxjSfYsLK+F/ZgQxf8bsrDKAcckwdMn0a3WMrP74pX3SnMgv7hkGfdGg7AqPD7QmAn8xvH/fZw93IJr725riLlK2/ghs29NO0mDYxsJ93hHI1jHONYasnya5l20sArPemiIE58R9+3u6GpUbqZiKco0N3r2vLcAkqSi7TU0PxXW3qLocQN4jQXq+KKiQvfF3Phrt09OM9Rnu8euhDxZfvo9GK63KVxkA== X-YMail-OSG: xQ1Lp5sVM1lsSNuBJQJ40Mt4SH8ZCEviCsS0qetZ.b9Ih_hIkk3RRHlXuVxkkTg VZb.4SRydWyLDjxXTmq.6xFOjzQT1alrOX8dhUcC809BpQKGsgYfsXlERM9lRUTagcWfN0kpQCXZ S8r3X6guqdrXnHyPKaEwaZNPrmPv0xWpObdH04F1kZ0aL1izQBFlsZQS6U9VImnRDMan01gaV0Um pdW5o3swHVl7Uc7iUqKA53iVvuMu7WhZzIloytSABIgwSOZ5V2PkLIK074afdTt9x18NRpmdnFJn KhI.oZNtdsIWfFjmf4wVWM8AOwYqtOYC21ZxftpWjd7geym_TMt9amxEIbVB8._sHz_2olu8Ke26 iCbc69uKDcDw7TsFtKNpuOxdObYWihvdqOdUcknofHY4FhmVah71Xpya0pxYuAbN5zBBi7Tmh5vn HPOGympdldfR06awqGaZ9_6T.LOpE3_0_BWNScvDm98CqJJ.3MoptMymlCPH2XHhhCy0XYyZS3Iv wimC5OVyw_LzjMXjsYKtIOOI9XF8zoIAogOSO4iJuosaoglRFLmzu3wgoFgYZctJupFPgdvcxOK3 O6Z2UfoIKQUVZaxVCV9_DUg_AICsEBBMITQOyjCCYaFle91HKegkHPhcsYsDPAyRPh_xk5tkHLIi RJY8jOCWUAEvHLv4Q6CP9D1o1TZzXbtunEyf9Gm4BN8lFY3rkoEJZgVNCsaxmRkyGXFWJhgDH5QQ IICyrcavutCbTYJrNhZeyLhr6Vwb23yugjWeo8X1S8gmQ3kQy0yOgfFd58cmgz2WDGQJQGp6wdqS IaQeKPA6Tx359.aZMnMPvPlRAuAD5AchdPHAAdfV40fxiur84.GDhun5XgONjcduBmAswmoig1_9 GTCix0CYe6zdnI8MQcoT4JCP2FuJYSQIQTvM8coW7fM2irzfbiFYeat9xA_psdErXw36E76s7i5S UxLLsk8tuTEjdBYcoVi2Af9gBvn2VnK7B2k.d8LQkzDlPINATognpcuJt2Y3COLtEsdS1ruqOjcO WnwsqKPP5uHmtjGV_rt8kPl5zJ5zRRA5lFAe9Oa.hw7cHFfPLmfADFmeaLaCXzB6C.chM1_IE3Yx TUdXTS5mz7UUbWPd6I2xQNyfsWXSidRyYX2_wIExlkOz7lWQFnjcThOQNAICn4myEU9hAPxcKXpu LcAX2rs_Ise9LM4aPheRxoA4IPbcasr8pG061u2CZD5iZjDvVErT1VblN3KwWDHECN1ZpdFhHFKb yiAT9HeCToWqootfdIKRnN8KbkK2CPrQNrVwPHR5xA4USYsnFkhqyfWOu1Ef_fljKHT66JNGzqOX vydDRlL4_77oDXN.2YkIJSidWH1jmMZRdf1u0Fhh0XoZq54u7o2owUZrS4B8YVPRtIIMOv_xxdnS rThp7vW.6MjhGz3IAdBfeTM_jMpnUZg_ALPXB1DTt6iw3JwDuJUXAc7uiFp01VdHPvZ51nEBawO5 ovE6Ge.BbESb3XOVuj5_hZIR9GCch6z1hRLIUGNkaQp42xvW2nXTtjEBL2Sgg6WSP3bZ09q7C1Et vSABTwxzUugFpkXcn5YNJ0.b9SMOsz8.vqmWB7goAmEoH7rkY6JsJbnw0rUbfIITzCyUKMrSzZxq tGQj335vToJlxS6UA8ZFVVXsz_Xqd8fZHEiARFeobSxVR1BTTp_lmj6ANkaSRi4Gq.m7yqb44YzF Ngfc_fnrAZ1t6kYnT7ljnxSszUQbMEFu8lCeupX5kqe0kwWNwCw_QxxJL0t7Z9gz0mODuBh6itPt CZJupJS5CazXHlDx1bw1IXX9k1ZgXEP05bf93oF3_N98zFxAW9U.spMdi00HPblj_RuSxeJyn9bp _PVWIGEr2kVrFepJjaU56VZln8.A4B7IcjPEFO6l_4ZPAmFMhziSmaEzUrNl6YLt0Xgg2cSTF.w9 KoT1wZKZK7dzijRErWeZU30kTYVqkJNCtmRhh2BLyYXsBGBLtdmIiKFsxgIIusAkTJ2obDQgQ9Sm KOVYrheRchb_o53_YAYnTji.TBD0nAcaSWwyaHdmQKGrNUaxO0tjJW4O4KJcD2erziqfhpN12Jff wPBGoKwuZkHzYaF1tZbQ9MDREe27zLWNthZEGu1CPrSHJLeWE1BAgNWfXPabgBXTLfeW869HUrKG WOY.vNgbQj7edd7i0qEyKfxDdGsUQIKR2rgX4BmVa555p_F9Ewtk3p9vU6KO7J4BOXnFp7sOMvy3 Gn8Juyke7xVxvMCWcGs6cF0Z.uXapQnM- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic312.consmr.mail.ne1.yahoo.com with HTTP; Tue, 26 Oct 2021 11:41:42 +0000 Received: by kubenode502.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 6f0a277848c11725ccb4507c09ab886f; Tue, 26 Oct 2021 11:41:35 +0000 (UTC) From: Po Lu To: bug-gnu-emacs@gnu.org Subject: NS port cleanups Date: Tue, 26 Oct 2021 19:41:31 +0800 Message-ID: <87mtmwt3mc.fsf@yahoo.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" References: <87mtmwt3mc.fsf.ref@yahoo.com> X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 91499 Received-SPF: pass client-ip=66.163.191.204; envelope-from=luangruo@yahoo.com; helo=sonic312-23.consmr.mail.ne1.yahoo.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -0.6 (/) X-Debbugs-Envelope-To: submit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.6 (-) --=-=-= Content-Type: text/plain I did not notice that the thread previously titled "NS port improvements" was moved off bug#51251 onto emacs-devel, but now that there are concrete changes I think it would be a good opportunity to post them on bug-gnu-emacs, per the CONTRIBUTE document. The changes, with the generic improvements split from the changes to font rendering are attached. Alan raised several questions, which I answered. I've reproduced that part of the discussion below: > Is there any reason to nest ns_focus? There are (according to Apple) > performance reasons to not save the context unless you really need to. Right now it's used in the code that clips to the exact bounds of a string, if a string's overhangs are already drawn. I couldn't find a cleaner way to do this, and that situation is rare, so I think the performance problems will usually be avoided. > I mean alt as defined by GNUstep in the quote I sent you in my last > email. I don't think it's our job to say that GNUstep's choice of > defaults is wrong and therefore do something that would be unexpected > for a GNUstep user. Well, on every other platform Meta is on the alt on the users' keyboard. Emacs in general doesn't conform to the platform expectations WRT to key bindings, so I think being consistent with Emacs on other platforms is more important here. But in the end, it's your call. Thanks. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-General-improvements-to-NS-port.patch >From 861f2bc781d459118e318b90277e88d52af6a6ca Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 23 Oct 2021 19:51:31 +0800 Subject: [PATCH 2/2] General improvements to NS port * src/dispextern.h: Remove some !HAVE_NS conditionals around grab related code. * src/frame.c (gui_mouse_grabbed, gui_redo_mouse_highlight): Remove !HAVE_NS conditionals around code. * src/nsmenu.m (ns_update_menubar): Prevent recursive calls and enable shallow updates on GNUstep. (menuNeedsUpdate): Prevent recursive calls. (ns_menu_show): Fix mysterious GC-related bug. (update_frame_tool_bar_1): Work around mysterious toolbar sizing bug on GNUstep. * src/nsterm.h (struct ns_output): New field for tracking toolbar visibility changes. * src/nsterm.m (frame_set_mouse_pixel_position): Implement for GNUstep. (ns_redraw_scroll_bars): Enable for GNUstep. (ns_clear_frame): Redraw scrollbars on GNUstep. (ns_update_window_end): New function. (ns_redisplay_interface): Add ns_update_window_end on GNUstep. (- keyDown): Remove debug code that doesn't work on GNUstep. (- mouseDown): Enable grab tracking on NS port. (- resizeWithOldSuperviewSize): Fix build with NSTRACE. (ns_alternate_modifier, ns_command_modifier): Fix default values for GNUstep. * src/xdisp.c (note_tab_bar_highlight): Enable some code for NS port. --- src/dispextern.h | 2 -- src/frame.c | 4 --- src/nsmenu.m | 76 +++++++++++++++++++++++++++++++++++++++--------- src/nsterm.h | 6 ++++ src/nsterm.m | 50 ++++++++++++++++++++++++++----- src/xdisp.c | 2 -- 6 files changed, 110 insertions(+), 30 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index 08dac5d455..58e9048556 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3722,10 +3722,8 @@ #define IMAGE_BACKGROUND_TRANSPARENT(img, f, mask) \ const char *, const char *, enum resource_types); -#ifndef HAVE_NS /* These both used on W32 and X only. */ extern bool gui_mouse_grabbed (Display_Info *); extern void gui_redo_mouse_highlight (Display_Info *); -#endif /* HAVE_NS */ #endif /* HAVE_WINDOW_SYSTEM */ diff --git a/src/frame.c b/src/frame.c index 2b1cb452ef..79a7c89e0d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -5028,8 +5028,6 @@ gui_set_no_special_glyphs (struct frame *f, Lisp_Object new_value, Lisp_Object o } -#ifndef HAVE_NS - /* Non-zero if mouse is grabbed on DPYINFO and we know the frame where it is. */ @@ -5054,8 +5052,6 @@ gui_redo_mouse_highlight (Display_Info *dpyinfo) dpyinfo->last_mouse_motion_y); } -#endif /* HAVE_NS */ - /* Subroutines of creating an X frame. */ /* Make sure that Vx_resource_name is set to a reasonable value. diff --git a/src/nsmenu.m b/src/nsmenu.m index a2540c1663..65cf53fa21 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -101,6 +101,15 @@ static void ns_update_menubar (struct frame *f, bool deep_p) { +#ifdef NS_IMPL_GNUSTEP + static int inside = 0; + + if (inside) + return; + + inside++; +#endif + BOOL needsSet = NO; id menu = [NSApp mainMenu]; bool owfi; @@ -120,7 +129,12 @@ NSTRACE ("ns_update_menubar"); if (f != SELECTED_FRAME () || FRAME_EXTERNAL_MENU_BAR (f) == 0) + { +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif return; + } XSETFRAME (Vmenu_updating_frame, f); /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */ @@ -144,10 +158,6 @@ t = -(1000*tb.time+tb.millitm); #endif -#ifdef NS_IMPL_GNUSTEP - deep_p = 1; /* See comment in menuNeedsUpdate. */ -#endif - if (deep_p) { /* Make a widget-value tree representing the entire menu trees. */ @@ -275,6 +285,9 @@ free_menubar_widget_value_tree (first_wv); discard_menu_items (); unbind_to (specpdl_count, Qnil); +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif return; } @@ -408,6 +421,10 @@ if (needsSet) [NSApp setMainMenu: menu]; +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif + unblock_input (); } @@ -452,17 +469,34 @@ - (instancetype)initWithTitle: (NSString *)title call to ns_update_menubar. */ - (void)menuNeedsUpdate: (NSMenu *)menu { +#ifdef NS_IMPL_GNUSTEP + static int inside = 0; +#endif + if (!FRAME_LIVE_P (SELECTED_FRAME ())) return; -#ifdef NS_IMPL_COCOA -/* TODO: GNUstep calls this method when the menu is still being built - which results in a recursive stack overflow. One possible solution - is to use menuWillOpen instead, but the Apple docs explicitly warn - against changing the contents of the menu in it. I don't know what - the right thing to do for GNUstep is. */ +#ifdef NS_IMPL_GNUSTEP + /* GNUstep calls this method when the menu is still being built + which results in a recursive stack overflow, which this variable + prevents. */ + + if (!inside) + ++inside; + else + return; +#endif + if (needsUpdate) - ns_update_menubar (SELECTED_FRAME (), true); + { +#ifdef NS_IMPL_GNUSTEP + needsUpdate = NO; +#endif + ns_update_menubar (SELECTED_FRAME (), true); + } + +#ifdef NS_IMPL_GNUSTEP + --inside; #endif } @@ -789,6 +823,9 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item p.x = x; p.y = y; + /* Don't GC due to a mysterious bug. */ + inhibit_garbage_collection (); + /* now parse stage 2 as in ns_update_menubar */ wv = make_widget_value ("contextmenu", NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; @@ -960,15 +997,17 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item pmenu = [[EmacsMenu alloc] initWithTitle: NILP (title) ? @"" : [NSString stringWithLispString: title]]; + /* On GNUstep, this call makes menu_items nil for whatever reason + when displaying a context menu from `context-menu-mode'. */ + Lisp_Object items = menu_items; [pmenu fillWithWidgetValue: first_wv->contents]; + menu_items = items; free_menubar_widget_value_tree (first_wv); - unbind_to (specpdl_count, Qnil); - popup_activated_flag = 1; tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps]; popup_activated_flag = 0; [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; - + unbind_to (specpdl_count, Qnil); unblock_input (); return tem; } @@ -1019,6 +1058,15 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item [toolbar clearActive]; #else [toolbar clearAll]; + /* It takes at least 3 such adjustments to fix an issue where the + tool bar is 2x too tall when a frame's tool bar is first shown. + This is ugly, but I have no other solution for this problem. */ + if (FRAME_OUTPUT_DATA (f)->tool_bar_adjusted < 3) + { + [toolbar setVisible: NO]; + FRAME_OUTPUT_DATA (f)->tool_bar_adjusted++; + [toolbar setVisible: YES]; + } #endif /* Update EmacsToolbar as in GtkUtils, build items list. */ diff --git a/src/nsterm.h b/src/nsterm.h index 944dbd727c..8175f99664 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -978,6 +978,12 @@ #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) /* Non-zero if we are doing an animation, e.g. toggling the tool bar. */ int in_animation; + +#ifdef NS_IMPL_GNUSTEP + /* Zero if this is the first time a toolbar has been updated on this + frame. */ + int tool_bar_adjusted; +#endif }; /* This dummy declaration needed to support TTYs. */ diff --git a/src/nsterm.m b/src/nsterm.m index 957cd815a0..d9c28cb191 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -65,6 +65,7 @@ Updated by Christian Limpach (chris@nice.ch) #ifdef NS_IMPL_GNUSTEP #include "process.h" +#import #endif #ifdef NS_IMPL_COCOA @@ -2259,13 +2260,19 @@ Hide the window (X11 semantics) { NSTRACE ("frame_set_mouse_pixel_position"); - /* FIXME: what about GNUstep? */ #ifdef NS_IMPL_COCOA CGPoint mouse_pos = CGPointMake(f->left_pos + pix_x, f->top_pos + pix_y + FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f)); CGWarpMouseCursorPosition (mouse_pos); +#else + GSDisplayServer *server = GSServerForWindow ([FRAME_NS_VIEW (f) window]); + [server setMouseLocation: NSMakePoint (f->left_pos + pix_x, + f->top_pos + pix_y + + FRAME_NS_TITLEBAR_HEIGHT(f) + + FRAME_TOOLBAR_HEIGHT(f)) + onScreen: [[[FRAME_NS_VIEW (f) window] screen] screenNumber]]; #endif } @@ -2578,8 +2585,7 @@ Hide the window (X11 semantics) ========================================================================== */ -#if 0 -/* FIXME: Remove this function. */ +#ifdef NS_IMPL_GNUSTEP static void ns_redraw_scroll_bars (struct frame *f) { @@ -2624,10 +2630,9 @@ Hide the window (X11 semantics) NSRectFill (r); ns_unfocus (f); - /* as of 2006/11 or so this is now needed */ - /* FIXME: I don't see any reason for this and removing it makes no - difference here. Do we need it for GNUstep? */ - //ns_redraw_scroll_bars (f); +#ifdef NS_IMPL_GNUSTEP + ns_redraw_scroll_bars (f); +#endif unblock_input (); } @@ -4933,6 +4938,17 @@ static Lisp_Object ns_string_to_lispmod (const char *s) { } +#ifdef NS_IMPL_GNUSTEP +static void +ns_update_window_end (struct window *w, bool cursor_on_p, + bool mouse_face_overwritten_p) +{ + NSTRACE ("ns_update_window_end (cursor_on_p = %d)", cursor_on_p); + + ns_redraw_scroll_bars (WINDOW_XFRAME (w)); +} +#endif + /* This and next define (many of the) public functions in this file. */ /* gui_* are generic versions in xdisp.c that we, and other terms, get away with using despite presence in the "system dependent" redisplay @@ -4949,7 +4965,11 @@ static Lisp_Object ns_string_to_lispmod (const char *s) ns_scroll_run, ns_after_update_window_line, NULL, /* update_window_begin */ +#ifndef NS_IMPL_GNUSTEP NULL, /* update_window_end */ +#else + ns_update_window_end, +#endif 0, /* flush_display */ gui_clear_window_mouse_face, gui_get_glyph_overhangs, @@ -6177,9 +6197,11 @@ In that case we use UCKeyTranslate (ns_get_shifted_character) Lisp_Object kind = fnKeysym ? QCfunction : QCordinary; emacs_event->modifiers = EV_MODIFIERS2 (flags, kind); +#ifndef NS_IMPL_GNUSTEP if (NS_KEYLOG) fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n", code, fnKeysym, flags, emacs_event->modifiers); +#endif /* If it was a function key or had control-like modifiers, pass it directly to Emacs. */ @@ -6692,6 +6714,11 @@ - (void)mouseDown: (NSEvent *)theEvent emacs_event->code = EV_BUTTON (theEvent); emacs_event->modifiers = EV_MODIFIERS (theEvent) | EV_UDMODIFIERS (theEvent); + + if (emacs_event->modifiers & down_modifier) + FRAME_DISPLAY_INFO (emacsframe)->grabbed |= 1 << EV_BUTTON (theEvent); + else + FRAME_DISPLAY_INFO (emacsframe)->grabbed &= ~(1 << EV_BUTTON (theEvent)); } XSETINT (emacs_event->x, lrint (p.x)); @@ -6992,7 +7019,6 @@ - (void)resizeWithOldSuperviewSize: (NSSize)oldSize height = (int)NSHeight (frame); NSTRACE_SIZE ("New size", NSMakeSize (width, height)); - NSTRACE_SIZE ("Original size", size); /* Reset the frame size to match the bounds of the superview (the NSWindow's contentView). We need to do this as sometimes the @@ -9854,7 +9880,11 @@ Convert an X font name (XLFD) to an NS font name. \n\ Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ If `none', the key is ignored by Emacs and retains its standard meaning."); +#ifdef NS_IMPL_GNUSTEP + ns_alternate_modifier = Qalt; +#else ns_alternate_modifier = Qmeta; +#endif DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier, "This variable describes the behavior of the right alternate or option key.\n\ @@ -9875,7 +9905,11 @@ Convert an X font name (XLFD) to an NS font name. \n\ Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ If `none', the key is ignored by Emacs and retains its standard meaning."); +#ifdef NS_IMPL_GNUSTEP + ns_command_modifier = Qmeta; +#else ns_command_modifier = Qsuper; +#endif DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier, "This variable describes the behavior of the right command key.\n\ diff --git a/src/xdisp.c b/src/xdisp.c index 9998677262..bfe7c571ab 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -13891,7 +13891,6 @@ note_tab_bar_highlight (struct frame *f, int x, int y) clear_mouse_face (hlinfo); bool mouse_down_p = false; -#ifndef HAVE_NS /* Mouse is down, but on different tab-bar item? Or alternatively, the mouse might've been pressed somewhere we don't know about, and then have moved onto the tab bar. In this case, @@ -13904,7 +13903,6 @@ note_tab_bar_highlight (struct frame *f, int x, int y) if (mouse_down_p && f->last_tab_bar_item != prop_idx && f->last_tab_bar_item != -1) return; -#endif draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; /* If tab-bar item is not enabled, don't highlight it. */ -- 2.31.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Improve-font-display-on-NS-port.patch >From a908e305c824fe466e381cdb6c279046d7cce781 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 23 Oct 2021 19:44:03 +0800 Subject: [PATCH 1/2] Improve font display on NS port * src/nsfns.m (Fx_create_frame): Use "fixed" for the default font on GNUstep. * src/nsfont.m (LCD_SMOOTHING_MARGIN, ns_escape_name) (ns_unescape_name, ns_attribute_fvalue) (STYLE_REF): Remove unused defines and functions. (struct ns_glyph_layout, enum lgstring_direction). (enum gs_font_slant, enum gs_font_weight, enum gs_font_width) (enum gs_specified, struct gs_font_data): New enumerators and structures. (ns_font_descs_match_p) (ns_done_font_data, ns_get_font_data): New functions. (ns_glyph_metrics): Stop escaping names. (ns_spec_to_descriptor): Fix font descriptor creation for symbolic font spec entires. (ns_descriptor_to_entity): Create entries with the correct symbolic styles. (ns_fallback_entity): Fix fallback entity selection. (ns_findfonts): Use our own font matcher instead of the broken GNUstep matcher. (ns_list_family): Remove obsolete comment. (nsfont_open): Remove obsolete code, comments, and synthItal logic which doesn't work on GNUstep. (nsfont_encode_char): Use a type that can fit NSGlyph (nsfont_draw): Chose correct font, remove obsolete mouse face logic, obsolete comments, and switch to using glyph-based drawing instead of character-based drawing. (ns_font_shape, nsfont_shape): New functions. (ns_uni_to_glyphs_1): New function. (ns_uni_to_glyphs): Return glyphs instead of unicode codepoints. (ns_glyph_metrics): Use NSGlyphs instead of unicode codepoints and fix left bearing, right bearing, ascent and descent computation. (struct nsfont_driver): Add shaping capability. * src/nsterm.h (struct nsfont_info): Use unsigned int for glyph cache. * src/nsterm.m (gsaved): Make integer. (ns_focus, ns_unfocus): Set DPS clipping on GNUstep and always save GC. (ns_compute_glyph_string_overhangs): Fix overhang computation by using xterm code. (ns_draw_window_cursor): Simplify cursor drawing. (ns_maybe_dumpglyphs_background): Test for cursor HL and remove obsolete mouse face logic. (ns_dumpglyphs_image) (ns_dumpglyphs_box_or_relief) (ns_dumpglyphs_stretch): Rectify for new cursor logic. (ns_draw_glyph_string_foreground): Remove mouse face logic. (ns_draw_glyph_strings): Implement overhangs and remove obsolete comment. (ns_draw_text_decoration): Add condition for DRAW_CURSOR and simplify color selection. (ns_define_frame_cursor): Remove nonsensical code (define_frame_cursor has nothing to do with the text cursor, aka caret). * src/xdisp.c (draw_glyphs): Enable code for NS port to fix mouse face cursor display. * src/macfont.m (get_cgcolor_from_nscolor): New function. (macfont_draw): Remove obsolete mouse-face code and enable cursor display. --- src/macfont.m | 36 +- src/nsfns.m | 6 + src/nsfont.m | 1184 ++++++++++++++++++++++++++++++++++++------------- src/nsterm.h | 2 +- src/nsterm.m | 373 ++++++++-------- src/xdisp.c | 2 - 6 files changed, 1085 insertions(+), 518 deletions(-) diff --git a/src/macfont.m b/src/macfont.m index d86f09f485..df552400e3 100644 --- a/src/macfont.m +++ b/src/macfont.m @@ -613,6 +613,21 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char, return cgColor; } +static CGColorRef +get_cgcolor_from_nscolor (NSColor *nsColor, struct frame *f) +{ + [nsColor set]; + CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace]; + NSInteger noc = [nsColor numberOfComponents]; + CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc)); + CGColorRef cgColor; + + [nsColor getComponents: components]; + cgColor = CGColorCreate (colorSpace, components); + xfree (components); + return cgColor; +} + #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f) \ do { \ CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f); \ @@ -2907,14 +2922,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no if (!CGRectIsNull (background_rect)) { - if (s->hl == DRAW_MOUSE_FACE) + if (s->hl == DRAW_CURSOR) { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_CURSOR_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); } - CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); + else + CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); CGContextFillRects (context, &background_rect, 1); } @@ -2923,7 +2938,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no CGAffineTransform atfm; CGContextScaleCTM (context, 1, -1); - CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); + if (s->hl == DRAW_CURSOR) + { + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_BACKGROUND_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); + } + else + CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); if (macfont_info->synthetic_italic_p) atfm = synthetic_italic_atfm; else diff --git a/src/nsfns.m b/src/nsfns.m index 797d0ce782..f4d8172246 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -1236,6 +1236,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. "fontBackend", "FontBackend", RES_TYPE_STRING); { +#ifdef NS_IMPL_COCOA /* use for default font name */ id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */ gui_default_parameter (f, parms, Qfontsize, @@ -1250,6 +1251,11 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. build_string (fontname), "font", "Font", RES_TYPE_STRING); xfree (fontname); +#else + gui_default_parameter (f, parms, Qfont, + build_string ("fixed"), + "font", "Font", RES_TYPE_STRING); +#endif } unblock_input (); diff --git a/src/nsfont.m b/src/nsfont.m index 5a9cdfebc0..f8208b4577 100644 --- a/src/nsfont.m +++ b/src/nsfont.m @@ -1,4 +1,4 @@ -/* Font back-end driver for the NeXT/Open/GNUstep and macOS window system. +/* Font back-end driver for the GNUstep window system. See font.h Copyright (C) 2006-2021 Free Software Foundation, Inc. @@ -38,47 +38,269 @@ #include "termchar.h" #include "pdumper.h" -/* TODO: Drop once we can assume gnustep-gui 0.17.1. */ +#import #import +#import +#import +#import #define NSFONT_TRACE 0 -#define LCD_SMOOTHING_MARGIN 2 -/* Font glyph and metrics caching functions, implemented at end. */ -static void ns_uni_to_glyphs (struct nsfont_info *font_info, - unsigned char block); -static void ns_glyph_metrics (struct nsfont_info *font_info, - unsigned char block); +/* Structure used by GS `shape' functions for storing layout + information for each glyph. Borrowed from macfont.h. */ +struct ns_glyph_layout +{ + /* Range of indices of the characters composed into the group of + glyphs that share the cursor position with this glyph. The + members `location' and `length' are in UTF-16 indices. */ + NSRange comp_range; -#define INVALID_GLYPH 0xFFFF + /* UTF-16 index in the source string for the first character + associated with this glyph. */ + NSUInteger string_index; -/* ========================================================================== + /* Horizontal and vertical adjustments of glyph position. The + coordinate space is that of Core Text. So, the `baseline_delta' + value is negative if the glyph should be placed below the + baseline. */ + CGFloat advance_delta, baseline_delta; - Utilities + /* Typographical width of the glyph. */ + CGFloat advance; - ========================================================================== */ + /* Glyph ID of the glyph. */ + NSGlyph glyph_id; +}; + + +enum lgstring_direction + { + DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1 + }; + +enum gs_font_slant + { + GS_FONT_SLANT_ITALIC, + GS_FONT_SLANT_REVERSE_ITALIC, + GS_FONT_SLANT_NORMAL + }; + +enum gs_font_weight + { + GS_FONT_WEIGHT_LIGHT, + GS_FONT_WEIGHT_BOLD, + GS_FONT_WEIGHT_NORMAL + }; +enum gs_font_width + { + GS_FONT_WIDTH_CONDENSED, + GS_FONT_WIDTH_EXPANDED, + GS_FONT_WIDTH_NORMAL + }; + +enum gs_specified + { + GS_SPECIFIED_SLANT = 1, + GS_SPECIFIED_WEIGHT = 1 << 1, + GS_SPECIFIED_WIDTH = 1 << 2, + GS_SPECIFIED_FAMILY = 1 << 3, + GS_SPECIFIED_SPACING = 1 << 4 + }; + +struct gs_font_data +{ + int specified; + enum gs_font_slant slant; + enum gs_font_weight weight; + enum gs_font_width width; + bool monospace_p; + char *family_name; +}; -/* Replace spaces w/another character so emacs core font parsing routines - aren't thrown off. */ static void -ns_escape_name (char *name) +ns_done_font_data (struct gs_font_data *data) { - for (; *name; name++) - if (*name == ' ') - *name = '_'; + if (data->specified & GS_SPECIFIED_FAMILY) + xfree (data->family_name); } - -/* Reconstruct spaces in a font family name passed through emacs. */ static void -ns_unescape_name (char *name) +ns_get_font_data (NSFontDescriptor *desc, struct gs_font_data *dat) +{ + NSNumber *tem; + NSFontSymbolicTraits traits = [desc symbolicTraits]; + NSDictionary *dict = [desc objectForKey: NSFontTraitsAttribute]; + NSString *family = [desc objectForKey: NSFontFamilyAttribute]; + + dat->specified = 0; + + if (family != nil) + { + dat->specified |= GS_SPECIFIED_FAMILY; + dat->family_name = xstrdup ([family cStringUsingEncoding: NSUTF8StringEncoding]); + } + + tem = [desc objectForKey: NSFontFixedAdvanceAttribute]; + + if ((tem != nil && [tem boolValue] != NO) + || (traits & NSFontMonoSpaceTrait)) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = true; + } + else if (tem != nil && [tem boolValue] == NO) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = false; + } + + if (traits & NSFontBoldTrait) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + dat->weight = GS_FONT_WEIGHT_BOLD; + } + + if (traits & NSFontItalicTrait) + { + dat->specified |= GS_SPECIFIED_SLANT; + dat->slant = GS_FONT_SLANT_ITALIC; + } + + if (traits & NSFontCondensedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_CONDENSED; + } + else if (traits & NSFontExpandedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_EXPANDED; + } + + if (dict != nil) + { + tem = [dict objectForKey: NSFontSlantTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_SLANT; + + dat->slant = [tem floatValue] > 0 + ? GS_FONT_SLANT_ITALIC + : ([tem floatValue] < 0 + ? GS_FONT_SLANT_REVERSE_ITALIC + : GS_FONT_SLANT_NORMAL); + } + + tem = [dict objectForKey: NSFontWeightTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + + dat->weight = [tem floatValue] > 0 + ? GS_FONT_WEIGHT_BOLD + : ([tem floatValue] < -0.4f + ? GS_FONT_WEIGHT_LIGHT + : GS_FONT_WEIGHT_NORMAL); + } + + tem = [dict objectForKey: NSFontWidthTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WIDTH; + + dat->width = [tem floatValue] > 0 + ? GS_FONT_WIDTH_EXPANDED + : ([tem floatValue] < 0 + ? GS_FONT_WIDTH_NORMAL + : GS_FONT_WIDTH_CONDENSED); + } + } +} + +static bool +ns_font_descs_match_p (NSFontDescriptor *desc, NSFontDescriptor *target) { - for (; *name; name++) - if (*name == '_') - *name = ' '; + struct gs_font_data dat; + struct gs_font_data t; + + ns_get_font_data (desc, &dat); + ns_get_font_data (target, &t); + + if (!(t.specified & GS_SPECIFIED_WIDTH)) + t.width = GS_FONT_WIDTH_NORMAL; + if (!(t.specified & GS_SPECIFIED_WEIGHT)) + t.weight = GS_FONT_WEIGHT_NORMAL; + if (!(t.specified & GS_SPECIFIED_SPACING)) + t.monospace_p = false; + if (!(t.specified & GS_SPECIFIED_SLANT)) + t.slant = GS_FONT_SLANT_NORMAL; + + if (!(t.specified & GS_SPECIFIED_FAMILY)) + emacs_abort (); + + bool match_p = true; + + if (dat.specified & GS_SPECIFIED_WIDTH + && dat.width != t.width) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_WEIGHT + && dat.weight != t.weight) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SPACING + && dat.monospace_p != t.monospace_p) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SLANT + && dat.monospace_p != t.monospace_p) + { + if (NSFONT_TRACE) + printf ("Matching monospace for %s: %d %d\n", + t.family_name, dat.monospace_p, + t.monospace_p); + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_FAMILY + && strcmp (dat.family_name, t.family_name)) + match_p = false; + + gout: + ns_done_font_data (&dat); + ns_done_font_data (&t); + + return match_p; } +/* Font glyph and metrics caching functions, implemented at end. */ +static void ns_uni_to_glyphs (struct nsfont_info *font_info, + unsigned char block); +static void ns_glyph_metrics (struct nsfont_info *font_info, + unsigned int block); + +#define INVALID_GLYPH 0xFFFF + +/* ========================================================================== + + Utilities + + ========================================================================== */ + /* Extract family name from a font spec. */ static NSString * @@ -91,66 +313,116 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, { char *tmp = xlispstrdup (SYMBOL_NAME (tem)); NSString *family; - ns_unescape_name (tmp); family = [NSString stringWithUTF8String: tmp]; xfree (tmp); return family; } } - -/* Return 0 if attr not set, else value (which might also be 0). - On Leopard 0 gets returned even on descriptors where the attribute - was never set, so there's no way to distinguish between unspecified - and set to not have. Callers should assume 0 means unspecified. */ -static float -ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait) -{ - NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute]; - NSNumber *val = [tdict objectForKey: trait]; - return val == nil ? 0.0F : [val floatValue]; -} - - /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang to NSFont descriptor. Information under extra only needed for matching. */ -#define STYLE_REF 100 static NSFontDescriptor * ns_spec_to_descriptor (Lisp_Object font_spec) { NSFontDescriptor *fdesc; NSMutableDictionary *fdAttrs = [NSMutableDictionary new]; - NSMutableDictionary *tdict = [NSMutableDictionary new]; NSString *family = ns_get_family (font_spec); - float n; - - /* Add each attr in font_spec to fdAttrs. */ - n = min (FONT_WEIGHT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWeightTrait]; - n = min (FONT_SLANT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontSlantTrait]; - n = min (FONT_WIDTH_NUMERIC (font_spec), 200); - if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10)) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWidthTrait]; - if ([tdict count] > 0) - [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + NSMutableDictionary *tdict = [NSMutableDictionary new]; - fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] - retain] autorelease]; + Lisp_Object tem; + + tem = FONT_SLANT_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qitalic) || EQ (tem, Qoblique)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontSlantTrait]; + else if (EQ (tem, intern ("reverse-italic")) || + EQ (tem, intern ("reverse-oblique"))) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontSlantTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontSlantTrait]; + } + + tem = FONT_WIDTH_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qcondensed)) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWidthTrait]; + else if (EQ (tem, Qexpanded)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWidthTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWidthTrait]; + } + + tem = FONT_WEIGHT_SYMBOLIC (font_spec); + + if (!NILP (tem)) + { + if (EQ (tem, Qbold)) + { + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWeightTrait]; + } + else if (EQ (tem, Qlight)) + { + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWeightTrait]; + } + else + { + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWeightTrait]; + } + } + + tem = AREF (font_spec, FONT_SPACING_INDEX); if (family != nil) { - NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family]; - fdesc = [[fdesc2 retain] autorelease]; + [fdAttrs setObject: family + forKey: NSFontFamilyAttribute]; } - [fdAttrs release]; + if (FIXNUMP (tem)) + { + if (XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL) + { + [fdAttrs setObject: [NSNumber numberWithBool:YES] + forKey: NSFontFixedAdvanceAttribute]; + } + else + { + [fdAttrs setObject: [NSNumber numberWithBool:NO] + forKey: NSFontFixedAdvanceAttribute]; + } + } + + /* Handle special families such as ``fixed'' or ``Sans Serif''. */ + + if ([family isEqualToString: @"fixed"]) + { + [fdAttrs setObject: [[NSFont userFixedPitchFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + else if ([family isEqualToString: @"Sans Serif"]) + { + [fdAttrs setObject: [[NSFont userFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + + [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + + fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] + retain] autorelease]; + [tdict release]; + [fdAttrs release]; return fdesc; } @@ -161,61 +433,64 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, Lisp_Object extra, const char *style) { - Lisp_Object font_entity = font_make_entity (); - /* NSString *psName = [desc postscriptName]; */ - NSString *family = [desc objectForKey: NSFontFamilyAttribute]; - unsigned int traits = [desc symbolicTraits]; - char *escapedFamily; - - /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */ - if (family == nil) - family = [desc objectForKey: NSFontNameAttribute]; - if (family == nil) - family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - - escapedFamily = xstrdup ([family UTF8String]); - ns_escape_name (escapedFamily); - - ASET (font_entity, FONT_TYPE_INDEX, Qns); - ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple); - ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily)); - ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); - ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); - - FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - traits & NSFontBoldTrait ? Qbold : Qmedium); -/* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - traits & NSFontItalicTrait ? Qitalic : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - traits & NSFontCondensedTrait ? Qcondensed : - traits & NSFontExpandedTrait ? Qexpanded : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/ - - ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_SPACING_INDEX, - make_fixnum([desc symbolicTraits] & NSFontMonoSpaceTrait - ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); - - ASET (font_entity, FONT_EXTRA_INDEX, extra); - ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + Lisp_Object font_entity = font_make_entity (); + struct gs_font_data data; + ns_get_font_data (desc, &data); + + ASET (font_entity, FONT_TYPE_INDEX, Qns); + ASET (font_entity, FONT_FOUNDRY_INDEX, Qns); + if (data.specified & GS_SPECIFIED_FAMILY) + ASET (font_entity, FONT_FAMILY_INDEX, intern (data.family_name)); + ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); + ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); + + if (data.specified & GS_SPECIFIED_WEIGHT) + { + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, + data.weight == GS_FONT_WEIGHT_BOLD + ? Qbold : (data.weight == GS_FONT_WEIGHT_LIGHT + ? Qlight : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, Qnormal); - if (NSFONT_TRACE) - { - fputs ("created font_entity:\n ", stderr); - debug_print (font_entity); - } + if (data.specified & GS_SPECIFIED_SLANT) + { + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, + data.slant == GS_FONT_SLANT_ITALIC + ? Qitalic : (data.slant == GS_FONT_SLANT_REVERSE_ITALIC + ? intern ("reverse-italic") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, Qnormal); - xfree (escapedFamily); - return font_entity; + if (data.specified & GS_SPECIFIED_WIDTH) + { + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, + data.width == GS_FONT_WIDTH_CONDENSED + ? Qcondensed : (data.width == GS_FONT_WIDTH_EXPANDED + ? intern ("expanded") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, Qnormal); + + ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_SPACING_INDEX, + make_fixnum ((data.specified & GS_SPECIFIED_WIDTH && data.monospace_p) + ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); + + ASET (font_entity, FONT_EXTRA_INDEX, extra); + ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + + if (NSFONT_TRACE) + { + fputs ("created font_entity:\n ", stderr); + debug_print (font_entity); + } + + ns_done_font_data (&data); + return font_entity; } @@ -223,8 +498,7 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, static Lisp_Object ns_fallback_entity (void) { - return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0] - fontDescriptor], Qnil, NULL); + return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 1] fontDescriptor], Qnil, NULL); } @@ -510,21 +784,20 @@ but also for ascii (which causes unnecessary font substitution). */ return families; } +/* GNUstep font matching is very mediocre (it can't even compare + symbolic styles correctly), which is why our own font matching + mechanism must be implemented. */ -/* Implementation for list() and match(). List() can return nil, match() -must return something. Strategy is to drop family name from attribute -matching set for match. */ +/* Implementation for list and match. */ static Lisp_Object ns_findfonts (Lisp_Object font_spec, BOOL isMatch) { Lisp_Object tem, list = Qnil; - NSFontDescriptor *fdesc, *desc; - NSMutableSet *fkeys; - NSArray *matchingDescs; - NSEnumerator *dEnum; - NSString *family; + NSFontDescriptor *fdesc; + NSArray *all_descs; + GSFontEnumerator *enumerator = [GSFontEnumerator sharedEnumerator]; + NSSet *cFamilies; - BOOL foundItal = NO; block_input (); if (NSFONT_TRACE) @@ -537,43 +810,22 @@ but also for ascii (which causes unnecessary font substitution). */ cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90); fdesc = ns_spec_to_descriptor (font_spec); - fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]]; - if (isMatch) - [fkeys removeObject: NSFontFamilyAttribute]; - - matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys]; + all_descs = [enumerator availableFontDescriptors]; - if (NSFONT_TRACE) - NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc, - (unsigned long)[matchingDescs count]); - - for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);) + for (NSFontDescriptor *desc in all_descs) { if (![cFamilies containsObject: [desc objectForKey: NSFontFamilyAttribute]]) continue; + if (!ns_font_descs_match_p (fdesc, desc)) + continue; + tem = ns_descriptor_to_entity (desc, - AREF (font_spec, FONT_EXTRA_INDEX), + AREF (font_spec, FONT_EXTRA_INDEX), NULL); if (isMatch) return tem; list = Fcons (tem, list); - if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05) - foundItal = YES; - } - - /* Add synthItal member if needed. */ - family = [fdesc objectForKey: NSFontFamilyAttribute]; - if (family != nil && !foundItal && !NILP (list)) - { - NSFontDescriptor *s1 = [NSFontDescriptor new]; - NSFontDescriptor *sDesc - = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait] - fontDescriptorWithFamily: family]; - list = Fcons (ns_descriptor_to_entity (sDesc, - AREF (font_spec, FONT_EXTRA_INDEX), - "synthItal"), list); - [s1 release]; } unblock_input (); @@ -652,7 +904,6 @@ Properties to be considered are same as for list(). */ objectEnumerator]; while ((family = [families nextObject])) list = Fcons (intern ([family UTF8String]), list); - /* FIXME: escape the name? */ if (NSFONT_TRACE) fprintf (stderr, "nsfont: list families returning %"pD"d entries\n", @@ -668,18 +919,15 @@ Properties to be considered are same as for list(). */ static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size) { - BOOL synthItal; - unsigned int traits = 0; struct nsfont_info *font_info; struct font *font; NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity); NSFontManager *fontMgr = [NSFontManager sharedFontManager]; NSString *family; NSFont *nsfont, *sfont; - Lisp_Object tem; NSRect brect; Lisp_Object font_object; - int fixLeopardBug; + Lisp_Object tem; block_input (); @@ -692,42 +940,20 @@ Properties to be considered are same as for list(). */ if (pixel_size <= 0) { /* try to get it out of frame params */ - Lisp_Object tem = get_frame_param (f, Qfontsize); - pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); + tem = get_frame_param (f, Qfontsize); + pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); } tem = AREF (font_entity, FONT_ADSTYLE_INDEX); - synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)), - 9); family = ns_get_family (font_entity); if (family == nil) family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that - when setting family in ns_spec_to_descriptor(). */ - if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F) - traits |= NSBoldFontMask; - if (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F) - traits |= NSItalicFontMask; - - /* see https://web.archive.org/web/20100201175731/http://cocoadev.com/forums/comments.php?DiscussionID=74 */ - fixLeopardBug = traits & NSBoldFontMask ? 10 : 5; - nsfont = [fontMgr fontWithFamily: family - traits: traits weight: fixLeopardBug - size: pixel_size]; - /* if didn't find, try synthetic italic */ - if (nsfont == nil && synthItal) - { - nsfont = [fontMgr fontWithFamily: family - traits: traits & ~NSItalicFontMask - weight: fixLeopardBug size: pixel_size]; - } + + nsfont = [NSFont fontWithDescriptor: fontDesc + size: pixel_size]; if (nsfont == nil) - { - message_with_string ("*** Warning: font in family `%s' not found", - build_string ([family UTF8String]), 1); - nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; - } + nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; if (NSFONT_TRACE) NSLog (@"%@\n", nsfont); @@ -740,7 +966,7 @@ when setting family in ns_spec_to_descriptor(). */ if (!font) { unblock_input (); - return Qnil; /* FIXME: other terms do, but returning Qnil causes segfault. */ + return Qnil; } font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs); @@ -781,7 +1007,7 @@ when setting family in ns_spec_to_descriptor(). */ font_info->name = xstrdup (fontName); font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask; font_info->ital = - synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); + ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); /* Metrics etc.; some fonts return an unusually large max advance, so we only use it for fonts that have wide characters. */ @@ -808,8 +1034,6 @@ when setting family in ns_spec_to_descriptor(). */ lrint (brect.size.width - (CGFloat) font_info->width); /* set up metrics portion of font struct */ - font->ascent = lrint([sfont ascender]); - font->descent = -lrint(floor(adjusted_descender)); font->space_width = lrint (ns_char_width (sfont, ' ')); font->max_width = lrint (font_info->max_bounds.width); font->min_width = font->space_width; /* Approximate. */ @@ -871,7 +1095,7 @@ when setting family in ns_spec_to_descriptor(). */ { struct nsfont_info *font_info = (struct nsfont_info *)font; unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff; - unsigned short g; + unsigned int g; if (c > 0xFFFF) return FONT_INVALID_CODE; @@ -934,51 +1158,26 @@ is false when (FROM > 0 || TO < S->nchars). */ static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, bool with_background) -/* NOTE: focus and clip must be set. */ { - static unsigned char cbuf[1024]; - unsigned char *c = cbuf; -#if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22 - static CGFloat advances[1024]; - CGFloat *adv = advances; -#else - static float advances[1024]; - float *adv = advances; -#endif + NSGlyph *c = alloca ((to - from) * sizeof *c); + NSSize *adv = alloca ((to - from) * sizeof *adv); + NSSize *advances = adv; + struct face *face; NSRect r; struct nsfont_info *font; - NSColor *col, *bgCol; + NSColor *col; unsigned *t = s->char2b; - int i, len, flags; + int i, len; char isComposite = s->first_glyph->type == COMPOSITE_GLYPH; block_input (); - font = (struct nsfont_info *)s->face->font; + font = (struct nsfont_info *) s->font; if (font == NULL) font = (struct nsfont_info *)FRAME_FONT (s->f); - /* Select face based on input flags. */ - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - - switch (flags) - { - case NS_DUMPGLYPH_CURSOR: - face = s->face; - break; - case NS_DUMPGLYPH_MOUSEFACE: - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - break; - default: - face = s->face; - } + face = s->face; r.origin.x = s->x; if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p) @@ -987,16 +1186,15 @@ is false when (FROM > 0 || TO < S->nchars). */ r.origin.y = s->y; r.size.height = FONT_HEIGHT (font); - /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask - NS to render the string, it will come out differently from the individual - character widths added up because of layout processing. */ + /* Determine advances. */ { int cwidth, twidth = 0; int hi, lo; - /* FIXME: composition: no vertical displacement is considered. */ + t += from; /* advance into composition */ for (i = from; i < to; i++, t++) { + c[i - from] = *t; hi = (*t & 0xFF00) >> 8; lo = *t & 0x00FF; if (isComposite) @@ -1012,7 +1210,7 @@ is false when (FROM > 0 || TO < S->nchars). */ else { cwidth = LGLYPH_WADJUST (glyph); - *(adv-1) += LGLYPH_XOFF (glyph); + (adv - 1)->width += LGLYPH_XOFF (glyph); } } } @@ -1023,55 +1221,27 @@ is false when (FROM > 0 || TO < S->nchars). */ cwidth = font->metrics[hi][lo].width; } twidth += cwidth; - *adv++ = cwidth; - c += CHAR_STRING (*t, c); /* This converts the char to UTF-8. */ + adv++->width = cwidth; } len = adv - advances; r.size.width = twidth; - *c = 0; } /* Fill background if requested. */ if (with_background && !isComposite) { - NSRect br = r; - int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); - int mbox_line_width = max (s->face->box_vertical_line_width, 0); - - if (s->row->full_width_p) - { - if (br.origin.x <= fibw + 1 + mbox_line_width) - { - br.size.width += br.origin.x - mbox_line_width; - br.origin.x = mbox_line_width; - } - if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) - <= fibw+1) - br.size.width += fibw; - } - if (s->face->box == FACE_NO_BOX) - { - /* Expand unboxed top row over internal border. */ - if (br.origin.y <= fibw + 1 + mbox_line_width) - { - br.size.height += br.origin.y; - br.origin.y = 0; - } - } - else - { - int correction = abs (s->face->box_horizontal_line_width)+1; - br.origin.y += correction; - br.size.height -= 2*correction; - correction = abs (s->face->box_vertical_line_width)+1; - br.origin.x += correction; - br.size.width -= 2*correction; - } + NSRect br = NSMakeRect (x, y - FONT_BASE (s->font), + s->width, FONT_HEIGHT (s->font)); if (!s->face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); @@ -1080,43 +1250,32 @@ is false when (FROM > 0 || TO < S->nchars). */ NSRectFill (br); } - /* set up for character rendering */ r.origin.y = y; - col = (NS_FACE_FOREGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - - bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil - : (NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f))); + if (s->hl == DRAW_CURSOR) + col = FRAME_BACKGROUND_COLOR (s->f); + else + col = (NS_FACE_FOREGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) + : FRAME_FOREGROUND_COLOR (s->f)); /* render under GNUstep using DPS */ { - NSGraphicsContext *context = GSCurrentContext (); - + NSGraphicsContext *context = [NSGraphicsContext currentContext]; DPSgsave (context); - [font->nsfont set]; - - /* do erase if "foreground" mode */ - if (bgCol != nil) + if (s->clip_head) { - [bgCol set]; - DPSmoveto (context, r.origin.x, r.origin.y); -/*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */ - DPSxshow (context, (const char *) cbuf, advances, len); - DPSstroke (context); - [col set]; -/*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */ + DPSrectclip (context, s->clip_head->x, 0, + FRAME_PIXEL_WIDTH (s->f), + FRAME_PIXEL_HEIGHT (s->f)); } + [font->nsfont set]; [col set]; - /* draw with DPSxshow () */ DPSmoveto (context, r.origin.x, r.origin.y); - DPSxshow (context, (const char *) cbuf, advances, len); + GSShowGlyphsWithAdvances (context, c, advances, len); DPSstroke (context); DPSgrestore (context); @@ -1126,6 +1285,360 @@ is false when (FROM > 0 || TO < S->nchars). */ return to-from; } +static NSUInteger +ns_font_shape (NSFont *font, NSString *string, + struct ns_glyph_layout *glyph_layouts, NSUInteger glyph_len, + enum lgstring_direction dir) +{ + NSUInteger i; + NSUInteger result = 0; + NSTextStorage *textStorage; + NSLayoutManager *layoutManager; + NSTextContainer *textContainer; + NSUInteger stringLength; + NSPoint spaceLocation; + /* numberOfGlyphs can't actually be 0, but this pacifies GCC */ + NSUInteger used, numberOfGlyphs = 0; + + textStorage = [[NSTextStorage alloc] initWithString:string]; + layoutManager = [[NSLayoutManager alloc] init]; + textContainer = [[NSTextContainer alloc] init]; + + /* Append a trailing space to measure baseline position. */ + [textStorage appendAttributedString:([[[NSAttributedString alloc] + initWithString:@" "] autorelease])]; + [textStorage setFont:font]; + [textContainer setLineFragmentPadding:0]; + + [layoutManager addTextContainer:textContainer]; + [textContainer release]; + [textStorage addLayoutManager:layoutManager]; + [layoutManager release]; + + if (!(textStorage && layoutManager && textContainer)) + emacs_abort (); + + stringLength = [string length]; + + /* Force layout. */ + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength]; + + /* Remove the appended trailing space because otherwise it may + generate a wrong result for a right-to-left text. */ + [textStorage beginEditing]; + [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))]; + [textStorage endEditing]; + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + i = 0; + while (i < stringLength) + { + NSRange range; + NSFont *fontInTextStorage = + [textStorage attribute: NSFontAttributeName + atIndex:i + longestEffectiveRange: &range + inRange: NSMakeRange (0, stringLength)]; + + if (!(fontInTextStorage == font + || [[fontInTextStorage fontName] isEqualToString:[font fontName]])) + break; + i = NSMaxRange (range); + } + if (i < stringLength) + /* Make the test `used <= glyph_len' below fail if textStorage + contained some fonts other than the specified one. */ + used = glyph_len + 1; + else + { + NSRange range = NSMakeRange (0, stringLength); + + range = [layoutManager glyphRangeForCharacterRange:range + actualCharacterRange:NULL]; + numberOfGlyphs = NSMaxRange (range); + used = numberOfGlyphs; + for (i = 0; i < numberOfGlyphs; i++) + if ([layoutManager notShownAttributeForGlyphAtIndex:i]) + used--; + } + + if (0 < used && used <= glyph_len) + { + NSUInteger glyphIndex, prevGlyphIndex; + NSUInteger *permutation; + NSRange compRange, range; + CGFloat totalAdvance; + + glyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + permutation = NULL; +#define RIGHT_TO_LEFT_P permutation + + /* Fill the `comp_range' member of struct mac_glyph_layout, and + setup a permutation for right-to-left text. */ + compRange = NSMakeRange (0, 0); + for (range = NSMakeRange (0, 0); NSMaxRange (range) < used; + range.length++) + { + struct ns_glyph_layout *gl = glyph_layouts + NSMaxRange (range); + NSUInteger characterIndex = + [layoutManager characterIndexForGlyphAtIndex:glyphIndex]; + + gl->string_index = characterIndex; + + if (characterIndex >= NSMaxRange (compRange)) + { + compRange.location = NSMaxRange (compRange); + do + { + NSRange characterRange = + [string + rangeOfComposedCharacterSequenceAtIndex:characterIndex]; + + compRange.length = + NSMaxRange (characterRange) - compRange.location; + [layoutManager glyphRangeForCharacterRange:compRange + actualCharacterRange:&characterRange]; + characterIndex = NSMaxRange (characterRange) - 1; + } + while (characterIndex >= NSMaxRange (compRange)); + + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + range = NSMakeRange (NSMaxRange (range), 0); + } + + gl->comp_range.location = compRange.location; + gl->comp_range.length = compRange.length; + + while (++glyphIndex < numberOfGlyphs) + if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + break; + } + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + /* Then fill the remaining members. */ + glyphIndex = prevGlyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + if (!RIGHT_TO_LEFT_P) + totalAdvance = 0; + else + { + NSUInteger nrects; + NSRect *glyphRects = + [layoutManager + rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs)) + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + + totalAdvance = NSMaxX (glyphRects[0]); + } + + for (i = 0; i < used; i++) + { + struct ns_glyph_layout *gl; + NSPoint location; + NSUInteger nextGlyphIndex; + NSRange glyphRange; + NSRect *glyphRects; + NSUInteger nrects; + + if (!RIGHT_TO_LEFT_P) + gl = glyph_layouts + i; + else + { + NSUInteger dest = permutation[i]; + + gl = glyph_layouts + dest; + if (i < dest) + { + NSUInteger tmp = gl->string_index; + + gl->string_index = glyph_layouts[i].string_index; + glyph_layouts[i].string_index = tmp; + } + } + gl->glyph_id = [layoutManager glyphAtIndex: glyphIndex]; + + location = [layoutManager locationForGlyphAtIndex:glyphIndex]; + gl->baseline_delta = spaceLocation.y - location.y; + + for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs; + nextGlyphIndex++) + if (![layoutManager + notShownAttributeForGlyphAtIndex:nextGlyphIndex]) + break; + + if (!RIGHT_TO_LEFT_P) + { + CGFloat maxX; + + if (prevGlyphIndex == 0) + glyphRange = NSMakeRange (0, nextGlyphIndex); + else + glyphRange = NSMakeRange (glyphIndex, + nextGlyphIndex - glyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + maxX = max (NSMaxX (glyphRects[0]), totalAdvance); + gl->advance_delta = location.x - totalAdvance; + gl->advance = maxX - totalAdvance; + totalAdvance = maxX; + } + else + { + CGFloat minX; + + if (nextGlyphIndex == numberOfGlyphs) + glyphRange = NSMakeRange (prevGlyphIndex, + numberOfGlyphs - prevGlyphIndex); + else + glyphRange = NSMakeRange (prevGlyphIndex, + glyphIndex + 1 - prevGlyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + minX = min (NSMinX (glyphRects[0]), totalAdvance); + gl->advance = totalAdvance - minX; + totalAdvance = minX; + gl->advance_delta = location.x - totalAdvance; + } + + prevGlyphIndex = glyphIndex + 1; + glyphIndex = nextGlyphIndex; + } + + if (RIGHT_TO_LEFT_P) + xfree (permutation); + +#undef RIGHT_TO_LEFT_P + + result = used; + } + [textStorage release]; + + return result; +} + +static Lisp_Object +nsfont_shape (Lisp_Object lgstring, Lisp_Object direction) +{ + struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring)); + struct nsfont_info *font_info = (struct nsfont_info *) font; + struct ns_glyph_layout *glyph_layouts; + NSFont *nsfont = font_info->nsfont; + ptrdiff_t glyph_len, len, i; + Lisp_Object tem; + unichar *mb_buf; + NSUInteger used; + + glyph_len = LGSTRING_GLYPH_LEN (lgstring); + for (i = 0; i < glyph_len; ++i) + { + tem = LGSTRING_GLYPH (lgstring, i); + + if (NILP (tem)) + break; + } + + len = i; + + if (INT_MAX / 2 < len) + memory_full (SIZE_MAX); + + block_input (); + + mb_buf = alloca (len * sizeof *mb_buf); + + for (i = 0; i < len; ++i) + { + uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i)); + mb_buf[i] = (unichar) c; + } + + NSString *string = [NSString stringWithCharacters: mb_buf + length: len]; + unblock_input (); + + if (!string) + return Qnil; + + block_input (); + + enum lgstring_direction dir = DIR_UNKNOWN; + + if (EQ (direction, QL2R)) + dir = DIR_L2R; + else if (EQ (direction, QR2L)) + dir = DIR_R2L; + glyph_layouts = alloca (sizeof (struct ns_glyph_layout) * glyph_len); + used = ns_font_shape (nsfont, string, glyph_layouts, glyph_len, dir); + + for (i = 0; i < used; i++) + { + Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i); + struct ns_glyph_layout *gl = glyph_layouts + i; + EMACS_INT from, to; + struct font_metrics metrics; + + if (NILP (lglyph)) + { + lglyph = LGLYPH_NEW (); + LGSTRING_SET_GLYPH (lgstring, i, lglyph); + } + + from = gl->comp_range.location; + LGLYPH_SET_FROM (lglyph, from); + + to = gl->comp_range.location + gl->comp_range.length; + LGLYPH_SET_TO (lglyph, to - 1); + + /* LGLYPH_CHAR is used in `describe-char' for checking whether + the composition is trivial. */ + { + UTF32Char c; + + if (mb_buf[gl->string_index] >= 0xD800 + && mb_buf[gl->string_index] < 0xDC00) + c = (((mb_buf[gl->string_index] - 0xD800) << 10) + + (mb_buf[gl->string_index + 1] - 0xDC00) + 0x10000); + else + c = mb_buf[gl->string_index]; + + LGLYPH_SET_CHAR (lglyph, c); + } + + { + unsigned long cc = gl->glyph_id; + LGLYPH_SET_CODE (lglyph, cc); + } + + nsfont_text_extents (font, &gl->glyph_id, 1, &metrics); + LGLYPH_SET_WIDTH (lglyph, metrics.width); + LGLYPH_SET_LBEARING (lglyph, metrics.lbearing); + LGLYPH_SET_RBEARING (lglyph, metrics.rbearing); + LGLYPH_SET_ASCENT (lglyph, metrics.ascent); + LGLYPH_SET_DESCENT (lglyph, metrics.descent); + } + unblock_input (); + + return make_fixnum (used); +} /* ========================================================================== @@ -1134,6 +1647,50 @@ is false when (FROM > 0 || TO < S->nchars). */ ========================================================================== */ +static NSGlyph +ns_uni_to_glyphs_1 (struct nsfont_info *info, unsigned int c) +{ + unichar characters[] = { c }; + NSString *string = + [NSString stringWithCharacters: characters + length: 1]; + NSDictionary *attributes = + [NSDictionary dictionaryWithObjectsAndKeys: + info->nsfont, NSFontAttributeName, nil]; + NSTextStorage *storage = [[NSTextStorage alloc] initWithString: string + attributes: attributes]; + NSTextContainer *text_container = [[NSTextContainer alloc] init]; + NSLayoutManager *manager = [[NSLayoutManager alloc] init]; + + [manager addTextContainer: text_container]; + [text_container release]; /* Retained by manager */ + [storage addLayoutManager: manager]; + [manager release]; /* Retained by storage */ + + NSFont *font_in_storage = [storage attribute: NSFontAttributeName + atIndex:0 + effectiveRange: NULL]; + NSGlyph glyph = FONT_INVALID_CODE; + + if ((font_in_storage == info->nsfont + || [[font_in_storage fontName] isEqualToString: [info->nsfont fontName]])) + { + @try + { + glyph = [manager glyphAtIndex: 0]; + } + @catch (NSException *e) + { + /* GNUstep bug? */ + glyph = 'X'; + } + } + + [storage release]; + + return glyph; +} + /* Find and cache corresponding glyph codes for unicode values in given hi-byte block of 256. */ static void @@ -1141,7 +1698,7 @@ is false when (FROM > 0 || TO < S->nchars). */ { unichar *unichars = xmalloc (0x101 * sizeof (unichar)); unsigned int i, g, idx; - unsigned short *glyphs; + unsigned int *glyphs; if (NSFONT_TRACE) fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n", @@ -1149,7 +1706,7 @@ is false when (FROM > 0 || TO < S->nchars). */ block_input (); - font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short)); + font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned int)); if (!unichars || !(font_info->glyphs[block])) emacs_abort (); @@ -1166,7 +1723,8 @@ is false when (FROM > 0 || TO < S->nchars). */ for (i = 0; i < 0x100; i++, glyphs++) { g = unichars[i]; - *glyphs = g; + NSGlyph glyph = ns_uni_to_glyphs_1 (font_info, g); + *glyphs = glyph; } } @@ -1175,18 +1733,19 @@ is false when (FROM > 0 || TO < S->nchars). */ } -/* Determine and cache metrics for corresponding glyph codes in given - hi-byte block of 256. */ +/* Determine and cache metrics for glyphs in given hi-byte block of + 256. */ static void -ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block) +ns_glyph_metrics (struct nsfont_info *font_info, unsigned int block) { - unsigned int i, g; + unsigned int i; + NSGlyph g; unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs]; NSFont *sfont; struct font_metrics *metrics; if (NSFONT_TRACE) - fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n", + fprintf (stderr, "%p\tComputing metrics for glyphs in block %u\n", font_info, block); /* not implemented yet (as of startup 0.18), so punt */ @@ -1209,19 +1768,14 @@ is false when (FROM > 0 || TO < S->nchars). */ w = max ([sfont advancementForGlyph: g].width, 2.0); metrics->width = lrint (w); - lb = r.origin.x; - rb = r.size.width - w; - // Add to bearing for LCD smoothing. We don't know if it is there. - if (lb < 0) - metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN); - if (font_info->ital) - rb += (CGFloat) (0.22F * font_info->height); - metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN); - - metrics->descent = r.origin.y < 0 ? -r.origin.y : 0; - /* lrint (hshrink * [sfont ascender] + expand * hd/2); */ - metrics->ascent = r.size.height - metrics->descent; - /* -lrint (hshrink* [sfont descender] - expand * hd/2); */ + lb = NSMinX (r); + rb = NSMaxX (r); + + metrics->rbearing = lrint (rb); + metrics->lbearing = lrint (lb); + + metrics->descent = NSMinY (r); + metrics->ascent = NSMaxY (r); } unblock_input (); } @@ -1257,6 +1811,7 @@ is false when (FROM > 0 || TO < S->nchars). */ .has_char = nsfont_has_char, .encode_char = nsfont_encode_char, .text_extents = nsfont_text_extents, + .shape = nsfont_shape, .draw = nsfont_draw, }; @@ -1265,7 +1820,6 @@ is false when (FROM > 0 || TO < S->nchars). */ { DEFSYM (Qcondensed, "condensed"); DEFSYM (Qexpanded, "expanded"); - DEFSYM (Qapple, "apple"); DEFSYM (Qmedium, "medium"); DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script, doc: /* Internal use: maps font registry to Unicode script. */); diff --git a/src/nsterm.h b/src/nsterm.h index 4bbcf43973..944dbd727c 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -820,7 +820,7 @@ #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) XCharStruct max_bounds; /* We compute glyph codes and metrics on-demand in blocks of 256 indexed by hibyte, lobyte. */ - unsigned short **glyphs; /* map Unicode index to glyph */ + unsigned int **glyphs; /* map Unicode index to glyph */ struct font_metrics **metrics; }; #endif diff --git a/src/nsterm.m b/src/nsterm.m index ed692f95a2..957cd815a0 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -270,7 +270,7 @@ - (NSColor *)colorUsingDefaultColorSpace /* display update */ static struct frame *ns_updating_frame; static int ns_window_num = 0; -static BOOL gsaved = NO; +static int gsaved = 0; #ifdef NS_IMPL_COCOA static BOOL ns_menu_bar_is_hidden = NO; #endif @@ -1074,15 +1074,25 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) [view lockFocus]; } + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; + gsaved++; + /* clipping */ if (r) { - [[NSGraphicsContext currentContext] saveGraphicsState]; if (n == 2) NSRectClipList (r, 2); else NSRectClip (*r); - gsaved = YES; +#ifdef NS_IMPL_GNUSTEP + DPSrectclip (ctx, NSMinX (*r), NSMinY (*r), + NSWidth (*r), NSHeight (*r)); + + if (n == 2) + DPSrectclip (ctx, NSMinX (r[1]), NSMinY (r[1]), + NSWidth (r[1]), NSHeight (r[1])); +#endif } } @@ -1098,7 +1108,7 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) if (gsaved) { [[NSGraphicsContext currentContext] restoreGraphicsState]; - gsaved = NO; + gsaved--; } if (f != ns_updating_frame) @@ -2433,9 +2443,6 @@ Hide the window (X11 semantics) EmacsView *view = FRAME_NS_VIEW (f); FRAME_POINTER_TYPE (f) = cursor; [[view window] invalidateCursorRectsForView: view]; - /* Redisplay assumes this function also draws the changed frame - cursor, but this function doesn't, so do it explicitly. */ - gui_update_cursor (f, 1); } } @@ -2847,31 +2854,31 @@ Hide the window (X11 semantics) External (RIF); compute left/right overhang of whole string and set in s -------------------------------------------------------------------------- */ { - struct font *font = s->font; - - if (s->char2b) + if (s->cmp == NULL + && (s->first_glyph->type == CHAR_GLYPH + || s->first_glyph->type == COMPOSITE_GLYPH)) { struct font_metrics metrics; - unsigned int codes[2]; - codes[0] = *(s->char2b); - codes[1] = *(s->char2b + s->nchars - 1); - font->driver->text_extents (font, codes, 2, &metrics); - s->left_overhang = -metrics.lbearing; - s->right_overhang - = metrics.rbearing > metrics.width - ? metrics.rbearing - metrics.width : 0; + if (s->first_glyph->type == CHAR_GLYPH) + { + struct font *font = s->font; + font->driver->text_extents (font, s->char2b, s->nchars, &metrics); + } + else + { + Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); + + composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); + } + s->right_overhang = (metrics.rbearing > metrics.width + ? metrics.rbearing - metrics.width : 0); + s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0; } - else + else if (s->cmp) { - s->left_overhang = 0; -#ifdef NS_IMPL_GNUSTEP - if (EQ (font->driver->type, Qns)) - s->right_overhang = ((struct nsfont_info *)font)->ital ? - FONT_HEIGHT (font) * 0.2 : 0; - else -#endif - s->right_overhang = 0; + s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width; + s->left_overhang = - s->cmp->lbearing; } } @@ -3011,14 +3018,13 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. struct frame *f = WINDOW_XFRAME (w); struct glyph *phys_cursor_glyph; struct glyph *cursor_glyph; - struct face *face; - NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f); /* If cursor is out of bounds, don't draw garbage. This can happen in mini-buffer windows when switching between echo area glyphs and mini-buffer. */ - NSTRACE ("ns_draw_window_cursor"); + NSTRACE ("ns_draw_window_cursor (on = %d, cursor_type = %d)", + on_p, cursor_type); if (!on_p) return; @@ -3034,6 +3040,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL) { + NSTRACE_MSG ("No phys cursor glyph was found!"); + if (glyph_row->exact_window_width_line_p && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) { @@ -3043,10 +3051,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. return; } - /* We draw the cursor (with NSRectFill), then draw the glyph on top - (other terminals do it the other way round). We must set - w->phys_cursor_width to the cursor width. For bar cursors, that - is CURSOR_WIDTH; for box cursors, it is the glyph width. */ get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h); /* The above get_phys_cursor_geometry call set w->phys_cursor_width @@ -3080,15 +3084,7 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. ns_focus (f, &r, 1); - face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id); - if (face && NS_FACE_BACKGROUND (face) - == ns_index_color (FRAME_CURSOR_COLOR (f), f)) - { - [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set]; - hollow_color = FRAME_CURSOR_COLOR (f); - } - else - [FRAME_CURSOR_COLOR (f) set]; + [FRAME_CURSOR_COLOR (f) set]; switch (cursor_type) { @@ -3096,13 +3092,11 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. case NO_CURSOR: break; case FILLED_BOX_CURSOR: - NSRectFill (r); + draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); break; case HOLLOW_BOX_CURSOR: - NSRectFill (r); - [hollow_color set]; - NSRectFill (NSInsetRect (r, 1, 1)); - [FRAME_CURSOR_COLOR (f) set]; + draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT); + [NSBezierPath strokeRect: r]; break; case HBAR_CURSOR: NSRectFill (r); @@ -3119,11 +3113,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. break; } ns_unfocus (f); - - /* Draw the character under the cursor. Other terms only draw - the character on top of box cursors, so do the same here. */ - if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR) - draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); } @@ -3303,16 +3292,18 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if (s->for_overlaps) return; + if (s->hl == DRAW_CURSOR) + [FRAME_BACKGROUND_COLOR (s->f) set]; + else if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + /* Do underline. */ if (face->underline) { if (s->face->underline == FACE_UNDER_WAVE) { - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; - ns_draw_underwave (s, width, x); } else if (s->face->underline == FACE_UNDER_LINE) @@ -3383,11 +3374,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. s->underline_position = position; r = NSMakeRect (x, s->ybase + position, width, thickness); - - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; NSRectFill (r); } } @@ -3397,11 +3383,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. { NSRect r; r = NSMakeRect (x, s->y, width, 1); - - if (face->overline_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->overline_color, s->f) set]; NSRectFill (r); } @@ -3424,10 +3405,6 @@ larger if there are taller display elements (e.g., characters dy = lrint ((glyph_height - h) / 2); r = NSMakeRect (x, glyph_y + dy, width, 1); - if (face->strike_through_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->strike_through_color, s->f) set]; NSRectFill (r); } } @@ -3575,17 +3552,7 @@ Function modeled after x_draw_glyph_string_box (). struct glyph *last_glyph; NSRect r; int hthickness, vthickness; - struct face *face; - - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = s->face; + struct face *face = s->face; vthickness = face->box_vertical_line_width; hthickness = face->box_horizontal_line_width; @@ -3659,34 +3626,26 @@ Function modeled after x_draw_glyph_string_box (). || FONT_TOO_HIGH (s->font) || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) { - struct face *face; - if (s->hl == DRAW_MOUSE_FACE) - { - face - = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + struct face *face = s->face; if (!face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set]; } - if (s->hl != DRAW_CURSOR) - { - NSRect r = NSMakeRect (s->x, s->y + box_line_width, - s->background_width, - s->height-2*box_line_width); - NSRectFill (r); - } + NSRect r = NSMakeRect (s->x, s->y + box_line_width, + s->background_width, + s->height-2*box_line_width); + NSRectFill (r); s->background_filled_p = 1; } @@ -3707,7 +3666,7 @@ Function modeled after x_draw_glyph_string_box (). int th; char raised_p; NSRect br; - struct face *face; + struct face *face = s->face; NSColor *tdCol; NSTRACE ("ns_dumpglyphs_image"); @@ -3728,15 +3687,6 @@ Function modeled after x_draw_glyph_string_box (). /* Draw BG: if we need larger area than image itself cleared, do that, otherwise, since we composite the image under NS (instead of mucking with its background color), we must clear just the image area. */ - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set]; @@ -3807,16 +3757,8 @@ Function modeled after x_draw_glyph_string_box (). if (s->hl == DRAW_CURSOR) { - [FRAME_CURSOR_COLOR (s->f) set]; - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) + [FRAME_CURSOR_COLOR (s->f) set]; tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); - else - /* Currently on NS img->mask is always 0. Since - get_window_cursor_type specifies a hollow box cursor when on - a non-masked image we never reach this clause. But we put it - in, in anticipation of better support for image masks on - NS. */ - tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); } else { @@ -3871,7 +3813,7 @@ Function modeled after x_draw_glyph_string_box (). NSRect r[2]; NSRect glyphRect; int n; - struct face *face; + struct face *face = s->face; NSColor *fgCol, *bgCol; if (!s->background_filled_p) @@ -3879,48 +3821,22 @@ Function modeled after x_draw_glyph_string_box (). n = ns_get_glyph_string_clip_rect (s, r); ns_focus (s->f, r, n); - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + face = s->face; bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); + if (s->hl == DRAW_CURSOR) + { + fgCol = bgCol; + bgCol = FRAME_CURSOR_COLOR (s->f); + } + glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); [bgCol set]; - /* NOTE: under NS this is NOT used to draw cursors, but we must avoid - overwriting cursor (usually when cursor on a tab) */ - if (s->hl == DRAW_CURSOR) - { - CGFloat x, width; - - /* FIXME: This looks like it will only work for left to - right languages. */ - x = NSMinX (glyphRect); - width = s->w->phys_cursor_width; - glyphRect.size.width -= width; - glyphRect.origin.x += width; - - NSRectFill (glyphRect); - - /* Draw overlining, etc. on the cursor. */ - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) - ns_draw_text_decoration (s, face, bgCol, width, x); - else - ns_draw_text_decoration (s, face, fgCol, width, x); - } - else - { - NSRectFill (glyphRect); - } + NSRectFill (glyphRect); /* Draw overlining, etc. on the stretch glyph (or the part of the stretch glyph after the cursor). */ @@ -3936,7 +3852,7 @@ overwriting cursor (usually when cursor on a tab) */ static void ns_draw_glyph_string_foreground (struct glyph_string *s) { - int x, flags; + int x; struct font *font = s->font; /* If first glyph of S has a left box line, start drawing the text @@ -3947,15 +3863,9 @@ overwriting cursor (usually when cursor on a tab) */ else x = s->x; - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - font->driver->draw (s, s->cmp_from, s->nchars, x, s->ybase, - (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p) - || flags == NS_DUMPGLYPH_MOUSEFACE); + !s->for_overlaps && !s->background_filled_p); } @@ -4062,9 +3972,9 @@ overwriting cursor (usually when cursor on a tab) */ struct font *font = s->face->font; if (! font) font = FRAME_FONT (s->f); - NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string"); + NSTRACE ("ns_draw_glyph_string (hl = %u)", s->hl); - if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/) + if (s->next && s->right_overhang && !s->for_overlaps) { int width; struct glyph_string *next; @@ -4101,6 +4011,18 @@ overwriting cursor (usually when cursor on a tab) */ box_drawn_p = 1; } + bool must_unfocus = false; + + if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */ + && !s->clip_tail + && ((s->prev && s->prev->hl != s->hl && s->left_overhang) + || (s->next && s->next->hl != s->hl && s->right_overhang))) + { + NSRect rect = NSMakeRect (s->x, s->y, s->width, s->height); + ns_focus (s->f, &rect, 1); + must_unfocus = true; + } + switch (s->first_glyph->type) { @@ -4124,28 +4046,19 @@ overwriting cursor (usually when cursor on a tab) */ n = ns_get_glyph_string_clip_rect (s, r); ns_focus (s->f, r, n); - if (s->for_overlaps || (s->cmp_from > 0 - && ! s->first_glyph->u.cmp.automatic)) - s->background_filled_p = 1; + BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + if (s->for_overlaps || (isComposite + && (s->cmp_from > 0 + && ! s->first_glyph->u.cmp.automatic))) + s->background_filled_p = 1; else ns_maybe_dumpglyphs_background (s, s->first_glyph->type == COMPOSITE_GLYPH); - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - - { - BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; - - if (isComposite) - ns_draw_composite_glyph_string_foreground (s); - else - ns_draw_glyph_string_foreground (s); - } + if (isComposite) + ns_draw_composite_glyph_string_foreground (s); + else + ns_draw_glyph_string_foreground (s); { NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 @@ -4158,13 +4071,6 @@ overwriting cursor (usually when cursor on a tab) */ ns_draw_text_decoration (s, s->face, col, s->width, s->x); } - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - ns_unfocus (s->f); break; @@ -4197,7 +4103,88 @@ overwriting cursor (usually when cursor on a tab) */ ns_unfocus (s->f); } + /* Draw surrounding overhangs. */ + if (s->prev) + { + struct glyph_string *prev; + + for (prev = s->prev; prev; prev = prev->prev) + if (prev->hl != s->hl + && prev->x + prev->width + prev->right_overhang > s->x) + { + /* As prev was drawn while clipped to its own area, we + must draw the right_overhang part using s->hl now. */ + enum draw_glyphs_face save = prev->hl; + struct face *save_face = prev->face; + + prev->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + ns_focus (s->f, &r, 1); + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + prev->num_clips = 1; + prev->hl = s->hl; + if (prev->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (prev); + else + ns_draw_composite_glyph_string_foreground (prev); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + ns_unfocus (s->f); + prev->hl = save; + prev->face = save_face; + prev->num_clips = 0; + } + } + + if (s->next) + { + struct glyph_string *next; + + for (next = s->next; next; next = next->next) + if (next->hl != s->hl + && next->x - next->left_overhang < s->x + s->width) + { + /* As next will be drawn while clipped to its own area, + we must draw the left_overhang part using s->hl now. */ + enum draw_glyphs_face save = next->hl; + struct face *save_face = next->face; + + next->hl = s->hl; + next->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + ns_focus (s->f, NULL, 0); + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + next->num_clips = 1; + if (next->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (next); + else + ns_draw_composite_glyph_string_foreground (next); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + ns_unfocus (s->f); + next->hl = save; + next->num_clips = 0; + next->face = save_face; + next->clip_head = next; + next->background_filled_p = 0; + } + } s->num_clips = 0; + + if (must_unfocus) + ns_unfocus (s->f); } diff --git a/src/xdisp.c b/src/xdisp.c index bbe7e2701b..9998677262 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -29297,7 +29297,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, for (s = head; s; s = s->next) FRAME_RIF (f)->draw_glyph_string (s); -#ifndef HAVE_NS /* When focus a sole frame and move horizontally, this clears on_p causing a failure to erase prev cursor position. */ if (area == TEXT_AREA @@ -29316,7 +29315,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, notice_overwritten_cursor (w, TEXT_AREA, x0, x1, row->y, MATRIX_ROW_BOTTOM_Y (row)); } -#endif /* Value is the x-position up to which drawn, relative to AREA of W. This doesn't include parts drawn because of overhangs. */ -- 2.31.1 --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Tue Oct 26 08:39:22 2021 Received: (at 51411) by debbugs.gnu.org; 26 Oct 2021 12:39:23 +0000 Received: from localhost ([127.0.0.1]:45349 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfLje-0006Bm-MF for submit@debbugs.gnu.org; Tue, 26 Oct 2021 08:39:22 -0400 Received: from outbound.soverin.net ([116.202.126.228]:52243) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfLjc-0006Bc-Dx for 51411@debbugs.gnu.org; Tue, 26 Oct 2021 08:39:21 -0400 Received: from smtp.soverin.net (unknown [10.10.3.24]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by outbound.soverin.net (Postfix) with ESMTPS id 8F61DE3; Tue, 26 Oct 2021 12:39:18 +0000 (UTC) Received: from smtp.soverin.net (smtp.soverin.net [159.69.232.138]) by soverin.net DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=idiocy.org; s=soverin; t=1635251958; bh=tlEO0fIROkeUI6WJiJdgs1MMIubCUvIRAz8i0x7wrHg=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=QLrBBlsDu9TRAowPA64Th+NFVuIisFuO+pe2ipjOfMAn8cfIBNPBAVWn7BuV2ffxM zNQKFaosU6MWU5oa7OtwZf6TmrQamw88/W+3HH/M0XmC0Yv0e8hSS3hLBpjIZp8f6/ HRhJvLWgFAXymI+t/HP9X0MzA8EXuWAMVCtUNUkd4ThyoWsw/GnY/GSQjqxzNLkJWR Z1wwjwLa1wTUjxoY6VykquBsBxqYCRLSaOHSsl+lOhAE9RaLroFgNTQJwa48aLhcu3 Wku72A+no1ti5zyNC0sDXsNH97xvVJCvmL/3lb5esg/gy9Z5O5lrUWr76i9YAld9te BHoqIsjseHJ0w== Received: from alan by faroe.holly.idiocy.org with local (Exim 4.95-RC2) (envelope-from ) id 1mfLjX-000iLJ-Ur; Tue, 26 Oct 2021 13:39:15 +0100 Date: Tue, 26 Oct 2021 13:39:15 +0100 From: Alan Third To: Po Lu Subject: Re: bug#51411: NS port cleanups Message-ID: Mail-Followup-To: Alan Third , Po Lu , 51411@debbugs.gnu.org References: <87mtmwt3mc.fsf.ref@yahoo.com> <87mtmwt3mc.fsf@yahoo.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <87mtmwt3mc.fsf@yahoo.com> X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) On Tue, Oct 26, 2021 at 07:41:31PM +0800, Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors wrote: > > Is there any reason to nest ns_focus? There are (according to Apple) > > performance reasons to not save the context unless you really need to. > > Right now it's used in the code that clips to the exact bounds of a > string, if a string's overhangs are already drawn. > > I couldn't find a cleaner way to do this, and that situation is rare, so > I think the performance problems will usually be avoided. Is this the code in ns_draw_glyph_string? > > I mean alt as defined by GNUstep in the quote I sent you in my last > > email. I don't think it's our job to say that GNUstep's choice of > > defaults is wrong and therefore do something that would be unexpected > > for a GNUstep user. > > Well, on every other platform Meta is on the alt on the users' keyboard. > Emacs in general doesn't conform to the platform expectations WRT to key > bindings, so I think being consistent with Emacs on other platforms is > more important here. I think we normally accept what the system tells us is Alt, or the nearest equivalent. In this case GNUstep tells us what it's understanding of the nearest equivalent (option) is, and I don't see any reason to override that. So please remove the changes to modifier keys. -- Alan Third From debbugs-submit-bounces@debbugs.gnu.org Tue Oct 26 08:51:13 2021 Received: (at 51411) by debbugs.gnu.org; 26 Oct 2021 12:51:13 +0000 Received: from localhost ([127.0.0.1]:45379 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfLv6-0006Zg-Ei for submit@debbugs.gnu.org; Tue, 26 Oct 2021 08:51:13 -0400 Received: from sonic303-21.consmr.mail.ne1.yahoo.com ([66.163.188.147]:43301) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfLv3-0006ZP-Pa for 51411@debbugs.gnu.org; Tue, 26 Oct 2021 08:51:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635252663; bh=5BmcFT+/4XMEMlVwLu6JQlDogJ9n6TRxmOzse6YjNl0=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=dLgugrOtG0fBAvmmVwQTWJZyE7OcNJXJqQJjjaE2fzg6gUpvPpazSJ9fok9+rJDmYu69ttHsV4iBDpUPk9N6jMSOieEty55RY673zb9ehjlD6LdZzQDXgYdNstvSBLQ4xmUujqOnjPN0MAd17R8Y/JSVkNtupThA2dJ72FUGI1lQr0S9Zs/8733B+N1bQqIItqV9gNQf1y3T0UbwruMXISUshDcdEh9KYJmKHSs2APWaarsXm3vbI9CvckbF2/HIM7CLL+K5HGTZ/46zeN/YCiFoAtVRg/bSPL1LJPsvG51D+pHcYKuQMnFrUI3Vx11BUrJv7vZc+ff6xRkNwcmx8g== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635252663; bh=IrtTn0Qw38WDNej6c/KMl5c/hrf5wH1flC9uy3G9xoN=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=sXS88Y/NKM2SwqD/IZVMnDDZu006zXq/SNKPR9PgVifTaUjYKQIdwea6K00sCy52eL+QQOBvNB5SUrBUKYhyfkpZN4UtLNDwrN5SjgWCJpaM8Wb+uRa8ieNRku1H9HnY/wZA1F+tBuBgOxi03nBZfanOFavTXPFsXu1kSB16j0YWPwJ6vGsUnX8128Sx1fMtxk5sNFi3DZoxIEDCPCm2V6r4pRr8CF0TIDMyRqoRxILMFEVrUDdWuHE93xRkY5jF7zveg9GQBNOwkOimofhAEoAC7K5VZiNE/YrZ98Pw1EumSFRREjGNXcZS2qISP0T7Ugsio56B0T+6xmgJJYbkMA== X-YMail-OSG: cZNE2BwVM1lEzLeV0LJoJZk7TFzal6ku6gVzeoW0RviIocIYFDakAbL0SM6AgNw L3sm2wicv.4RkLfeEBHK4Lrl2PHR5MLTleN_iSBFlx0UgoUJBbY.O1cdr9s4QqVO7jH2TnQNtHve gSIGWUE9.mhdmuVTjwiYoGiisoexaCyQLATp0hozguPN2sCRE8.T8IAui.k.aRqySS.JPHBR7az0 XA9QUs._MjuS.ND9K1UDHaF2IZgM6aqGbr5iyhSsuwOQIpiuSDPMilMTez8dyKqYbBbMUqBDPhre .LqpmOHnXd_PBQivabjM0_I6JqrxzteVA5z_3kRtzKjjJK1u9wOtJIoHXBBf.YkCKAoJ9zD_rmrx 4LNDhjOTteln.KxzJXXHd2C1vCnbOnQOSELALPNh93vJTDOsOvTZtl6tKSCjJ6bECFWYZrlCUsxI XjD7K0i9mfcnEbd0QwALwf_WOuISsnvNrYDx.aYrnJL1gPkBGaUVfKaUZ7PQ5xJDVGQqVoIzbxPm .MqQWamiF2i6sLbwbKIU6FJ3oaCRVpq0cCVAjrf6JRnBVqmqB4VonbZK0PV.xKw5P2..god3fLI5 p2dzNceXoMY43s2VXKi19swNH36LmWjntrNSb9tEcdp9wJX9CIj8YFwnGk9XNs.bdR7KngT0N3_o 4shosIYErZQqJHWLcpRSnOvnCNXnteQ682A0FWSeeXjXwmbcLuzLiLJ5aa8C3NcyGLvkPkxfBtvC 96eNX405OJMQKHy.c4nUxD45iuaNmi7tANeKLqRoS5IbMTOI6tCwHfz58kQfOns3XhT0OLfhc8jM sbPSUxvcTeLayx5jX.cMWg6iSN_rfp4OQznmr03V25KMeuuC5wxYUpRhunDQFaDx7RrjtEn4JtNa cPy0uxE2Ap47a_zdhD30XxMRcNkp0UnvkYNvgXa3uPgio2d.WXGDvpuE5z23zslu4z0DCQeDcufq .JXEqKBQfJyhEoSgPntlPVRu2WzD24zvBMhoISPVAxc5EUo6TYW1dhkn0x3IZH6DUpGR21jkZJcJ axysWi4mcrRhDptP.Vu11yxHKqJiTWxDbwffosKREz5ZEBSkI8Ascg0Z5msD9M5ww6LvkcUYbboS SVwhGWj4gft_AZBV_BemvIT89jaDdtYW2eLO28zsC0eB.A_g0hAqu57p9HWv6ESk2gFrOm2Meq0w l3cbbD6f3Qluvn30jhFRnihLunnCiWo5enZJIsOwxaiV9VO2asVCE6mQt5RbTYURdiRjEdH8jqzc FlhfDD.UXGJW.uFVaBI.dnYz57FJD8ZeKxd2x6rKBL8K9e1z1HfZkkfHxwIK7B.o_Pgfx_50h8bd csuYuWOfJ2_0MXVGr6rD.cPu6B7l2AeTn_7bGLis.tH.IIWqgpN5hKqa_wM991k48994S.PaUsIr M8IjZhTNwrZYGbQntW_iyKlKAyuvlT7VXZlVeJktX3b4w9yR6YE9UtXYU_41hcxjFdfjR3W7iB4e xmxLZytxshlmJmMPx8Hd4Q2XptLTvzLa2J7fQUOmWEBKMQoVuVrHGPUcSBslHAYCHZVkc0XQORw6 JEg3w5odvUp86LZNXHGXKIklGJb9fQqeVl7.gr0GFLl27ZmaCAJy4PswHhEBH9EFjPAISwykOQYr IqGvc007YyjHSLJNv3nDg8fBHu0KrgHfbWbqjf3vtYtpI0Qh3AXXD0ijiXe_M1Roa1LnowhvFuKt 4pVoZaoxU1Q5A4eQv4m1xjNkcL_k6DPhO9LAwzo1ce93x1QqbHKx7rAnCE2GFtfjpT.eK7HovyFd K_RwPa.NqqrMQOR1Pw.SZM5bJZ0jyr0R7cpTw_NSm1Yu3zBMFgRrSMIQmkwjw3FVfI_v.2oawj2k 6FS_k7o02c0pJldI48EdGEzCb5Xoe.zpA8Q0bb0wm1ac5MPqYxckB0ic1gQ9v2cvxNfaYjx1OoVv NIGfCMjSLrw40ZDbXMULdfdmt2shduca7JWtu9EXRvEFFUxrPVMRyv9D1NZes0usaLOGTymzy_3E 3gGUcVos2ruryW5DOrBtO_5SUMrHOyhzWae8TGGS3rAZ97dgFlmos3Tt1LQN57RLooZsXzCqNdjv .KC5ke2WgT.1m_8fZof5HTfcQl4XsmTbla9tDDcpdzxitdV_EN4wwofCeKx0NFxvWFrwqAypt0SQ 4ztNZUkWelkX26JvOGHjysj_BxwoZXR0TGzjCrnKCiZZGtm.5tE4pG21IhK6HNMpawn4PTugApPf 1zL7IaPriOKkUl5svr75HmENhvD816Z3gN3kMnTn8fewPRGHOnxbdIRtyYLc- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic303.consmr.mail.ne1.yahoo.com with HTTP; Tue, 26 Oct 2021 12:51:03 +0000 Received: by kubenode515.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID c567801393c0d9000aee6eef2da962df; Tue, 26 Oct 2021 12:50:58 +0000 (UTC) From: Po Lu To: Alan Third Subject: Re: bug#51411: NS port cleanups References: <87mtmwt3mc.fsf.ref@yahoo.com> <87mtmwt3mc.fsf@yahoo.com> Date: Tue, 26 Oct 2021 20:50:52 +0800 In-Reply-To: (Alan Third's message of "Tue, 26 Oct 2021 13:39:15 +0100") Message-ID: <87h7d4t0er.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 12713 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Alan Third writes: > Is this the code in ns_draw_glyph_string? Yes, it is. > I think we normally accept what the system tells us is Alt, or the > nearest equivalent. In this case GNUstep tells us what it's > understanding of the nearest equivalent (option) is, and I don't see > any reason to override that. > So please remove the changes to modifier keys. Fair enough, thanks for the feedback. Done. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-General-improvements-to-NS-port.patch >From b4060ca7357091ef0ba6abf3faf0314321cd85be Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 23 Oct 2021 19:51:31 +0800 Subject: [PATCH] General improvements to NS port * src/dispextern.h: Remove some !HAVE_NS conditionals around grab related code. * src/frame.c (gui_mouse_grabbed, gui_redo_mouse_highlight): Remove !HAVE_NS conditionals around code. * src/nsmenu.m (ns_update_menubar): Prevent recursive calls and enable shallow updates on GNUstep. (menuNeedsUpdate): Prevent recursive calls. (ns_menu_show): Fix mysterious GC-related bug. (update_frame_tool_bar_1): Work around mysterious toolbar sizing bug on GNUstep. * src/nsterm.h (struct ns_output): New field for tracking toolbar visibility changes. * src/nsterm.m (frame_set_mouse_pixel_position): Implement for GNUstep. (ns_redraw_scroll_bars): Enable for GNUstep. (ns_clear_frame): Redraw scrollbars on GNUstep. (ns_update_window_end): New function. (ns_redisplay_interface): Add ns_update_window_end on GNUstep. (- keyDown): Remove debug code that doesn't work on GNUstep. (- mouseDown): Enable grab tracking on NS port. (- resizeWithOldSuperviewSize): Fix build with NSTRACE. * src/xdisp.c (note_tab_bar_highlight): Enable some code for NS port. --- src/dispextern.h | 2 -- src/frame.c | 4 --- src/nsmenu.m | 76 +++++++++++++++++++++++++++++++++++++++--------- src/nsterm.h | 6 ++++ src/nsterm.m | 42 +++++++++++++++++++++----- src/xdisp.c | 2 -- 6 files changed, 102 insertions(+), 30 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index 08dac5d455..58e9048556 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3722,10 +3722,8 @@ #define IMAGE_BACKGROUND_TRANSPARENT(img, f, mask) \ const char *, const char *, enum resource_types); -#ifndef HAVE_NS /* These both used on W32 and X only. */ extern bool gui_mouse_grabbed (Display_Info *); extern void gui_redo_mouse_highlight (Display_Info *); -#endif /* HAVE_NS */ #endif /* HAVE_WINDOW_SYSTEM */ diff --git a/src/frame.c b/src/frame.c index 2b1cb452ef..79a7c89e0d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -5028,8 +5028,6 @@ gui_set_no_special_glyphs (struct frame *f, Lisp_Object new_value, Lisp_Object o } -#ifndef HAVE_NS - /* Non-zero if mouse is grabbed on DPYINFO and we know the frame where it is. */ @@ -5054,8 +5052,6 @@ gui_redo_mouse_highlight (Display_Info *dpyinfo) dpyinfo->last_mouse_motion_y); } -#endif /* HAVE_NS */ - /* Subroutines of creating an X frame. */ /* Make sure that Vx_resource_name is set to a reasonable value. diff --git a/src/nsmenu.m b/src/nsmenu.m index 05b89c2f56..b93d3a79bd 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -101,6 +101,15 @@ static void ns_update_menubar (struct frame *f, bool deep_p) { +#ifdef NS_IMPL_GNUSTEP + static int inside = 0; + + if (inside) + return; + + inside++; +#endif + BOOL needsSet = NO; id menu = [NSApp mainMenu]; bool owfi; @@ -120,7 +129,12 @@ NSTRACE ("ns_update_menubar"); if (f != SELECTED_FRAME () || FRAME_EXTERNAL_MENU_BAR (f) == 0) + { +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif return; + } XSETFRAME (Vmenu_updating_frame, f); /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */ @@ -144,10 +158,6 @@ t = -(1000*tb.time+tb.millitm); #endif -#ifdef NS_IMPL_GNUSTEP - deep_p = 1; /* See comment in menuNeedsUpdate. */ -#endif - if (deep_p) { /* Make a widget-value tree representing the entire menu trees. */ @@ -275,6 +285,9 @@ free_menubar_widget_value_tree (first_wv); discard_menu_items (); unbind_to (specpdl_count, Qnil); +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif return; } @@ -408,6 +421,10 @@ if (needsSet) [NSApp setMainMenu: menu]; +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif + unblock_input (); } @@ -490,17 +507,34 @@ - (instancetype)initWithTitle: (NSString *)title call to ns_update_menubar. */ - (void)menuNeedsUpdate: (NSMenu *)menu { +#ifdef NS_IMPL_GNUSTEP + static int inside = 0; +#endif + if (!FRAME_LIVE_P (SELECTED_FRAME ())) return; -#ifdef NS_IMPL_COCOA -/* TODO: GNUstep calls this method when the menu is still being built - which results in a recursive stack overflow. One possible solution - is to use menuWillOpen instead, but the Apple docs explicitly warn - against changing the contents of the menu in it. I don't know what - the right thing to do for GNUstep is. */ +#ifdef NS_IMPL_GNUSTEP + /* GNUstep calls this method when the menu is still being built + which results in a recursive stack overflow, which this variable + prevents. */ + + if (!inside) + ++inside; + else + return; +#endif + if (needsUpdate) - ns_update_menubar (SELECTED_FRAME (), true); + { +#ifdef NS_IMPL_GNUSTEP + needsUpdate = NO; +#endif + ns_update_menubar (SELECTED_FRAME (), true); + } + +#ifdef NS_IMPL_GNUSTEP + --inside; #endif } @@ -827,6 +861,9 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item p.x = x; p.y = y; + /* Don't GC due to a mysterious bug. */ + inhibit_garbage_collection (); + /* now parse stage 2 as in ns_update_menubar */ wv = make_widget_value ("contextmenu", NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; @@ -998,15 +1035,17 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item pmenu = [[EmacsMenu alloc] initWithTitle: NILP (title) ? @"" : [NSString stringWithLispString: title]]; + /* On GNUstep, this call makes menu_items nil for whatever reason + when displaying a context menu from `context-menu-mode'. */ + Lisp_Object items = menu_items; [pmenu fillWithWidgetValue: first_wv->contents]; + menu_items = items; free_menubar_widget_value_tree (first_wv); - unbind_to (specpdl_count, Qnil); - popup_activated_flag = 1; tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps]; popup_activated_flag = 0; [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; - + unbind_to (specpdl_count, Qnil); unblock_input (); return tem; } @@ -1057,6 +1096,15 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item [toolbar clearActive]; #else [toolbar clearAll]; + /* It takes at least 3 such adjustments to fix an issue where the + tool bar is 2x too tall when a frame's tool bar is first shown. + This is ugly, but I have no other solution for this problem. */ + if (FRAME_OUTPUT_DATA (f)->tool_bar_adjusted < 3) + { + [toolbar setVisible: NO]; + FRAME_OUTPUT_DATA (f)->tool_bar_adjusted++; + [toolbar setVisible: YES]; + } #endif /* Update EmacsToolbar as in GtkUtils, build items list. */ diff --git a/src/nsterm.h b/src/nsterm.h index 944dbd727c..8175f99664 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -978,6 +978,12 @@ #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) /* Non-zero if we are doing an animation, e.g. toggling the tool bar. */ int in_animation; + +#ifdef NS_IMPL_GNUSTEP + /* Zero if this is the first time a toolbar has been updated on this + frame. */ + int tool_bar_adjusted; +#endif }; /* This dummy declaration needed to support TTYs. */ diff --git a/src/nsterm.m b/src/nsterm.m index 957cd815a0..cb308ea23c 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -65,6 +65,7 @@ Updated by Christian Limpach (chris@nice.ch) #ifdef NS_IMPL_GNUSTEP #include "process.h" +#import #endif #ifdef NS_IMPL_COCOA @@ -2259,13 +2260,19 @@ Hide the window (X11 semantics) { NSTRACE ("frame_set_mouse_pixel_position"); - /* FIXME: what about GNUstep? */ #ifdef NS_IMPL_COCOA CGPoint mouse_pos = CGPointMake(f->left_pos + pix_x, f->top_pos + pix_y + FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f)); CGWarpMouseCursorPosition (mouse_pos); +#else + GSDisplayServer *server = GSServerForWindow ([FRAME_NS_VIEW (f) window]); + [server setMouseLocation: NSMakePoint (f->left_pos + pix_x, + f->top_pos + pix_y + + FRAME_NS_TITLEBAR_HEIGHT(f) + + FRAME_TOOLBAR_HEIGHT(f)) + onScreen: [[[FRAME_NS_VIEW (f) window] screen] screenNumber]]; #endif } @@ -2578,8 +2585,7 @@ Hide the window (X11 semantics) ========================================================================== */ -#if 0 -/* FIXME: Remove this function. */ +#ifdef NS_IMPL_GNUSTEP static void ns_redraw_scroll_bars (struct frame *f) { @@ -2624,10 +2630,9 @@ Hide the window (X11 semantics) NSRectFill (r); ns_unfocus (f); - /* as of 2006/11 or so this is now needed */ - /* FIXME: I don't see any reason for this and removing it makes no - difference here. Do we need it for GNUstep? */ - //ns_redraw_scroll_bars (f); +#ifdef NS_IMPL_GNUSTEP + ns_redraw_scroll_bars (f); +#endif unblock_input (); } @@ -4933,6 +4938,17 @@ static Lisp_Object ns_string_to_lispmod (const char *s) { } +#ifdef NS_IMPL_GNUSTEP +static void +ns_update_window_end (struct window *w, bool cursor_on_p, + bool mouse_face_overwritten_p) +{ + NSTRACE ("ns_update_window_end (cursor_on_p = %d)", cursor_on_p); + + ns_redraw_scroll_bars (WINDOW_XFRAME (w)); +} +#endif + /* This and next define (many of the) public functions in this file. */ /* gui_* are generic versions in xdisp.c that we, and other terms, get away with using despite presence in the "system dependent" redisplay @@ -4949,7 +4965,11 @@ static Lisp_Object ns_string_to_lispmod (const char *s) ns_scroll_run, ns_after_update_window_line, NULL, /* update_window_begin */ +#ifndef NS_IMPL_GNUSTEP NULL, /* update_window_end */ +#else + ns_update_window_end, +#endif 0, /* flush_display */ gui_clear_window_mouse_face, gui_get_glyph_overhangs, @@ -6177,9 +6197,11 @@ In that case we use UCKeyTranslate (ns_get_shifted_character) Lisp_Object kind = fnKeysym ? QCfunction : QCordinary; emacs_event->modifiers = EV_MODIFIERS2 (flags, kind); +#ifndef NS_IMPL_GNUSTEP if (NS_KEYLOG) fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n", code, fnKeysym, flags, emacs_event->modifiers); +#endif /* If it was a function key or had control-like modifiers, pass it directly to Emacs. */ @@ -6692,6 +6714,11 @@ - (void)mouseDown: (NSEvent *)theEvent emacs_event->code = EV_BUTTON (theEvent); emacs_event->modifiers = EV_MODIFIERS (theEvent) | EV_UDMODIFIERS (theEvent); + + if (emacs_event->modifiers & down_modifier) + FRAME_DISPLAY_INFO (emacsframe)->grabbed |= 1 << EV_BUTTON (theEvent); + else + FRAME_DISPLAY_INFO (emacsframe)->grabbed &= ~(1 << EV_BUTTON (theEvent)); } XSETINT (emacs_event->x, lrint (p.x)); @@ -6992,7 +7019,6 @@ - (void)resizeWithOldSuperviewSize: (NSSize)oldSize height = (int)NSHeight (frame); NSTRACE_SIZE ("New size", NSMakeSize (width, height)); - NSTRACE_SIZE ("Original size", size); /* Reset the frame size to match the bounds of the superview (the NSWindow's contentView). We need to do this as sometimes the diff --git a/src/xdisp.c b/src/xdisp.c index 9998677262..bfe7c571ab 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -13891,7 +13891,6 @@ note_tab_bar_highlight (struct frame *f, int x, int y) clear_mouse_face (hlinfo); bool mouse_down_p = false; -#ifndef HAVE_NS /* Mouse is down, but on different tab-bar item? Or alternatively, the mouse might've been pressed somewhere we don't know about, and then have moved onto the tab bar. In this case, @@ -13904,7 +13903,6 @@ note_tab_bar_highlight (struct frame *f, int x, int y) if (mouse_down_p && f->last_tab_bar_item != prop_idx && f->last_tab_bar_item != -1) return; -#endif draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; /* If tab-bar item is not enabled, don't highlight it. */ -- 2.31.1 --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Tue Oct 26 18:40:09 2021 Received: (at control) by debbugs.gnu.org; 26 Oct 2021 22:40:10 +0000 Received: from localhost ([127.0.0.1]:47825 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfV73-0000k0-KV for submit@debbugs.gnu.org; Tue, 26 Oct 2021 18:40:09 -0400 Received: from mail-pj1-f52.google.com ([209.85.216.52]:52137) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfV6p-0000iG-Sc for control@debbugs.gnu.org; Tue, 26 Oct 2021 18:39:56 -0400 Received: by mail-pj1-f52.google.com with SMTP id u12so593198pjy.1 for ; Tue, 26 Oct 2021 15:39:55 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:mime-version:date:message-id:subject:to; bh=PMDNI8xI33wT460vLSXvkHijZKkV3CsB/Q7dYUorlR0=; b=dlzIps4So7ypfMhdidCo14OlVwAzFEOpA1HIb9Xr8Hw8x1t7KsrMW0cJnFNviHM7JH WBM88wzNo7VTC6JNZEr1nANHGDOVhB3BFoYJbCusb6BK9g4ceZGRDSjdzThNpz2+glEf qMyLpnunVdrCioeZANKa9BBROaoX+xD+1YxLC6GxwlTY8EdNap21eXaKF0taV0Jr72ZD K7yp62SfIYQt91Gv57TKAsH7mwF8+ze3+VqpTme5ZYoOUOh2csPelWzJm3wqowv8Wd9M IkMCQncCgUa24NeMimb75qJh4W8eNeC4bjNGrK7BL1+olswEguP6vsv56QP52BnUb8nD QMGw== X-Gm-Message-State: AOAM5335JIwKa1KHSaTmiBw/1WVmRq0fd+TPXKudrsSYkk/Q+3Nc5ByR ZvIbsVqas+BuYWuXe9MPh3nyHvKgrwAfMTGDJ22ffeqFScY= X-Google-Smtp-Source: ABdhPJzWpjbaV1ujAFimuhCMiV87uCt8p9HilDpY6r4VP/BQ1XYsXffpZQqw1pE8THpm1jE3BnA5gaFjoouDkGPm5is= X-Received: by 2002:a17:90b:3b86:: with SMTP id pc6mr1725456pjb.143.1635287990288; Tue, 26 Oct 2021 15:39:50 -0700 (PDT) Received: from 753933720722 named unknown by gmailapi.google.com with HTTPREST; Wed, 27 Oct 2021 00:39:49 +0200 From: Stefan Kangas MIME-Version: 1.0 Date: Wed, 27 Oct 2021 00:39:49 +0200 Message-ID: Subject: control message for bug #51411 To: control@debbugs.gnu.org Content-Type: text/plain; charset="UTF-8" X-Spam-Score: 0.5 (/) X-Debbugs-Envelope-To: control X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.5 (/) tags 51411 + patch quit From debbugs-submit-bounces@debbugs.gnu.org Wed Oct 27 13:20:44 2021 Received: (at 51411) by debbugs.gnu.org; 27 Oct 2021 17:20:44 +0000 Received: from localhost ([127.0.0.1]:50441 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfmbU-0006Ur-6N for submit@debbugs.gnu.org; Wed, 27 Oct 2021 13:20:44 -0400 Received: from outbound.soverin.net ([116.202.126.228]:37731) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfmbP-0006Uc-8C for 51411@debbugs.gnu.org; Wed, 27 Oct 2021 13:20:43 -0400 Received: from smtp.soverin.net (unknown [10.10.3.24]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by outbound.soverin.net (Postfix) with ESMTPS id B2EC695; Wed, 27 Oct 2021 17:20:37 +0000 (UTC) Received: from smtp.soverin.net (smtp.soverin.net [159.69.232.138]) by soverin.net DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=idiocy.org; s=soverin; t=1635355237; bh=jzDQFZtKiZvdzlpJCpU1p11OA9+NuPVQoCYVTihzcxo=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=H4jkbcbAngQZlE845n6+MxRBoxtBqLDi80kqS+UErXA2Il7ZTsEuVYmGT0s0E5aed bAwTXxrE62KpTbGqWQK/Sp5dx9JYlDSLBeuy+cBnQn2vzVIn9tX7jDGbC/r9xEAVYN E3txVQVBjAw+4EJ3D4OBwQE/5pDKwrfj086AhSySk06vtg1WlhquWEIdkyD/69xdVF OLyKUf708DgV/2b9G79nzHq+hyKUo0+oPSUXVSPgCkrOC711/cBF99ET3liLWuTcai wKeG/9niSUAhmexpy62OSvJbY9+z3U35rIgzHpuVGfvz2Le2Ll0Ul5cblDBc5R8f6a F4grHl1waM7/g== Received: from alan by faroe.holly.idiocy.org with local (Exim 4.95-RC2) (envelope-from ) id 1mfmbK-000k5t-B1; Wed, 27 Oct 2021 18:20:34 +0100 Date: Wed, 27 Oct 2021 18:20:34 +0100 From: Alan Third To: Po Lu Subject: Re: bug#51411: NS port cleanups Message-ID: Mail-Followup-To: Alan Third , Po Lu , 51411@debbugs.gnu.org References: <87mtmwt3mc.fsf.ref@yahoo.com> <87mtmwt3mc.fsf@yahoo.com> <87h7d4t0er.fsf@yahoo.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <87h7d4t0er.fsf@yahoo.com> X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) On Tue, Oct 26, 2021 at 08:50:52PM +0800, Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors wrote: > Alan Third writes: > > > Is this the code in ns_draw_glyph_string? > > Yes, it is. That function is a real mess of calls to ns_focus and ns_unfocus. I think there's no good reason for them to be called as often as they are, and some related functions (ns_dumpglyphs_stretch) don't need to call them themselves either. I think we need to have a rethink of how clipping is handled here. We don't need to use ns_focus to clip and we repeatedly call ns_focus on the same rectangle. For a lot of those calls we could replace them with a single clipping rectangle and adjust it as required for overhangs or whatever. I also think you misunderstood what I was saying about the performance problems with calling saveGraphicsState. Calling it when not required is frowned upon by Apple as they say it causes performance problems. Your code is now calling it in ns_focus whether it's required or not. Ideally we only call it when modifying the clipping rectangle, because there are times ns_focus is called where we don't modify the clipping rectangle and therefore we don't need to save the graphics context. I understand what you did, but I think the better solution is for us is to try to untangle ns_draw_glyph_string, even if that means saving the context there directly on occasion. If you want me to have a look at it let me know, I think I know what needs to be done, but I probably won't get round to it as soon as you could. -- Alan Third From debbugs-submit-bounces@debbugs.gnu.org Wed Oct 27 17:28:32 2021 Received: (at control) by debbugs.gnu.org; 27 Oct 2021 21:28:32 +0000 Received: from localhost ([127.0.0.1]:50703 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfqTI-00059n-AI for submit@debbugs.gnu.org; Wed, 27 Oct 2021 17:28:32 -0400 Received: from mail-pj1-f43.google.com ([209.85.216.43]:50923) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfqTG-00059P-Ol for control@debbugs.gnu.org; Wed, 27 Oct 2021 17:28:31 -0400 Received: by mail-pj1-f43.google.com with SMTP id gn3so3119455pjb.0 for ; Wed, 27 Oct 2021 14:28:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:mime-version:date:message-id:subject:to; bh=Lf4lU0SOi/kxPI60nN2GsrR4lfMHINFnmJCtJTIUOBU=; b=ilu1gx+O/VmFmxB2QaMHSsLnlQrcY8ORTGIvX1UsOS52IxANcAvlwhtIA52F4M/vSZ Bl1TGBIDX9u1q9KF6oK14jkEznx9J9q+oaLHtLOzzl7woQQPEAkYdBnRTO/6xyHk2Fqz oVA958gf2g0r2NGdmjADEHz2jKEdiNyIxb3jvD84ScwToWXFb70q4YQxuGGAWc30yFqc Kev9hNpT/SEsv76TI992n1xc2t3R81JU5E4hMaFpfdELU5g+uoKICBPu6YKT31wTorZW 9cXikVd2NXbBmvRVeGBMLE2dWF3vigEfHGcVNMsVtSkwKEf2wGqmu09HrxgaI4fIxnS+ +ybA== X-Gm-Message-State: AOAM530ANCnIYKHKbb13mc42mOOqE5osCXgdsxfwdO+WB8+PuV/NUlaC 4qn0Z5JSpgArolsV+W075dnpmlve7tNs//L8KzliAxFA X-Google-Smtp-Source: ABdhPJzSR7LvoQvMxpN22d2BKXKOprLLuBqAQ+zYTy5mmlr5UI2EcqBPe8HKEbCJrt86+I6fIfvIq8BK25oqf7jaCpg= X-Received: by 2002:a17:90b:11c2:: with SMTP id gv2mr165406pjb.133.1635370104976; Wed, 27 Oct 2021 14:28:24 -0700 (PDT) Received: from 753933720722 named unknown by gmailapi.google.com with HTTPREST; Wed, 27 Oct 2021 14:28:24 -0700 From: Stefan Kangas MIME-Version: 1.0 Date: Wed, 27 Oct 2021 14:28:24 -0700 Message-ID: Subject: control message for bug #51411 To: control@debbugs.gnu.org Content-Type: text/plain; charset="UTF-8" X-Spam-Score: 0.5 (/) X-Debbugs-Envelope-To: control X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.5 (/) severity 51411 wishlist quit From debbugs-submit-bounces@debbugs.gnu.org Wed Oct 27 21:09:56 2021 Received: (at 51411) by debbugs.gnu.org; 28 Oct 2021 01:09:56 +0000 Received: from localhost ([127.0.0.1]:50893 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mftvV-0001Od-1N for submit@debbugs.gnu.org; Wed, 27 Oct 2021 21:09:56 -0400 Received: from sonic310-25.consmr.mail.ne1.yahoo.com ([66.163.186.206]:35442) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mftvP-0001OC-IW for 51411@debbugs.gnu.org; Wed, 27 Oct 2021 21:09:51 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635383380; bh=NACP+OygeiHf+sa7dmZ+6rsCE8dr7E8GuZBDHuHhngY=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=hwE+bDsk/UD3aN3FulkN+7dslymeG4H6LD7OLoxE2b8MBs/6xr+pEJ2NeS3j4U/AF7yPNOCKT2jpFT0LUugQscE3cGz/29oQtXxcJTMzAXFAo1Bcb1285AI8IbETuQiPjhH9dpzo2/gvEPJsDA+cUVD5gSJ2YbQOWtV66zIAr7NPx1e0KeulLHvbPiZ6mMsv3ikb0TdCrCxA4ln4Um28j+qBfpWc3kzOvgSyzz/cgm5LZPTGooyr7jv2Sx1b3AWBGzaVZ4RgvN9tTcbLjKmZELlGWA5TInmLULrgP/NVtHfe+ygFtJdpA7Yu2PA6xKplvnVzpSH+2zEgguRjNdm92g== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635383380; bh=LidgyPnsTnTIP1rm/kxHn2IoCINvBbeaeTujFQL90Ty=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=Rz/9m6jde2B+g3uKDMlFPTypMxZnWi6xOfZrsC94WA3GWvNpTSUI/XuChAWnvpHUnV9ELD4uls759Ptzu7wW06+kMD4B4c4wqzfvbnxJ3Kk6YT14KlB0Wjfln3JtYjKhfFQEgxNP/QwqIgb6oiUfIne+q5AXAc5XGMqq4RGfs6e0kG2vN8zE9R+T68kUZPX7Fd9B8ayx8U5zdI/ZGtfE0wJWNb5yRk/umpN4DKVcWbJDLl1LdyP7u1Elgfpf7V4476DBn6ZuMlVES8EfJ/7ZoThj49/OYAYYqjrYzrG4Q8PY35zWH0ZBKCqLmEdojMiQXN+kpLv7vJ0PODgp1e+BuA== X-YMail-OSG: 0G3wIDEVM1nKQlgb2S0gukfLJLCBauBLLNKMk257sfXLy9PB3LpFihoWyeSp6ZU C9rUPyGdkJ8O84EoO7EixkiWP6AILhDBEi5cprP8pYy39izioo3pW7bBiCPacLSKiovgPNcivY4u RHlhoSrX2CMK4T.vSbfam9VH9CSP.y0sbwKsGuyQccSfH5_zOtJ_do4Ko4H3W9mmkvYUYybYMzVk 7eykK6ZvFkbCEGO1wUeSx3qmnmy8UgsGjt.dQwz_lGM7B6lQaIkPq.so_rxYCt.jDYSJsHUmyarP EXChE9QREG5hthy8GDmMilTWd98cWUYSNLmHrrk.C63_3j0WF0nzlgwwpP3O4I2jB28xKE90khD8 Oqvxhr0emxIpvF3sfhqKVRsOmnOICVc3jT6jqGBBgDRLXaiOyVi39pD5RErhL0LKwHLeezDSusPx cfeWWkSHJSpk1XmpuYg1gL0h6vHfoWUzC_RSht6.USZAfPHqrBy5jSWtWkmR0SL8h8LGh5SFZmu1 Eeozj1LNxRYUbCmgrWXmIt8lO0Dyf2ZWWBn92OCaNZyexEUVrE1908.whBMr8En2Ms9zhkHQF_ym UU6M8BTZIAHQpIcrrTrfE1_UAUoZEGk7xtmWPVjU7GGN7HgTLgTOkWMSQXb0lTW1Fg1Ryci1XVWz xmfHyJbE1.fxvEYSIInA_pmQCFkQknLyqczktShrA.bWS2NWSYEQx1Cqer69FMDqe0aB1csd_WWw LeL20h8Imqlx4dDVDsO2AJin42bW2U1Uq0UsJGZ0DB_ZL.ZX5uj.6N7b5PMHKt6P08eFZOvdtTRy fa.Cxiw7urBTggtZ5H4Xps15WKx0PrQwBeWClFM9IGzcDZUxbCi3aj8dlNkO2paw2tn7Xc.bSuK3 6WUiP9vmLWmpY9aSuebX.cfzfrjq983ICsdSPcFwOx1OZHsBWom1BPemjxT30aHhWfO3Ehguty6d wlIDWcmCfknQeW3aQmGfaXz_3dPm6UWhlmGFCRKmOlC4o6XUN9ls9A9rzxhyjCQ52z5HZTM5FUs8 QXmuDuvdka8Dn6lUuVsgQAqPa28b9GCVAvwHFIBgrqqmhuvOx1gqkosLrlnMn5WkeDVLikGfcP.l nOY.vHFA4n4CvJmFs4QSBn1BNarPApeKPW1sa.8zC7r40xS3jAOkM.CZAjPSti5JjzSxbAKqsaAz CXS7lvrQshf5.T0jZ6SkbVTcL9_fmDus3eHJMEplZ6HnDr5brtzTuYRjgKvHtnRoD0U7LQomWpED nXuFSVTEYJnAbQzpusMw25ftRCKIOfrH98qEq08isSkE5tM9AOQ_t09HyrCqgHL0yx9_g5_B2coB N9k4KZWpDY1_DRUdeQ_eClpTKKR6F71IBe7orMPSVzWgyzKkO.vuMtcLwbkZBZ6eUv7PtkeSiDcU bg6NY5KUmiq6lztDt_0r8AEBUNsI1J72lEuoJMPPibOJp4F56bcrZSQg_AL43BHunfNdXIkulnit SzpSo0myyz5OrDA9Bm5S0YIf7xk4jL.9dHWHfjq.iRIWsPfnJwGZelS1e4TO9ETnPKuT1MXZce.k jlb8yISc76UdPV9Eae_LnnNoyk4s6dckc3udmIA57b5gVnj1l_hs2Iz_Ol4owDSltF1sjN4lOYvO vH851eVJVsw8UECpvrOetwC.00W8Q74RmdtfDXcQ_kvbU3R5VqLJ0ekFYT_X2RbjkYQYxgoTA1_O u_8EHG9dTPznBeiNc2iqiNECWB96RjI49GjPyoapCCKEKyRQS0ywkaVumS_kVEzgAcKCd7h8UUmq A1dyLbYFA3djItWml5a5qdx.sZ8jmpsrBXQkDClZEWPnCP9yeV6quYETctB9UYc9e5JX2aNKO85D Doia6sQT8HILUzLhkxUutlnQG.geAtGdy5htqENVyoeU60UTaVCRxETZRjerK8yvYgU7wOd._u6d egrE54CGLAN_10QgsuSlz4NlTBvFVrOHcvz7IwwJPonU3H5Z3xiBv6H5hy5xnPYJFTzQQz1fC7uB sb68aHDIkwRnhjulV85MMm0a4Qh70EF72GwyqBvcNPhsnDGnocugljqnJTmalPd4MY8UGyUQ3h2q 6XWKwirTNRFc4ja6M0OITMzyS.w_06e16mw.C4JKMvHh4BZyi5eU7_vXy7C5frZHFvqaaUzkRTSC PC2Hb5yoqIAItukeGnZ6a2bnNx09AaWr9KGxEa0t_if01AHAu27.ypi_4FPheLHYeW.8T8Kz0oCh SCrq.qQere7P1A5BumpobUB4vWf.K_bOJp0xEiPM2SeaYo5UFjQ-- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic310.consmr.mail.ne1.yahoo.com with HTTP; Thu, 28 Oct 2021 01:09:40 +0000 Received: by kubenode503.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 3f1de0740e3f9e597124a2e7f576bfbc; Thu, 28 Oct 2021 01:09:36 +0000 (UTC) From: Po Lu To: Alan Third Subject: Re: bug#51411: NS port cleanups References: <87mtmwt3mc.fsf.ref@yahoo.com> <87mtmwt3mc.fsf@yahoo.com> <87h7d4t0er.fsf@yahoo.com> Date: Thu, 28 Oct 2021 09:09:33 +0800 In-Reply-To: (Alan Third's message of "Wed, 27 Oct 2021 18:20:34 +0100") Message-ID: <87ee86q7jm.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 80754 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Alan Third writes: > That function is a real mess of calls to ns_focus and ns_unfocus. I > think there's no good reason for them to be called as often as they > are, and some related functions (ns_dumpglyphs_stretch) don't need to > call them themselves either. > I think we need to have a rethink of how clipping is handled here. We > don't need to use ns_focus to clip and we repeatedly call ns_focus on > the same rectangle. For a lot of those calls we could replace them > with a single clipping rectangle and adjust it as required for > overhangs or whatever. > I also think you misunderstood what I was saying about the performance > problems with calling saveGraphicsState. Calling it when not required > is frowned upon by Apple as they say it causes performance problems. > Your code is now calling it in ns_focus whether it's required or not. > Ideally we only call it when modifying the clipping rectangle, because > there are times ns_focus is called where we don't modify the clipping > rectangle and therefore we don't need to save the graphics context. I understand what you mean now, thanks. > I understand what you did, but I think the better solution is for us > is to try to untangle ns_draw_glyph_string, even if that means saving > the context there directly on occasion. > If you want me to have a look at it let me know, I think I know what > needs to be done, but I probably won't get round to it as soon as you > could. Thanks. I had a try at it, cleaning up much of what appeared obviously unnecessary. (Though I did not dare change what seemed to be mysterious to me.) Though, OTOH, I think calling saveGraphicsState inside the overhang draw process is not too much of a problem as it happens infrequently enough to not be relevant. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Improve-font-display-on-NS-port.patch >From 6e21a00e22a4fccecfc0dd41617217adcdb7e724 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 23 Oct 2021 19:44:03 +0800 Subject: [PATCH] Improve font display on NS port * src/nsfns.m (Fx_create_frame): Use "fixed" for the default font on GNUstep. * src/nsfont.m (LCD_SMOOTHING_MARGIN, ns_escape_name) (ns_unescape_name, ns_attribute_fvalue) (STYLE_REF): Remove unused defines and functions. (struct ns_glyph_layout, enum lgstring_direction). (enum gs_font_slant, enum gs_font_weight, enum gs_font_width) (enum gs_specified, struct gs_font_data): New enumerators and structures. (ns_font_descs_match_p) (ns_done_font_data, ns_get_font_data): New functions. (ns_glyph_metrics): Stop escaping names. (ns_spec_to_descriptor): Fix font descriptor creation for symbolic font spec entires. (ns_descriptor_to_entity): Create entries with the correct symbolic styles. (ns_fallback_entity): Fix fallback entity selection. (ns_findfonts): Use our own font matcher instead of the broken GNUstep matcher. (ns_list_family): Remove obsolete comment. (nsfont_open): Remove obsolete code, comments, and synthItal logic which doesn't work on GNUstep. (nsfont_encode_char): Use a type that can fit NSGlyph (nsfont_draw): Chose correct font, remove obsolete mouse face logic, obsolete comments, and switch to using glyph-based drawing instead of character-based drawing. (ns_font_shape, nsfont_shape): New functions. (ns_uni_to_glyphs_1): New function. (ns_uni_to_glyphs): Return glyphs instead of unicode codepoints. (ns_glyph_metrics): Use NSGlyphs instead of unicode codepoints and fix left bearing, right bearing, ascent and descent computation. (struct nsfont_driver): Add shaping capability. * src/nsterm.h (struct nsfont_info): Use unsigned int for glyph cache. * src/nsterm.c (ns_focus): Set DPS clipping on GNUstep. (ns_compute_glyph_string_overhangs): Fix overhang computation by using xterm code. (ns_draw_window_cursor): Simplify cursor drawing. (ns_maybe_dumpglyphs_background): Test for cursor HL and remove obsolete mouse face logic. (ns_dumpglyphs_image) (ns_dumpglyphs_box_or_relief): Rectify for new cursor logic. (ns_dumpglyphs_stretch): Rectify for new cursor logic and rely on ns_draw_glyph_string to set focus. (ns_draw_glyph_string_foreground): Remove mouse face logic. (ns_draw_glyph_strings): Implement overhangs, remove obsolete comment, and always focus before dumping glyphs. (ns_draw_text_decoration): Add condition for DRAW_CURSOR and simplify color selection. (ns_define_frame_cursor): Remove nonsensical code (define_frame_cursor has nothing to do with the text cursor, aka caret). * src/xdisp.c (draw_glyphs): Enable code for NS port to fix mouse face cursor display. * src/macfont.m (get_cgcolor_from_nscolor): New function. (macfont_draw): Remove obsolete mouse-face code and enable cursor display. --- src/macfont.m | 36 +- src/nsfns.m | 6 + src/nsfont.m | 1215 +++++++++++++++++++++++++++++++++++-------------- src/nsterm.h | 2 +- src/nsterm.m | 415 ++++++++--------- src/xdisp.c | 2 - 6 files changed, 1093 insertions(+), 583 deletions(-) diff --git a/src/macfont.m b/src/macfont.m index d86f09f485..df552400e3 100644 --- a/src/macfont.m +++ b/src/macfont.m @@ -613,6 +613,21 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char, return cgColor; } +static CGColorRef +get_cgcolor_from_nscolor (NSColor *nsColor, struct frame *f) +{ + [nsColor set]; + CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace]; + NSInteger noc = [nsColor numberOfComponents]; + CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc)); + CGColorRef cgColor; + + [nsColor getComponents: components]; + cgColor = CGColorCreate (colorSpace, components); + xfree (components); + return cgColor; +} + #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f) \ do { \ CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f); \ @@ -2907,14 +2922,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no if (!CGRectIsNull (background_rect)) { - if (s->hl == DRAW_MOUSE_FACE) + if (s->hl == DRAW_CURSOR) { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_CURSOR_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); } - CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); + else + CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); CGContextFillRects (context, &background_rect, 1); } @@ -2923,7 +2938,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no CGAffineTransform atfm; CGContextScaleCTM (context, 1, -1); - CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); + if (s->hl == DRAW_CURSOR) + { + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_BACKGROUND_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); + } + else + CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); if (macfont_info->synthetic_italic_p) atfm = synthetic_italic_atfm; else diff --git a/src/nsfns.m b/src/nsfns.m index 797d0ce782..f4d8172246 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -1236,6 +1236,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. "fontBackend", "FontBackend", RES_TYPE_STRING); { +#ifdef NS_IMPL_COCOA /* use for default font name */ id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */ gui_default_parameter (f, parms, Qfontsize, @@ -1250,6 +1251,11 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. build_string (fontname), "font", "Font", RES_TYPE_STRING); xfree (fontname); +#else + gui_default_parameter (f, parms, Qfont, + build_string ("fixed"), + "font", "Font", RES_TYPE_STRING); +#endif } unblock_input (); diff --git a/src/nsfont.m b/src/nsfont.m index 5a9cdfebc0..b3224629f0 100644 --- a/src/nsfont.m +++ b/src/nsfont.m @@ -1,4 +1,4 @@ -/* Font back-end driver for the NeXT/Open/GNUstep and macOS window system. +/* Font back-end driver for the GNUstep window system. See font.h Copyright (C) 2006-2021 Free Software Foundation, Inc. @@ -38,47 +38,269 @@ #include "termchar.h" #include "pdumper.h" -/* TODO: Drop once we can assume gnustep-gui 0.17.1. */ +#import #import +#import +#import +#import #define NSFONT_TRACE 0 -#define LCD_SMOOTHING_MARGIN 2 -/* Font glyph and metrics caching functions, implemented at end. */ -static void ns_uni_to_glyphs (struct nsfont_info *font_info, - unsigned char block); -static void ns_glyph_metrics (struct nsfont_info *font_info, - unsigned char block); +/* Structure used by GS `shape' functions for storing layout + information for each glyph. Borrowed from macfont.h. */ +struct ns_glyph_layout +{ + /* Range of indices of the characters composed into the group of + glyphs that share the cursor position with this glyph. The + members `location' and `length' are in UTF-16 indices. */ + NSRange comp_range; -#define INVALID_GLYPH 0xFFFF + /* UTF-16 index in the source string for the first character + associated with this glyph. */ + NSUInteger string_index; -/* ========================================================================== + /* Horizontal and vertical adjustments of glyph position. The + coordinate space is that of Core Text. So, the `baseline_delta' + value is negative if the glyph should be placed below the + baseline. */ + CGFloat advance_delta, baseline_delta; - Utilities + /* Typographical width of the glyph. */ + CGFloat advance; - ========================================================================== */ + /* Glyph ID of the glyph. */ + NSGlyph glyph_id; +}; + + +enum lgstring_direction + { + DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1 + }; + +enum gs_font_slant + { + GS_FONT_SLANT_ITALIC, + GS_FONT_SLANT_REVERSE_ITALIC, + GS_FONT_SLANT_NORMAL + }; + +enum gs_font_weight + { + GS_FONT_WEIGHT_LIGHT, + GS_FONT_WEIGHT_BOLD, + GS_FONT_WEIGHT_NORMAL + }; + +enum gs_font_width + { + GS_FONT_WIDTH_CONDENSED, + GS_FONT_WIDTH_EXPANDED, + GS_FONT_WIDTH_NORMAL + }; + +enum gs_specified + { + GS_SPECIFIED_SLANT = 1, + GS_SPECIFIED_WEIGHT = 1 << 1, + GS_SPECIFIED_WIDTH = 1 << 2, + GS_SPECIFIED_FAMILY = 1 << 3, + GS_SPECIFIED_SPACING = 1 << 4 + }; +struct gs_font_data +{ + int specified; + enum gs_font_slant slant; + enum gs_font_weight weight; + enum gs_font_width width; + bool monospace_p; + char *family_name; +}; -/* Replace spaces w/another character so emacs core font parsing routines - aren't thrown off. */ static void -ns_escape_name (char *name) +ns_done_font_data (struct gs_font_data *data) { - for (; *name; name++) - if (*name == ' ') - *name = '_'; + if (data->specified & GS_SPECIFIED_FAMILY) + xfree (data->family_name); } - -/* Reconstruct spaces in a font family name passed through emacs. */ static void -ns_unescape_name (char *name) +ns_get_font_data (NSFontDescriptor *desc, struct gs_font_data *dat) { - for (; *name; name++) - if (*name == '_') - *name = ' '; + NSNumber *tem; + NSFontSymbolicTraits traits = [desc symbolicTraits]; + NSDictionary *dict = [desc objectForKey: NSFontTraitsAttribute]; + NSString *family = [desc objectForKey: NSFontFamilyAttribute]; + + dat->specified = 0; + + if (family != nil) + { + dat->specified |= GS_SPECIFIED_FAMILY; + dat->family_name = xstrdup ([family cStringUsingEncoding: NSUTF8StringEncoding]); + } + + tem = [desc objectForKey: NSFontFixedAdvanceAttribute]; + + if ((tem != nil && [tem boolValue] != NO) + || (traits & NSFontMonoSpaceTrait)) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = true; + } + else if (tem != nil && [tem boolValue] == NO) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = false; + } + + if (traits & NSFontBoldTrait) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + dat->weight = GS_FONT_WEIGHT_BOLD; + } + + if (traits & NSFontItalicTrait) + { + dat->specified |= GS_SPECIFIED_SLANT; + dat->slant = GS_FONT_SLANT_ITALIC; + } + + if (traits & NSFontCondensedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_CONDENSED; + } + else if (traits & NSFontExpandedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_EXPANDED; + } + + if (dict != nil) + { + tem = [dict objectForKey: NSFontSlantTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_SLANT; + + dat->slant = [tem floatValue] > 0 + ? GS_FONT_SLANT_ITALIC + : ([tem floatValue] < 0 + ? GS_FONT_SLANT_REVERSE_ITALIC + : GS_FONT_SLANT_NORMAL); + } + + tem = [dict objectForKey: NSFontWeightTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + + dat->weight = [tem floatValue] > 0 + ? GS_FONT_WEIGHT_BOLD + : ([tem floatValue] < -0.4f + ? GS_FONT_WEIGHT_LIGHT + : GS_FONT_WEIGHT_NORMAL); + } + + tem = [dict objectForKey: NSFontWidthTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WIDTH; + + dat->width = [tem floatValue] > 0 + ? GS_FONT_WIDTH_EXPANDED + : ([tem floatValue] < 0 + ? GS_FONT_WIDTH_NORMAL + : GS_FONT_WIDTH_CONDENSED); + } + } +} + +static bool +ns_font_descs_match_p (NSFontDescriptor *desc, NSFontDescriptor *target) +{ + struct gs_font_data dat; + struct gs_font_data t; + + ns_get_font_data (desc, &dat); + ns_get_font_data (target, &t); + + if (!(t.specified & GS_SPECIFIED_WIDTH)) + t.width = GS_FONT_WIDTH_NORMAL; + if (!(t.specified & GS_SPECIFIED_WEIGHT)) + t.weight = GS_FONT_WEIGHT_NORMAL; + if (!(t.specified & GS_SPECIFIED_SPACING)) + t.monospace_p = false; + if (!(t.specified & GS_SPECIFIED_SLANT)) + t.slant = GS_FONT_SLANT_NORMAL; + + if (!(t.specified & GS_SPECIFIED_FAMILY)) + emacs_abort (); + + bool match_p = true; + + if (dat.specified & GS_SPECIFIED_WIDTH + && dat.width != t.width) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_WEIGHT + && dat.weight != t.weight) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SPACING + && dat.monospace_p != t.monospace_p) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SLANT + && dat.monospace_p != t.monospace_p) + { + if (NSFONT_TRACE) + printf ("Matching monospace for %s: %d %d\n", + t.family_name, dat.monospace_p, + t.monospace_p); + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_FAMILY + && strcmp (dat.family_name, t.family_name)) + match_p = false; + + gout: + ns_done_font_data (&dat); + ns_done_font_data (&t); + + return match_p; } +/* Font glyph and metrics caching functions, implemented at end. */ +static void ns_uni_to_glyphs (struct nsfont_info *font_info, + unsigned char block); +static void ns_glyph_metrics (struct nsfont_info *font_info, + unsigned int block); + +#define INVALID_GLYPH 0xFFFF + +/* ========================================================================== + + Utilities + + ========================================================================== */ + /* Extract family name from a font spec. */ static NSString * @@ -91,66 +313,116 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, { char *tmp = xlispstrdup (SYMBOL_NAME (tem)); NSString *family; - ns_unescape_name (tmp); family = [NSString stringWithUTF8String: tmp]; xfree (tmp); return family; } } - -/* Return 0 if attr not set, else value (which might also be 0). - On Leopard 0 gets returned even on descriptors where the attribute - was never set, so there's no way to distinguish between unspecified - and set to not have. Callers should assume 0 means unspecified. */ -static float -ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait) -{ - NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute]; - NSNumber *val = [tdict objectForKey: trait]; - return val == nil ? 0.0F : [val floatValue]; -} - - /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang to NSFont descriptor. Information under extra only needed for matching. */ -#define STYLE_REF 100 static NSFontDescriptor * ns_spec_to_descriptor (Lisp_Object font_spec) { NSFontDescriptor *fdesc; NSMutableDictionary *fdAttrs = [NSMutableDictionary new]; - NSMutableDictionary *tdict = [NSMutableDictionary new]; NSString *family = ns_get_family (font_spec); - float n; - - /* Add each attr in font_spec to fdAttrs. */ - n = min (FONT_WEIGHT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWeightTrait]; - n = min (FONT_SLANT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontSlantTrait]; - n = min (FONT_WIDTH_NUMERIC (font_spec), 200); - if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10)) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWidthTrait]; - if ([tdict count] > 0) - [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + NSMutableDictionary *tdict = [NSMutableDictionary new]; - fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] - retain] autorelease]; + Lisp_Object tem; + + tem = FONT_SLANT_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qitalic) || EQ (tem, Qoblique)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontSlantTrait]; + else if (EQ (tem, intern ("reverse-italic")) || + EQ (tem, intern ("reverse-oblique"))) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontSlantTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontSlantTrait]; + } + + tem = FONT_WIDTH_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qcondensed)) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWidthTrait]; + else if (EQ (tem, Qexpanded)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWidthTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWidthTrait]; + } + + tem = FONT_WEIGHT_SYMBOLIC (font_spec); + + if (!NILP (tem)) + { + if (EQ (tem, Qbold)) + { + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWeightTrait]; + } + else if (EQ (tem, Qlight)) + { + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWeightTrait]; + } + else + { + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWeightTrait]; + } + } + + tem = AREF (font_spec, FONT_SPACING_INDEX); if (family != nil) { - NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family]; - fdesc = [[fdesc2 retain] autorelease]; + [fdAttrs setObject: family + forKey: NSFontFamilyAttribute]; } - [fdAttrs release]; + if (FIXNUMP (tem)) + { + if (XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL) + { + [fdAttrs setObject: [NSNumber numberWithBool:YES] + forKey: NSFontFixedAdvanceAttribute]; + } + else + { + [fdAttrs setObject: [NSNumber numberWithBool:NO] + forKey: NSFontFixedAdvanceAttribute]; + } + } + + /* Handle special families such as ``fixed'' or ``Sans Serif''. */ + + if ([family isEqualToString: @"fixed"]) + { + [fdAttrs setObject: [[NSFont userFixedPitchFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + else if ([family isEqualToString: @"Sans Serif"]) + { + [fdAttrs setObject: [[NSFont userFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + + [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + + fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] + retain] autorelease]; + [tdict release]; + [fdAttrs release]; return fdesc; } @@ -161,61 +433,64 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, Lisp_Object extra, const char *style) { - Lisp_Object font_entity = font_make_entity (); - /* NSString *psName = [desc postscriptName]; */ - NSString *family = [desc objectForKey: NSFontFamilyAttribute]; - unsigned int traits = [desc symbolicTraits]; - char *escapedFamily; - - /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */ - if (family == nil) - family = [desc objectForKey: NSFontNameAttribute]; - if (family == nil) - family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - - escapedFamily = xstrdup ([family UTF8String]); - ns_escape_name (escapedFamily); - - ASET (font_entity, FONT_TYPE_INDEX, Qns); - ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple); - ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily)); - ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); - ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); - - FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - traits & NSFontBoldTrait ? Qbold : Qmedium); -/* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - traits & NSFontItalicTrait ? Qitalic : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - traits & NSFontCondensedTrait ? Qcondensed : - traits & NSFontExpandedTrait ? Qexpanded : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/ - - ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_SPACING_INDEX, - make_fixnum([desc symbolicTraits] & NSFontMonoSpaceTrait - ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); - - ASET (font_entity, FONT_EXTRA_INDEX, extra); - ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + Lisp_Object font_entity = font_make_entity (); + struct gs_font_data data; + ns_get_font_data (desc, &data); + + ASET (font_entity, FONT_TYPE_INDEX, Qns); + ASET (font_entity, FONT_FOUNDRY_INDEX, Qns); + if (data.specified & GS_SPECIFIED_FAMILY) + ASET (font_entity, FONT_FAMILY_INDEX, intern (data.family_name)); + ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); + ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); + + if (data.specified & GS_SPECIFIED_WEIGHT) + { + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, + data.weight == GS_FONT_WEIGHT_BOLD + ? Qbold : (data.weight == GS_FONT_WEIGHT_LIGHT + ? Qlight : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, Qnormal); - if (NSFONT_TRACE) - { - fputs ("created font_entity:\n ", stderr); - debug_print (font_entity); - } + if (data.specified & GS_SPECIFIED_SLANT) + { + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, + data.slant == GS_FONT_SLANT_ITALIC + ? Qitalic : (data.slant == GS_FONT_SLANT_REVERSE_ITALIC + ? intern ("reverse-italic") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, Qnormal); + + if (data.specified & GS_SPECIFIED_WIDTH) + { + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, + data.width == GS_FONT_WIDTH_CONDENSED + ? Qcondensed : (data.width == GS_FONT_WIDTH_EXPANDED + ? intern ("expanded") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, Qnormal); - xfree (escapedFamily); - return font_entity; + ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_SPACING_INDEX, + make_fixnum ((data.specified & GS_SPECIFIED_WIDTH && data.monospace_p) + ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); + + ASET (font_entity, FONT_EXTRA_INDEX, extra); + ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + + if (NSFONT_TRACE) + { + fputs ("created font_entity:\n ", stderr); + debug_print (font_entity); + } + + ns_done_font_data (&data); + return font_entity; } @@ -223,8 +498,7 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, static Lisp_Object ns_fallback_entity (void) { - return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0] - fontDescriptor], Qnil, NULL); + return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 1] fontDescriptor], Qnil, NULL); } @@ -510,21 +784,20 @@ but also for ascii (which causes unnecessary font substitution). */ return families; } +/* GNUstep font matching is very mediocre (it can't even compare + symbolic styles correctly), which is why our own font matching + mechanism must be implemented. */ -/* Implementation for list() and match(). List() can return nil, match() -must return something. Strategy is to drop family name from attribute -matching set for match. */ +/* Implementation for list and match. */ static Lisp_Object ns_findfonts (Lisp_Object font_spec, BOOL isMatch) { Lisp_Object tem, list = Qnil; - NSFontDescriptor *fdesc, *desc; - NSMutableSet *fkeys; - NSArray *matchingDescs; - NSEnumerator *dEnum; - NSString *family; + NSFontDescriptor *fdesc; + NSArray *all_descs; + GSFontEnumerator *enumerator = [GSFontEnumerator sharedEnumerator]; + NSSet *cFamilies; - BOOL foundItal = NO; block_input (); if (NSFONT_TRACE) @@ -537,43 +810,22 @@ but also for ascii (which causes unnecessary font substitution). */ cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90); fdesc = ns_spec_to_descriptor (font_spec); - fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]]; - if (isMatch) - [fkeys removeObject: NSFontFamilyAttribute]; - - matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys]; + all_descs = [enumerator availableFontDescriptors]; - if (NSFONT_TRACE) - NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc, - (unsigned long)[matchingDescs count]); - - for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);) + for (NSFontDescriptor *desc in all_descs) { if (![cFamilies containsObject: [desc objectForKey: NSFontFamilyAttribute]]) continue; + if (!ns_font_descs_match_p (fdesc, desc)) + continue; + tem = ns_descriptor_to_entity (desc, - AREF (font_spec, FONT_EXTRA_INDEX), + AREF (font_spec, FONT_EXTRA_INDEX), NULL); if (isMatch) return tem; list = Fcons (tem, list); - if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05) - foundItal = YES; - } - - /* Add synthItal member if needed. */ - family = [fdesc objectForKey: NSFontFamilyAttribute]; - if (family != nil && !foundItal && !NILP (list)) - { - NSFontDescriptor *s1 = [NSFontDescriptor new]; - NSFontDescriptor *sDesc - = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait] - fontDescriptorWithFamily: family]; - list = Fcons (ns_descriptor_to_entity (sDesc, - AREF (font_spec, FONT_EXTRA_INDEX), - "synthItal"), list); - [s1 release]; } unblock_input (); @@ -652,7 +904,6 @@ Properties to be considered are same as for list(). */ objectEnumerator]; while ((family = [families nextObject])) list = Fcons (intern ([family UTF8String]), list); - /* FIXME: escape the name? */ if (NSFONT_TRACE) fprintf (stderr, "nsfont: list families returning %"pD"d entries\n", @@ -668,18 +919,15 @@ Properties to be considered are same as for list(). */ static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size) { - BOOL synthItal; - unsigned int traits = 0; struct nsfont_info *font_info; struct font *font; NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity); NSFontManager *fontMgr = [NSFontManager sharedFontManager]; NSString *family; NSFont *nsfont, *sfont; - Lisp_Object tem; NSRect brect; Lisp_Object font_object; - int fixLeopardBug; + Lisp_Object tem; block_input (); @@ -692,42 +940,20 @@ Properties to be considered are same as for list(). */ if (pixel_size <= 0) { /* try to get it out of frame params */ - Lisp_Object tem = get_frame_param (f, Qfontsize); - pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); + tem = get_frame_param (f, Qfontsize); + pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); } tem = AREF (font_entity, FONT_ADSTYLE_INDEX); - synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)), - 9); family = ns_get_family (font_entity); if (family == nil) family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that - when setting family in ns_spec_to_descriptor(). */ - if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F) - traits |= NSBoldFontMask; - if (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F) - traits |= NSItalicFontMask; - - /* see https://web.archive.org/web/20100201175731/http://cocoadev.com/forums/comments.php?DiscussionID=74 */ - fixLeopardBug = traits & NSBoldFontMask ? 10 : 5; - nsfont = [fontMgr fontWithFamily: family - traits: traits weight: fixLeopardBug - size: pixel_size]; - /* if didn't find, try synthetic italic */ - if (nsfont == nil && synthItal) - { - nsfont = [fontMgr fontWithFamily: family - traits: traits & ~NSItalicFontMask - weight: fixLeopardBug size: pixel_size]; - } + + nsfont = [NSFont fontWithDescriptor: fontDesc + size: pixel_size]; if (nsfont == nil) - { - message_with_string ("*** Warning: font in family `%s' not found", - build_string ([family UTF8String]), 1); - nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; - } + nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; if (NSFONT_TRACE) NSLog (@"%@\n", nsfont); @@ -740,7 +966,7 @@ when setting family in ns_spec_to_descriptor(). */ if (!font) { unblock_input (); - return Qnil; /* FIXME: other terms do, but returning Qnil causes segfault. */ + return Qnil; } font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs); @@ -781,7 +1007,7 @@ when setting family in ns_spec_to_descriptor(). */ font_info->name = xstrdup (fontName); font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask; font_info->ital = - synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); + ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); /* Metrics etc.; some fonts return an unusually large max advance, so we only use it for fonts that have wide characters. */ @@ -808,8 +1034,6 @@ when setting family in ns_spec_to_descriptor(). */ lrint (brect.size.width - (CGFloat) font_info->width); /* set up metrics portion of font struct */ - font->ascent = lrint([sfont ascender]); - font->descent = -lrint(floor(adjusted_descender)); font->space_width = lrint (ns_char_width (sfont, ' ')); font->max_width = lrint (font_info->max_bounds.width); font->min_width = font->space_width; /* Approximate. */ @@ -871,7 +1095,7 @@ when setting family in ns_spec_to_descriptor(). */ { struct nsfont_info *font_info = (struct nsfont_info *)font; unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff; - unsigned short g; + unsigned int g; if (c > 0xFFFF) return FONT_INVALID_CODE; @@ -934,51 +1158,23 @@ is false when (FROM > 0 || TO < S->nchars). */ static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, bool with_background) -/* NOTE: focus and clip must be set. */ { - static unsigned char cbuf[1024]; - unsigned char *c = cbuf; -#if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22 - static CGFloat advances[1024]; - CGFloat *adv = advances; -#else - static float advances[1024]; - float *adv = advances; -#endif + NSGlyph *c = alloca ((to - from) * sizeof *c); + struct face *face; NSRect r; struct nsfont_info *font; - NSColor *col, *bgCol; - unsigned *t = s->char2b; - int i, len, flags; + NSColor *col; + int len = to - from; char isComposite = s->first_glyph->type == COMPOSITE_GLYPH; block_input (); - font = (struct nsfont_info *)s->face->font; + font = (struct nsfont_info *) s->font; if (font == NULL) font = (struct nsfont_info *)FRAME_FONT (s->f); - /* Select face based on input flags. */ - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - - switch (flags) - { - case NS_DUMPGLYPH_CURSOR: - face = s->face; - break; - case NS_DUMPGLYPH_MOUSEFACE: - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - break; - default: - face = s->face; - } + face = s->face; r.origin.x = s->x; if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p) @@ -987,91 +1183,24 @@ is false when (FROM > 0 || TO < S->nchars). */ r.origin.y = s->y; r.size.height = FONT_HEIGHT (font); - /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask - NS to render the string, it will come out differently from the individual - character widths added up because of layout processing. */ - { - int cwidth, twidth = 0; - int hi, lo; - /* FIXME: composition: no vertical displacement is considered. */ - t += from; /* advance into composition */ - for (i = from; i < to; i++, t++) - { - hi = (*t & 0xFF00) >> 8; - lo = *t & 0x00FF; - if (isComposite) - { - if (!s->first_glyph->u.cmp.automatic) - cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth; - else - { - Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); - Lisp_Object glyph = LGSTRING_GLYPH (gstring, i); - if (NILP (LGLYPH_ADJUSTMENT (glyph))) - cwidth = LGLYPH_WIDTH (glyph); - else - { - cwidth = LGLYPH_WADJUST (glyph); - *(adv-1) += LGLYPH_XOFF (glyph); - } - } - } - else - { - if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */ - ns_glyph_metrics (font, hi); - cwidth = font->metrics[hi][lo].width; - } - twidth += cwidth; - *adv++ = cwidth; - c += CHAR_STRING (*t, c); /* This converts the char to UTF-8. */ - } - len = adv - advances; - r.size.width = twidth; - *c = 0; - } + for (int i = from; i < to; ++i) + c[i] = s->char2b[i]; /* Fill background if requested. */ if (with_background && !isComposite) { - NSRect br = r; - int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); - int mbox_line_width = max (s->face->box_vertical_line_width, 0); - - if (s->row->full_width_p) - { - if (br.origin.x <= fibw + 1 + mbox_line_width) - { - br.size.width += br.origin.x - mbox_line_width; - br.origin.x = mbox_line_width; - } - if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) - <= fibw+1) - br.size.width += fibw; - } - if (s->face->box == FACE_NO_BOX) - { - /* Expand unboxed top row over internal border. */ - if (br.origin.y <= fibw + 1 + mbox_line_width) - { - br.size.height += br.origin.y; - br.origin.y = 0; - } - } - else - { - int correction = abs (s->face->box_horizontal_line_width)+1; - br.origin.y += correction; - br.size.height -= 2*correction; - correction = abs (s->face->box_vertical_line_width)+1; - br.origin.x += correction; - br.size.width -= 2*correction; - } + NSRect br = NSMakeRect (x, y - FONT_BASE (s->font), + s->width, FONT_HEIGHT (s->font)); if (!s->face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); @@ -1080,43 +1209,32 @@ is false when (FROM > 0 || TO < S->nchars). */ NSRectFill (br); } - /* set up for character rendering */ r.origin.y = y; - col = (NS_FACE_FOREGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - - bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil - : (NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f))); + if (s->hl == DRAW_CURSOR) + col = FRAME_BACKGROUND_COLOR (s->f); + else + col = (NS_FACE_FOREGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) + : FRAME_FOREGROUND_COLOR (s->f)); /* render under GNUstep using DPS */ { - NSGraphicsContext *context = GSCurrentContext (); - + NSGraphicsContext *context = [NSGraphicsContext currentContext]; DPSgsave (context); - [font->nsfont set]; - - /* do erase if "foreground" mode */ - if (bgCol != nil) + if (s->clip_head) { - [bgCol set]; - DPSmoveto (context, r.origin.x, r.origin.y); -/*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */ - DPSxshow (context, (const char *) cbuf, advances, len); - DPSstroke (context); - [col set]; -/*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */ + DPSrectclip (context, s->clip_head->x, 0, + FRAME_PIXEL_WIDTH (s->f), + FRAME_PIXEL_HEIGHT (s->f)); } + [font->nsfont set]; [col set]; - /* draw with DPSxshow () */ DPSmoveto (context, r.origin.x, r.origin.y); - DPSxshow (context, (const char *) cbuf, advances, len); + GSShowGlyphs (context, c, len); DPSstroke (context); DPSgrestore (context); @@ -1126,6 +1244,360 @@ is false when (FROM > 0 || TO < S->nchars). */ return to-from; } +static NSUInteger +ns_font_shape (NSFont *font, NSString *string, + struct ns_glyph_layout *glyph_layouts, NSUInteger glyph_len, + enum lgstring_direction dir) +{ + NSUInteger i; + NSUInteger result = 0; + NSTextStorage *textStorage; + NSLayoutManager *layoutManager; + NSTextContainer *textContainer; + NSUInteger stringLength; + NSPoint spaceLocation; + /* numberOfGlyphs can't actually be 0, but this pacifies GCC */ + NSUInteger used, numberOfGlyphs = 0; + + textStorage = [[NSTextStorage alloc] initWithString:string]; + layoutManager = [[NSLayoutManager alloc] init]; + textContainer = [[NSTextContainer alloc] init]; + + /* Append a trailing space to measure baseline position. */ + [textStorage appendAttributedString:([[[NSAttributedString alloc] + initWithString:@" "] autorelease])]; + [textStorage setFont:font]; + [textContainer setLineFragmentPadding:0]; + + [layoutManager addTextContainer:textContainer]; + [textContainer release]; + [textStorage addLayoutManager:layoutManager]; + [layoutManager release]; + + if (!(textStorage && layoutManager && textContainer)) + emacs_abort (); + + stringLength = [string length]; + + /* Force layout. */ + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength]; + + /* Remove the appended trailing space because otherwise it may + generate a wrong result for a right-to-left text. */ + [textStorage beginEditing]; + [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))]; + [textStorage endEditing]; + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + i = 0; + while (i < stringLength) + { + NSRange range; + NSFont *fontInTextStorage = + [textStorage attribute: NSFontAttributeName + atIndex:i + longestEffectiveRange: &range + inRange: NSMakeRange (0, stringLength)]; + + if (!(fontInTextStorage == font + || [[fontInTextStorage fontName] isEqualToString:[font fontName]])) + break; + i = NSMaxRange (range); + } + if (i < stringLength) + /* Make the test `used <= glyph_len' below fail if textStorage + contained some fonts other than the specified one. */ + used = glyph_len + 1; + else + { + NSRange range = NSMakeRange (0, stringLength); + + range = [layoutManager glyphRangeForCharacterRange:range + actualCharacterRange:NULL]; + numberOfGlyphs = NSMaxRange (range); + used = numberOfGlyphs; + for (i = 0; i < numberOfGlyphs; i++) + if ([layoutManager notShownAttributeForGlyphAtIndex:i]) + used--; + } + + if (0 < used && used <= glyph_len) + { + NSUInteger glyphIndex, prevGlyphIndex; + NSUInteger *permutation; + NSRange compRange, range; + CGFloat totalAdvance; + + glyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + permutation = NULL; +#define RIGHT_TO_LEFT_P permutation + + /* Fill the `comp_range' member of struct mac_glyph_layout, and + setup a permutation for right-to-left text. */ + compRange = NSMakeRange (0, 0); + for (range = NSMakeRange (0, 0); NSMaxRange (range) < used; + range.length++) + { + struct ns_glyph_layout *gl = glyph_layouts + NSMaxRange (range); + NSUInteger characterIndex = + [layoutManager characterIndexForGlyphAtIndex:glyphIndex]; + + gl->string_index = characterIndex; + + if (characterIndex >= NSMaxRange (compRange)) + { + compRange.location = NSMaxRange (compRange); + do + { + NSRange characterRange = + [string + rangeOfComposedCharacterSequenceAtIndex:characterIndex]; + + compRange.length = + NSMaxRange (characterRange) - compRange.location; + [layoutManager glyphRangeForCharacterRange:compRange + actualCharacterRange:&characterRange]; + characterIndex = NSMaxRange (characterRange) - 1; + } + while (characterIndex >= NSMaxRange (compRange)); + + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + range = NSMakeRange (NSMaxRange (range), 0); + } + + gl->comp_range.location = compRange.location; + gl->comp_range.length = compRange.length; + + while (++glyphIndex < numberOfGlyphs) + if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + break; + } + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + /* Then fill the remaining members. */ + glyphIndex = prevGlyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + if (!RIGHT_TO_LEFT_P) + totalAdvance = 0; + else + { + NSUInteger nrects; + NSRect *glyphRects = + [layoutManager + rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs)) + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + + totalAdvance = NSMaxX (glyphRects[0]); + } + + for (i = 0; i < used; i++) + { + struct ns_glyph_layout *gl; + NSPoint location; + NSUInteger nextGlyphIndex; + NSRange glyphRange; + NSRect *glyphRects; + NSUInteger nrects; + + if (!RIGHT_TO_LEFT_P) + gl = glyph_layouts + i; + else + { + NSUInteger dest = permutation[i]; + + gl = glyph_layouts + dest; + if (i < dest) + { + NSUInteger tmp = gl->string_index; + + gl->string_index = glyph_layouts[i].string_index; + glyph_layouts[i].string_index = tmp; + } + } + gl->glyph_id = [layoutManager glyphAtIndex: glyphIndex]; + + location = [layoutManager locationForGlyphAtIndex:glyphIndex]; + gl->baseline_delta = spaceLocation.y - location.y; + + for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs; + nextGlyphIndex++) + if (![layoutManager + notShownAttributeForGlyphAtIndex:nextGlyphIndex]) + break; + + if (!RIGHT_TO_LEFT_P) + { + CGFloat maxX; + + if (prevGlyphIndex == 0) + glyphRange = NSMakeRange (0, nextGlyphIndex); + else + glyphRange = NSMakeRange (glyphIndex, + nextGlyphIndex - glyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + maxX = max (NSMaxX (glyphRects[0]), totalAdvance); + gl->advance_delta = location.x - totalAdvance; + gl->advance = maxX - totalAdvance; + totalAdvance = maxX; + } + else + { + CGFloat minX; + + if (nextGlyphIndex == numberOfGlyphs) + glyphRange = NSMakeRange (prevGlyphIndex, + numberOfGlyphs - prevGlyphIndex); + else + glyphRange = NSMakeRange (prevGlyphIndex, + glyphIndex + 1 - prevGlyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + minX = min (NSMinX (glyphRects[0]), totalAdvance); + gl->advance = totalAdvance - minX; + totalAdvance = minX; + gl->advance_delta = location.x - totalAdvance; + } + + prevGlyphIndex = glyphIndex + 1; + glyphIndex = nextGlyphIndex; + } + + if (RIGHT_TO_LEFT_P) + xfree (permutation); + +#undef RIGHT_TO_LEFT_P + + result = used; + } + [textStorage release]; + + return result; +} + +static Lisp_Object +nsfont_shape (Lisp_Object lgstring, Lisp_Object direction) +{ + struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring)); + struct nsfont_info *font_info = (struct nsfont_info *) font; + struct ns_glyph_layout *glyph_layouts; + NSFont *nsfont = font_info->nsfont; + ptrdiff_t glyph_len, len, i; + Lisp_Object tem; + unichar *mb_buf; + NSUInteger used; + + glyph_len = LGSTRING_GLYPH_LEN (lgstring); + for (i = 0; i < glyph_len; ++i) + { + tem = LGSTRING_GLYPH (lgstring, i); + + if (NILP (tem)) + break; + } + + len = i; + + if (INT_MAX / 2 < len) + memory_full (SIZE_MAX); + + block_input (); + + mb_buf = alloca (len * sizeof *mb_buf); + + for (i = 0; i < len; ++i) + { + uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i)); + mb_buf[i] = (unichar) c; + } + + NSString *string = [NSString stringWithCharacters: mb_buf + length: len]; + unblock_input (); + + if (!string) + return Qnil; + + block_input (); + + enum lgstring_direction dir = DIR_UNKNOWN; + + if (EQ (direction, QL2R)) + dir = DIR_L2R; + else if (EQ (direction, QR2L)) + dir = DIR_R2L; + glyph_layouts = alloca (sizeof (struct ns_glyph_layout) * glyph_len); + used = ns_font_shape (nsfont, string, glyph_layouts, glyph_len, dir); + + for (i = 0; i < used; i++) + { + Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i); + struct ns_glyph_layout *gl = glyph_layouts + i; + EMACS_INT from, to; + struct font_metrics metrics; + + if (NILP (lglyph)) + { + lglyph = LGLYPH_NEW (); + LGSTRING_SET_GLYPH (lgstring, i, lglyph); + } + + from = gl->comp_range.location; + LGLYPH_SET_FROM (lglyph, from); + + to = gl->comp_range.location + gl->comp_range.length; + LGLYPH_SET_TO (lglyph, to - 1); + + /* LGLYPH_CHAR is used in `describe-char' for checking whether + the composition is trivial. */ + { + UTF32Char c; + + if (mb_buf[gl->string_index] >= 0xD800 + && mb_buf[gl->string_index] < 0xDC00) + c = (((mb_buf[gl->string_index] - 0xD800) << 10) + + (mb_buf[gl->string_index + 1] - 0xDC00) + 0x10000); + else + c = mb_buf[gl->string_index]; + + LGLYPH_SET_CHAR (lglyph, c); + } + + { + unsigned long cc = gl->glyph_id; + LGLYPH_SET_CODE (lglyph, cc); + } + + nsfont_text_extents (font, &gl->glyph_id, 1, &metrics); + LGLYPH_SET_WIDTH (lglyph, metrics.width); + LGLYPH_SET_LBEARING (lglyph, metrics.lbearing); + LGLYPH_SET_RBEARING (lglyph, metrics.rbearing); + LGLYPH_SET_ASCENT (lglyph, metrics.ascent); + LGLYPH_SET_DESCENT (lglyph, metrics.descent); + } + unblock_input (); + + return make_fixnum (used); +} /* ========================================================================== @@ -1134,6 +1606,50 @@ is false when (FROM > 0 || TO < S->nchars). */ ========================================================================== */ +static NSGlyph +ns_uni_to_glyphs_1 (struct nsfont_info *info, unsigned int c) +{ + unichar characters[] = { c }; + NSString *string = + [NSString stringWithCharacters: characters + length: 1]; + NSDictionary *attributes = + [NSDictionary dictionaryWithObjectsAndKeys: + info->nsfont, NSFontAttributeName, nil]; + NSTextStorage *storage = [[NSTextStorage alloc] initWithString: string + attributes: attributes]; + NSTextContainer *text_container = [[NSTextContainer alloc] init]; + NSLayoutManager *manager = [[NSLayoutManager alloc] init]; + + [manager addTextContainer: text_container]; + [text_container release]; /* Retained by manager */ + [storage addLayoutManager: manager]; + [manager release]; /* Retained by storage */ + + NSFont *font_in_storage = [storage attribute: NSFontAttributeName + atIndex:0 + effectiveRange: NULL]; + NSGlyph glyph = FONT_INVALID_CODE; + + if ((font_in_storage == info->nsfont + || [[font_in_storage fontName] isEqualToString: [info->nsfont fontName]])) + { + @try + { + glyph = [manager glyphAtIndex: 0]; + } + @catch (NSException *e) + { + /* GNUstep bug? */ + glyph = 'X'; + } + } + + [storage release]; + + return glyph; +} + /* Find and cache corresponding glyph codes for unicode values in given hi-byte block of 256. */ static void @@ -1141,7 +1657,7 @@ is false when (FROM > 0 || TO < S->nchars). */ { unichar *unichars = xmalloc (0x101 * sizeof (unichar)); unsigned int i, g, idx; - unsigned short *glyphs; + unsigned int *glyphs; if (NSFONT_TRACE) fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n", @@ -1149,7 +1665,7 @@ is false when (FROM > 0 || TO < S->nchars). */ block_input (); - font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short)); + font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned int)); if (!unichars || !(font_info->glyphs[block])) emacs_abort (); @@ -1166,7 +1682,8 @@ is false when (FROM > 0 || TO < S->nchars). */ for (i = 0; i < 0x100; i++, glyphs++) { g = unichars[i]; - *glyphs = g; + NSGlyph glyph = ns_uni_to_glyphs_1 (font_info, g); + *glyphs = glyph; } } @@ -1175,18 +1692,19 @@ is false when (FROM > 0 || TO < S->nchars). */ } -/* Determine and cache metrics for corresponding glyph codes in given - hi-byte block of 256. */ +/* Determine and cache metrics for glyphs in given hi-byte block of + 256. */ static void -ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block) +ns_glyph_metrics (struct nsfont_info *font_info, unsigned int block) { - unsigned int i, g; + unsigned int i; + NSGlyph g; unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs]; NSFont *sfont; struct font_metrics *metrics; if (NSFONT_TRACE) - fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n", + fprintf (stderr, "%p\tComputing metrics for glyphs in block %u\n", font_info, block); /* not implemented yet (as of startup 0.18), so punt */ @@ -1209,19 +1727,14 @@ is false when (FROM > 0 || TO < S->nchars). */ w = max ([sfont advancementForGlyph: g].width, 2.0); metrics->width = lrint (w); - lb = r.origin.x; - rb = r.size.width - w; - // Add to bearing for LCD smoothing. We don't know if it is there. - if (lb < 0) - metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN); - if (font_info->ital) - rb += (CGFloat) (0.22F * font_info->height); - metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN); - - metrics->descent = r.origin.y < 0 ? -r.origin.y : 0; - /* lrint (hshrink * [sfont ascender] + expand * hd/2); */ - metrics->ascent = r.size.height - metrics->descent; - /* -lrint (hshrink* [sfont descender] - expand * hd/2); */ + lb = NSMinX (r); + rb = NSMaxX (r); + + metrics->rbearing = lrint (rb); + metrics->lbearing = lrint (lb); + + metrics->descent = NSMinY (r); + metrics->ascent = NSMaxY (r); } unblock_input (); } @@ -1257,6 +1770,7 @@ is false when (FROM > 0 || TO < S->nchars). */ .has_char = nsfont_has_char, .encode_char = nsfont_encode_char, .text_extents = nsfont_text_extents, + .shape = nsfont_shape, .draw = nsfont_draw, }; @@ -1265,7 +1779,6 @@ is false when (FROM > 0 || TO < S->nchars). */ { DEFSYM (Qcondensed, "condensed"); DEFSYM (Qexpanded, "expanded"); - DEFSYM (Qapple, "apple"); DEFSYM (Qmedium, "medium"); DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script, doc: /* Internal use: maps font registry to Unicode script. */); diff --git a/src/nsterm.h b/src/nsterm.h index c750d1bd99..8175f99664 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -820,7 +820,7 @@ #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) XCharStruct max_bounds; /* We compute glyph codes and metrics on-demand in blocks of 256 indexed by hibyte, lobyte. */ - unsigned short **glyphs; /* map Unicode index to glyph */ + unsigned int **glyphs; /* map Unicode index to glyph */ struct font_metrics **metrics; }; #endif diff --git a/src/nsterm.m b/src/nsterm.m index 4c2a3f287c..051ee511ca 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1078,11 +1078,20 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) /* clipping */ if (r) { - [[NSGraphicsContext currentContext] saveGraphicsState]; + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; if (n == 2) NSRectClipList (r, 2); else NSRectClip (*r); +#ifdef NS_IMPL_GNUSTEP + DPSrectclip (ctx, NSMinX (*r), NSMinY (*r), + NSWidth (*r), NSHeight (*r)); + + if (n == 2) + DPSrectclip (ctx, NSMinX (r[1]), NSMinY (r[1]), + NSWidth (r[1]), NSHeight (r[1])); +#endif gsaved = YES; } } @@ -2440,9 +2449,6 @@ Hide the window (X11 semantics) EmacsView *view = FRAME_NS_VIEW (f); FRAME_POINTER_TYPE (f) = cursor; [[view window] invalidateCursorRectsForView: view]; - /* Redisplay assumes this function also draws the changed frame - cursor, but this function doesn't, so do it explicitly. */ - gui_update_cursor (f, 1); } } @@ -2852,31 +2858,31 @@ Hide the window (X11 semantics) External (RIF); compute left/right overhang of whole string and set in s -------------------------------------------------------------------------- */ { - struct font *font = s->font; - - if (s->char2b) + if (s->cmp == NULL + && (s->first_glyph->type == CHAR_GLYPH + || s->first_glyph->type == COMPOSITE_GLYPH)) { struct font_metrics metrics; - unsigned int codes[2]; - codes[0] = *(s->char2b); - codes[1] = *(s->char2b + s->nchars - 1); - font->driver->text_extents (font, codes, 2, &metrics); - s->left_overhang = -metrics.lbearing; - s->right_overhang - = metrics.rbearing > metrics.width - ? metrics.rbearing - metrics.width : 0; + if (s->first_glyph->type == CHAR_GLYPH) + { + struct font *font = s->font; + font->driver->text_extents (font, s->char2b, s->nchars, &metrics); + } + else + { + Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); + + composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); + } + s->right_overhang = (metrics.rbearing > metrics.width + ? metrics.rbearing - metrics.width : 0); + s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0; } - else + else if (s->cmp) { - s->left_overhang = 0; -#ifdef NS_IMPL_GNUSTEP - if (EQ (font->driver->type, Qns)) - s->right_overhang = ((struct nsfont_info *)font)->ital ? - FONT_HEIGHT (font) * 0.2 : 0; - else -#endif - s->right_overhang = 0; + s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width; + s->left_overhang = - s->cmp->lbearing; } } @@ -3016,14 +3022,13 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. struct frame *f = WINDOW_XFRAME (w); struct glyph *phys_cursor_glyph; struct glyph *cursor_glyph; - struct face *face; - NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f); /* If cursor is out of bounds, don't draw garbage. This can happen in mini-buffer windows when switching between echo area glyphs and mini-buffer. */ - NSTRACE ("ns_draw_window_cursor"); + NSTRACE ("ns_draw_window_cursor (on = %d, cursor_type = %d)", + on_p, cursor_type); if (!on_p) return; @@ -3039,6 +3044,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL) { + NSTRACE_MSG ("No phys cursor glyph was found!"); + if (glyph_row->exact_window_width_line_p && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) { @@ -3048,10 +3055,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. return; } - /* We draw the cursor (with NSRectFill), then draw the glyph on top - (other terminals do it the other way round). We must set - w->phys_cursor_width to the cursor width. For bar cursors, that - is CURSOR_WIDTH; for box cursors, it is the glyph width. */ get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h); /* The above get_phys_cursor_geometry call set w->phys_cursor_width @@ -3083,17 +3086,15 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. /* Prevent the cursor from being drawn outside the text area. */ r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA)); - ns_focus (f, &r, 1); + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSrectclip (ctx, r.origin.x, r.origin.y, + r.size.width, r.size.height); +#endif - face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id); - if (face && NS_FACE_BACKGROUND (face) - == ns_index_color (FRAME_CURSOR_COLOR (f), f)) - { - [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set]; - hollow_color = FRAME_CURSOR_COLOR (f); - } - else - [FRAME_CURSOR_COLOR (f) set]; + [FRAME_CURSOR_COLOR (f) set]; switch (cursor_type) { @@ -3101,13 +3102,11 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. case NO_CURSOR: break; case FILLED_BOX_CURSOR: - NSRectFill (r); + draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); break; case HOLLOW_BOX_CURSOR: - NSRectFill (r); - [hollow_color set]; - NSRectFill (NSInsetRect (r, 1, 1)); - [FRAME_CURSOR_COLOR (f) set]; + draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT); + [NSBezierPath strokeRect: r]; break; case HBAR_CURSOR: NSRectFill (r); @@ -3123,12 +3122,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. NSRectFill (s); break; } - ns_unfocus (f); - /* Draw the character under the cursor. Other terms only draw - the character on top of box cursors, so do the same here. */ - if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR) - draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); + [ctx restoreGraphicsState]; } @@ -3308,16 +3303,18 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if (s->for_overlaps) return; + if (s->hl == DRAW_CURSOR) + [FRAME_BACKGROUND_COLOR (s->f) set]; + else if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + /* Do underline. */ if (face->underline) { if (s->face->underline == FACE_UNDER_WAVE) { - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; - ns_draw_underwave (s, width, x); } else if (s->face->underline == FACE_UNDER_LINE) @@ -3388,11 +3385,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. s->underline_position = position; r = NSMakeRect (x, s->ybase + position, width, thickness); - - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; NSRectFill (r); } } @@ -3402,11 +3394,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. { NSRect r; r = NSMakeRect (x, s->y, width, 1); - - if (face->overline_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->overline_color, s->f) set]; NSRectFill (r); } @@ -3429,10 +3416,6 @@ larger if there are taller display elements (e.g., characters dy = lrint ((glyph_height - h) / 2); r = NSMakeRect (x, glyph_y + dy, width, 1); - if (face->strike_through_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->strike_through_color, s->f) set]; NSRectFill (r); } } @@ -3580,17 +3563,7 @@ Function modeled after x_draw_glyph_string_box (). struct glyph *last_glyph; NSRect r; int hthickness, vthickness; - struct face *face; - - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = s->face; + struct face *face = s->face; vthickness = face->box_vertical_line_width; hthickness = face->box_horizontal_line_width; @@ -3664,34 +3637,26 @@ Function modeled after x_draw_glyph_string_box (). || FONT_TOO_HIGH (s->font) || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) { - struct face *face; - if (s->hl == DRAW_MOUSE_FACE) - { - face - = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + struct face *face = s->face; if (!face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set]; } - if (s->hl != DRAW_CURSOR) - { - NSRect r = NSMakeRect (s->x, s->y + box_line_width, - s->background_width, - s->height-2*box_line_width); - NSRectFill (r); - } + NSRect r = NSMakeRect (s->x, s->y + box_line_width, + s->background_width, + s->height-2*box_line_width); + NSRectFill (r); s->background_filled_p = 1; } @@ -3712,7 +3677,7 @@ Function modeled after x_draw_glyph_string_box (). int th; char raised_p; NSRect br; - struct face *face; + struct face *face = s->face; NSColor *tdCol; NSTRACE ("ns_dumpglyphs_image"); @@ -3733,15 +3698,6 @@ Function modeled after x_draw_glyph_string_box (). /* Draw BG: if we need larger area than image itself cleared, do that, otherwise, since we composite the image under NS (instead of mucking with its background color), we must clear just the image area. */ - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set]; @@ -3812,16 +3768,8 @@ Function modeled after x_draw_glyph_string_box (). if (s->hl == DRAW_CURSOR) { - [FRAME_CURSOR_COLOR (s->f) set]; - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) + [FRAME_CURSOR_COLOR (s->f) set]; tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); - else - /* Currently on NS img->mask is always 0. Since - get_window_cursor_type specifies a hollow box cursor when on - a non-masked image we never reach this clause. But we put it - in, in anticipation of better support for image masks on - NS. */ - tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); } else { @@ -3873,66 +3821,35 @@ Function modeled after x_draw_glyph_string_box (). static void ns_dumpglyphs_stretch (struct glyph_string *s) { - NSRect r[2]; NSRect glyphRect; - int n; - struct face *face; + struct face *face = s->face; NSColor *fgCol, *bgCol; if (!s->background_filled_p) { - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + face = s->face; bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); - glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); - - [bgCol set]; - - /* NOTE: under NS this is NOT used to draw cursors, but we must avoid - overwriting cursor (usually when cursor on a tab) */ if (s->hl == DRAW_CURSOR) - { - CGFloat x, width; + { + fgCol = bgCol; + bgCol = FRAME_CURSOR_COLOR (s->f); + } - /* FIXME: This looks like it will only work for left to - right languages. */ - x = NSMinX (glyphRect); - width = s->w->phys_cursor_width; - glyphRect.size.width -= width; - glyphRect.origin.x += width; + glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); - NSRectFill (glyphRect); + [bgCol set]; - /* Draw overlining, etc. on the cursor. */ - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) - ns_draw_text_decoration (s, face, bgCol, width, x); - else - ns_draw_text_decoration (s, face, fgCol, width, x); - } - else - { - NSRectFill (glyphRect); - } + NSRectFill (glyphRect); /* Draw overlining, etc. on the stretch glyph (or the part of the stretch glyph after the cursor). */ ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect), NSMinX (glyphRect)); - ns_unfocus (s->f); s->background_filled_p = 1; } } @@ -3941,7 +3858,7 @@ overwriting cursor (usually when cursor on a tab) */ static void ns_draw_glyph_string_foreground (struct glyph_string *s) { - int x, flags; + int x; struct font *font = s->font; /* If first glyph of S has a left box line, start drawing the text @@ -3952,15 +3869,9 @@ overwriting cursor (usually when cursor on a tab) */ else x = s->x; - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - font->driver->draw (s, s->cmp_from, s->nchars, x, s->ybase, - (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p) - || flags == NS_DUMPGLYPH_MOUSEFACE); + !s->for_overlaps && !s->background_filled_p); } @@ -4067,9 +3978,9 @@ overwriting cursor (usually when cursor on a tab) */ struct font *font = s->face->font; if (! font) font = FRAME_FONT (s->f); - NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string"); + NSTRACE ("ns_draw_glyph_string (hl = %u)", s->hl); - if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/) + if (s->next && s->right_overhang && !s->for_overlaps) { int width; struct glyph_string *next; @@ -4106,14 +4017,21 @@ overwriting cursor (usually when cursor on a tab) */ box_drawn_p = 1; } + n = ns_get_glyph_string_clip_rect (s, r); + + if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */ + && !s->clip_tail + && ((s->prev && s->prev->hl != s->hl && s->left_overhang) + || (s->next && s->next->hl != s->hl && s->right_overhang))) + r[0] = NSIntersectionRect (r[0], NSMakeRect (s->x, s->y, s->width, s->height)); + + ns_focus (s->f, r, n); + switch (s->first_glyph->type) { case IMAGE_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); ns_dumpglyphs_image (s, r[0]); - ns_unfocus (s->f); break; case XWIDGET_GLYPH: @@ -4126,57 +4044,36 @@ overwriting cursor (usually when cursor on a tab) */ case CHAR_GLYPH: case COMPOSITE_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - - if (s->for_overlaps || (s->cmp_from > 0 - && ! s->first_glyph->u.cmp.automatic)) - s->background_filled_p = 1; - else - ns_maybe_dumpglyphs_background - (s, s->first_glyph->type == COMPOSITE_GLYPH); - - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - { - BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + if (s->for_overlaps || (isComposite + && (s->cmp_from > 0 + && ! s->first_glyph->u.cmp.automatic))) + s->background_filled_p = 1; + else + ns_maybe_dumpglyphs_background + (s, s->first_glyph->type == COMPOSITE_GLYPH); - if (isComposite) - ns_draw_composite_glyph_string_foreground (s); - else - ns_draw_glyph_string_foreground (s); - } + if (isComposite) + ns_draw_composite_glyph_string_foreground (s); + else + ns_draw_glyph_string_foreground (s); - { - NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), - s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - [col set]; - - /* Draw underline, overline, strike-through. */ - ns_draw_text_decoration (s, s->face, col, s->width, s->x); + { + NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), + s->f) + : FRAME_FOREGROUND_COLOR (s->f)); + [col set]; + + /* Draw underline, overline, strike-through. */ + ns_draw_text_decoration (s, s->face, col, s->width, s->x); + } } - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - - ns_unfocus (s->f); break; case GLYPHLESS_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - if (s->for_overlaps || (s->cmp_from > 0 && ! s->first_glyph->u.cmp.automatic)) s->background_filled_p = 1; @@ -4186,7 +4083,6 @@ overwriting cursor (usually when cursor on a tab) */ /* ... */ /* Not yet implemented. */ /* ... */ - ns_unfocus (s->f); break; default: @@ -4195,13 +4091,88 @@ overwriting cursor (usually when cursor on a tab) */ /* Draw box if not done already. */ if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) + ns_dumpglyphs_box_or_relief (s); + + ns_unfocus (s->f); + + /* Draw surrounding overhangs. */ + if (s->prev) { - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - ns_dumpglyphs_box_or_relief (s); - ns_unfocus (s->f); + struct glyph_string *prev; + + for (prev = s->prev; prev; prev = prev->prev) + if (prev->hl != s->hl + && prev->x + prev->width + prev->right_overhang > s->x) + { + /* As prev was drawn while clipped to its own area, we + must draw the right_overhang part using s->hl now. */ + enum draw_glyphs_face save = prev->hl; + struct face *save_face = prev->face; + + prev->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + prev->num_clips = 1; + prev->hl = s->hl; + if (prev->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (prev); + else + ns_draw_composite_glyph_string_foreground (prev); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + [[NSGraphicsContext currentContext] restoreGraphicsState]; + prev->hl = save; + prev->face = save_face; + prev->num_clips = 0; + } } + if (s->next) + { + struct glyph_string *next; + + for (next = s->next; next; next = next->next) + if (next->hl != s->hl + && next->x - next->left_overhang < s->x + s->width) + { + /* As next will be drawn while clipped to its own area, + we must draw the left_overhang part using s->hl now. */ + enum draw_glyphs_face save = next->hl; + struct face *save_face = next->face; + + next->hl = s->hl; + next->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + next->num_clips = 1; + if (next->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (next); + else + ns_draw_composite_glyph_string_foreground (next); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + [[NSGraphicsContext currentContext] restoreGraphicsState]; + next->hl = save; + next->num_clips = 0; + next->face = save_face; + next->clip_head = next; + next->background_filled_p = 0; + } + } s->num_clips = 0; } diff --git a/src/xdisp.c b/src/xdisp.c index cb8b793cfb..bfe7c571ab 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -29295,7 +29295,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, for (s = head; s; s = s->next) FRAME_RIF (f)->draw_glyph_string (s); -#ifndef HAVE_NS /* When focus a sole frame and move horizontally, this clears on_p causing a failure to erase prev cursor position. */ if (area == TEXT_AREA @@ -29314,7 +29313,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, notice_overwritten_cursor (w, TEXT_AREA, x0, x1, row->y, MATRIX_ROW_BOTTOM_Y (row)); } -#endif /* Value is the x-position up to which drawn, relative to AREA of W. This doesn't include parts drawn because of overhangs. */ -- 2.31.1 --=-=-= Content-Type: text/plain I think these changes are appropriate enough for the font display patch, as they affect cursor display and overhang drawing. --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Thu Oct 28 06:17:38 2021 Received: (at 51411) by debbugs.gnu.org; 28 Oct 2021 10:17:38 +0000 Received: from localhost ([127.0.0.1]:51413 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mg2Ta-0007dW-5I for submit@debbugs.gnu.org; Thu, 28 Oct 2021 06:17:38 -0400 Received: from outbound.soverin.net ([116.202.126.228]:54941) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mg2TU-0007d3-Ae for 51411@debbugs.gnu.org; Thu, 28 Oct 2021 06:17:36 -0400 Received: from smtp.soverin.net (unknown [10.10.3.24]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by outbound.soverin.net (Postfix) with ESMTPS id AA0EC97; Thu, 28 Oct 2021 10:17:30 +0000 (UTC) Received: from smtp.soverin.net (smtp.soverin.net [159.69.232.138]) by soverin.net DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=idiocy.org; s=soverin; t=1635416250; bh=Z2SsmT5zQFGYqIWwxkOmJMvArAN/gCIodaCgzpsMeiE=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=BYssDX2VXocako09qT9EuF2KCwMeMI0k8pNzq111TNi5qk9v76dm8DxicoFqiAPyW yUpzhx/qcxf/5l7/0WpnkkiWbKjtdFnVP8n7MhB6Fb6T5r8e8yr/2eEo+TvPcWGpbO mX8lapeVj+M4VzxZ92mGKK8L2mPj0LZDEgpqMdNzbaEIoBGSMpUuxngsvDONwsUMkm H0WfxqojZwTxmZOHpjMLllwW3w0bL3iMnLDfu7FI2Dce3l8S0E2aRN0OXSXrbyHU85 0nkyXk9+OoQGYVgbTbZJsBvVkM/nNRxppz9dWFYahpi6QlBaQsINrQjtGX683nGQUL rf1Qxwk6aIFYQ== Received: from alan by faroe.holly.idiocy.org with local (Exim 4.95-RC2) (envelope-from ) id 1mg2TP-000lZS-JB; Thu, 28 Oct 2021 11:17:27 +0100 Date: Thu, 28 Oct 2021 11:17:27 +0100 From: Alan Third To: Po Lu Subject: Re: bug#51411: NS port cleanups Message-ID: Mail-Followup-To: Alan Third , Po Lu , 51411@debbugs.gnu.org References: <87mtmwt3mc.fsf.ref@yahoo.com> <87mtmwt3mc.fsf@yahoo.com> <87h7d4t0er.fsf@yahoo.com> <87ee86q7jm.fsf@yahoo.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <87ee86q7jm.fsf@yahoo.com> X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) On Thu, Oct 28, 2021 at 09:09:33AM +0800, Po Lu wrote: > Alan Third writes: > > > I understand what you did, but I think the better solution is for us > > is to try to untangle ns_draw_glyph_string, even if that means saving > > the context there directly on occasion. > > > If you want me to have a look at it let me know, I think I know what > > needs to be done, but I probably won't get round to it as soon as you > > could. > > Thanks. I had a try at it, cleaning up much of what appeared obviously > unnecessary. (Though I did not dare change what seemed to be mysterious > to me.) > > Though, OTOH, I think calling saveGraphicsState inside the overhang draw > process is not too much of a problem as it happens infrequently enough > to not be relevant. Thanks, I'm much happier with this now. I have no problem with saveGraphicsState being called within functions directly, I'd just rather avoid adding complexity to commonly used functions like ns_focus, which I already think are doing too much. I've got a couple of further notes. > diff --git a/src/nsterm.m b/src/nsterm.m > index 4c2a3f287c..051ee511ca 100644 > --- a/src/nsterm.m > +++ b/src/nsterm.m > @@ -1078,11 +1078,20 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) > /* clipping */ > if (r) > { > - [[NSGraphicsContext currentContext] saveGraphicsState]; > + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; > + [ctx saveGraphicsState]; > if (n == 2) > NSRectClipList (r, 2); > else > NSRectClip (*r); > +#ifdef NS_IMPL_GNUSTEP > + DPSrectclip (ctx, NSMinX (*r), NSMinY (*r), > + NSWidth (*r), NSHeight (*r)); > + > + if (n == 2) > + DPSrectclip (ctx, NSMinX (r[1]), NSMinY (r[1]), > + NSWidth (r[1]), NSHeight (r[1])); > +#endif > gsaved = YES; > } > } NSRectClipList creates a union of the passed rectangles and then sets the clipping rectangle to that, so it contains all of them. That's useful because NSRectClip uses the intersection of the current clipping rectangle and the new one. Does DPSrectclip use the intersection? If so this may not work as intended and it might be better to union the rectangles ourselves. > @@ -4195,13 +4091,88 @@ overwriting cursor (usually when cursor on a tab) */ > > /* Draw box if not done already. */ > if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) > + ns_dumpglyphs_box_or_relief (s); > + > + ns_unfocus (s->f); You unfocus here... > + > + /* Draw surrounding overhangs. */ > + if (s->prev) > { > - n = ns_get_glyph_string_clip_rect (s, r); > - ns_focus (s->f, r, n); > - ns_dumpglyphs_box_or_relief (s); > - ns_unfocus (s->f); > + struct glyph_string *prev; > + > + for (prev = s->prev; prev; prev = prev->prev) > + if (prev->hl != s->hl > + && prev->x + prev->width + prev->right_overhang > s->x) > + { > + /* As prev was drawn while clipped to its own area, we > + must draw the right_overhang part using s->hl now. */ > + enum draw_glyphs_face save = prev->hl; > + struct face *save_face = prev->face; > + > + prev->face = s->face; > + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); > + [[NSGraphicsContext currentContext] saveGraphicsState]; ... then continue working on the frame here. You either need to focus again or extend the original focus. Remember you can focus without setting the clipping, then save and reset the graphics state as required if you prefer. -- Alan Third From debbugs-submit-bounces@debbugs.gnu.org Thu Oct 28 07:25:48 2021 Received: (at 51411) by debbugs.gnu.org; 28 Oct 2021 11:25:48 +0000 Received: from localhost ([127.0.0.1]:51478 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mg3XU-0003SI-KI for submit@debbugs.gnu.org; Thu, 28 Oct 2021 07:25:47 -0400 Received: from sonic313-56.consmr.mail.ne1.yahoo.com ([66.163.185.31]:34696) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mg3XP-0003S0-I7 for 51411@debbugs.gnu.org; Thu, 28 Oct 2021 07:25:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635420333; bh=cBlAhq9wnJ8WT9tpTXiFoFMkqxMpfPck6nGmWe6Ocbk=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=h5tLXa2oFZ2b3Y+w00MtQOXzieaaFvNMKCvILnNq+R9VDuHdO0lfxQ32oXQ/nvEAodAZ6uYzoeHqLdhrI+YftsZzyvWUyV1U2iHXbtQ7mMXe7h78e2pcBD7zib7Jw03M59u7KKWlFPxmRvDYNc8ERM5sQhepjEvdPveLOrBnJW7h5adNq4UPjX5T1IXJVo4RG/ig8i98d2l+ovAwGZlWaQJYlViC0tyVlwcawTKjU+fNrewcRPaUDWeueqqpzxYBzqfx0wAJ8QodGjNLeIkhxhvETyqh1QevJ6LrFRkD3x1HIOglCck/ejWtsggZ68PZ6OrcldVArVXeyZvfWCC3yA== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635420333; bh=mN5xm/YrKD1HgN7xjKZcLz98rSFrQfSuFbJlQqv7sEd=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=AlpukJrkR4H8UdyQ+3qkWujiVU/NmcXbuUTvGzkGwQOFTIAf5ZlOC7bS+xybi/mLY00C+4gbPSZRsPxMGJzpNEu0vZevZNIOGb0kLgvGzAJy2wTiLcjgV5hnQm4088Bj1fXdMFq7ruxPdSxE5OoXChp/vj5bGbET0wM4iSc+t5Spiy/LzaQpmEdmqmF62CTUX7bSARED0oJzuc4FpC7V1mydij75N2CNyhXyS9iLilv6UCsI79GFIWXfhKVHH07cAxCXFQEpzU6upJDcXFSc7+fS/UquJ/irJ+A+vxmvnODqpmKVivsKEi102x0WvqSxSG1E5euGaHHHUktHnKGYsQ== X-YMail-OSG: r0cXUqYVM1lmMPyeXoLTprRV1Rh_ziumuPAbuX5Enfv5DumEj6yweDkpXIJImy0 qjjgNLcBHMNekFqqFv7MSIGbikhTZZpyAY25h7RpsLYm0SKCyE12Ui1DPQn5g7rgoek.aEXjOSfT pmK52c2oP9ayLMN.b.ZbGsGRgcYXE8a_ZnVQ6lHPB6hCKERwz3899QQ7AxwdpjDk8noCwSnHUsKI luCY11zvCadSyHKM_fDSdDb5aEAXKaLehjrgqMcD1SLM3tmLm03lekM9NiktXG.Y_w9QN77fsHzS .G0LuUr5NEchwb0rh7avoGcqF0aIbu2YdEu.9y.K4sClp8tPalvJPvPERuDsmLtuzc_4_qb92VZd v_fYx7hpg1uSANG1Cs64BbYpwCLyu9HRrwM.oKjfEH.mFWHU7WWMYAfrv2Qneq0.e2NYsN1UCm0j a6bTAf7r.xNj5slkPC6MmaBG5oiOkFB3Gnvb_uc2o44EsqnIaYf_yuP7UDljr7Rr1Gwcd.eEdeXI 9S03BcVJvl8qwyrPJZ0QJA82gEYJiAOH1qfH944sYN_acZMSAmgpH0x5pIy6vlfTQq7HSR_kwrTG ZUCH0mVhK78erRboUFUGsaoA4U7oDOdkhkld1nNut4JB55ABjHBpRpW9BPEpoIpmtvZ1l2Ft9pyH YtCPY3WN7yg.9T9AZDhYYCLfJh9nv10TonJHAO8Xf1QfTBmqAsLpTDkHENzLQlFEeaAW6eRDUVwM EkgUT2Xq7ypHj_nXYcyJmO7U6O4ayPVo0WEPAqyuCCHQzgo5FvgnFAqHKm2CNLZyYK_uGF87nvhR bVVuyLQ8uuUyXaor7q29zlubRftplcBXxeHnoFFgherXfh2PMh1m3AehSBCyM1EzTh8xzpz5dzHK fmIB6X_xQ1WM2WgeQ4UJ_wkFCBRuhQabAf4lnkF1O7wAa9SlGxJTPjBBfo9QE7P4jjtgdvgfG.lG CJgOrJRSBICewvi_BTk3Em5.jgaB.pmfy7sXaNKNJ8Oequ2mDaoZyN9.en.rf7nRhdzyGp09B9dQ wYsPPeJmYDhhpK3B9L_KlJvlzv296OPX61DHjGn7vVwRS3dw7riXh0vfQ8i9bMVgx4CPNUEA9IHu nFeg6CbeU.Vyh21GWUllXLpDHJbPBlNL71sHOCc6BwuAE5A258tcZr6UYJcE9zbn8pnvd09ttIDy oYWT2M82Cwx1n9Z_e0G4a3ED.KC0cJpwmfTuZon_fN4rRICBHCjOLedQje8rWbrbr2OqJikTm64e J4ftANDJhA8g24clK86M1BoeVpl_4oHaee78ciCtrjqkdAaqZqHAysF62azLxQ79iVwBX5VR4zFw dXngHmzLbZRV4KvAD8JRncpRktQI7zWIr3sxUAjd0dPPvm2GN7ZsrnAZwTWwJusglPo9EL5gP8Y. h80wGF6MIn0x6I1iN1kQ.xqUrf.o2TztPebBkv8bcVHFotqzVYeisyRffEMkYlphPo6FtNvR1c1k MdyM6lfEknfmdMBxPYi8Ryxw5O2dKkMbhz58f2Mjjm9bbkAbytit5MOCg5dmMx2nTsIqN3albvfl wOub.3vQhwT3fKFd9JXiU1RrTk_mmRLx2jRjggB4wmboNdrnVVqANqm1NTWW2M4Vvpj3tFFFkGpg wHjGEmDhVvqr5ExCBJu8VIzkR5bhQG4jxH8kwqJdH4tXZjrUG5icGhHtAn4B5J1MYupFj2FmhG2T H3ZaTzXZhESl9IG2NHmorZ2VX.Iu6yCmxzpXWUprfbMWAIvCfz7e7QiSh05.oJv4Lg3gfgnlZ8Ie vn4EYZCIG4b8FvRMGxRXHQjffVeyr2K6lXvbDIHjjpEbk3KTyr4TzNaZOpK5oBWaRRD3nXF0Nxzc 2Rh0Aon_9IpmojeNs.sAkA91OqeOtdX8WxoKNjOB7E0e_2gwgh4uSDgsabyons6bZEnNVpWqacer vW2gtaB422wODKU6VAkWLDvPYY13zwYactF_TuUXJWQjyRMUq15f8PK.q96QIKvpINM8aAqscrZ8 oPyl3Qg7dy0j7bJW7J_f1EX17TTQfbEtkuMEdm6xY4Nahr2KGpbOWfMOylenBH3C1BWGLxDAfsA3 I1G9nzJAtJTVqHyP5gjq4PWiOoHEX.3ygpHewaTLI2nDJGu5Fe7GE11agIYzG5hDR3TiB3K0C2x9 qEyozO82pltgEUWJ7wOy.8XyGgiOWzRNhoOlpW3ZhO1cQX.wBeHrY47tFoq6R6YBgc5nrHlnp1Zi py1C6f1hHTpCtFSqRGF_b3_QsScHfoX.vFbbst5ytMSxI1AYHIfKWfxY- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic313.consmr.mail.ne1.yahoo.com with HTTP; Thu, 28 Oct 2021 11:25:33 +0000 Received: by kubenode517.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 913cdd5a606e7996ca59f57ab59ddd07; Thu, 28 Oct 2021 11:25:28 +0000 (UTC) From: Po Lu To: Alan Third Subject: Re: bug#51411: NS port cleanups References: <87mtmwt3mc.fsf.ref@yahoo.com> <87mtmwt3mc.fsf@yahoo.com> <87h7d4t0er.fsf@yahoo.com> <87ee86q7jm.fsf@yahoo.com> Date: Thu, 28 Oct 2021 19:25:23 +0800 In-Reply-To: (Alan Third's message of "Thu, 28 Oct 2021 11:17:27 +0100") Message-ID: <87ilxhmlwc.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 80117 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Alan Third writes: > NSRectClipList creates a union of the passed rectangles and then sets > the clipping rectangle to that, so it contains all of them. That's > useful because NSRectClip uses the intersection of the current > clipping rectangle and the new one. > > Does DPSrectclip use the intersection? If so this may not work as > intended and it might be better to union the rectangles ourselves. It does intersect the rectangle with the current clipping. I determined that from a cursory examination of the source code, as the function appeared in the documentation as documented, but no documentation was actually written for it. >> @@ -4195,13 +4091,88 @@ overwriting cursor (usually when cursor on a tab) */ >> >> /* Draw box if not done already. */ >> if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) >> + ns_dumpglyphs_box_or_relief (s); >> + >> + ns_unfocus (s->f); > You unfocus here, then continue working on the frame here. You either > need to focus again or extend the original focus. Remember you can > focus without setting the clipping, then save and reset the graphics > state as required if you prefer. Hmm. Will this work better? Thanks. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Improve-font-display-on-NS-port.patch >From f33043632baf3e6ae55ff7dbff8bddcbf74b4d0d Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 23 Oct 2021 19:44:03 +0800 Subject: [PATCH] Improve font display on NS port * src/nsfns.m (Fx_create_frame): Use "fixed" for the default font on GNUstep. * src/nsfont.m (LCD_SMOOTHING_MARGIN, ns_escape_name) (ns_unescape_name, ns_attribute_fvalue) (STYLE_REF): Remove unused defines and functions. (struct ns_glyph_layout, enum lgstring_direction). (enum gs_font_slant, enum gs_font_weight, enum gs_font_width) (enum gs_specified, struct gs_font_data): New enumerators and structures. (ns_font_descs_match_p) (ns_done_font_data, ns_get_font_data): New functions. (ns_glyph_metrics): Stop escaping names. (ns_spec_to_descriptor): Fix font descriptor creation for symbolic font spec entires. (ns_descriptor_to_entity): Create entries with the correct symbolic styles. (ns_fallback_entity): Fix fallback entity selection. (ns_findfonts): Use our own font matcher instead of the broken GNUstep matcher. (ns_list_family): Remove obsolete comment. (nsfont_open): Remove obsolete code, comments, and synthItal logic which doesn't work on GNUstep. (nsfont_encode_char): Use a type that can fit NSGlyph (nsfont_draw): Chose correct font, remove obsolete mouse face logic, obsolete comments, and switch to using glyph-based drawing instead of character-based drawing. (ns_font_shape, nsfont_shape): New functions. (ns_uni_to_glyphs_1): New function. (ns_uni_to_glyphs): Return glyphs instead of unicode codepoints. (ns_glyph_metrics): Use NSGlyphs instead of unicode codepoints and fix left bearing, right bearing, ascent and descent computation. (struct nsfont_driver): Add shaping capability. * src/nsterm.h (struct nsfont_info): Use unsigned int for glyph cache. * src/nsterm.c (ns_focus): Set DPS clipping on GNUstep. (ns_compute_glyph_string_overhangs): Fix overhang computation by using xterm code. (ns_draw_window_cursor): Simplify cursor drawing. (ns_maybe_dumpglyphs_background): Test for cursor HL and remove obsolete mouse face logic. (ns_dumpglyphs_image) (ns_dumpglyphs_box_or_relief): Rectify for new cursor logic. (ns_dumpglyphs_stretch): Rectify for new cursor logic and rely on ns_draw_glyph_string to set focus. (ns_draw_glyph_string_foreground): Remove mouse face logic. (ns_draw_glyph_strings): Implement overhangs, remove obsolete comment, and always focus before dumping glyphs. (ns_draw_text_decoration): Add condition for DRAW_CURSOR and simplify color selection. (ns_define_frame_cursor): Remove nonsensical code (define_frame_cursor has nothing to do with the text cursor, aka caret). * src/xdisp.c (draw_glyphs): Enable code for NS port to fix mouse face cursor display. * src/macfont.m (get_cgcolor_from_nscolor): New function. (macfont_draw): Remove obsolete mouse-face code and enable cursor display. --- src/macfont.m | 36 +- src/nsfns.m | 6 + src/nsfont.m | 1215 +++++++++++++++++++++++++++++++++++-------------- src/nsterm.h | 2 +- src/nsterm.m | 417 ++++++++--------- src/xdisp.c | 2 - 6 files changed, 1096 insertions(+), 582 deletions(-) diff --git a/src/macfont.m b/src/macfont.m index d86f09f485..df552400e3 100644 --- a/src/macfont.m +++ b/src/macfont.m @@ -613,6 +613,21 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char, return cgColor; } +static CGColorRef +get_cgcolor_from_nscolor (NSColor *nsColor, struct frame *f) +{ + [nsColor set]; + CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace]; + NSInteger noc = [nsColor numberOfComponents]; + CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc)); + CGColorRef cgColor; + + [nsColor getComponents: components]; + cgColor = CGColorCreate (colorSpace, components); + xfree (components); + return cgColor; +} + #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f) \ do { \ CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f); \ @@ -2907,14 +2922,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no if (!CGRectIsNull (background_rect)) { - if (s->hl == DRAW_MOUSE_FACE) + if (s->hl == DRAW_CURSOR) { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_CURSOR_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); } - CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); + else + CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); CGContextFillRects (context, &background_rect, 1); } @@ -2923,7 +2938,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no CGAffineTransform atfm; CGContextScaleCTM (context, 1, -1); - CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); + if (s->hl == DRAW_CURSOR) + { + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_BACKGROUND_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); + } + else + CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); if (macfont_info->synthetic_italic_p) atfm = synthetic_italic_atfm; else diff --git a/src/nsfns.m b/src/nsfns.m index 797d0ce782..f4d8172246 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -1236,6 +1236,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. "fontBackend", "FontBackend", RES_TYPE_STRING); { +#ifdef NS_IMPL_COCOA /* use for default font name */ id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */ gui_default_parameter (f, parms, Qfontsize, @@ -1250,6 +1251,11 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. build_string (fontname), "font", "Font", RES_TYPE_STRING); xfree (fontname); +#else + gui_default_parameter (f, parms, Qfont, + build_string ("fixed"), + "font", "Font", RES_TYPE_STRING); +#endif } unblock_input (); diff --git a/src/nsfont.m b/src/nsfont.m index 5a9cdfebc0..b3224629f0 100644 --- a/src/nsfont.m +++ b/src/nsfont.m @@ -1,4 +1,4 @@ -/* Font back-end driver for the NeXT/Open/GNUstep and macOS window system. +/* Font back-end driver for the GNUstep window system. See font.h Copyright (C) 2006-2021 Free Software Foundation, Inc. @@ -38,47 +38,269 @@ #include "termchar.h" #include "pdumper.h" -/* TODO: Drop once we can assume gnustep-gui 0.17.1. */ +#import #import +#import +#import +#import #define NSFONT_TRACE 0 -#define LCD_SMOOTHING_MARGIN 2 -/* Font glyph and metrics caching functions, implemented at end. */ -static void ns_uni_to_glyphs (struct nsfont_info *font_info, - unsigned char block); -static void ns_glyph_metrics (struct nsfont_info *font_info, - unsigned char block); +/* Structure used by GS `shape' functions for storing layout + information for each glyph. Borrowed from macfont.h. */ +struct ns_glyph_layout +{ + /* Range of indices of the characters composed into the group of + glyphs that share the cursor position with this glyph. The + members `location' and `length' are in UTF-16 indices. */ + NSRange comp_range; -#define INVALID_GLYPH 0xFFFF + /* UTF-16 index in the source string for the first character + associated with this glyph. */ + NSUInteger string_index; -/* ========================================================================== + /* Horizontal and vertical adjustments of glyph position. The + coordinate space is that of Core Text. So, the `baseline_delta' + value is negative if the glyph should be placed below the + baseline. */ + CGFloat advance_delta, baseline_delta; - Utilities + /* Typographical width of the glyph. */ + CGFloat advance; - ========================================================================== */ + /* Glyph ID of the glyph. */ + NSGlyph glyph_id; +}; + + +enum lgstring_direction + { + DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1 + }; + +enum gs_font_slant + { + GS_FONT_SLANT_ITALIC, + GS_FONT_SLANT_REVERSE_ITALIC, + GS_FONT_SLANT_NORMAL + }; + +enum gs_font_weight + { + GS_FONT_WEIGHT_LIGHT, + GS_FONT_WEIGHT_BOLD, + GS_FONT_WEIGHT_NORMAL + }; + +enum gs_font_width + { + GS_FONT_WIDTH_CONDENSED, + GS_FONT_WIDTH_EXPANDED, + GS_FONT_WIDTH_NORMAL + }; + +enum gs_specified + { + GS_SPECIFIED_SLANT = 1, + GS_SPECIFIED_WEIGHT = 1 << 1, + GS_SPECIFIED_WIDTH = 1 << 2, + GS_SPECIFIED_FAMILY = 1 << 3, + GS_SPECIFIED_SPACING = 1 << 4 + }; +struct gs_font_data +{ + int specified; + enum gs_font_slant slant; + enum gs_font_weight weight; + enum gs_font_width width; + bool monospace_p; + char *family_name; +}; -/* Replace spaces w/another character so emacs core font parsing routines - aren't thrown off. */ static void -ns_escape_name (char *name) +ns_done_font_data (struct gs_font_data *data) { - for (; *name; name++) - if (*name == ' ') - *name = '_'; + if (data->specified & GS_SPECIFIED_FAMILY) + xfree (data->family_name); } - -/* Reconstruct spaces in a font family name passed through emacs. */ static void -ns_unescape_name (char *name) +ns_get_font_data (NSFontDescriptor *desc, struct gs_font_data *dat) { - for (; *name; name++) - if (*name == '_') - *name = ' '; + NSNumber *tem; + NSFontSymbolicTraits traits = [desc symbolicTraits]; + NSDictionary *dict = [desc objectForKey: NSFontTraitsAttribute]; + NSString *family = [desc objectForKey: NSFontFamilyAttribute]; + + dat->specified = 0; + + if (family != nil) + { + dat->specified |= GS_SPECIFIED_FAMILY; + dat->family_name = xstrdup ([family cStringUsingEncoding: NSUTF8StringEncoding]); + } + + tem = [desc objectForKey: NSFontFixedAdvanceAttribute]; + + if ((tem != nil && [tem boolValue] != NO) + || (traits & NSFontMonoSpaceTrait)) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = true; + } + else if (tem != nil && [tem boolValue] == NO) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = false; + } + + if (traits & NSFontBoldTrait) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + dat->weight = GS_FONT_WEIGHT_BOLD; + } + + if (traits & NSFontItalicTrait) + { + dat->specified |= GS_SPECIFIED_SLANT; + dat->slant = GS_FONT_SLANT_ITALIC; + } + + if (traits & NSFontCondensedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_CONDENSED; + } + else if (traits & NSFontExpandedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_EXPANDED; + } + + if (dict != nil) + { + tem = [dict objectForKey: NSFontSlantTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_SLANT; + + dat->slant = [tem floatValue] > 0 + ? GS_FONT_SLANT_ITALIC + : ([tem floatValue] < 0 + ? GS_FONT_SLANT_REVERSE_ITALIC + : GS_FONT_SLANT_NORMAL); + } + + tem = [dict objectForKey: NSFontWeightTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + + dat->weight = [tem floatValue] > 0 + ? GS_FONT_WEIGHT_BOLD + : ([tem floatValue] < -0.4f + ? GS_FONT_WEIGHT_LIGHT + : GS_FONT_WEIGHT_NORMAL); + } + + tem = [dict objectForKey: NSFontWidthTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WIDTH; + + dat->width = [tem floatValue] > 0 + ? GS_FONT_WIDTH_EXPANDED + : ([tem floatValue] < 0 + ? GS_FONT_WIDTH_NORMAL + : GS_FONT_WIDTH_CONDENSED); + } + } +} + +static bool +ns_font_descs_match_p (NSFontDescriptor *desc, NSFontDescriptor *target) +{ + struct gs_font_data dat; + struct gs_font_data t; + + ns_get_font_data (desc, &dat); + ns_get_font_data (target, &t); + + if (!(t.specified & GS_SPECIFIED_WIDTH)) + t.width = GS_FONT_WIDTH_NORMAL; + if (!(t.specified & GS_SPECIFIED_WEIGHT)) + t.weight = GS_FONT_WEIGHT_NORMAL; + if (!(t.specified & GS_SPECIFIED_SPACING)) + t.monospace_p = false; + if (!(t.specified & GS_SPECIFIED_SLANT)) + t.slant = GS_FONT_SLANT_NORMAL; + + if (!(t.specified & GS_SPECIFIED_FAMILY)) + emacs_abort (); + + bool match_p = true; + + if (dat.specified & GS_SPECIFIED_WIDTH + && dat.width != t.width) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_WEIGHT + && dat.weight != t.weight) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SPACING + && dat.monospace_p != t.monospace_p) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SLANT + && dat.monospace_p != t.monospace_p) + { + if (NSFONT_TRACE) + printf ("Matching monospace for %s: %d %d\n", + t.family_name, dat.monospace_p, + t.monospace_p); + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_FAMILY + && strcmp (dat.family_name, t.family_name)) + match_p = false; + + gout: + ns_done_font_data (&dat); + ns_done_font_data (&t); + + return match_p; } +/* Font glyph and metrics caching functions, implemented at end. */ +static void ns_uni_to_glyphs (struct nsfont_info *font_info, + unsigned char block); +static void ns_glyph_metrics (struct nsfont_info *font_info, + unsigned int block); + +#define INVALID_GLYPH 0xFFFF + +/* ========================================================================== + + Utilities + + ========================================================================== */ + /* Extract family name from a font spec. */ static NSString * @@ -91,66 +313,116 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, { char *tmp = xlispstrdup (SYMBOL_NAME (tem)); NSString *family; - ns_unescape_name (tmp); family = [NSString stringWithUTF8String: tmp]; xfree (tmp); return family; } } - -/* Return 0 if attr not set, else value (which might also be 0). - On Leopard 0 gets returned even on descriptors where the attribute - was never set, so there's no way to distinguish between unspecified - and set to not have. Callers should assume 0 means unspecified. */ -static float -ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait) -{ - NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute]; - NSNumber *val = [tdict objectForKey: trait]; - return val == nil ? 0.0F : [val floatValue]; -} - - /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang to NSFont descriptor. Information under extra only needed for matching. */ -#define STYLE_REF 100 static NSFontDescriptor * ns_spec_to_descriptor (Lisp_Object font_spec) { NSFontDescriptor *fdesc; NSMutableDictionary *fdAttrs = [NSMutableDictionary new]; - NSMutableDictionary *tdict = [NSMutableDictionary new]; NSString *family = ns_get_family (font_spec); - float n; - - /* Add each attr in font_spec to fdAttrs. */ - n = min (FONT_WEIGHT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWeightTrait]; - n = min (FONT_SLANT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontSlantTrait]; - n = min (FONT_WIDTH_NUMERIC (font_spec), 200); - if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10)) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWidthTrait]; - if ([tdict count] > 0) - [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + NSMutableDictionary *tdict = [NSMutableDictionary new]; - fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] - retain] autorelease]; + Lisp_Object tem; + + tem = FONT_SLANT_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qitalic) || EQ (tem, Qoblique)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontSlantTrait]; + else if (EQ (tem, intern ("reverse-italic")) || + EQ (tem, intern ("reverse-oblique"))) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontSlantTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontSlantTrait]; + } + + tem = FONT_WIDTH_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qcondensed)) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWidthTrait]; + else if (EQ (tem, Qexpanded)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWidthTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWidthTrait]; + } + + tem = FONT_WEIGHT_SYMBOLIC (font_spec); + + if (!NILP (tem)) + { + if (EQ (tem, Qbold)) + { + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWeightTrait]; + } + else if (EQ (tem, Qlight)) + { + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWeightTrait]; + } + else + { + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWeightTrait]; + } + } + + tem = AREF (font_spec, FONT_SPACING_INDEX); if (family != nil) { - NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family]; - fdesc = [[fdesc2 retain] autorelease]; + [fdAttrs setObject: family + forKey: NSFontFamilyAttribute]; } - [fdAttrs release]; + if (FIXNUMP (tem)) + { + if (XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL) + { + [fdAttrs setObject: [NSNumber numberWithBool:YES] + forKey: NSFontFixedAdvanceAttribute]; + } + else + { + [fdAttrs setObject: [NSNumber numberWithBool:NO] + forKey: NSFontFixedAdvanceAttribute]; + } + } + + /* Handle special families such as ``fixed'' or ``Sans Serif''. */ + + if ([family isEqualToString: @"fixed"]) + { + [fdAttrs setObject: [[NSFont userFixedPitchFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + else if ([family isEqualToString: @"Sans Serif"]) + { + [fdAttrs setObject: [[NSFont userFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + + [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + + fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] + retain] autorelease]; + [tdict release]; + [fdAttrs release]; return fdesc; } @@ -161,61 +433,64 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, Lisp_Object extra, const char *style) { - Lisp_Object font_entity = font_make_entity (); - /* NSString *psName = [desc postscriptName]; */ - NSString *family = [desc objectForKey: NSFontFamilyAttribute]; - unsigned int traits = [desc symbolicTraits]; - char *escapedFamily; - - /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */ - if (family == nil) - family = [desc objectForKey: NSFontNameAttribute]; - if (family == nil) - family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - - escapedFamily = xstrdup ([family UTF8String]); - ns_escape_name (escapedFamily); - - ASET (font_entity, FONT_TYPE_INDEX, Qns); - ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple); - ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily)); - ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); - ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); - - FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - traits & NSFontBoldTrait ? Qbold : Qmedium); -/* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - traits & NSFontItalicTrait ? Qitalic : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - traits & NSFontCondensedTrait ? Qcondensed : - traits & NSFontExpandedTrait ? Qexpanded : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/ - - ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_SPACING_INDEX, - make_fixnum([desc symbolicTraits] & NSFontMonoSpaceTrait - ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); - - ASET (font_entity, FONT_EXTRA_INDEX, extra); - ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + Lisp_Object font_entity = font_make_entity (); + struct gs_font_data data; + ns_get_font_data (desc, &data); + + ASET (font_entity, FONT_TYPE_INDEX, Qns); + ASET (font_entity, FONT_FOUNDRY_INDEX, Qns); + if (data.specified & GS_SPECIFIED_FAMILY) + ASET (font_entity, FONT_FAMILY_INDEX, intern (data.family_name)); + ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); + ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); + + if (data.specified & GS_SPECIFIED_WEIGHT) + { + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, + data.weight == GS_FONT_WEIGHT_BOLD + ? Qbold : (data.weight == GS_FONT_WEIGHT_LIGHT + ? Qlight : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, Qnormal); - if (NSFONT_TRACE) - { - fputs ("created font_entity:\n ", stderr); - debug_print (font_entity); - } + if (data.specified & GS_SPECIFIED_SLANT) + { + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, + data.slant == GS_FONT_SLANT_ITALIC + ? Qitalic : (data.slant == GS_FONT_SLANT_REVERSE_ITALIC + ? intern ("reverse-italic") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, Qnormal); + + if (data.specified & GS_SPECIFIED_WIDTH) + { + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, + data.width == GS_FONT_WIDTH_CONDENSED + ? Qcondensed : (data.width == GS_FONT_WIDTH_EXPANDED + ? intern ("expanded") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, Qnormal); - xfree (escapedFamily); - return font_entity; + ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_SPACING_INDEX, + make_fixnum ((data.specified & GS_SPECIFIED_WIDTH && data.monospace_p) + ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); + + ASET (font_entity, FONT_EXTRA_INDEX, extra); + ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + + if (NSFONT_TRACE) + { + fputs ("created font_entity:\n ", stderr); + debug_print (font_entity); + } + + ns_done_font_data (&data); + return font_entity; } @@ -223,8 +498,7 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, static Lisp_Object ns_fallback_entity (void) { - return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0] - fontDescriptor], Qnil, NULL); + return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 1] fontDescriptor], Qnil, NULL); } @@ -510,21 +784,20 @@ but also for ascii (which causes unnecessary font substitution). */ return families; } +/* GNUstep font matching is very mediocre (it can't even compare + symbolic styles correctly), which is why our own font matching + mechanism must be implemented. */ -/* Implementation for list() and match(). List() can return nil, match() -must return something. Strategy is to drop family name from attribute -matching set for match. */ +/* Implementation for list and match. */ static Lisp_Object ns_findfonts (Lisp_Object font_spec, BOOL isMatch) { Lisp_Object tem, list = Qnil; - NSFontDescriptor *fdesc, *desc; - NSMutableSet *fkeys; - NSArray *matchingDescs; - NSEnumerator *dEnum; - NSString *family; + NSFontDescriptor *fdesc; + NSArray *all_descs; + GSFontEnumerator *enumerator = [GSFontEnumerator sharedEnumerator]; + NSSet *cFamilies; - BOOL foundItal = NO; block_input (); if (NSFONT_TRACE) @@ -537,43 +810,22 @@ but also for ascii (which causes unnecessary font substitution). */ cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90); fdesc = ns_spec_to_descriptor (font_spec); - fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]]; - if (isMatch) - [fkeys removeObject: NSFontFamilyAttribute]; - - matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys]; + all_descs = [enumerator availableFontDescriptors]; - if (NSFONT_TRACE) - NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc, - (unsigned long)[matchingDescs count]); - - for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);) + for (NSFontDescriptor *desc in all_descs) { if (![cFamilies containsObject: [desc objectForKey: NSFontFamilyAttribute]]) continue; + if (!ns_font_descs_match_p (fdesc, desc)) + continue; + tem = ns_descriptor_to_entity (desc, - AREF (font_spec, FONT_EXTRA_INDEX), + AREF (font_spec, FONT_EXTRA_INDEX), NULL); if (isMatch) return tem; list = Fcons (tem, list); - if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05) - foundItal = YES; - } - - /* Add synthItal member if needed. */ - family = [fdesc objectForKey: NSFontFamilyAttribute]; - if (family != nil && !foundItal && !NILP (list)) - { - NSFontDescriptor *s1 = [NSFontDescriptor new]; - NSFontDescriptor *sDesc - = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait] - fontDescriptorWithFamily: family]; - list = Fcons (ns_descriptor_to_entity (sDesc, - AREF (font_spec, FONT_EXTRA_INDEX), - "synthItal"), list); - [s1 release]; } unblock_input (); @@ -652,7 +904,6 @@ Properties to be considered are same as for list(). */ objectEnumerator]; while ((family = [families nextObject])) list = Fcons (intern ([family UTF8String]), list); - /* FIXME: escape the name? */ if (NSFONT_TRACE) fprintf (stderr, "nsfont: list families returning %"pD"d entries\n", @@ -668,18 +919,15 @@ Properties to be considered are same as for list(). */ static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size) { - BOOL synthItal; - unsigned int traits = 0; struct nsfont_info *font_info; struct font *font; NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity); NSFontManager *fontMgr = [NSFontManager sharedFontManager]; NSString *family; NSFont *nsfont, *sfont; - Lisp_Object tem; NSRect brect; Lisp_Object font_object; - int fixLeopardBug; + Lisp_Object tem; block_input (); @@ -692,42 +940,20 @@ Properties to be considered are same as for list(). */ if (pixel_size <= 0) { /* try to get it out of frame params */ - Lisp_Object tem = get_frame_param (f, Qfontsize); - pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); + tem = get_frame_param (f, Qfontsize); + pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); } tem = AREF (font_entity, FONT_ADSTYLE_INDEX); - synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)), - 9); family = ns_get_family (font_entity); if (family == nil) family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that - when setting family in ns_spec_to_descriptor(). */ - if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F) - traits |= NSBoldFontMask; - if (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F) - traits |= NSItalicFontMask; - - /* see https://web.archive.org/web/20100201175731/http://cocoadev.com/forums/comments.php?DiscussionID=74 */ - fixLeopardBug = traits & NSBoldFontMask ? 10 : 5; - nsfont = [fontMgr fontWithFamily: family - traits: traits weight: fixLeopardBug - size: pixel_size]; - /* if didn't find, try synthetic italic */ - if (nsfont == nil && synthItal) - { - nsfont = [fontMgr fontWithFamily: family - traits: traits & ~NSItalicFontMask - weight: fixLeopardBug size: pixel_size]; - } + + nsfont = [NSFont fontWithDescriptor: fontDesc + size: pixel_size]; if (nsfont == nil) - { - message_with_string ("*** Warning: font in family `%s' not found", - build_string ([family UTF8String]), 1); - nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; - } + nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; if (NSFONT_TRACE) NSLog (@"%@\n", nsfont); @@ -740,7 +966,7 @@ when setting family in ns_spec_to_descriptor(). */ if (!font) { unblock_input (); - return Qnil; /* FIXME: other terms do, but returning Qnil causes segfault. */ + return Qnil; } font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs); @@ -781,7 +1007,7 @@ when setting family in ns_spec_to_descriptor(). */ font_info->name = xstrdup (fontName); font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask; font_info->ital = - synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); + ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); /* Metrics etc.; some fonts return an unusually large max advance, so we only use it for fonts that have wide characters. */ @@ -808,8 +1034,6 @@ when setting family in ns_spec_to_descriptor(). */ lrint (brect.size.width - (CGFloat) font_info->width); /* set up metrics portion of font struct */ - font->ascent = lrint([sfont ascender]); - font->descent = -lrint(floor(adjusted_descender)); font->space_width = lrint (ns_char_width (sfont, ' ')); font->max_width = lrint (font_info->max_bounds.width); font->min_width = font->space_width; /* Approximate. */ @@ -871,7 +1095,7 @@ when setting family in ns_spec_to_descriptor(). */ { struct nsfont_info *font_info = (struct nsfont_info *)font; unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff; - unsigned short g; + unsigned int g; if (c > 0xFFFF) return FONT_INVALID_CODE; @@ -934,51 +1158,23 @@ is false when (FROM > 0 || TO < S->nchars). */ static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, bool with_background) -/* NOTE: focus and clip must be set. */ { - static unsigned char cbuf[1024]; - unsigned char *c = cbuf; -#if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22 - static CGFloat advances[1024]; - CGFloat *adv = advances; -#else - static float advances[1024]; - float *adv = advances; -#endif + NSGlyph *c = alloca ((to - from) * sizeof *c); + struct face *face; NSRect r; struct nsfont_info *font; - NSColor *col, *bgCol; - unsigned *t = s->char2b; - int i, len, flags; + NSColor *col; + int len = to - from; char isComposite = s->first_glyph->type == COMPOSITE_GLYPH; block_input (); - font = (struct nsfont_info *)s->face->font; + font = (struct nsfont_info *) s->font; if (font == NULL) font = (struct nsfont_info *)FRAME_FONT (s->f); - /* Select face based on input flags. */ - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - - switch (flags) - { - case NS_DUMPGLYPH_CURSOR: - face = s->face; - break; - case NS_DUMPGLYPH_MOUSEFACE: - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - break; - default: - face = s->face; - } + face = s->face; r.origin.x = s->x; if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p) @@ -987,91 +1183,24 @@ is false when (FROM > 0 || TO < S->nchars). */ r.origin.y = s->y; r.size.height = FONT_HEIGHT (font); - /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask - NS to render the string, it will come out differently from the individual - character widths added up because of layout processing. */ - { - int cwidth, twidth = 0; - int hi, lo; - /* FIXME: composition: no vertical displacement is considered. */ - t += from; /* advance into composition */ - for (i = from; i < to; i++, t++) - { - hi = (*t & 0xFF00) >> 8; - lo = *t & 0x00FF; - if (isComposite) - { - if (!s->first_glyph->u.cmp.automatic) - cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth; - else - { - Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); - Lisp_Object glyph = LGSTRING_GLYPH (gstring, i); - if (NILP (LGLYPH_ADJUSTMENT (glyph))) - cwidth = LGLYPH_WIDTH (glyph); - else - { - cwidth = LGLYPH_WADJUST (glyph); - *(adv-1) += LGLYPH_XOFF (glyph); - } - } - } - else - { - if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */ - ns_glyph_metrics (font, hi); - cwidth = font->metrics[hi][lo].width; - } - twidth += cwidth; - *adv++ = cwidth; - c += CHAR_STRING (*t, c); /* This converts the char to UTF-8. */ - } - len = adv - advances; - r.size.width = twidth; - *c = 0; - } + for (int i = from; i < to; ++i) + c[i] = s->char2b[i]; /* Fill background if requested. */ if (with_background && !isComposite) { - NSRect br = r; - int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); - int mbox_line_width = max (s->face->box_vertical_line_width, 0); - - if (s->row->full_width_p) - { - if (br.origin.x <= fibw + 1 + mbox_line_width) - { - br.size.width += br.origin.x - mbox_line_width; - br.origin.x = mbox_line_width; - } - if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) - <= fibw+1) - br.size.width += fibw; - } - if (s->face->box == FACE_NO_BOX) - { - /* Expand unboxed top row over internal border. */ - if (br.origin.y <= fibw + 1 + mbox_line_width) - { - br.size.height += br.origin.y; - br.origin.y = 0; - } - } - else - { - int correction = abs (s->face->box_horizontal_line_width)+1; - br.origin.y += correction; - br.size.height -= 2*correction; - correction = abs (s->face->box_vertical_line_width)+1; - br.origin.x += correction; - br.size.width -= 2*correction; - } + NSRect br = NSMakeRect (x, y - FONT_BASE (s->font), + s->width, FONT_HEIGHT (s->font)); if (!s->face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); @@ -1080,43 +1209,32 @@ is false when (FROM > 0 || TO < S->nchars). */ NSRectFill (br); } - /* set up for character rendering */ r.origin.y = y; - col = (NS_FACE_FOREGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - - bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil - : (NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f))); + if (s->hl == DRAW_CURSOR) + col = FRAME_BACKGROUND_COLOR (s->f); + else + col = (NS_FACE_FOREGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) + : FRAME_FOREGROUND_COLOR (s->f)); /* render under GNUstep using DPS */ { - NSGraphicsContext *context = GSCurrentContext (); - + NSGraphicsContext *context = [NSGraphicsContext currentContext]; DPSgsave (context); - [font->nsfont set]; - - /* do erase if "foreground" mode */ - if (bgCol != nil) + if (s->clip_head) { - [bgCol set]; - DPSmoveto (context, r.origin.x, r.origin.y); -/*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */ - DPSxshow (context, (const char *) cbuf, advances, len); - DPSstroke (context); - [col set]; -/*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */ + DPSrectclip (context, s->clip_head->x, 0, + FRAME_PIXEL_WIDTH (s->f), + FRAME_PIXEL_HEIGHT (s->f)); } + [font->nsfont set]; [col set]; - /* draw with DPSxshow () */ DPSmoveto (context, r.origin.x, r.origin.y); - DPSxshow (context, (const char *) cbuf, advances, len); + GSShowGlyphs (context, c, len); DPSstroke (context); DPSgrestore (context); @@ -1126,6 +1244,360 @@ is false when (FROM > 0 || TO < S->nchars). */ return to-from; } +static NSUInteger +ns_font_shape (NSFont *font, NSString *string, + struct ns_glyph_layout *glyph_layouts, NSUInteger glyph_len, + enum lgstring_direction dir) +{ + NSUInteger i; + NSUInteger result = 0; + NSTextStorage *textStorage; + NSLayoutManager *layoutManager; + NSTextContainer *textContainer; + NSUInteger stringLength; + NSPoint spaceLocation; + /* numberOfGlyphs can't actually be 0, but this pacifies GCC */ + NSUInteger used, numberOfGlyphs = 0; + + textStorage = [[NSTextStorage alloc] initWithString:string]; + layoutManager = [[NSLayoutManager alloc] init]; + textContainer = [[NSTextContainer alloc] init]; + + /* Append a trailing space to measure baseline position. */ + [textStorage appendAttributedString:([[[NSAttributedString alloc] + initWithString:@" "] autorelease])]; + [textStorage setFont:font]; + [textContainer setLineFragmentPadding:0]; + + [layoutManager addTextContainer:textContainer]; + [textContainer release]; + [textStorage addLayoutManager:layoutManager]; + [layoutManager release]; + + if (!(textStorage && layoutManager && textContainer)) + emacs_abort (); + + stringLength = [string length]; + + /* Force layout. */ + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength]; + + /* Remove the appended trailing space because otherwise it may + generate a wrong result for a right-to-left text. */ + [textStorage beginEditing]; + [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))]; + [textStorage endEditing]; + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + i = 0; + while (i < stringLength) + { + NSRange range; + NSFont *fontInTextStorage = + [textStorage attribute: NSFontAttributeName + atIndex:i + longestEffectiveRange: &range + inRange: NSMakeRange (0, stringLength)]; + + if (!(fontInTextStorage == font + || [[fontInTextStorage fontName] isEqualToString:[font fontName]])) + break; + i = NSMaxRange (range); + } + if (i < stringLength) + /* Make the test `used <= glyph_len' below fail if textStorage + contained some fonts other than the specified one. */ + used = glyph_len + 1; + else + { + NSRange range = NSMakeRange (0, stringLength); + + range = [layoutManager glyphRangeForCharacterRange:range + actualCharacterRange:NULL]; + numberOfGlyphs = NSMaxRange (range); + used = numberOfGlyphs; + for (i = 0; i < numberOfGlyphs; i++) + if ([layoutManager notShownAttributeForGlyphAtIndex:i]) + used--; + } + + if (0 < used && used <= glyph_len) + { + NSUInteger glyphIndex, prevGlyphIndex; + NSUInteger *permutation; + NSRange compRange, range; + CGFloat totalAdvance; + + glyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + permutation = NULL; +#define RIGHT_TO_LEFT_P permutation + + /* Fill the `comp_range' member of struct mac_glyph_layout, and + setup a permutation for right-to-left text. */ + compRange = NSMakeRange (0, 0); + for (range = NSMakeRange (0, 0); NSMaxRange (range) < used; + range.length++) + { + struct ns_glyph_layout *gl = glyph_layouts + NSMaxRange (range); + NSUInteger characterIndex = + [layoutManager characterIndexForGlyphAtIndex:glyphIndex]; + + gl->string_index = characterIndex; + + if (characterIndex >= NSMaxRange (compRange)) + { + compRange.location = NSMaxRange (compRange); + do + { + NSRange characterRange = + [string + rangeOfComposedCharacterSequenceAtIndex:characterIndex]; + + compRange.length = + NSMaxRange (characterRange) - compRange.location; + [layoutManager glyphRangeForCharacterRange:compRange + actualCharacterRange:&characterRange]; + characterIndex = NSMaxRange (characterRange) - 1; + } + while (characterIndex >= NSMaxRange (compRange)); + + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + range = NSMakeRange (NSMaxRange (range), 0); + } + + gl->comp_range.location = compRange.location; + gl->comp_range.length = compRange.length; + + while (++glyphIndex < numberOfGlyphs) + if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + break; + } + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + /* Then fill the remaining members. */ + glyphIndex = prevGlyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + if (!RIGHT_TO_LEFT_P) + totalAdvance = 0; + else + { + NSUInteger nrects; + NSRect *glyphRects = + [layoutManager + rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs)) + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + + totalAdvance = NSMaxX (glyphRects[0]); + } + + for (i = 0; i < used; i++) + { + struct ns_glyph_layout *gl; + NSPoint location; + NSUInteger nextGlyphIndex; + NSRange glyphRange; + NSRect *glyphRects; + NSUInteger nrects; + + if (!RIGHT_TO_LEFT_P) + gl = glyph_layouts + i; + else + { + NSUInteger dest = permutation[i]; + + gl = glyph_layouts + dest; + if (i < dest) + { + NSUInteger tmp = gl->string_index; + + gl->string_index = glyph_layouts[i].string_index; + glyph_layouts[i].string_index = tmp; + } + } + gl->glyph_id = [layoutManager glyphAtIndex: glyphIndex]; + + location = [layoutManager locationForGlyphAtIndex:glyphIndex]; + gl->baseline_delta = spaceLocation.y - location.y; + + for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs; + nextGlyphIndex++) + if (![layoutManager + notShownAttributeForGlyphAtIndex:nextGlyphIndex]) + break; + + if (!RIGHT_TO_LEFT_P) + { + CGFloat maxX; + + if (prevGlyphIndex == 0) + glyphRange = NSMakeRange (0, nextGlyphIndex); + else + glyphRange = NSMakeRange (glyphIndex, + nextGlyphIndex - glyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + maxX = max (NSMaxX (glyphRects[0]), totalAdvance); + gl->advance_delta = location.x - totalAdvance; + gl->advance = maxX - totalAdvance; + totalAdvance = maxX; + } + else + { + CGFloat minX; + + if (nextGlyphIndex == numberOfGlyphs) + glyphRange = NSMakeRange (prevGlyphIndex, + numberOfGlyphs - prevGlyphIndex); + else + glyphRange = NSMakeRange (prevGlyphIndex, + glyphIndex + 1 - prevGlyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + minX = min (NSMinX (glyphRects[0]), totalAdvance); + gl->advance = totalAdvance - minX; + totalAdvance = minX; + gl->advance_delta = location.x - totalAdvance; + } + + prevGlyphIndex = glyphIndex + 1; + glyphIndex = nextGlyphIndex; + } + + if (RIGHT_TO_LEFT_P) + xfree (permutation); + +#undef RIGHT_TO_LEFT_P + + result = used; + } + [textStorage release]; + + return result; +} + +static Lisp_Object +nsfont_shape (Lisp_Object lgstring, Lisp_Object direction) +{ + struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring)); + struct nsfont_info *font_info = (struct nsfont_info *) font; + struct ns_glyph_layout *glyph_layouts; + NSFont *nsfont = font_info->nsfont; + ptrdiff_t glyph_len, len, i; + Lisp_Object tem; + unichar *mb_buf; + NSUInteger used; + + glyph_len = LGSTRING_GLYPH_LEN (lgstring); + for (i = 0; i < glyph_len; ++i) + { + tem = LGSTRING_GLYPH (lgstring, i); + + if (NILP (tem)) + break; + } + + len = i; + + if (INT_MAX / 2 < len) + memory_full (SIZE_MAX); + + block_input (); + + mb_buf = alloca (len * sizeof *mb_buf); + + for (i = 0; i < len; ++i) + { + uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i)); + mb_buf[i] = (unichar) c; + } + + NSString *string = [NSString stringWithCharacters: mb_buf + length: len]; + unblock_input (); + + if (!string) + return Qnil; + + block_input (); + + enum lgstring_direction dir = DIR_UNKNOWN; + + if (EQ (direction, QL2R)) + dir = DIR_L2R; + else if (EQ (direction, QR2L)) + dir = DIR_R2L; + glyph_layouts = alloca (sizeof (struct ns_glyph_layout) * glyph_len); + used = ns_font_shape (nsfont, string, glyph_layouts, glyph_len, dir); + + for (i = 0; i < used; i++) + { + Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i); + struct ns_glyph_layout *gl = glyph_layouts + i; + EMACS_INT from, to; + struct font_metrics metrics; + + if (NILP (lglyph)) + { + lglyph = LGLYPH_NEW (); + LGSTRING_SET_GLYPH (lgstring, i, lglyph); + } + + from = gl->comp_range.location; + LGLYPH_SET_FROM (lglyph, from); + + to = gl->comp_range.location + gl->comp_range.length; + LGLYPH_SET_TO (lglyph, to - 1); + + /* LGLYPH_CHAR is used in `describe-char' for checking whether + the composition is trivial. */ + { + UTF32Char c; + + if (mb_buf[gl->string_index] >= 0xD800 + && mb_buf[gl->string_index] < 0xDC00) + c = (((mb_buf[gl->string_index] - 0xD800) << 10) + + (mb_buf[gl->string_index + 1] - 0xDC00) + 0x10000); + else + c = mb_buf[gl->string_index]; + + LGLYPH_SET_CHAR (lglyph, c); + } + + { + unsigned long cc = gl->glyph_id; + LGLYPH_SET_CODE (lglyph, cc); + } + + nsfont_text_extents (font, &gl->glyph_id, 1, &metrics); + LGLYPH_SET_WIDTH (lglyph, metrics.width); + LGLYPH_SET_LBEARING (lglyph, metrics.lbearing); + LGLYPH_SET_RBEARING (lglyph, metrics.rbearing); + LGLYPH_SET_ASCENT (lglyph, metrics.ascent); + LGLYPH_SET_DESCENT (lglyph, metrics.descent); + } + unblock_input (); + + return make_fixnum (used); +} /* ========================================================================== @@ -1134,6 +1606,50 @@ is false when (FROM > 0 || TO < S->nchars). */ ========================================================================== */ +static NSGlyph +ns_uni_to_glyphs_1 (struct nsfont_info *info, unsigned int c) +{ + unichar characters[] = { c }; + NSString *string = + [NSString stringWithCharacters: characters + length: 1]; + NSDictionary *attributes = + [NSDictionary dictionaryWithObjectsAndKeys: + info->nsfont, NSFontAttributeName, nil]; + NSTextStorage *storage = [[NSTextStorage alloc] initWithString: string + attributes: attributes]; + NSTextContainer *text_container = [[NSTextContainer alloc] init]; + NSLayoutManager *manager = [[NSLayoutManager alloc] init]; + + [manager addTextContainer: text_container]; + [text_container release]; /* Retained by manager */ + [storage addLayoutManager: manager]; + [manager release]; /* Retained by storage */ + + NSFont *font_in_storage = [storage attribute: NSFontAttributeName + atIndex:0 + effectiveRange: NULL]; + NSGlyph glyph = FONT_INVALID_CODE; + + if ((font_in_storage == info->nsfont + || [[font_in_storage fontName] isEqualToString: [info->nsfont fontName]])) + { + @try + { + glyph = [manager glyphAtIndex: 0]; + } + @catch (NSException *e) + { + /* GNUstep bug? */ + glyph = 'X'; + } + } + + [storage release]; + + return glyph; +} + /* Find and cache corresponding glyph codes for unicode values in given hi-byte block of 256. */ static void @@ -1141,7 +1657,7 @@ is false when (FROM > 0 || TO < S->nchars). */ { unichar *unichars = xmalloc (0x101 * sizeof (unichar)); unsigned int i, g, idx; - unsigned short *glyphs; + unsigned int *glyphs; if (NSFONT_TRACE) fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n", @@ -1149,7 +1665,7 @@ is false when (FROM > 0 || TO < S->nchars). */ block_input (); - font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short)); + font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned int)); if (!unichars || !(font_info->glyphs[block])) emacs_abort (); @@ -1166,7 +1682,8 @@ is false when (FROM > 0 || TO < S->nchars). */ for (i = 0; i < 0x100; i++, glyphs++) { g = unichars[i]; - *glyphs = g; + NSGlyph glyph = ns_uni_to_glyphs_1 (font_info, g); + *glyphs = glyph; } } @@ -1175,18 +1692,19 @@ is false when (FROM > 0 || TO < S->nchars). */ } -/* Determine and cache metrics for corresponding glyph codes in given - hi-byte block of 256. */ +/* Determine and cache metrics for glyphs in given hi-byte block of + 256. */ static void -ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block) +ns_glyph_metrics (struct nsfont_info *font_info, unsigned int block) { - unsigned int i, g; + unsigned int i; + NSGlyph g; unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs]; NSFont *sfont; struct font_metrics *metrics; if (NSFONT_TRACE) - fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n", + fprintf (stderr, "%p\tComputing metrics for glyphs in block %u\n", font_info, block); /* not implemented yet (as of startup 0.18), so punt */ @@ -1209,19 +1727,14 @@ is false when (FROM > 0 || TO < S->nchars). */ w = max ([sfont advancementForGlyph: g].width, 2.0); metrics->width = lrint (w); - lb = r.origin.x; - rb = r.size.width - w; - // Add to bearing for LCD smoothing. We don't know if it is there. - if (lb < 0) - metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN); - if (font_info->ital) - rb += (CGFloat) (0.22F * font_info->height); - metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN); - - metrics->descent = r.origin.y < 0 ? -r.origin.y : 0; - /* lrint (hshrink * [sfont ascender] + expand * hd/2); */ - metrics->ascent = r.size.height - metrics->descent; - /* -lrint (hshrink* [sfont descender] - expand * hd/2); */ + lb = NSMinX (r); + rb = NSMaxX (r); + + metrics->rbearing = lrint (rb); + metrics->lbearing = lrint (lb); + + metrics->descent = NSMinY (r); + metrics->ascent = NSMaxY (r); } unblock_input (); } @@ -1257,6 +1770,7 @@ is false when (FROM > 0 || TO < S->nchars). */ .has_char = nsfont_has_char, .encode_char = nsfont_encode_char, .text_extents = nsfont_text_extents, + .shape = nsfont_shape, .draw = nsfont_draw, }; @@ -1265,7 +1779,6 @@ is false when (FROM > 0 || TO < S->nchars). */ { DEFSYM (Qcondensed, "condensed"); DEFSYM (Qexpanded, "expanded"); - DEFSYM (Qapple, "apple"); DEFSYM (Qmedium, "medium"); DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script, doc: /* Internal use: maps font registry to Unicode script. */); diff --git a/src/nsterm.h b/src/nsterm.h index c750d1bd99..8175f99664 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -820,7 +820,7 @@ #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) XCharStruct max_bounds; /* We compute glyph codes and metrics on-demand in blocks of 256 indexed by hibyte, lobyte. */ - unsigned short **glyphs; /* map Unicode index to glyph */ + unsigned int **glyphs; /* map Unicode index to glyph */ struct font_metrics **metrics; }; #endif diff --git a/src/nsterm.m b/src/nsterm.m index 4c2a3f287c..b4d03e668d 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1078,11 +1078,20 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) /* clipping */ if (r) { - [[NSGraphicsContext currentContext] saveGraphicsState]; + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; if (n == 2) NSRectClipList (r, 2); else NSRectClip (*r); +#ifdef NS_IMPL_GNUSTEP + DPSrectclip (ctx, NSMinX (*r), NSMinY (*r), + NSWidth (*r), NSHeight (*r)); + + if (n == 2) + DPSrectclip (ctx, NSMinX (r[1]), NSMinY (r[1]), + NSWidth (r[1]), NSHeight (r[1])); +#endif gsaved = YES; } } @@ -2440,9 +2449,6 @@ Hide the window (X11 semantics) EmacsView *view = FRAME_NS_VIEW (f); FRAME_POINTER_TYPE (f) = cursor; [[view window] invalidateCursorRectsForView: view]; - /* Redisplay assumes this function also draws the changed frame - cursor, but this function doesn't, so do it explicitly. */ - gui_update_cursor (f, 1); } } @@ -2852,31 +2858,31 @@ Hide the window (X11 semantics) External (RIF); compute left/right overhang of whole string and set in s -------------------------------------------------------------------------- */ { - struct font *font = s->font; - - if (s->char2b) + if (s->cmp == NULL + && (s->first_glyph->type == CHAR_GLYPH + || s->first_glyph->type == COMPOSITE_GLYPH)) { struct font_metrics metrics; - unsigned int codes[2]; - codes[0] = *(s->char2b); - codes[1] = *(s->char2b + s->nchars - 1); - font->driver->text_extents (font, codes, 2, &metrics); - s->left_overhang = -metrics.lbearing; - s->right_overhang - = metrics.rbearing > metrics.width - ? metrics.rbearing - metrics.width : 0; + if (s->first_glyph->type == CHAR_GLYPH) + { + struct font *font = s->font; + font->driver->text_extents (font, s->char2b, s->nchars, &metrics); + } + else + { + Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); + + composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); + } + s->right_overhang = (metrics.rbearing > metrics.width + ? metrics.rbearing - metrics.width : 0); + s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0; } - else + else if (s->cmp) { - s->left_overhang = 0; -#ifdef NS_IMPL_GNUSTEP - if (EQ (font->driver->type, Qns)) - s->right_overhang = ((struct nsfont_info *)font)->ital ? - FONT_HEIGHT (font) * 0.2 : 0; - else -#endif - s->right_overhang = 0; + s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width; + s->left_overhang = - s->cmp->lbearing; } } @@ -3016,14 +3022,13 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. struct frame *f = WINDOW_XFRAME (w); struct glyph *phys_cursor_glyph; struct glyph *cursor_glyph; - struct face *face; - NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f); /* If cursor is out of bounds, don't draw garbage. This can happen in mini-buffer windows when switching between echo area glyphs and mini-buffer. */ - NSTRACE ("ns_draw_window_cursor"); + NSTRACE ("ns_draw_window_cursor (on = %d, cursor_type = %d)", + on_p, cursor_type); if (!on_p) return; @@ -3039,6 +3044,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL) { + NSTRACE_MSG ("No phys cursor glyph was found!"); + if (glyph_row->exact_window_width_line_p && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) { @@ -3048,10 +3055,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. return; } - /* We draw the cursor (with NSRectFill), then draw the glyph on top - (other terminals do it the other way round). We must set - w->phys_cursor_width to the cursor width. For bar cursors, that - is CURSOR_WIDTH; for box cursors, it is the glyph width. */ get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h); /* The above get_phys_cursor_geometry call set w->phys_cursor_width @@ -3083,17 +3086,15 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. /* Prevent the cursor from being drawn outside the text area. */ r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA)); - ns_focus (f, &r, 1); + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSrectclip (ctx, r.origin.x, r.origin.y, + r.size.width, r.size.height); +#endif - face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id); - if (face && NS_FACE_BACKGROUND (face) - == ns_index_color (FRAME_CURSOR_COLOR (f), f)) - { - [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set]; - hollow_color = FRAME_CURSOR_COLOR (f); - } - else - [FRAME_CURSOR_COLOR (f) set]; + [FRAME_CURSOR_COLOR (f) set]; switch (cursor_type) { @@ -3101,13 +3102,11 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. case NO_CURSOR: break; case FILLED_BOX_CURSOR: - NSRectFill (r); + draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); break; case HOLLOW_BOX_CURSOR: - NSRectFill (r); - [hollow_color set]; - NSRectFill (NSInsetRect (r, 1, 1)); - [FRAME_CURSOR_COLOR (f) set]; + draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT); + [NSBezierPath strokeRect: r]; break; case HBAR_CURSOR: NSRectFill (r); @@ -3123,12 +3122,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. NSRectFill (s); break; } - ns_unfocus (f); - /* Draw the character under the cursor. Other terms only draw - the character on top of box cursors, so do the same here. */ - if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR) - draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); + [ctx restoreGraphicsState]; } @@ -3308,16 +3303,18 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if (s->for_overlaps) return; + if (s->hl == DRAW_CURSOR) + [FRAME_BACKGROUND_COLOR (s->f) set]; + else if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + /* Do underline. */ if (face->underline) { if (s->face->underline == FACE_UNDER_WAVE) { - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; - ns_draw_underwave (s, width, x); } else if (s->face->underline == FACE_UNDER_LINE) @@ -3388,11 +3385,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. s->underline_position = position; r = NSMakeRect (x, s->ybase + position, width, thickness); - - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; NSRectFill (r); } } @@ -3402,11 +3394,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. { NSRect r; r = NSMakeRect (x, s->y, width, 1); - - if (face->overline_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->overline_color, s->f) set]; NSRectFill (r); } @@ -3429,10 +3416,6 @@ larger if there are taller display elements (e.g., characters dy = lrint ((glyph_height - h) / 2); r = NSMakeRect (x, glyph_y + dy, width, 1); - if (face->strike_through_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->strike_through_color, s->f) set]; NSRectFill (r); } } @@ -3580,17 +3563,7 @@ Function modeled after x_draw_glyph_string_box (). struct glyph *last_glyph; NSRect r; int hthickness, vthickness; - struct face *face; - - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = s->face; + struct face *face = s->face; vthickness = face->box_vertical_line_width; hthickness = face->box_horizontal_line_width; @@ -3664,34 +3637,26 @@ Function modeled after x_draw_glyph_string_box (). || FONT_TOO_HIGH (s->font) || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) { - struct face *face; - if (s->hl == DRAW_MOUSE_FACE) - { - face - = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + struct face *face = s->face; if (!face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set]; } - if (s->hl != DRAW_CURSOR) - { - NSRect r = NSMakeRect (s->x, s->y + box_line_width, - s->background_width, - s->height-2*box_line_width); - NSRectFill (r); - } + NSRect r = NSMakeRect (s->x, s->y + box_line_width, + s->background_width, + s->height-2*box_line_width); + NSRectFill (r); s->background_filled_p = 1; } @@ -3712,7 +3677,7 @@ Function modeled after x_draw_glyph_string_box (). int th; char raised_p; NSRect br; - struct face *face; + struct face *face = s->face; NSColor *tdCol; NSTRACE ("ns_dumpglyphs_image"); @@ -3733,15 +3698,6 @@ Function modeled after x_draw_glyph_string_box (). /* Draw BG: if we need larger area than image itself cleared, do that, otherwise, since we composite the image under NS (instead of mucking with its background color), we must clear just the image area. */ - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set]; @@ -3812,16 +3768,8 @@ Function modeled after x_draw_glyph_string_box (). if (s->hl == DRAW_CURSOR) { - [FRAME_CURSOR_COLOR (s->f) set]; - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) + [FRAME_CURSOR_COLOR (s->f) set]; tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); - else - /* Currently on NS img->mask is always 0. Since - get_window_cursor_type specifies a hollow box cursor when on - a non-masked image we never reach this clause. But we put it - in, in anticipation of better support for image masks on - NS. */ - tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); } else { @@ -3873,66 +3821,35 @@ Function modeled after x_draw_glyph_string_box (). static void ns_dumpglyphs_stretch (struct glyph_string *s) { - NSRect r[2]; NSRect glyphRect; - int n; - struct face *face; + struct face *face = s->face; NSColor *fgCol, *bgCol; if (!s->background_filled_p) { - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + face = s->face; bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); - glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); - - [bgCol set]; - - /* NOTE: under NS this is NOT used to draw cursors, but we must avoid - overwriting cursor (usually when cursor on a tab) */ if (s->hl == DRAW_CURSOR) - { - CGFloat x, width; + { + fgCol = bgCol; + bgCol = FRAME_CURSOR_COLOR (s->f); + } - /* FIXME: This looks like it will only work for left to - right languages. */ - x = NSMinX (glyphRect); - width = s->w->phys_cursor_width; - glyphRect.size.width -= width; - glyphRect.origin.x += width; + glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); - NSRectFill (glyphRect); + [bgCol set]; - /* Draw overlining, etc. on the cursor. */ - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) - ns_draw_text_decoration (s, face, bgCol, width, x); - else - ns_draw_text_decoration (s, face, fgCol, width, x); - } - else - { - NSRectFill (glyphRect); - } + NSRectFill (glyphRect); /* Draw overlining, etc. on the stretch glyph (or the part of the stretch glyph after the cursor). */ ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect), NSMinX (glyphRect)); - ns_unfocus (s->f); s->background_filled_p = 1; } } @@ -3941,7 +3858,7 @@ overwriting cursor (usually when cursor on a tab) */ static void ns_draw_glyph_string_foreground (struct glyph_string *s) { - int x, flags; + int x; struct font *font = s->font; /* If first glyph of S has a left box line, start drawing the text @@ -3952,15 +3869,9 @@ overwriting cursor (usually when cursor on a tab) */ else x = s->x; - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - font->driver->draw (s, s->cmp_from, s->nchars, x, s->ybase, - (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p) - || flags == NS_DUMPGLYPH_MOUSEFACE); + !s->for_overlaps && !s->background_filled_p); } @@ -4067,9 +3978,9 @@ overwriting cursor (usually when cursor on a tab) */ struct font *font = s->face->font; if (! font) font = FRAME_FONT (s->f); - NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string"); + NSTRACE ("ns_draw_glyph_string (hl = %u)", s->hl); - if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/) + if (s->next && s->right_overhang && !s->for_overlaps) { int width; struct glyph_string *next; @@ -4106,14 +4017,21 @@ overwriting cursor (usually when cursor on a tab) */ box_drawn_p = 1; } + n = ns_get_glyph_string_clip_rect (s, r); + + if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */ + && !s->clip_tail + && ((s->prev && s->prev->hl != s->hl && s->left_overhang) + || (s->next && s->next->hl != s->hl && s->right_overhang))) + r[0] = NSIntersectionRect (r[0], NSMakeRect (s->x, s->y, s->width, s->height)); + + ns_focus (s->f, r, n); + switch (s->first_glyph->type) { case IMAGE_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); ns_dumpglyphs_image (s, r[0]); - ns_unfocus (s->f); break; case XWIDGET_GLYPH: @@ -4126,57 +4044,36 @@ overwriting cursor (usually when cursor on a tab) */ case CHAR_GLYPH: case COMPOSITE_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - - if (s->for_overlaps || (s->cmp_from > 0 - && ! s->first_glyph->u.cmp.automatic)) - s->background_filled_p = 1; - else - ns_maybe_dumpglyphs_background - (s, s->first_glyph->type == COMPOSITE_GLYPH); - - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - { - BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + if (s->for_overlaps || (isComposite + && (s->cmp_from > 0 + && ! s->first_glyph->u.cmp.automatic))) + s->background_filled_p = 1; + else + ns_maybe_dumpglyphs_background + (s, s->first_glyph->type == COMPOSITE_GLYPH); - if (isComposite) - ns_draw_composite_glyph_string_foreground (s); - else - ns_draw_glyph_string_foreground (s); - } + if (isComposite) + ns_draw_composite_glyph_string_foreground (s); + else + ns_draw_glyph_string_foreground (s); - { - NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), - s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - [col set]; - - /* Draw underline, overline, strike-through. */ - ns_draw_text_decoration (s, s->face, col, s->width, s->x); + { + NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), + s->f) + : FRAME_FOREGROUND_COLOR (s->f)); + [col set]; + + /* Draw underline, overline, strike-through. */ + ns_draw_text_decoration (s, s->face, col, s->width, s->x); + } } - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - - ns_unfocus (s->f); break; case GLYPHLESS_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - if (s->for_overlaps || (s->cmp_from > 0 && ! s->first_glyph->u.cmp.automatic)) s->background_filled_p = 1; @@ -4186,7 +4083,6 @@ overwriting cursor (usually when cursor on a tab) */ /* ... */ /* Not yet implemented. */ /* ... */ - ns_unfocus (s->f); break; default: @@ -4195,13 +4091,92 @@ overwriting cursor (usually when cursor on a tab) */ /* Draw box if not done already. */ if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) + ns_dumpglyphs_box_or_relief (s); + + ns_unfocus (s->f); + + /* Draw surrounding overhangs. */ + if (s->prev) { - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - ns_dumpglyphs_box_or_relief (s); + ns_focus (s->f, NULL, 0); + struct glyph_string *prev; + + for (prev = s->prev; prev; prev = prev->prev) + if (prev->hl != s->hl + && prev->x + prev->width + prev->right_overhang > s->x) + { + /* As prev was drawn while clipped to its own area, we + must draw the right_overhang part using s->hl now. */ + enum draw_glyphs_face save = prev->hl; + struct face *save_face = prev->face; + + prev->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + prev->num_clips = 1; + prev->hl = s->hl; + if (prev->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (prev); + else + ns_draw_composite_glyph_string_foreground (prev); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + [[NSGraphicsContext currentContext] restoreGraphicsState]; + prev->hl = save; + prev->face = save_face; + prev->num_clips = 0; + } ns_unfocus (s->f); } + if (s->next) + { + ns_focus (s->f, NULL, 0); + struct glyph_string *next; + + for (next = s->next; next; next = next->next) + if (next->hl != s->hl + && next->x - next->left_overhang < s->x + s->width) + { + /* As next will be drawn while clipped to its own area, + we must draw the left_overhang part using s->hl now. */ + enum draw_glyphs_face save = next->hl; + struct face *save_face = next->face; + + next->hl = s->hl; + next->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + next->num_clips = 1; + if (next->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (next); + else + ns_draw_composite_glyph_string_foreground (next); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + [[NSGraphicsContext currentContext] restoreGraphicsState]; + next->hl = save; + next->num_clips = 0; + next->face = save_face; + next->clip_head = next; + next->background_filled_p = 0; + } + ns_unfocus (s->f); + } s->num_clips = 0; } diff --git a/src/xdisp.c b/src/xdisp.c index dffbdb8d1e..0d95e70212 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -29298,7 +29298,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, for (s = head; s; s = s->next) FRAME_RIF (f)->draw_glyph_string (s); -#ifndef HAVE_NS /* When focus a sole frame and move horizontally, this clears on_p causing a failure to erase prev cursor position. */ if (area == TEXT_AREA @@ -29317,7 +29316,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, notice_overwritten_cursor (w, TEXT_AREA, x0, x1, row->y, MATRIX_ROW_BOTTOM_Y (row)); } -#endif /* Value is the x-position up to which drawn, relative to AREA of W. This doesn't include parts drawn because of overhangs. */ -- 2.31.1 --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Sat Oct 30 22:38:24 2021 Received: (at 51411) by debbugs.gnu.org; 31 Oct 2021 02:38:24 +0000 Received: from localhost ([127.0.0.1]:58751 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh0jo-0004Pc-1I for submit@debbugs.gnu.org; Sat, 30 Oct 2021 22:38:24 -0400 Received: from sonic312-25.consmr.mail.ne1.yahoo.com ([66.163.191.206]:40974) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh0jl-0004PN-D8 for 51411@debbugs.gnu.org; Sat, 30 Oct 2021 22:38:22 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635647895; bh=628Y6TUY9TuBuhVbbJTooTyg4Rr8c7z1By75gAn1mqU=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=GPriJTeh/QLS+1OPK/sWTUwQeieEbACI9lQ62Uybqmq9stdwZhIvcsmBd/yv36dHOpq/PPk55bNH8Zx1xGz5wPqV6cHpkzXldiCm5JsRhzk+yJYf5uyiJd9pdRs4++bG/g5aaxZfdBCKUNIoVzCgMOp5epJVH3uvj6mkNca+dWOt2v2SIyxSpxsBdQ/xUR2Oltphi7R9eYTUdQHrAZwB6st/G+kMVuDs7XG4abyjuSfFdtuxN8PxrTYZzdBWCu3JBOhmwhF0Kp+/xU8oSkebuL7EH80E8ltDERXajX47qDa7ILWW6O/klVGIMk57gj65B3TIH1doyNKO8PagqEGPfA== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635647895; bh=4hj8syCrIRn/mw6CrMNKsUxW5rrtUkRAdfXR9hMFk5Y=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=fmX6AVwt9R19gf/LnS6OuemOzcN5uYZ4sl1KXbVps3STJIS4sJoWI7BQhjXCt1yevorQ1IeL6vt3BWb/Kdc0ucRkds5V6pRpO4sy8dcyU3Ir6L8V+4xdIYa0bNh1P5jtxuYKEzJS6Laa7YKQ16J+JOx4UqZRPxXJGwqorCv8WpPimAjqoc3hpU6KS654QWiLqRv9zs2QxXdt2YLNeFRqFlGz+pz4n9UjJQhozEmgG1V7MIRWg7tjheKpy0V5jVXD6htvmoK3/NMKDnUPZDl9HJNFb7jZHi6/2ZBpFi43VM8aXHTzKAFmCKSw9ZodhfLrX+EiZZPNLxzDAwypAE/7LQ== X-YMail-OSG: GWP9oMwVM1kVM.QiC4La7jHX.Cvz2al1UszalU2.um2FAylLT5H4b_mBrLMzCZ4 WlDvWdLyEFCv8edYy906FZra6SEHcMR.wfaXo9FWyVsmmKxKqjkUGHTzVs5SmugWWHP4vx2CfBsi mo8vQBAjLvkkGZ9jMApTYxlt32whqnpJoPm32VJgy5bGa2ISNP_7vzLRMoHI127RcEIfmLItwoVX V33V.XeCxUsKaV0lrsUTCgqqyO9.YDbI2whaOjB3iL4LFt9BU_UBGgwVvo.w62lAb7Q.MWEqbdxY kFqaJsWPs5_4GpDf5sl_5Qo_XOGgjLEgZUy0l.HmbeFLxi59KUKNGeT_Bs0hYL3S39K8sDVBEioI w4_40fje.nHQhXnBaVA3UxX56H.zM.ZY4oj9RGGvtsiA.DXAThJESauC4gdJeYnXzGgVgB.QVA26 spPxCWbSlyIAspKwLON8yv8_0l3hRSNNzC2XkiDlWZp2xUt9ZcGDn78FxW2KrrW8fFm8bJgP3AF. klndclE_OkSlsK81vqG_Y22Q.1RFmUGYs86IfSEapsBmoYD7J3EA4tLKBM7HliO4HsB7z5S_FnRl ZvePyKBlbpKxK.790wtULIsXJWSoPNphCJWtc8w4HYvNZoRCeRELh.DYKJnNDkXCYXYXS5ykY1PP z4HRd4V0HwI61Gf_51f4Gm8UalA_qmBk4siqqc_Yo4Za_J7D0h_SQX0MlfAZfm2zen8DugnEHcI_ LdbReCTcSmy70uhzbREvj4aejml5yDB0fPbuLEvKpqZ1FnjiKZrCR.9zed0gSYtQ.TfBuYvy2.E_ wg7G6DZY2jxqKgMvF42oO.K9P1giEJtH0uG5mzN9elNNZqZkUxkcgiqCoZzrVS4oRzlLLcX.2MJu fx6v7wflbbntImEZsoXEt.9TByoibQ5tu_ua54C5o2Amce6.iPt2pf9XZrLIOa.GcmC5U9mVmqUF 5Z4msp7KRe2U5jSzcqKnezEjsbY2xTwJqJ4eKNfnpcH7AYLic_tgXcgKENbcrnDNfzF.QmUmsIBW hwKVaOOV45m_fCzfSXoaeFpXHWz0xjjYD.Bi5MpRpA.ddGF1TBbxjY7OSsLZhrSFawZY0MwP6SWN KN2W6z6LkPStRJ4Y4MvUQY3pjkyZgS7iUs3GaHQxsIHoZZDB1xNivTRxA.iRT5cBxNqk6gURXne1 onGxIOZ9G4Z_RuLMBmalaAY1KI75EM1PrCsgRkio9p3Fopcqgn06BYcrrA8SRy2FcvSm.7.r4QnL GTtkMcY3rWzufsGI5LtNWtbTVI1boytLCMZIeuFgARP0hifp4d3oCvUvYDMXUAPP5eWjWT1BLvzy R6jzKL1tacdf0mIMT0Hjz8RuYCOJ16qV6HzFbs.bBG8_SJELx4q6cCyLU1zNqFnCL3c51VUqgBUy Rc854Py3HCiF3E.19Uyydang4AkEoQx7Yqhpmuw9qAIB9iixRm8OjrfTZj8IppBJdxaT.eSeQrxQ CYTpNOA3vMfVv4ANFJl3gdKDYKW6nZR.38pmzfrfDzpdbctubjHL82AoFgbwE3E8OKKc4OKZpZES fFzzduMM9rynjrt87bz0aH83Irix_9ch6.XoPL0UdSKJ0BDtBImFJK4QRotvlSaZNAY5ZtPGVlYp eidHy36QhzXuAk1miOk6IqvXDTucLrkbeEzpZhaxhuuS1MyBia7pmtMMlQZ3qGc3eVE9s1gNI9PP khRzngTvsKRAYzCwNOliu00npmHq_FTLxVni6H9Mxv5D1bVSRtrvSUgbVJlPgK6U3POPvn3Pj20l SYtEy8pNnzK2yc7vnktPo5XPymLDDPocJfQYJAMSH.JodPe4AJGgOluwnVeF3wCd.kcsj.EKtLG1 2s4EixK2ck6F6JLUYA5nL4I7Kok4brOA7ZeY1A4heY44eUaeNyZptzDPmn3L6Hfe.E5osb7XPT2a r6nqW5O1sjdAVCVZr1GoWE7CP5IThIC2UXJAAWz5xItANQGfzQ3XeTR1NK1GRLZeMVsjE5hqjvlz sngtqBlTcKliDuRz9F0ggP_SMed.NahBRamGsYglMB_N6BS6XDE1.QHX6Ujs63ANWk7pZS15Iole hDlo2pNAZ14Y9YOY85xGE5ZhYugArZnJADwN0a.vSFz.tdMdw53_AfxacqVRq4ryKmVOu18mKod. CJQCdnUjD_nrDIvwKE_aK4aUK5uK49S8_hZinAVJ_NDDoBmyWpVk0pPT0XmYu7bln3fv79Zx6Wjz mj_v3YGy6nKR1YXZEl7DLPc1PFJau4tkTZ6mKnXKkRVbmBln.ZdQjfWSw X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic312.consmr.mail.ne1.yahoo.com with HTTP; Sun, 31 Oct 2021 02:38:15 +0000 Received: by kubenode512.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 1f2fd0135036f2586ae81fea68630ce7; Sun, 31 Oct 2021 02:38:09 +0000 (UTC) From: Po Lu To: Stefan Kangas Subject: Re: bug#51411: NS port cleanups References: Date: Sun, 31 Oct 2021 10:38:05 +0800 In-Reply-To: (Stefan Kangas's message of "Wed, 27 Oct 2021 14:28:24 -0700") Message-ID: <871r41ly0i.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 279 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 51411 Cc: Alan Third , 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Stefan Kangas writes: > severity 51411 wishlist > quit Is it really fair to tag this issue as wishlist? It fixes two concrete issues, bad font display on GNUstep being one, and crashes with the context menu from `context-menu-mode' being another. Thanks. From debbugs-submit-bounces@debbugs.gnu.org Sat Oct 30 22:56:44 2021 Received: (at 51411) by debbugs.gnu.org; 31 Oct 2021 02:56:44 +0000 Received: from localhost ([127.0.0.1]:58775 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh11Y-00074G-Dx for submit@debbugs.gnu.org; Sat, 30 Oct 2021 22:56:44 -0400 Received: from mail-pg1-f173.google.com ([209.85.215.173]:40488) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh11X-00073z-Ga for 51411@debbugs.gnu.org; Sat, 30 Oct 2021 22:56:43 -0400 Received: by mail-pg1-f173.google.com with SMTP id a9so3357239pgg.7 for <51411@debbugs.gnu.org>; Sat, 30 Oct 2021 19:56:43 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:in-reply-to:references:mime-version:date :message-id:subject:to:cc; bh=0sMOkfjJAkJaCS849r++ZknS31EjBJGdb91fGFZAFOs=; b=E/IBFtup+82tMQcJUpw1Il+jfbaAiaUGFaDRxjH6mqHP2/QhEiWCtGLOzD1tGzvxOD GHzhu5nKli4glqyvFFnF1/k1/52ovEbNBEvEpjbq/zvArl8A+kx0CqUjDgm0AoB/agzD s8lBI5Q5q5V9Ii5mWdi0doZtl0aJ54NGKYJ97nDX0SyYuqemnRCL4sJ3x96W052GUsHR U/UEPn90j5uVl79mV+xIByw4WGg9QyJNa6NST38TXk0c98s3Zg/a4/U7adAlIe9Ka3Rb d6VK4QimprC2P2n8KQkZaxlz6GcgPDDV2E2vm0xK1GhwLkjLETnZLLnGGQCLuGdEqbai cwhQ== X-Gm-Message-State: AOAM530I1JsU3YkukyDPMgWGaxNQaoYBc3J9XP62I+3MPQ9YDOGG4qz1 e35RGyPqgIxumgcbL0M/dLFWh/lkTnAB6t9Yodc= X-Google-Smtp-Source: ABdhPJxS0PYAJRiEqR55C4YerIdZtwtLi4sb6dpFTjhfVICA9OzsCuX0fMxcaR+6Tj5GRvGQJGYXFHSw78OzQ+7A5us= X-Received: by 2002:a05:6a00:1955:b0:47c:1d32:84de with SMTP id s21-20020a056a00195500b0047c1d3284demr20103083pfk.70.1635648997738; Sat, 30 Oct 2021 19:56:37 -0700 (PDT) Received: from 753933720722 named unknown by gmailapi.google.com with HTTPREST; Sat, 30 Oct 2021 19:56:37 -0700 From: Stefan Kangas In-Reply-To: <871r41ly0i.fsf@yahoo.com> References: <871r41ly0i.fsf@yahoo.com> MIME-Version: 1.0 Date: Sat, 30 Oct 2021 19:56:37 -0700 Message-ID: Subject: Re: bug#51411: NS port cleanups To: Po Lu Content-Type: text/plain; charset="UTF-8" X-Spam-Score: 0.5 (/) X-Debbugs-Envelope-To: 51411 Cc: Alan Third , 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.5 (/) tags 51411 normal thanks Po Lu writes: > Stefan Kangas writes: > >> severity 51411 wishlist >> quit > > Is it really fair to tag this issue as wishlist? It fixes two concrete > issues, bad font display on GNUstep being one, and crashes with the > context menu from `context-menu-mode' being another. Sorry, I had missed that part. It sounds to me that this should better be tagged "normal", so I'm adjusting the tag back to that with this message. Thanks for paying attention to the severity tagging. From debbugs-submit-bounces@debbugs.gnu.org Sat Oct 30 23:13:43 2021 Received: (at 51411) by debbugs.gnu.org; 31 Oct 2021 03:13:43 +0000 Received: from localhost ([127.0.0.1]:58804 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh1Hz-0001Ed-19 for submit@debbugs.gnu.org; Sat, 30 Oct 2021 23:13:43 -0400 Received: from sonic309-22.consmr.mail.ne1.yahoo.com ([66.163.184.148]:32946) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh1Hv-0001EN-Ku for 51411@debbugs.gnu.org; Sat, 30 Oct 2021 23:13:41 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635650013; bh=ev2Qq/SsMfz7Bs+OOr7XW+6pGluulsSAPUhnJKuVUJ8=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=jJqKa04V8xBQ+/nI6KlaRJ2sPBjwMF99vDNy4Pi65NDI3MsP320HuXAxONXMsyLhmWIc+sYUNcsvwxZ8T6ZENJVOxyL7wPKU5TlWTk6IfoHEMBMA3qnVmeADmVXOropSpuCEjC5wNOTSecxMH78yoEQTzFxc7L0pT8eQ+yU3caY+5Tz6lhAIEF6NijW0bdWusGEOwb+PuWgIhG2LfqrdMpO2azEL6p0nJNj5k7iqVYPaw9xXeRAdHRU6gzPcWBnwg/Mm8S72WgEPRP5MwtLRtE+WMfHeAwvE7h7fv/GrBGqG3hsigDskQnh8aT64LzHU8dDjfGaXC0knUWKjKJGu/g== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635650013; bh=Z7hke5bKBu9NQUqcor8iagghm8anvYw9W75aYkWFbnj=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=lYda5h8S08/Ah3b9lAMRJQub2iuxEizfHZs/VvFKKzsxPWc9bAZZfmVKDoJ4+D2Q0yHg2ssHlGheWzioDDmpcDPLIr4MOVleaZhYWTgNfP1/qhLN8zwuQCD0Jmy1jidXW13xRNcR6/zYiD1UYMqvyQsDTE9iz4XB9nAZJCQV6ZNz2rdzIAROOuWfrrYU6ggOGk8UNFDGDoucupTGayk3gcDi3o0hU6V1rOPwoRhmqSuH/9xMSrHLIZJimP9yL0QyKtmrJZOrI9ppL5pzQvXb29H6lsOdPjIKjM9uZqEatUY/n/8cTC2R6ttCWhCZoDgLcSLdS92o0k+s11UuYRAUhg== X-YMail-OSG: 4JFNnR0VM1nOO6TefZ3GfAcMR9wAkVGRW9TrisolC3IEOzWs.hkp6gvsTK8xcZQ K9K8PwAl12CTNBwmfNzpP4u9hyvyUk9yvQBF2qNnf64GyfhqMmRfWIZmr.Z.UHTxVN_hX72jepE_ JnN.r9o0v0DIDTSVXgXz9q_Wz0WLRsVdPMcoBR.xQUCFsjPxrGjo5CeZNHrRT9XWf6LpTrnjttAR fz5pJsNJj.03ayoiOLGN9YlFhXexdtBjMxo5gfoVnrPgTj.V1LOby0RFrHWDosjDvyp6_WR2Z9nm PBd_O241vAyRiAxOVuShde479er3kG2_tg9AQiaH2dHHohVOlNBvCLpCK2fSlTx9wP_ovDGU93VO o5jeYj.wx8.jLbUOTnNDl2z4vqnGCcu16y1dYK0j7_4KbNkQDwZUqJd8MLL5UptX_dHBgWYZ8_9y O7PBzTqNriKbi72wVl2dCIppAahmk8qDeGEuseO2qNNLWrsu9gKUQ1I24BbOe_XGy7jqS.dVsnSh osrVsImRE8Y7hbjAu4t3IMFWvWV1mvyVIMlG_.2G_R_U05.hnTyYPJgpwFHzcOkka1zabPORYXJy tylL7BF9mKZPh4lp7s9xBoiAzKIKSqFMESbg0thRcx250ApVXlR.GUbMrJMPpMRrz.ydpztUVeh9 Stgrj_LIBOSi0q8Hq9tTYE2F.0Anyo.LJz27RtAO_4zLuPAki7x8fa442sFPFSKmcA7VU24QHLdl j3mb1SD7SYjvl1ALG3IwfMvFemtIIud_XToIOnvsLZUOgYHe1rIQWxBjKI0TJ0.9Jz1EHaB.iqTb hotEjDegD27Z1eJqGjHzS5UAndJOprb39ah_fkrkLAxH_g0j0NWHQ2XS7IdrMAfJILG4Wxt78Wek EWgqscPVEd5haJigzx43SHX1lQgxnx7RxA_V1MpA8PQ4tJ69dhdprPfhDYwEIUO3XyGV7On8NFoL RpSpR_IpQB796hjGUL3WJokljPnFyD5VR0KpFTtR6xA8wP6lCtaTScC_7ueeZFzSuMT61qEvQDGz FOswUMKzTvcZJxR9rBOKxPRDPCIj_foEUNyNcIHEi8.i6yMcsvofg9S5FHev3V07qY2JIX..7c3o 56o3jmwXpK78AH87bxVTUaOY4FU1sTWTsXIhxCMKlGFiOL5yhJFZowfUsiYhe0_xeaioDnfO8ic6 UNR4Nu.eskVB.oyjpx2t3xzf9vbZrZZaT1JU1ZOsX0U82X6LoONO_Y87l28edNVuSurE.FMxDmo3 mYi6dNPpUbaiAv9Eke9Y_fTRrCjjEvPrJ2_XQOnY2na4GaIKGvYQWJUccaHLbGUvVeBkqU4zEksO 97wBxz.TYLDQQqUwvbH1zoRu0YmgutNtCDahjDzEfVCFQ6ePAXCM13GaMhBH2CzCU04uxTzdd8yT A4P3Ex7NEO0hVDunxcu9GpxU0GLEpUzVnQYVgmRppC98AiRqn7dihPqxbzUuemt8X9KKW8UpLjL1 oFye5wvM5uEnkxI2mhE6gpZoWpa24tgH8kPX_Vf.vnPut4ZLJ2PMgHPtOC53Hb6.LWlQXK7jM3uv cCDMVVBFe6LMS5LGzmD9MV60tdBsGi6dZTgd7utQy1aZQlpzMG31Q.gFF4ddXGqi52uY8e5I0qSu KTY2K49F2F4v7ODzlOYKm6RLcAReGwO5rTIH8bxyAsV7CWfZk8_AnxPlBpJ14KX2xqUjIo7jR0Nb 4jbjkGqAFLAEZpuoxBwWkGxRXshqI2ebaRBRwXYuFMTpsaiUYi6hoW6kfjJVJBtIcuS3ctGRgx0B tShb6ynz15hHCi85widoIs4QQkTSkD80Yehf85LlvSSEg7lOoWs2huDhJx3czKXiGEFk5H0xiGKS g5k9ZaxV_9RnWVv8By_WtT_ExNKpHE_g6v5fNn6gMHLwOJTnoygsE6Mm3mXM2hdxMGEGI7Dv6LVr WhDRI17oEChvI8PoEd3qzvsCdUWwQw2vz10LmL.fkxzw8rPveOmA0Li9N5f6WxJ7ZUo5n_qjTyli KpktphhYXveM0R5S7k.spzSvo9kIQ7LTJv4hzljgjz4Ft0XGkSjcIP3kRGBOmQ0TpXvVbRn0cq8r BQRiB2pN8SqmIdwBnFdUuSx_Z0bpqYxM0KIvUWlO8BX0yWE.iDpBM5t_GKkcYlBQ74VFqx25sAmb ThlBP3NeLyynwcjk1OrAMmffdrvAZiEAjyRg9Phulog28Wm6v6Sw5i5tM4b9z7QEhlwVFX6GRlHD upLirz2vGJEjNFIBl4tlSCmkZmyDjEie90qMeYzg9xXC2GtecfoYcZ2g- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic309.consmr.mail.ne1.yahoo.com with HTTP; Sun, 31 Oct 2021 03:13:33 +0000 Received: by kubenode514.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 1972bdd0f60c0259ccb7acc8359f0d84; Sun, 31 Oct 2021 03:13:29 +0000 (UTC) From: Po Lu To: Stefan Kangas Subject: Re: bug#51411: NS port cleanups References: <871r41ly0i.fsf@yahoo.com> Date: Sun, 31 Oct 2021 11:13:25 +0800 In-Reply-To: (Stefan Kangas's message of "Sat, 30 Oct 2021 19:56:37 -0700") Message-ID: <87wnltkht6.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 353 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 51411 Cc: Alan Third , 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Stefan Kangas writes: > Sorry, I had missed that part. It sounds to me that this should better > be tagged "normal", so I'm adjusting the tag back to that with this > message. > > Thanks for paying attention to the severity tagging. Thanks, but you forgot to reply to the control server. (Partly my fault for removing it from Cc) From debbugs-submit-bounces@debbugs.gnu.org Sat Oct 30 23:29:16 2021 Received: (at control) by debbugs.gnu.org; 31 Oct 2021 03:29:16 +0000 Received: from localhost ([127.0.0.1]:58809 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh1X2-0003mR-CJ for submit@debbugs.gnu.org; Sat, 30 Oct 2021 23:29:16 -0400 Received: from mail-pl1-f182.google.com ([209.85.214.182]:41799) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh1Wz-0003mD-U5 for control@debbugs.gnu.org; Sat, 30 Oct 2021 23:29:15 -0400 Received: by mail-pl1-f182.google.com with SMTP id z11so9413605plg.8 for ; Sat, 30 Oct 2021 20:29:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:mime-version:date:message-id:subject:to; bh=cfAPud6E0lCBhCnIrdOfqEqI4OJFb8PUM+s/GDPWQzE=; b=8BbiuzIsArDawOLoHwSX83cm5HcoA9UBF1x+GzWqzmODI4v0nMwKma3YsEpJzSpi4h SLe4TFbRJmECJpC5Z1tYV/Zi0+97EA4q36rfbcrbGVTR1n9/Ac2IwJI0+n+8P/jsnRui EbZRHYTOkehTmHo4ywQ/mfR3bThGfIu6zj/folzNEcA4gIUu9Y9H1BZr1H92XOumRpdo mbwf67klVPnaiHJfIQ4fYeWf4p5n4Qo9yyYe3HEyJLG6DArPgupGshy2BY/dt80BJtmv FtIzrIKHvCqOvhr7n+QqDLzdrm10/fOSwVfyBpBxA6+r+EU8kOWKPxV8b3ksQ+iEoLI1 05Iw== X-Gm-Message-State: AOAM533qqLU8G9gqFSEC1lnS2iIHvRQKJAvdsSjK5itJqw+6pQosUBEa raPMgLxc6qJyLhAKU/GNBHHe0prxWEeuCDxKNjPO4ngF X-Google-Smtp-Source: ABdhPJy9Sx7XD1NDTypChIN+DHIabS800IU4jyi2iCwSQdNX5vJz+gH5xmA68eXSIknF39saK49G2Dlz5bVfn9V/Fww= X-Received: by 2002:a17:902:8c93:b0:141:5442:e608 with SMTP id t19-20020a1709028c9300b001415442e608mr18020407plo.32.1635650948068; Sat, 30 Oct 2021 20:29:08 -0700 (PDT) Received: from 753933720722 named unknown by gmailapi.google.com with HTTPREST; Sat, 30 Oct 2021 20:29:07 -0700 From: Stefan Kangas MIME-Version: 1.0 Date: Sat, 30 Oct 2021 20:29:07 -0700 Message-ID: Subject: To: control@debbugs.gnu.org Content-Type: text/plain; charset="UTF-8" X-Spam-Score: 2.5 (++) X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: severity 51411 normal thanks Content analysis details: (2.5 points, 10.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (stefankangas[at]gmail.com) 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.214.182 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [209.85.214.182 listed in wl.mailspike.net] 2.0 BLANK_SUBJECT Subject is present but empty 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines -0.0 RCVD_IN_MSPIKE_WL Mailspike good senders 0.2 FREEMAIL_FORGED_FROMDOMAIN 2nd level domains in From and EnvelopeFrom freemail headers are different X-Debbugs-Envelope-To: control X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: 1.5 (+) X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: severity 51411 normal thanks Content analysis details: (1.5 points, 10.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [209.85.214.182 listed in wl.mailspike.net] -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.214.182 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (stefankangas[at]gmail.com) 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 2.0 BLANK_SUBJECT Subject is present but empty 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines -0.0 RCVD_IN_MSPIKE_WL Mailspike good senders 0.2 FREEMAIL_FORGED_FROMDOMAIN 2nd level domains in From and EnvelopeFrom freemail headers are different -1.0 MAILING_LIST_MULTI Multiple indicators imply a widely-seen list manager severity 51411 normal thanks From debbugs-submit-bounces@debbugs.gnu.org Sat Oct 30 23:59:33 2021 Received: (at 51411) by debbugs.gnu.org; 31 Oct 2021 03:59:33 +0000 Received: from localhost ([127.0.0.1]:58819 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh20K-0006fL-PK for submit@debbugs.gnu.org; Sat, 30 Oct 2021 23:59:32 -0400 Received: from mail-pg1-f171.google.com ([209.85.215.171]:34460) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh20I-0006f7-Sz for 51411@debbugs.gnu.org; Sat, 30 Oct 2021 23:59:31 -0400 Received: by mail-pg1-f171.google.com with SMTP id j9so5810021pgh.1 for <51411@debbugs.gnu.org>; Sat, 30 Oct 2021 20:59:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:in-reply-to:references:mime-version:date :message-id:subject:to:cc; bh=QZBJkr6QpL3i4HL2fOyp3+H+jR2/zzoyIeLUZfm9CqM=; b=7qNa3EFhygBvfcy4gMbsiSd6RBwENIj2+1+jVjorNnF3Jojz2WSTA3O2CK/9442rzI I17dLlPUoPVLH38s/rCbiERcIz0EfOlOBhitQoa2vpuUUWoJqh2978y4Jz9VkHxY/z8F UB18Fhm10QvKBrM2XA8K8hwVGSYGfclEsBrFNu19mUTCBbKZjwHL+OJU0f3DM33Dmq32 S8x9G8Hl0q7eKE3NclduGcx4ik2Htf+7eKS8Kw9hUIzhiKWOODM37uT9HkdRIlePfIpy uQ+vxq/lXf8pBjtoNmjrpM63mOy6NxxOO9HKns12s1VRSAClYNtQRnMuB4Zs/bGT0gVd OOEQ== X-Gm-Message-State: AOAM5334hnYhY4PhQ8wH0dr7QluDJgNsnYP08U2apzrBgYkuh2CzyZ3a CcmMtN69+ZtGN2XdepwMMRhQmv28oJqdPQTZeyY= X-Google-Smtp-Source: ABdhPJyGd6qRcWnpgIPai5OJ68EjhYXziKKIRjhQ/EkWXTWpEQVCFGOSW2QKmxDNUfRtA1fPMt5drDAK6yg1yuyUry4= X-Received: by 2002:a63:370c:: with SMTP id e12mr15378179pga.359.1635652765037; Sat, 30 Oct 2021 20:59:25 -0700 (PDT) Received: from 753933720722 named unknown by gmailapi.google.com with HTTPREST; Sat, 30 Oct 2021 20:59:24 -0700 From: Stefan Kangas In-Reply-To: <87wnltkht6.fsf@yahoo.com> References: <871r41ly0i.fsf@yahoo.com> <87wnltkht6.fsf@yahoo.com> MIME-Version: 1.0 Date: Sat, 30 Oct 2021 20:59:24 -0700 Message-ID: Subject: Re: bug#51411: NS port cleanups To: Po Lu Content-Type: text/plain; charset="UTF-8" X-Spam-Score: 0.5 (/) X-Debbugs-Envelope-To: 51411 Cc: Alan Third , 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.5 (/) Po Lu writes: > Thanks, but you forgot to reply to the control server. > (Partly my fault for removing it from Cc) I actually had it in Bcc, which is best practice, but I said "tags 51411 normal" instead of "severity 51411 normal" so it didn't take. Should be fixed now. From debbugs-submit-bounces@debbugs.gnu.org Sun Oct 31 06:22:56 2021 Received: (at 51411) by debbugs.gnu.org; 31 Oct 2021 10:22:56 +0000 Received: from localhost ([127.0.0.1]:59084 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh7zL-0001g3-W0 for submit@debbugs.gnu.org; Sun, 31 Oct 2021 06:22:56 -0400 Received: from outbound.soverin.net ([116.202.126.228]:43713) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh7zK-0001fv-H8 for 51411@debbugs.gnu.org; Sun, 31 Oct 2021 06:22:55 -0400 Received: from smtp.soverin.net (unknown [10.10.3.24]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by outbound.soverin.net (Postfix) with ESMTPS id 5CA5692; Sun, 31 Oct 2021 10:22:53 +0000 (UTC) Received: from smtp.soverin.net (smtp.soverin.net [159.69.232.138]) by soverin.net DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=idiocy.org; s=soverin; t=1635675772; bh=3SxL2+1J03YMTjQAzPigZTUsWHoiu/mHf5YcV9t8Ab0=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=HhtF0BzIqEnd1UUvHzh5Je4LWeTAydUIfbKrSOIEv2PxgF4ylWz0nGyEA1GldPK+O dQkSP5fHKjOT8HCcgKdPPOD/B2xnRtBEu3kGwRbdrkCx8x9alr6d6uajdGCzf/HA5t CDpl9Wp8BVquf9AH4vueywGKjFizDwircqAevXRQDf1KXH9f5u+j8htBsdx8RsQCf8 N4c8TnG5MUc6rteMY6fwpB6z5+e03SsseNe9HgK6ZX2yF5WewFhSw+7GP8UzhmFmou VDWF3MNY2vbgQ8uSvXVmKEs+q2opydv8akoX5QswQJYJLnWfL0hcH26xcvox+/jCCN UjL9/Op5Feufw== Received: from alan by faroe.holly.idiocy.org with local (Exim 4.95-RC2) (envelope-from ) id 1mh7zG-0002Ox-6q; Sun, 31 Oct 2021 10:22:50 +0000 Date: Sun, 31 Oct 2021 10:22:50 +0000 From: Alan Third To: Po Lu Subject: Re: bug#51411: NS port cleanups Message-ID: Mail-Followup-To: Alan Third , Po Lu , 51411@debbugs.gnu.org References: <87mtmwt3mc.fsf.ref@yahoo.com> <87mtmwt3mc.fsf@yahoo.com> <87h7d4t0er.fsf@yahoo.com> <87ee86q7jm.fsf@yahoo.com> <87ilxhmlwc.fsf@yahoo.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <87ilxhmlwc.fsf@yahoo.com> X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) On Thu, Oct 28, 2021 at 07:25:23PM +0800, Po Lu wrote: > Alan Third writes: > > > NSRectClipList creates a union of the passed rectangles and then sets > > the clipping rectangle to that, so it contains all of them. That's > > useful because NSRectClip uses the intersection of the current > > clipping rectangle and the new one. > > > > Does DPSrectclip use the intersection? If so this may not work as > > intended and it might be better to union the rectangles ourselves. > > It does intersect the rectangle with the current clipping. I determined > that from a cursory examination of the source code, as the function > appeared in the documentation as documented, but no documentation was > actually written for it. I think what you'll need to do is union the two rectangles and then clip to that, rather than clipping them both separately. That will then provide the same clipping as the NSClipRect code does. > >> @@ -4195,13 +4091,88 @@ overwriting cursor (usually when cursor on a tab) */ > >> > >> /* Draw box if not done already. */ > >> if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) > >> + ns_dumpglyphs_box_or_relief (s); > >> + > >> + ns_unfocus (s->f); > > > You unfocus here, then continue working on the frame here. You either > > need to focus again or extend the original focus. Remember you can > > focus without setting the clipping, then save and reset the graphics > > state as required if you prefer. > > Hmm. Will this work better? Thanks. I must be failing to communicate well, we keep seeming to misunderstand each other. You still need to focus, however you don't have to clip when you focus. For example you could do something like: ns_focus (f, nil, 0); [[NSGraphicsContext currentContext] saveGraphicsState]; NSClipRect (r1); // do something [[NSGraphicsContext currentContext] restoreGraphicsState] [[NSGraphicsContext currentContext] saveGraphicsState]; NSClipRect (r2); // do something else [[NSGraphicsContext currentContext] restoreGraphicsState] ns_unfocus (f); The only time you don't need to focus is when you can guarantee the calling function (or its caller, etc.) has already focused the view. -- Alan Third From debbugs-submit-bounces@debbugs.gnu.org Sun Oct 31 06:34:32 2021 Received: (at 51411) by debbugs.gnu.org; 31 Oct 2021 10:34:32 +0000 Received: from localhost ([127.0.0.1]:59091 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh8Aa-00027f-6T for submit@debbugs.gnu.org; Sun, 31 Oct 2021 06:34:32 -0400 Received: from sonic306-20.consmr.mail.ne1.yahoo.com ([66.163.189.82]:33910) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh8AX-00027N-OO for 51411@debbugs.gnu.org; Sun, 31 Oct 2021 06:34:30 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635676463; bh=pco6MiDFQhTNkCwHV/BE/Gg+YWc4gW4u7KvUEWKaGxg=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=bNflU5zjSCD0LjTXmea+cqM5tk9kvKwYlyinoLBy1y1rp7mKwkWYLBdc0l0yM82cb0dlIdm3LmgA49rSu0m/Ma/lRLrptLrTLP+XUwHng4NYpTHTB/8dMAaZ4EaODJ3kwCBMYs7ngm9IPEK5ngquwd+f+SfgAaPKPaIJeoT3yn4hSpUCfGLYMCxuuyB6yNkWXxt1/TUcyBCcu+I12NnsXooJhayyxn8jIiMeRIz0Af9Xw09WWVo9CzssduO7H6AMEvbdUBLAQVjGjOlGXnAZHaNRmazUjJawXSK2Dggtq2o65bUJXx+dVIiJIahCzHtJsqdF4SLmCGZydidSqc+DDg== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635676463; bh=Y+6ahAFjTDZSwfv7aPwOny7GCdCztIFcw+Q//RHYjTx=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=WDFASOWptuMaTbTL3M/fh8giAGNBSkkEJ33kK6wvY+bfQxamFEvOaQ8gR5JNcXV5lESNSShQKkqOsfgwFp/1Sp87pPA2bS3WcgP9ffVyPP8J19vR72HT8C2gGjzU1WeNzUZt15FBYYtcsrtzS97rOahJZpkfTUNE+w5Xx7KuUTpIZ1jlUD5D7DGuku/I8OQ8PN2mymYZ0T6ZChm6u0F6wFNcUkDWWnxlRPPvFWlMX3FvFrZFtwUZpJm6ffGVIRK1Esqdw49VUSocCPX4UyDAO4Z1O2+kiFs0SYGCtNfhSnrXIVr0j4xNAqbTPh2VmD4QXDO2e283J/ECVXmhC0EsaQ== X-YMail-OSG: 9Y0V.u8VM1k8vaMwLFmxxJgobWhdfEBJeC_ixdQXl4HmxJx4t6l19qvUTDrzIgY 7j.XE7SFBHizs3rCtpb_cVkR3ZjMrFYJv1kYkHIIDLLaJqDJYun7P_bNJDtLBrFeoXnpHKVKqGXF KRoEZNFkb5ln1ZA.BdDHnVEn5beUQbrESZeMTBHHxmwSeeC2PqZrz9ai6isuyfJndSVaktc1rGNR DszPeD9_tAYh1exSP802YrDIJlLzrkropb3PFmd1Twe7PklrZU86qlOleghlIZw.zEXIcxQCC7oO HoIVEq3Ep_hyWMYceeFQWS32t99SVCbxb8.FL9ar64VHtzDJ.Ff0B1oHwfqbqJoFTddeoHWUVjtU pM6aAl2eTWhLbS365Rd_3yAAYuaRL2LTjJx6eCnf.FIyVZdk2EvEpmH4wmhr393Ql6fVZThNjInq IfmA2fQOd6NW_7g1901k8SCWj0fCFlRtSP73B5lpNKoI65qwDK_h0XShKQyWPVPJPjvfnP0zOdsC Qj1PXoYF.BuQCgOFBtHYjhPVfQkn7lTpvfbupHpb9uSrkuJPVIYhDUGvyAuggBGjHoFO853JzbQA lYwsKGvH23M5P8WjZ5wO3pW4Xueav68BAWIy84f5j6U83xrOhaBbnwWWHL7aUMJJlt0hebI1lHzR 1vdxROrv.On8s8dnZgPM7Ygg8jFaaOCHqfNtaIgjPn615tU6ecMyY6TfC8U0hYHE7iv2E3UPxNIj 4hktM91dt6_5LrPnI82yp33yWpaH6UkAX3yrbzJUePe59UW.n7tC9cVzs7Rwh6k7MqN8dpUdJazH Zwzl_r5HaaDhZK2xf0ePpmpF7Gw2hsDGNoJKDJCtwIrV8IUatWtl_zd7wodGfB_._3fvY.bGPWhw d9HfbPTJ9ohZHRRsL4cSOEX6YfNyLhzHr72TQVpUtiOweEvaITVITf9wNDLT9PjevcMhC2O9biFr 6.SFKdDyNvyWNed5YMPTUMA0NdqATRVGlOPwy7f.f1XkvbcIIHImtmFGpYS34H1W_6lqQWONOavc 19wbY0M0Dpvk8jnrElFIHFmpEZGiATguKfSPDnqpQQAPXIjA6QoQM_G0vc0w78cYbvMI.jgVZ7pt LC3r_l2yFQCDTNNeacbvaDGvVEo7TJbzRmtmwbA8b7G4BSpkQpiTruMoG4qugiYHMHaY4kQxDIaz pJTukyI.qs.6UR.5ObZYYNAjKhXXW7TkB1A5A719uF5R_0fq71lwpxGcg41gJw6wdx8HaeFwtor8 XhtgQ_6txMUl7EXi2bl7tQeMVAHTy_D5jaDilftIJLYrAebS1UobRCoOgzyljmMttaHJAnIiljwB nZ9YfYrHlf56E6J4YkGTS2lfRuuj7ISDNzzhSEN2qTvYJIHyJtD2Shh2NFvK9DqxITlPLXywCDu6 a018fErEB6SSz_h0wSl5WGZ.zzfgdtAji6TE70KIEZrZ04H_7QQlRsz4jPPgObUgIpQe_Ne.eRRD oNotXt0qaPSR8vpSz.FLBsn3ELgup016fPiXD5lkr5WModqlQ_dE8h0BK3q7gQWiSbLRFbL.U6t3 V1msAFaLGreKKwIbgSUcdofEF3GWV2uh3zMaUTMZbrrQdZGk7dNVEGCOrLSeqWbAszH2gXNkGzdg d67iJKQs0zeLgsjiILN7iBllVFIjj0xUkKvsfLERo3zpuTzzDnLGtWZ_7eGgz8ssXI7C9pZK11iF vOr8z0AW7Mnpo1tvcf5mEUzuwXvKaWkVwJxS34.3.e8VMgmv1AwqItYJD.cElkbVVm5JaMsT8HXr SbYDjVa4r.JhR4bYLSQHnj20_UMsoCz_6QW8RIASu0eLXdrD9qouEdqhWnqf_FywlaBZljnkmozP SNemmJ9cUkc8Po28G8BoStNYX8gXe_dgh1BQM9MTQ4kaaCiotyuC0YqK2GWDub7dspExlMCZXOI3 1Og65M2I.fvsldXxUZlga6nup2pDwS8ckUKIfVl9FRexfICHI7aUoVgBdfnCXRBnjgRuQs5Oj7ni pQTsXKIQXj4kqwbfLyX8iwuOOWgP7fKIDTAASxsoAmPW2y6lcomOlnifBzx96yvkCfkAXK1yP4ka QV0DkCs3vdiTerck5vmEVjb56OXZcdNtw.8bSm.pxFkmcD2rsN_03.cV9eeJ5IuQ1oEDCXPkIcsR WzM70tNcHx1tz0uYYvWRo3sVhJenImTStPumeEOOB4TXxkoEFwc0G3tDEdFKobum85K7NsSF938J kFAcgh3_e7E4m_8tJUkp6_PjoroGv5o5sae.xNAfpn_fqjRstGfy_HA-- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic306.consmr.mail.ne1.yahoo.com with HTTP; Sun, 31 Oct 2021 10:34:23 +0000 Received: by kubenode504.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID c57b703441c09305a95699b807bcc611; Sun, 31 Oct 2021 10:34:18 +0000 (UTC) From: Po Lu To: Alan Third Subject: Re: bug#51411: NS port cleanups References: <87mtmwt3mc.fsf.ref@yahoo.com> <87mtmwt3mc.fsf@yahoo.com> <87h7d4t0er.fsf@yahoo.com> <87ee86q7jm.fsf@yahoo.com> <87ilxhmlwc.fsf@yahoo.com> Date: Sun, 31 Oct 2021 18:34:15 +0800 In-Reply-To: (Alan Third's message of "Sun, 31 Oct 2021 10:22:50 +0000") Message-ID: <87lf29jxeg.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 1292 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Alan Third writes: > I think what you'll need to do is union the two rectangles and then > clip to that, rather than clipping them both separately. That will > then provide the same clipping as the NSClipRect code does. I meant to say that DPSrectclip intersects (IOW, behaves just as NSClipRect does). Unless that's incorrect, I think what I'm doing right now should work fine. > I must be failing to communicate well, we keep seeming to > misunderstand each other. It could be my problem as well: my reading comprehension is nowhere near as good as I would rather it be. Thanks a lot for tolerating it. > You still need to focus, however you don't have to clip when you > focus. After I unfocus here: /* Draw box if not done already. */ if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) ns_dumpglyphs_box_or_relief (s); -> ns_unfocus (s->f); I make sure to focus again if an overhang might be drawn again (inside if (s->prev) and if (s->next)), like so: /* Draw surrounding overhangs. */ if (s->prev) { -> ns_focus (s->f, NULL, 0); struct glyph_string *prev; There is, of course, a matching unfocus. Is that not adequate, and if so, could you please explain how? Thanks for the feedback, I really appreciate it. From debbugs-submit-bounces@debbugs.gnu.org Sun Oct 31 06:54:59 2021 Received: (at 51411) by debbugs.gnu.org; 31 Oct 2021 10:54:59 +0000 Received: from localhost ([127.0.0.1]:59102 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh8UK-0002fW-03 for submit@debbugs.gnu.org; Sun, 31 Oct 2021 06:54:59 -0400 Received: from sonic308-56.consmr.mail.ne1.yahoo.com ([66.163.187.31]:37230) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh8UE-0002fF-Mh for 51411@debbugs.gnu.org; Sun, 31 Oct 2021 06:54:54 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635677683; bh=cW1kG4+Y1cTgT+TpKDxuG9dM98XsTVC6LwFdlimJBq8=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=ZaTUnxemLrSGT5F+14mNeYKm6YkLIyy5WSGYWXQlqmQFJJmemRR8DLTtNOune9MZMzh7Yp4fRwitOX/e4DAnvVzaKCTsIGtY2+nb7L2VOtuAvDnhMmaKkQVSodjYCpLWIRHt7xXewa5SYmdfiYa+fVaeK6yIEqH/2hgxK69aKo9GWiWEkogLdxu3L9uIXt0BzDKt7R6MExC/56VGN5lzKFcjagZp5j7e2GJTBpqau7Jij0U35HgSLBH2iAj444hxSlxMY9jvfQK9LX9C67FYA9Fn+ewy8sqNeCB+H66MrGUjIUwRfhvyEl67hi9Aviyvzlzn0t9zeIx9X8NaD21AUg== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635677683; bh=5qvuhcyui1gJDmeqIAu9Fuix57H9Jj4AkHkCAEZXe1i=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=LLk14nWL/HsXFjpPzW3qrW9J0mpxxIccNtrhrGdZ/ftKo73+QSY7bt7+GzXjfG4FsOw+qfWygv56Gf4mI/NXsc+AMad42BP58aWNbS9A5Z7/bt7Y/+rIzHNo/EQldIg9hinthCZsW/iw7xnuWaRIednmmej9HAzAematlXxkdRo0539dKNpmZO+Ime2wqOdIbkLqvQl+sVQgpDteoF1PGWM674zlfhCWWMnavBOs8Vr/xOS/LtJ6JqdOCC1FdEK2YZJAH9esaoKNmare5s5YronDVG4m90GmpRuRAIY0gPVfZyH2HDMnSMHmR1SPfeOn74kYyskWbhd6D3/cxYj9Gw== X-YMail-OSG: P.Q7UdQVM1la9Of0jR4.aMpadKNi2LYSIk9yyU6xH_BQ9jxAzVxi4JjzMIWZgCG iSdVsTNSKRTxIPOiQxzloV.bQWGLvbYz8KSuztqSee8NUNAxtbq5fIoAH0Oa.po3C9aDlN3Vhs6. 0y3JXSHD0n5OdQWvzd6LeZXNBe_V1zpU9fdT.z4BrpLlTKm2C2.XXb7HbMNedDFOIKz3QhjIG_yS SFibcCgLL9Cx3QvEf_ICUmYRirDl_hhaG6tfN2SmY.paEYnJaGDDLxG2h0CaDzqOkhZgUt1fSEHF AxBSpzAkeaOWhh1aq5eWazPK0EfiK0PGoHSO0OGDDLch1ZYFBaSshnHG6XI.2KdpZQi0MmfAbBb6 9vh0We_NlUd.JrJn80SX8VM6Ov.Y.4qFRIkDc59khtkq2NpV6azAra.xIM6Kaw3dVVENAokC1w1J tm5QsdXxYJPMRRcnLEuqNC881bQoYJqvTCtveom.mgXQat1IL15JRqbJg9wD2_qQzGcUtT._I65M 9lQjDSjTKMGR0Jaq3OPrlXzHp8lOI8IWncLZQS7fmZQhvZqBXxeuJcU6_a6S72n2klfuiB3p5mtN HAEbmvIXGhLO3PZVq5rn.JgSfVu0XKL6dsD1ARb4KCrjfbNbP0YfIK4lFyjQH1xAH2Jcq97LzpUd Nf.u.0QZ8l17FmfJoRAiAMReKqet8IZuSdDZD23xTqTM_RoGbF5qSbJ47BqOqQ6h2J9kBtkPYJ_w e34PC.6HG8Rkr6wGmlK1zTOOk7YwJS88.gbrPEm0u9ANhLEiH17LduA7DccvOY4WBIRbWl.cA8lg 5XQE1Rx_J9L00kdneBZYY3h.3pINmQBxjn9pTuRe5swVlKx111tCETFvDJ0WCSLhmbAs1YtWmtNi i33GNHGodF8helJRW9sI7SG827dLpw.oSTwaY.c30pBCIVP1lOJSBzRxz5nSROpTjMfChPArpkwh XwBEyWMWKoeMrCHE.rwFIztDW7E6Vxy8fajMKmYy7mm5DMeorUIfJxM.r_CAS..PhTZ7QvDWtrlc fAe72UcAZkgzzYlMpE46Zoc8lV08BFem_XmExgOAwfM3B2x1_SUvBlVBK6kgByYj6eW_xLU4Oihh ZFTjP47tPyILHa7UPovl_5ua0IMltPkoYkcE0Mja6CdeVzexOC_3TKRM3qjwIVnr.DSO4qPG4MRR DzFVK9mlkxv74nRqiW4H7b0Ksrf8wzsm0r_0CA3LZvgzjijDrUFIY0WK1fiWAO98rutseJPEp2uZ kBAT.MQ3j9OklDnazCtRutcvzmBdSGWY7qNpTpvl7vl0S_0Vp8vyQF5TLBA0GOwCmjuuhQA1NEqU yB.E5Ws9lDiH7STbpjd9u2WMzPYLeb1MfwzAZmnC6P7_v.5MrExUEtJD1NJLfKNKka_SnVnjkfg_ ul.fSfnKTPBXppP6QKrnMIFeCBKvSLXvBO7V6Qf2j7CkU__.HOfN.THlrbLbRmGbDnWYlPqGsCgb ImCPfiRytRXUyJo1qxcbIZ4FklYAXEIott1f9shThIhV_XjmB1B5D2j_xcFDDZlyqilU8ucs4Wiq cK78BAGZ3uMgVNJwrTenPCvAFOfH3Q2UhCyoOo7rDco66.c4n7wuCZtlXeu87_f1K4wzeexAKOgH hDo0nvfSr1Z6kJw5XVo63mVGlYWvFIoxNRlJg2ivss0MOcnjZgrpn811H4_.1q5pegH5oyOCTtgX pl7SVcDz5u9_b1VjrOX3BnrkITnC2WNShePwMI5x7oN_9fR7aSMYojekTOD2XHoh..8vG6wjhAgM JIKRRqe9RJ1shuoR0HNcEiKW38St1_BEcJY2I6BNzoB58bfKXcrUzNSY.m8B8H_uAwayUCfEl.dW 0dtvxPcUXhl7Anj1CgVDIp67.WN6kaZmGTaiFNM2u4SOTp2.zqGYFllr9AojwFbT7uoF1oHhEh1f YUPr_rDu2hS7Im.0h4a9gXiDYRLaDdoF2nU6tCN7LgjJtrrZFdH0A8ZkIwrmMAEJJGLAE4R7rrhs 5u2cNSFqoCVKCIaOfsCbhTfshIEBDctSreb6nBs60VH2Dl3he5YoK3z7dobzyJpPuy1AfX4JzQu9 U.eOcTTOkwyKA16nkFKkuA5thTSTKnB0vokdWRAj4LtZNLeFfjRAguJ_Ugw9eiwH0JC0s3lFTjtG wl3VgXQjL83yayYugLUp9k.azf19VeIu6xT6KK1qrrPWIQEqd4vh9U6A.ltISZUT.dzpi009uhg1 oqWUPqGiL4y7YM85UsCvmj9.ns4xqV9F1MdlcBtjanhN18shnK9m2hRCyug-- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic308.consmr.mail.ne1.yahoo.com with HTTP; Sun, 31 Oct 2021 10:54:43 +0000 Received: by kubenode515.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID cd7a35433735ab3e35ae719007ad264e; Sun, 31 Oct 2021 10:54:38 +0000 (UTC) From: Po Lu To: Alan Third Subject: Re: bug#51411: NS port cleanups References: <87mtmwt3mc.fsf.ref@yahoo.com> <87mtmwt3mc.fsf@yahoo.com> <87h7d4t0er.fsf@yahoo.com> <87ee86q7jm.fsf@yahoo.com> <87ilxhmlwc.fsf@yahoo.com> <87lf29jxeg.fsf@yahoo.com> Date: Sun, 31 Oct 2021 18:54:34 +0800 In-Reply-To: <87lf29jxeg.fsf@yahoo.com> (Po Lu's message of "Sun, 31 Oct 2021 18:34:15 +0800") Message-ID: <87a6ipjwgl.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 79176 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Po Lu writes: > I meant to say that DPSrectclip intersects (IOW, behaves just as > NSClipRect does). Unless that's incorrect, I think what I'm doing right > now should work fine. Please disregard what I said here, as I just found out my understanding of NSRectClip has been incorrect. OTOH, I found a function that should better suit the situation. GSRectClipList sets both the DPS and NS clipping, so I changed the function to just use that instead. Thanks. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Improve-font-display-on-NS-port.patch >From 5ab36735d30bb475a3bc44b9f52194e236f3372e Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 23 Oct 2021 19:44:03 +0800 Subject: [PATCH] Improve font display on NS port * src/nsfns.m (Fx_create_frame): Use "fixed" for the default font on GNUstep. * src/nsfont.m (LCD_SMOOTHING_MARGIN, ns_escape_name) (ns_unescape_name, ns_attribute_fvalue) (STYLE_REF): Remove unused defines and functions. (struct ns_glyph_layout, enum lgstring_direction). (enum gs_font_slant, enum gs_font_weight, enum gs_font_width) (enum gs_specified, struct gs_font_data): New enumerators and structures. (ns_font_descs_match_p) (ns_done_font_data, ns_get_font_data): New functions. (ns_glyph_metrics): Stop escaping names. (ns_spec_to_descriptor): Fix font descriptor creation for symbolic font spec entires. (ns_descriptor_to_entity): Create entries with the correct symbolic styles. (ns_fallback_entity): Fix fallback entity selection. (ns_findfonts): Use our own font matcher instead of the broken GNUstep matcher. (ns_list_family): Remove obsolete comment. (nsfont_open): Remove obsolete code, comments, and synthItal logic which doesn't work on GNUstep. (nsfont_encode_char): Use a type that can fit NSGlyph (nsfont_draw): Chose correct font, remove obsolete mouse face logic, obsolete comments, and switch to using glyph-based drawing instead of character-based drawing. (ns_font_shape, nsfont_shape): New functions. (ns_uni_to_glyphs_1): New function. (ns_uni_to_glyphs): Return glyphs instead of unicode codepoints. (ns_glyph_metrics): Use NSGlyphs instead of unicode codepoints and fix left bearing, right bearing, ascent and descent computation. (struct nsfont_driver): Add shaping capability. * src/nsterm.h (struct nsfont_info): Use unsigned int for glyph cache. * src/nsterm.c (ns_focus): Set DPS clipping on GNUstep. (ns_compute_glyph_string_overhangs): Fix overhang computation by using xterm code. (ns_draw_window_cursor): Simplify cursor drawing. (ns_maybe_dumpglyphs_background): Test for cursor HL and remove obsolete mouse face logic. (ns_dumpglyphs_image) (ns_dumpglyphs_box_or_relief): Rectify for new cursor logic. (ns_dumpglyphs_stretch): Rectify for new cursor logic and rely on ns_draw_glyph_string to set focus. (ns_draw_glyph_string_foreground): Remove mouse face logic. (ns_draw_glyph_strings): Implement overhangs, remove obsolete comment, and always focus before dumping glyphs. (ns_draw_text_decoration): Add condition for DRAW_CURSOR and simplify color selection. (ns_define_frame_cursor): Remove nonsensical code (define_frame_cursor has nothing to do with the text cursor, aka caret). * src/xdisp.c (draw_glyphs): Enable code for NS port to fix mouse face cursor display. * src/macfont.m (get_cgcolor_from_nscolor): New function. (macfont_draw): Remove obsolete mouse-face code and enable cursor display. --- src/macfont.m | 36 +- src/nsfns.m | 6 + src/nsfont.m | 1215 +++++++++++++++++++++++++++++++++++-------------- src/nsterm.h | 2 +- src/nsterm.m | 413 ++++++++--------- src/xdisp.c | 2 - 6 files changed, 1092 insertions(+), 582 deletions(-) diff --git a/src/macfont.m b/src/macfont.m index 78ed5d53f3..1426cae6dc 100644 --- a/src/macfont.m +++ b/src/macfont.m @@ -613,6 +613,21 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char, return cgColor; } +static CGColorRef +get_cgcolor_from_nscolor (NSColor *nsColor, struct frame *f) +{ + [nsColor set]; + CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace]; + NSInteger noc = [nsColor numberOfComponents]; + CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc)); + CGColorRef cgColor; + + [nsColor getComponents: components]; + cgColor = CGColorCreate (colorSpace, components); + xfree (components); + return cgColor; +} + #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f) \ do { \ CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f); \ @@ -2911,14 +2926,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no if (!CGRectIsNull (background_rect)) { - if (s->hl == DRAW_MOUSE_FACE) + if (s->hl == DRAW_CURSOR) { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_CURSOR_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); } - CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); + else + CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); CGContextFillRects (context, &background_rect, 1); } @@ -2927,7 +2942,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no CGAffineTransform atfm; CGContextScaleCTM (context, 1, -1); - CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); + if (s->hl == DRAW_CURSOR) + { + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_BACKGROUND_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); + } + else + CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); if (macfont_info->synthetic_italic_p) atfm = synthetic_italic_atfm; else diff --git a/src/nsfns.m b/src/nsfns.m index 797d0ce782..f4d8172246 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -1236,6 +1236,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. "fontBackend", "FontBackend", RES_TYPE_STRING); { +#ifdef NS_IMPL_COCOA /* use for default font name */ id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */ gui_default_parameter (f, parms, Qfontsize, @@ -1250,6 +1251,11 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. build_string (fontname), "font", "Font", RES_TYPE_STRING); xfree (fontname); +#else + gui_default_parameter (f, parms, Qfont, + build_string ("fixed"), + "font", "Font", RES_TYPE_STRING); +#endif } unblock_input (); diff --git a/src/nsfont.m b/src/nsfont.m index 5a9cdfebc0..b3224629f0 100644 --- a/src/nsfont.m +++ b/src/nsfont.m @@ -1,4 +1,4 @@ -/* Font back-end driver for the NeXT/Open/GNUstep and macOS window system. +/* Font back-end driver for the GNUstep window system. See font.h Copyright (C) 2006-2021 Free Software Foundation, Inc. @@ -38,47 +38,269 @@ #include "termchar.h" #include "pdumper.h" -/* TODO: Drop once we can assume gnustep-gui 0.17.1. */ +#import #import +#import +#import +#import #define NSFONT_TRACE 0 -#define LCD_SMOOTHING_MARGIN 2 -/* Font glyph and metrics caching functions, implemented at end. */ -static void ns_uni_to_glyphs (struct nsfont_info *font_info, - unsigned char block); -static void ns_glyph_metrics (struct nsfont_info *font_info, - unsigned char block); +/* Structure used by GS `shape' functions for storing layout + information for each glyph. Borrowed from macfont.h. */ +struct ns_glyph_layout +{ + /* Range of indices of the characters composed into the group of + glyphs that share the cursor position with this glyph. The + members `location' and `length' are in UTF-16 indices. */ + NSRange comp_range; -#define INVALID_GLYPH 0xFFFF + /* UTF-16 index in the source string for the first character + associated with this glyph. */ + NSUInteger string_index; -/* ========================================================================== + /* Horizontal and vertical adjustments of glyph position. The + coordinate space is that of Core Text. So, the `baseline_delta' + value is negative if the glyph should be placed below the + baseline. */ + CGFloat advance_delta, baseline_delta; - Utilities + /* Typographical width of the glyph. */ + CGFloat advance; - ========================================================================== */ + /* Glyph ID of the glyph. */ + NSGlyph glyph_id; +}; + + +enum lgstring_direction + { + DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1 + }; + +enum gs_font_slant + { + GS_FONT_SLANT_ITALIC, + GS_FONT_SLANT_REVERSE_ITALIC, + GS_FONT_SLANT_NORMAL + }; + +enum gs_font_weight + { + GS_FONT_WEIGHT_LIGHT, + GS_FONT_WEIGHT_BOLD, + GS_FONT_WEIGHT_NORMAL + }; + +enum gs_font_width + { + GS_FONT_WIDTH_CONDENSED, + GS_FONT_WIDTH_EXPANDED, + GS_FONT_WIDTH_NORMAL + }; + +enum gs_specified + { + GS_SPECIFIED_SLANT = 1, + GS_SPECIFIED_WEIGHT = 1 << 1, + GS_SPECIFIED_WIDTH = 1 << 2, + GS_SPECIFIED_FAMILY = 1 << 3, + GS_SPECIFIED_SPACING = 1 << 4 + }; +struct gs_font_data +{ + int specified; + enum gs_font_slant slant; + enum gs_font_weight weight; + enum gs_font_width width; + bool monospace_p; + char *family_name; +}; -/* Replace spaces w/another character so emacs core font parsing routines - aren't thrown off. */ static void -ns_escape_name (char *name) +ns_done_font_data (struct gs_font_data *data) { - for (; *name; name++) - if (*name == ' ') - *name = '_'; + if (data->specified & GS_SPECIFIED_FAMILY) + xfree (data->family_name); } - -/* Reconstruct spaces in a font family name passed through emacs. */ static void -ns_unescape_name (char *name) +ns_get_font_data (NSFontDescriptor *desc, struct gs_font_data *dat) { - for (; *name; name++) - if (*name == '_') - *name = ' '; + NSNumber *tem; + NSFontSymbolicTraits traits = [desc symbolicTraits]; + NSDictionary *dict = [desc objectForKey: NSFontTraitsAttribute]; + NSString *family = [desc objectForKey: NSFontFamilyAttribute]; + + dat->specified = 0; + + if (family != nil) + { + dat->specified |= GS_SPECIFIED_FAMILY; + dat->family_name = xstrdup ([family cStringUsingEncoding: NSUTF8StringEncoding]); + } + + tem = [desc objectForKey: NSFontFixedAdvanceAttribute]; + + if ((tem != nil && [tem boolValue] != NO) + || (traits & NSFontMonoSpaceTrait)) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = true; + } + else if (tem != nil && [tem boolValue] == NO) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = false; + } + + if (traits & NSFontBoldTrait) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + dat->weight = GS_FONT_WEIGHT_BOLD; + } + + if (traits & NSFontItalicTrait) + { + dat->specified |= GS_SPECIFIED_SLANT; + dat->slant = GS_FONT_SLANT_ITALIC; + } + + if (traits & NSFontCondensedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_CONDENSED; + } + else if (traits & NSFontExpandedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_EXPANDED; + } + + if (dict != nil) + { + tem = [dict objectForKey: NSFontSlantTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_SLANT; + + dat->slant = [tem floatValue] > 0 + ? GS_FONT_SLANT_ITALIC + : ([tem floatValue] < 0 + ? GS_FONT_SLANT_REVERSE_ITALIC + : GS_FONT_SLANT_NORMAL); + } + + tem = [dict objectForKey: NSFontWeightTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + + dat->weight = [tem floatValue] > 0 + ? GS_FONT_WEIGHT_BOLD + : ([tem floatValue] < -0.4f + ? GS_FONT_WEIGHT_LIGHT + : GS_FONT_WEIGHT_NORMAL); + } + + tem = [dict objectForKey: NSFontWidthTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WIDTH; + + dat->width = [tem floatValue] > 0 + ? GS_FONT_WIDTH_EXPANDED + : ([tem floatValue] < 0 + ? GS_FONT_WIDTH_NORMAL + : GS_FONT_WIDTH_CONDENSED); + } + } +} + +static bool +ns_font_descs_match_p (NSFontDescriptor *desc, NSFontDescriptor *target) +{ + struct gs_font_data dat; + struct gs_font_data t; + + ns_get_font_data (desc, &dat); + ns_get_font_data (target, &t); + + if (!(t.specified & GS_SPECIFIED_WIDTH)) + t.width = GS_FONT_WIDTH_NORMAL; + if (!(t.specified & GS_SPECIFIED_WEIGHT)) + t.weight = GS_FONT_WEIGHT_NORMAL; + if (!(t.specified & GS_SPECIFIED_SPACING)) + t.monospace_p = false; + if (!(t.specified & GS_SPECIFIED_SLANT)) + t.slant = GS_FONT_SLANT_NORMAL; + + if (!(t.specified & GS_SPECIFIED_FAMILY)) + emacs_abort (); + + bool match_p = true; + + if (dat.specified & GS_SPECIFIED_WIDTH + && dat.width != t.width) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_WEIGHT + && dat.weight != t.weight) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SPACING + && dat.monospace_p != t.monospace_p) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SLANT + && dat.monospace_p != t.monospace_p) + { + if (NSFONT_TRACE) + printf ("Matching monospace for %s: %d %d\n", + t.family_name, dat.monospace_p, + t.monospace_p); + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_FAMILY + && strcmp (dat.family_name, t.family_name)) + match_p = false; + + gout: + ns_done_font_data (&dat); + ns_done_font_data (&t); + + return match_p; } +/* Font glyph and metrics caching functions, implemented at end. */ +static void ns_uni_to_glyphs (struct nsfont_info *font_info, + unsigned char block); +static void ns_glyph_metrics (struct nsfont_info *font_info, + unsigned int block); + +#define INVALID_GLYPH 0xFFFF + +/* ========================================================================== + + Utilities + + ========================================================================== */ + /* Extract family name from a font spec. */ static NSString * @@ -91,66 +313,116 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, { char *tmp = xlispstrdup (SYMBOL_NAME (tem)); NSString *family; - ns_unescape_name (tmp); family = [NSString stringWithUTF8String: tmp]; xfree (tmp); return family; } } - -/* Return 0 if attr not set, else value (which might also be 0). - On Leopard 0 gets returned even on descriptors where the attribute - was never set, so there's no way to distinguish between unspecified - and set to not have. Callers should assume 0 means unspecified. */ -static float -ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait) -{ - NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute]; - NSNumber *val = [tdict objectForKey: trait]; - return val == nil ? 0.0F : [val floatValue]; -} - - /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang to NSFont descriptor. Information under extra only needed for matching. */ -#define STYLE_REF 100 static NSFontDescriptor * ns_spec_to_descriptor (Lisp_Object font_spec) { NSFontDescriptor *fdesc; NSMutableDictionary *fdAttrs = [NSMutableDictionary new]; - NSMutableDictionary *tdict = [NSMutableDictionary new]; NSString *family = ns_get_family (font_spec); - float n; - - /* Add each attr in font_spec to fdAttrs. */ - n = min (FONT_WEIGHT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWeightTrait]; - n = min (FONT_SLANT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontSlantTrait]; - n = min (FONT_WIDTH_NUMERIC (font_spec), 200); - if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10)) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWidthTrait]; - if ([tdict count] > 0) - [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + NSMutableDictionary *tdict = [NSMutableDictionary new]; - fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] - retain] autorelease]; + Lisp_Object tem; + + tem = FONT_SLANT_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qitalic) || EQ (tem, Qoblique)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontSlantTrait]; + else if (EQ (tem, intern ("reverse-italic")) || + EQ (tem, intern ("reverse-oblique"))) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontSlantTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontSlantTrait]; + } + + tem = FONT_WIDTH_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qcondensed)) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWidthTrait]; + else if (EQ (tem, Qexpanded)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWidthTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWidthTrait]; + } + + tem = FONT_WEIGHT_SYMBOLIC (font_spec); + + if (!NILP (tem)) + { + if (EQ (tem, Qbold)) + { + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWeightTrait]; + } + else if (EQ (tem, Qlight)) + { + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWeightTrait]; + } + else + { + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWeightTrait]; + } + } + + tem = AREF (font_spec, FONT_SPACING_INDEX); if (family != nil) { - NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family]; - fdesc = [[fdesc2 retain] autorelease]; + [fdAttrs setObject: family + forKey: NSFontFamilyAttribute]; } - [fdAttrs release]; + if (FIXNUMP (tem)) + { + if (XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL) + { + [fdAttrs setObject: [NSNumber numberWithBool:YES] + forKey: NSFontFixedAdvanceAttribute]; + } + else + { + [fdAttrs setObject: [NSNumber numberWithBool:NO] + forKey: NSFontFixedAdvanceAttribute]; + } + } + + /* Handle special families such as ``fixed'' or ``Sans Serif''. */ + + if ([family isEqualToString: @"fixed"]) + { + [fdAttrs setObject: [[NSFont userFixedPitchFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + else if ([family isEqualToString: @"Sans Serif"]) + { + [fdAttrs setObject: [[NSFont userFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + + [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + + fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] + retain] autorelease]; + [tdict release]; + [fdAttrs release]; return fdesc; } @@ -161,61 +433,64 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, Lisp_Object extra, const char *style) { - Lisp_Object font_entity = font_make_entity (); - /* NSString *psName = [desc postscriptName]; */ - NSString *family = [desc objectForKey: NSFontFamilyAttribute]; - unsigned int traits = [desc symbolicTraits]; - char *escapedFamily; - - /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */ - if (family == nil) - family = [desc objectForKey: NSFontNameAttribute]; - if (family == nil) - family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - - escapedFamily = xstrdup ([family UTF8String]); - ns_escape_name (escapedFamily); - - ASET (font_entity, FONT_TYPE_INDEX, Qns); - ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple); - ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily)); - ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); - ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); - - FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - traits & NSFontBoldTrait ? Qbold : Qmedium); -/* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - traits & NSFontItalicTrait ? Qitalic : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - traits & NSFontCondensedTrait ? Qcondensed : - traits & NSFontExpandedTrait ? Qexpanded : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/ - - ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_SPACING_INDEX, - make_fixnum([desc symbolicTraits] & NSFontMonoSpaceTrait - ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); - - ASET (font_entity, FONT_EXTRA_INDEX, extra); - ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + Lisp_Object font_entity = font_make_entity (); + struct gs_font_data data; + ns_get_font_data (desc, &data); + + ASET (font_entity, FONT_TYPE_INDEX, Qns); + ASET (font_entity, FONT_FOUNDRY_INDEX, Qns); + if (data.specified & GS_SPECIFIED_FAMILY) + ASET (font_entity, FONT_FAMILY_INDEX, intern (data.family_name)); + ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); + ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); + + if (data.specified & GS_SPECIFIED_WEIGHT) + { + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, + data.weight == GS_FONT_WEIGHT_BOLD + ? Qbold : (data.weight == GS_FONT_WEIGHT_LIGHT + ? Qlight : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, Qnormal); - if (NSFONT_TRACE) - { - fputs ("created font_entity:\n ", stderr); - debug_print (font_entity); - } + if (data.specified & GS_SPECIFIED_SLANT) + { + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, + data.slant == GS_FONT_SLANT_ITALIC + ? Qitalic : (data.slant == GS_FONT_SLANT_REVERSE_ITALIC + ? intern ("reverse-italic") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, Qnormal); + + if (data.specified & GS_SPECIFIED_WIDTH) + { + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, + data.width == GS_FONT_WIDTH_CONDENSED + ? Qcondensed : (data.width == GS_FONT_WIDTH_EXPANDED + ? intern ("expanded") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, Qnormal); - xfree (escapedFamily); - return font_entity; + ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_SPACING_INDEX, + make_fixnum ((data.specified & GS_SPECIFIED_WIDTH && data.monospace_p) + ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); + + ASET (font_entity, FONT_EXTRA_INDEX, extra); + ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + + if (NSFONT_TRACE) + { + fputs ("created font_entity:\n ", stderr); + debug_print (font_entity); + } + + ns_done_font_data (&data); + return font_entity; } @@ -223,8 +498,7 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, static Lisp_Object ns_fallback_entity (void) { - return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0] - fontDescriptor], Qnil, NULL); + return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 1] fontDescriptor], Qnil, NULL); } @@ -510,21 +784,20 @@ but also for ascii (which causes unnecessary font substitution). */ return families; } +/* GNUstep font matching is very mediocre (it can't even compare + symbolic styles correctly), which is why our own font matching + mechanism must be implemented. */ -/* Implementation for list() and match(). List() can return nil, match() -must return something. Strategy is to drop family name from attribute -matching set for match. */ +/* Implementation for list and match. */ static Lisp_Object ns_findfonts (Lisp_Object font_spec, BOOL isMatch) { Lisp_Object tem, list = Qnil; - NSFontDescriptor *fdesc, *desc; - NSMutableSet *fkeys; - NSArray *matchingDescs; - NSEnumerator *dEnum; - NSString *family; + NSFontDescriptor *fdesc; + NSArray *all_descs; + GSFontEnumerator *enumerator = [GSFontEnumerator sharedEnumerator]; + NSSet *cFamilies; - BOOL foundItal = NO; block_input (); if (NSFONT_TRACE) @@ -537,43 +810,22 @@ but also for ascii (which causes unnecessary font substitution). */ cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90); fdesc = ns_spec_to_descriptor (font_spec); - fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]]; - if (isMatch) - [fkeys removeObject: NSFontFamilyAttribute]; - - matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys]; + all_descs = [enumerator availableFontDescriptors]; - if (NSFONT_TRACE) - NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc, - (unsigned long)[matchingDescs count]); - - for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);) + for (NSFontDescriptor *desc in all_descs) { if (![cFamilies containsObject: [desc objectForKey: NSFontFamilyAttribute]]) continue; + if (!ns_font_descs_match_p (fdesc, desc)) + continue; + tem = ns_descriptor_to_entity (desc, - AREF (font_spec, FONT_EXTRA_INDEX), + AREF (font_spec, FONT_EXTRA_INDEX), NULL); if (isMatch) return tem; list = Fcons (tem, list); - if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05) - foundItal = YES; - } - - /* Add synthItal member if needed. */ - family = [fdesc objectForKey: NSFontFamilyAttribute]; - if (family != nil && !foundItal && !NILP (list)) - { - NSFontDescriptor *s1 = [NSFontDescriptor new]; - NSFontDescriptor *sDesc - = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait] - fontDescriptorWithFamily: family]; - list = Fcons (ns_descriptor_to_entity (sDesc, - AREF (font_spec, FONT_EXTRA_INDEX), - "synthItal"), list); - [s1 release]; } unblock_input (); @@ -652,7 +904,6 @@ Properties to be considered are same as for list(). */ objectEnumerator]; while ((family = [families nextObject])) list = Fcons (intern ([family UTF8String]), list); - /* FIXME: escape the name? */ if (NSFONT_TRACE) fprintf (stderr, "nsfont: list families returning %"pD"d entries\n", @@ -668,18 +919,15 @@ Properties to be considered are same as for list(). */ static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size) { - BOOL synthItal; - unsigned int traits = 0; struct nsfont_info *font_info; struct font *font; NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity); NSFontManager *fontMgr = [NSFontManager sharedFontManager]; NSString *family; NSFont *nsfont, *sfont; - Lisp_Object tem; NSRect brect; Lisp_Object font_object; - int fixLeopardBug; + Lisp_Object tem; block_input (); @@ -692,42 +940,20 @@ Properties to be considered are same as for list(). */ if (pixel_size <= 0) { /* try to get it out of frame params */ - Lisp_Object tem = get_frame_param (f, Qfontsize); - pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); + tem = get_frame_param (f, Qfontsize); + pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); } tem = AREF (font_entity, FONT_ADSTYLE_INDEX); - synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)), - 9); family = ns_get_family (font_entity); if (family == nil) family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that - when setting family in ns_spec_to_descriptor(). */ - if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F) - traits |= NSBoldFontMask; - if (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F) - traits |= NSItalicFontMask; - - /* see https://web.archive.org/web/20100201175731/http://cocoadev.com/forums/comments.php?DiscussionID=74 */ - fixLeopardBug = traits & NSBoldFontMask ? 10 : 5; - nsfont = [fontMgr fontWithFamily: family - traits: traits weight: fixLeopardBug - size: pixel_size]; - /* if didn't find, try synthetic italic */ - if (nsfont == nil && synthItal) - { - nsfont = [fontMgr fontWithFamily: family - traits: traits & ~NSItalicFontMask - weight: fixLeopardBug size: pixel_size]; - } + + nsfont = [NSFont fontWithDescriptor: fontDesc + size: pixel_size]; if (nsfont == nil) - { - message_with_string ("*** Warning: font in family `%s' not found", - build_string ([family UTF8String]), 1); - nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; - } + nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; if (NSFONT_TRACE) NSLog (@"%@\n", nsfont); @@ -740,7 +966,7 @@ when setting family in ns_spec_to_descriptor(). */ if (!font) { unblock_input (); - return Qnil; /* FIXME: other terms do, but returning Qnil causes segfault. */ + return Qnil; } font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs); @@ -781,7 +1007,7 @@ when setting family in ns_spec_to_descriptor(). */ font_info->name = xstrdup (fontName); font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask; font_info->ital = - synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); + ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); /* Metrics etc.; some fonts return an unusually large max advance, so we only use it for fonts that have wide characters. */ @@ -808,8 +1034,6 @@ when setting family in ns_spec_to_descriptor(). */ lrint (brect.size.width - (CGFloat) font_info->width); /* set up metrics portion of font struct */ - font->ascent = lrint([sfont ascender]); - font->descent = -lrint(floor(adjusted_descender)); font->space_width = lrint (ns_char_width (sfont, ' ')); font->max_width = lrint (font_info->max_bounds.width); font->min_width = font->space_width; /* Approximate. */ @@ -871,7 +1095,7 @@ when setting family in ns_spec_to_descriptor(). */ { struct nsfont_info *font_info = (struct nsfont_info *)font; unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff; - unsigned short g; + unsigned int g; if (c > 0xFFFF) return FONT_INVALID_CODE; @@ -934,51 +1158,23 @@ is false when (FROM > 0 || TO < S->nchars). */ static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, bool with_background) -/* NOTE: focus and clip must be set. */ { - static unsigned char cbuf[1024]; - unsigned char *c = cbuf; -#if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22 - static CGFloat advances[1024]; - CGFloat *adv = advances; -#else - static float advances[1024]; - float *adv = advances; -#endif + NSGlyph *c = alloca ((to - from) * sizeof *c); + struct face *face; NSRect r; struct nsfont_info *font; - NSColor *col, *bgCol; - unsigned *t = s->char2b; - int i, len, flags; + NSColor *col; + int len = to - from; char isComposite = s->first_glyph->type == COMPOSITE_GLYPH; block_input (); - font = (struct nsfont_info *)s->face->font; + font = (struct nsfont_info *) s->font; if (font == NULL) font = (struct nsfont_info *)FRAME_FONT (s->f); - /* Select face based on input flags. */ - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - - switch (flags) - { - case NS_DUMPGLYPH_CURSOR: - face = s->face; - break; - case NS_DUMPGLYPH_MOUSEFACE: - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - break; - default: - face = s->face; - } + face = s->face; r.origin.x = s->x; if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p) @@ -987,91 +1183,24 @@ is false when (FROM > 0 || TO < S->nchars). */ r.origin.y = s->y; r.size.height = FONT_HEIGHT (font); - /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask - NS to render the string, it will come out differently from the individual - character widths added up because of layout processing. */ - { - int cwidth, twidth = 0; - int hi, lo; - /* FIXME: composition: no vertical displacement is considered. */ - t += from; /* advance into composition */ - for (i = from; i < to; i++, t++) - { - hi = (*t & 0xFF00) >> 8; - lo = *t & 0x00FF; - if (isComposite) - { - if (!s->first_glyph->u.cmp.automatic) - cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth; - else - { - Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); - Lisp_Object glyph = LGSTRING_GLYPH (gstring, i); - if (NILP (LGLYPH_ADJUSTMENT (glyph))) - cwidth = LGLYPH_WIDTH (glyph); - else - { - cwidth = LGLYPH_WADJUST (glyph); - *(adv-1) += LGLYPH_XOFF (glyph); - } - } - } - else - { - if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */ - ns_glyph_metrics (font, hi); - cwidth = font->metrics[hi][lo].width; - } - twidth += cwidth; - *adv++ = cwidth; - c += CHAR_STRING (*t, c); /* This converts the char to UTF-8. */ - } - len = adv - advances; - r.size.width = twidth; - *c = 0; - } + for (int i = from; i < to; ++i) + c[i] = s->char2b[i]; /* Fill background if requested. */ if (with_background && !isComposite) { - NSRect br = r; - int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); - int mbox_line_width = max (s->face->box_vertical_line_width, 0); - - if (s->row->full_width_p) - { - if (br.origin.x <= fibw + 1 + mbox_line_width) - { - br.size.width += br.origin.x - mbox_line_width; - br.origin.x = mbox_line_width; - } - if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) - <= fibw+1) - br.size.width += fibw; - } - if (s->face->box == FACE_NO_BOX) - { - /* Expand unboxed top row over internal border. */ - if (br.origin.y <= fibw + 1 + mbox_line_width) - { - br.size.height += br.origin.y; - br.origin.y = 0; - } - } - else - { - int correction = abs (s->face->box_horizontal_line_width)+1; - br.origin.y += correction; - br.size.height -= 2*correction; - correction = abs (s->face->box_vertical_line_width)+1; - br.origin.x += correction; - br.size.width -= 2*correction; - } + NSRect br = NSMakeRect (x, y - FONT_BASE (s->font), + s->width, FONT_HEIGHT (s->font)); if (!s->face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); @@ -1080,43 +1209,32 @@ is false when (FROM > 0 || TO < S->nchars). */ NSRectFill (br); } - /* set up for character rendering */ r.origin.y = y; - col = (NS_FACE_FOREGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - - bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil - : (NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f))); + if (s->hl == DRAW_CURSOR) + col = FRAME_BACKGROUND_COLOR (s->f); + else + col = (NS_FACE_FOREGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) + : FRAME_FOREGROUND_COLOR (s->f)); /* render under GNUstep using DPS */ { - NSGraphicsContext *context = GSCurrentContext (); - + NSGraphicsContext *context = [NSGraphicsContext currentContext]; DPSgsave (context); - [font->nsfont set]; - - /* do erase if "foreground" mode */ - if (bgCol != nil) + if (s->clip_head) { - [bgCol set]; - DPSmoveto (context, r.origin.x, r.origin.y); -/*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */ - DPSxshow (context, (const char *) cbuf, advances, len); - DPSstroke (context); - [col set]; -/*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */ + DPSrectclip (context, s->clip_head->x, 0, + FRAME_PIXEL_WIDTH (s->f), + FRAME_PIXEL_HEIGHT (s->f)); } + [font->nsfont set]; [col set]; - /* draw with DPSxshow () */ DPSmoveto (context, r.origin.x, r.origin.y); - DPSxshow (context, (const char *) cbuf, advances, len); + GSShowGlyphs (context, c, len); DPSstroke (context); DPSgrestore (context); @@ -1126,6 +1244,360 @@ is false when (FROM > 0 || TO < S->nchars). */ return to-from; } +static NSUInteger +ns_font_shape (NSFont *font, NSString *string, + struct ns_glyph_layout *glyph_layouts, NSUInteger glyph_len, + enum lgstring_direction dir) +{ + NSUInteger i; + NSUInteger result = 0; + NSTextStorage *textStorage; + NSLayoutManager *layoutManager; + NSTextContainer *textContainer; + NSUInteger stringLength; + NSPoint spaceLocation; + /* numberOfGlyphs can't actually be 0, but this pacifies GCC */ + NSUInteger used, numberOfGlyphs = 0; + + textStorage = [[NSTextStorage alloc] initWithString:string]; + layoutManager = [[NSLayoutManager alloc] init]; + textContainer = [[NSTextContainer alloc] init]; + + /* Append a trailing space to measure baseline position. */ + [textStorage appendAttributedString:([[[NSAttributedString alloc] + initWithString:@" "] autorelease])]; + [textStorage setFont:font]; + [textContainer setLineFragmentPadding:0]; + + [layoutManager addTextContainer:textContainer]; + [textContainer release]; + [textStorage addLayoutManager:layoutManager]; + [layoutManager release]; + + if (!(textStorage && layoutManager && textContainer)) + emacs_abort (); + + stringLength = [string length]; + + /* Force layout. */ + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength]; + + /* Remove the appended trailing space because otherwise it may + generate a wrong result for a right-to-left text. */ + [textStorage beginEditing]; + [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))]; + [textStorage endEditing]; + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + i = 0; + while (i < stringLength) + { + NSRange range; + NSFont *fontInTextStorage = + [textStorage attribute: NSFontAttributeName + atIndex:i + longestEffectiveRange: &range + inRange: NSMakeRange (0, stringLength)]; + + if (!(fontInTextStorage == font + || [[fontInTextStorage fontName] isEqualToString:[font fontName]])) + break; + i = NSMaxRange (range); + } + if (i < stringLength) + /* Make the test `used <= glyph_len' below fail if textStorage + contained some fonts other than the specified one. */ + used = glyph_len + 1; + else + { + NSRange range = NSMakeRange (0, stringLength); + + range = [layoutManager glyphRangeForCharacterRange:range + actualCharacterRange:NULL]; + numberOfGlyphs = NSMaxRange (range); + used = numberOfGlyphs; + for (i = 0; i < numberOfGlyphs; i++) + if ([layoutManager notShownAttributeForGlyphAtIndex:i]) + used--; + } + + if (0 < used && used <= glyph_len) + { + NSUInteger glyphIndex, prevGlyphIndex; + NSUInteger *permutation; + NSRange compRange, range; + CGFloat totalAdvance; + + glyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + permutation = NULL; +#define RIGHT_TO_LEFT_P permutation + + /* Fill the `comp_range' member of struct mac_glyph_layout, and + setup a permutation for right-to-left text. */ + compRange = NSMakeRange (0, 0); + for (range = NSMakeRange (0, 0); NSMaxRange (range) < used; + range.length++) + { + struct ns_glyph_layout *gl = glyph_layouts + NSMaxRange (range); + NSUInteger characterIndex = + [layoutManager characterIndexForGlyphAtIndex:glyphIndex]; + + gl->string_index = characterIndex; + + if (characterIndex >= NSMaxRange (compRange)) + { + compRange.location = NSMaxRange (compRange); + do + { + NSRange characterRange = + [string + rangeOfComposedCharacterSequenceAtIndex:characterIndex]; + + compRange.length = + NSMaxRange (characterRange) - compRange.location; + [layoutManager glyphRangeForCharacterRange:compRange + actualCharacterRange:&characterRange]; + characterIndex = NSMaxRange (characterRange) - 1; + } + while (characterIndex >= NSMaxRange (compRange)); + + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + range = NSMakeRange (NSMaxRange (range), 0); + } + + gl->comp_range.location = compRange.location; + gl->comp_range.length = compRange.length; + + while (++glyphIndex < numberOfGlyphs) + if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + break; + } + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + /* Then fill the remaining members. */ + glyphIndex = prevGlyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + if (!RIGHT_TO_LEFT_P) + totalAdvance = 0; + else + { + NSUInteger nrects; + NSRect *glyphRects = + [layoutManager + rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs)) + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + + totalAdvance = NSMaxX (glyphRects[0]); + } + + for (i = 0; i < used; i++) + { + struct ns_glyph_layout *gl; + NSPoint location; + NSUInteger nextGlyphIndex; + NSRange glyphRange; + NSRect *glyphRects; + NSUInteger nrects; + + if (!RIGHT_TO_LEFT_P) + gl = glyph_layouts + i; + else + { + NSUInteger dest = permutation[i]; + + gl = glyph_layouts + dest; + if (i < dest) + { + NSUInteger tmp = gl->string_index; + + gl->string_index = glyph_layouts[i].string_index; + glyph_layouts[i].string_index = tmp; + } + } + gl->glyph_id = [layoutManager glyphAtIndex: glyphIndex]; + + location = [layoutManager locationForGlyphAtIndex:glyphIndex]; + gl->baseline_delta = spaceLocation.y - location.y; + + for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs; + nextGlyphIndex++) + if (![layoutManager + notShownAttributeForGlyphAtIndex:nextGlyphIndex]) + break; + + if (!RIGHT_TO_LEFT_P) + { + CGFloat maxX; + + if (prevGlyphIndex == 0) + glyphRange = NSMakeRange (0, nextGlyphIndex); + else + glyphRange = NSMakeRange (glyphIndex, + nextGlyphIndex - glyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + maxX = max (NSMaxX (glyphRects[0]), totalAdvance); + gl->advance_delta = location.x - totalAdvance; + gl->advance = maxX - totalAdvance; + totalAdvance = maxX; + } + else + { + CGFloat minX; + + if (nextGlyphIndex == numberOfGlyphs) + glyphRange = NSMakeRange (prevGlyphIndex, + numberOfGlyphs - prevGlyphIndex); + else + glyphRange = NSMakeRange (prevGlyphIndex, + glyphIndex + 1 - prevGlyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + minX = min (NSMinX (glyphRects[0]), totalAdvance); + gl->advance = totalAdvance - minX; + totalAdvance = minX; + gl->advance_delta = location.x - totalAdvance; + } + + prevGlyphIndex = glyphIndex + 1; + glyphIndex = nextGlyphIndex; + } + + if (RIGHT_TO_LEFT_P) + xfree (permutation); + +#undef RIGHT_TO_LEFT_P + + result = used; + } + [textStorage release]; + + return result; +} + +static Lisp_Object +nsfont_shape (Lisp_Object lgstring, Lisp_Object direction) +{ + struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring)); + struct nsfont_info *font_info = (struct nsfont_info *) font; + struct ns_glyph_layout *glyph_layouts; + NSFont *nsfont = font_info->nsfont; + ptrdiff_t glyph_len, len, i; + Lisp_Object tem; + unichar *mb_buf; + NSUInteger used; + + glyph_len = LGSTRING_GLYPH_LEN (lgstring); + for (i = 0; i < glyph_len; ++i) + { + tem = LGSTRING_GLYPH (lgstring, i); + + if (NILP (tem)) + break; + } + + len = i; + + if (INT_MAX / 2 < len) + memory_full (SIZE_MAX); + + block_input (); + + mb_buf = alloca (len * sizeof *mb_buf); + + for (i = 0; i < len; ++i) + { + uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i)); + mb_buf[i] = (unichar) c; + } + + NSString *string = [NSString stringWithCharacters: mb_buf + length: len]; + unblock_input (); + + if (!string) + return Qnil; + + block_input (); + + enum lgstring_direction dir = DIR_UNKNOWN; + + if (EQ (direction, QL2R)) + dir = DIR_L2R; + else if (EQ (direction, QR2L)) + dir = DIR_R2L; + glyph_layouts = alloca (sizeof (struct ns_glyph_layout) * glyph_len); + used = ns_font_shape (nsfont, string, glyph_layouts, glyph_len, dir); + + for (i = 0; i < used; i++) + { + Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i); + struct ns_glyph_layout *gl = glyph_layouts + i; + EMACS_INT from, to; + struct font_metrics metrics; + + if (NILP (lglyph)) + { + lglyph = LGLYPH_NEW (); + LGSTRING_SET_GLYPH (lgstring, i, lglyph); + } + + from = gl->comp_range.location; + LGLYPH_SET_FROM (lglyph, from); + + to = gl->comp_range.location + gl->comp_range.length; + LGLYPH_SET_TO (lglyph, to - 1); + + /* LGLYPH_CHAR is used in `describe-char' for checking whether + the composition is trivial. */ + { + UTF32Char c; + + if (mb_buf[gl->string_index] >= 0xD800 + && mb_buf[gl->string_index] < 0xDC00) + c = (((mb_buf[gl->string_index] - 0xD800) << 10) + + (mb_buf[gl->string_index + 1] - 0xDC00) + 0x10000); + else + c = mb_buf[gl->string_index]; + + LGLYPH_SET_CHAR (lglyph, c); + } + + { + unsigned long cc = gl->glyph_id; + LGLYPH_SET_CODE (lglyph, cc); + } + + nsfont_text_extents (font, &gl->glyph_id, 1, &metrics); + LGLYPH_SET_WIDTH (lglyph, metrics.width); + LGLYPH_SET_LBEARING (lglyph, metrics.lbearing); + LGLYPH_SET_RBEARING (lglyph, metrics.rbearing); + LGLYPH_SET_ASCENT (lglyph, metrics.ascent); + LGLYPH_SET_DESCENT (lglyph, metrics.descent); + } + unblock_input (); + + return make_fixnum (used); +} /* ========================================================================== @@ -1134,6 +1606,50 @@ is false when (FROM > 0 || TO < S->nchars). */ ========================================================================== */ +static NSGlyph +ns_uni_to_glyphs_1 (struct nsfont_info *info, unsigned int c) +{ + unichar characters[] = { c }; + NSString *string = + [NSString stringWithCharacters: characters + length: 1]; + NSDictionary *attributes = + [NSDictionary dictionaryWithObjectsAndKeys: + info->nsfont, NSFontAttributeName, nil]; + NSTextStorage *storage = [[NSTextStorage alloc] initWithString: string + attributes: attributes]; + NSTextContainer *text_container = [[NSTextContainer alloc] init]; + NSLayoutManager *manager = [[NSLayoutManager alloc] init]; + + [manager addTextContainer: text_container]; + [text_container release]; /* Retained by manager */ + [storage addLayoutManager: manager]; + [manager release]; /* Retained by storage */ + + NSFont *font_in_storage = [storage attribute: NSFontAttributeName + atIndex:0 + effectiveRange: NULL]; + NSGlyph glyph = FONT_INVALID_CODE; + + if ((font_in_storage == info->nsfont + || [[font_in_storage fontName] isEqualToString: [info->nsfont fontName]])) + { + @try + { + glyph = [manager glyphAtIndex: 0]; + } + @catch (NSException *e) + { + /* GNUstep bug? */ + glyph = 'X'; + } + } + + [storage release]; + + return glyph; +} + /* Find and cache corresponding glyph codes for unicode values in given hi-byte block of 256. */ static void @@ -1141,7 +1657,7 @@ is false when (FROM > 0 || TO < S->nchars). */ { unichar *unichars = xmalloc (0x101 * sizeof (unichar)); unsigned int i, g, idx; - unsigned short *glyphs; + unsigned int *glyphs; if (NSFONT_TRACE) fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n", @@ -1149,7 +1665,7 @@ is false when (FROM > 0 || TO < S->nchars). */ block_input (); - font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short)); + font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned int)); if (!unichars || !(font_info->glyphs[block])) emacs_abort (); @@ -1166,7 +1682,8 @@ is false when (FROM > 0 || TO < S->nchars). */ for (i = 0; i < 0x100; i++, glyphs++) { g = unichars[i]; - *glyphs = g; + NSGlyph glyph = ns_uni_to_glyphs_1 (font_info, g); + *glyphs = glyph; } } @@ -1175,18 +1692,19 @@ is false when (FROM > 0 || TO < S->nchars). */ } -/* Determine and cache metrics for corresponding glyph codes in given - hi-byte block of 256. */ +/* Determine and cache metrics for glyphs in given hi-byte block of + 256. */ static void -ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block) +ns_glyph_metrics (struct nsfont_info *font_info, unsigned int block) { - unsigned int i, g; + unsigned int i; + NSGlyph g; unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs]; NSFont *sfont; struct font_metrics *metrics; if (NSFONT_TRACE) - fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n", + fprintf (stderr, "%p\tComputing metrics for glyphs in block %u\n", font_info, block); /* not implemented yet (as of startup 0.18), so punt */ @@ -1209,19 +1727,14 @@ is false when (FROM > 0 || TO < S->nchars). */ w = max ([sfont advancementForGlyph: g].width, 2.0); metrics->width = lrint (w); - lb = r.origin.x; - rb = r.size.width - w; - // Add to bearing for LCD smoothing. We don't know if it is there. - if (lb < 0) - metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN); - if (font_info->ital) - rb += (CGFloat) (0.22F * font_info->height); - metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN); - - metrics->descent = r.origin.y < 0 ? -r.origin.y : 0; - /* lrint (hshrink * [sfont ascender] + expand * hd/2); */ - metrics->ascent = r.size.height - metrics->descent; - /* -lrint (hshrink* [sfont descender] - expand * hd/2); */ + lb = NSMinX (r); + rb = NSMaxX (r); + + metrics->rbearing = lrint (rb); + metrics->lbearing = lrint (lb); + + metrics->descent = NSMinY (r); + metrics->ascent = NSMaxY (r); } unblock_input (); } @@ -1257,6 +1770,7 @@ is false when (FROM > 0 || TO < S->nchars). */ .has_char = nsfont_has_char, .encode_char = nsfont_encode_char, .text_extents = nsfont_text_extents, + .shape = nsfont_shape, .draw = nsfont_draw, }; @@ -1265,7 +1779,6 @@ is false when (FROM > 0 || TO < S->nchars). */ { DEFSYM (Qcondensed, "condensed"); DEFSYM (Qexpanded, "expanded"); - DEFSYM (Qapple, "apple"); DEFSYM (Qmedium, "medium"); DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script, doc: /* Internal use: maps font registry to Unicode script. */); diff --git a/src/nsterm.h b/src/nsterm.h index c750d1bd99..8175f99664 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -820,7 +820,7 @@ #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) XCharStruct max_bounds; /* We compute glyph codes and metrics on-demand in blocks of 256 indexed by hibyte, lobyte. */ - unsigned short **glyphs; /* map Unicode index to glyph */ + unsigned int **glyphs; /* map Unicode index to glyph */ struct font_metrics **metrics; }; #endif diff --git a/src/nsterm.m b/src/nsterm.m index 4c2a3f287c..9b036430ed 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1078,11 +1078,16 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) /* clipping */ if (r) { - [[NSGraphicsContext currentContext] saveGraphicsState]; + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; +#ifdef NS_IMPL_COCOA if (n == 2) NSRectClipList (r, 2); else NSRectClip (*r); +#else + GSRectClipList (ctx, r, n); +#endif gsaved = YES; } } @@ -2440,9 +2445,6 @@ Hide the window (X11 semantics) EmacsView *view = FRAME_NS_VIEW (f); FRAME_POINTER_TYPE (f) = cursor; [[view window] invalidateCursorRectsForView: view]; - /* Redisplay assumes this function also draws the changed frame - cursor, but this function doesn't, so do it explicitly. */ - gui_update_cursor (f, 1); } } @@ -2852,31 +2854,31 @@ Hide the window (X11 semantics) External (RIF); compute left/right overhang of whole string and set in s -------------------------------------------------------------------------- */ { - struct font *font = s->font; - - if (s->char2b) + if (s->cmp == NULL + && (s->first_glyph->type == CHAR_GLYPH + || s->first_glyph->type == COMPOSITE_GLYPH)) { struct font_metrics metrics; - unsigned int codes[2]; - codes[0] = *(s->char2b); - codes[1] = *(s->char2b + s->nchars - 1); - font->driver->text_extents (font, codes, 2, &metrics); - s->left_overhang = -metrics.lbearing; - s->right_overhang - = metrics.rbearing > metrics.width - ? metrics.rbearing - metrics.width : 0; + if (s->first_glyph->type == CHAR_GLYPH) + { + struct font *font = s->font; + font->driver->text_extents (font, s->char2b, s->nchars, &metrics); + } + else + { + Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); + + composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); + } + s->right_overhang = (metrics.rbearing > metrics.width + ? metrics.rbearing - metrics.width : 0); + s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0; } - else + else if (s->cmp) { - s->left_overhang = 0; -#ifdef NS_IMPL_GNUSTEP - if (EQ (font->driver->type, Qns)) - s->right_overhang = ((struct nsfont_info *)font)->ital ? - FONT_HEIGHT (font) * 0.2 : 0; - else -#endif - s->right_overhang = 0; + s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width; + s->left_overhang = - s->cmp->lbearing; } } @@ -3016,14 +3018,13 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. struct frame *f = WINDOW_XFRAME (w); struct glyph *phys_cursor_glyph; struct glyph *cursor_glyph; - struct face *face; - NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f); /* If cursor is out of bounds, don't draw garbage. This can happen in mini-buffer windows when switching between echo area glyphs and mini-buffer. */ - NSTRACE ("ns_draw_window_cursor"); + NSTRACE ("ns_draw_window_cursor (on = %d, cursor_type = %d)", + on_p, cursor_type); if (!on_p) return; @@ -3039,6 +3040,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL) { + NSTRACE_MSG ("No phys cursor glyph was found!"); + if (glyph_row->exact_window_width_line_p && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) { @@ -3048,10 +3051,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. return; } - /* We draw the cursor (with NSRectFill), then draw the glyph on top - (other terminals do it the other way round). We must set - w->phys_cursor_width to the cursor width. For bar cursors, that - is CURSOR_WIDTH; for box cursors, it is the glyph width. */ get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h); /* The above get_phys_cursor_geometry call set w->phys_cursor_width @@ -3083,17 +3082,15 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. /* Prevent the cursor from being drawn outside the text area. */ r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA)); - ns_focus (f, &r, 1); + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; +#ifdef NS_IMPL_GNUSTEP + GSRectClipList (ctx, &r, 1); +#else + NSRectClip (r); +#endif - face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id); - if (face && NS_FACE_BACKGROUND (face) - == ns_index_color (FRAME_CURSOR_COLOR (f), f)) - { - [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set]; - hollow_color = FRAME_CURSOR_COLOR (f); - } - else - [FRAME_CURSOR_COLOR (f) set]; + [FRAME_CURSOR_COLOR (f) set]; switch (cursor_type) { @@ -3101,13 +3098,11 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. case NO_CURSOR: break; case FILLED_BOX_CURSOR: - NSRectFill (r); + draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); break; case HOLLOW_BOX_CURSOR: - NSRectFill (r); - [hollow_color set]; - NSRectFill (NSInsetRect (r, 1, 1)); - [FRAME_CURSOR_COLOR (f) set]; + draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT); + [NSBezierPath strokeRect: r]; break; case HBAR_CURSOR: NSRectFill (r); @@ -3123,12 +3118,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. NSRectFill (s); break; } - ns_unfocus (f); - /* Draw the character under the cursor. Other terms only draw - the character on top of box cursors, so do the same here. */ - if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR) - draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); + [ctx restoreGraphicsState]; } @@ -3308,16 +3299,18 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if (s->for_overlaps) return; + if (s->hl == DRAW_CURSOR) + [FRAME_BACKGROUND_COLOR (s->f) set]; + else if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + /* Do underline. */ if (face->underline) { if (s->face->underline == FACE_UNDER_WAVE) { - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; - ns_draw_underwave (s, width, x); } else if (s->face->underline == FACE_UNDER_LINE) @@ -3388,11 +3381,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. s->underline_position = position; r = NSMakeRect (x, s->ybase + position, width, thickness); - - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; NSRectFill (r); } } @@ -3402,11 +3390,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. { NSRect r; r = NSMakeRect (x, s->y, width, 1); - - if (face->overline_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->overline_color, s->f) set]; NSRectFill (r); } @@ -3429,10 +3412,6 @@ larger if there are taller display elements (e.g., characters dy = lrint ((glyph_height - h) / 2); r = NSMakeRect (x, glyph_y + dy, width, 1); - if (face->strike_through_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->strike_through_color, s->f) set]; NSRectFill (r); } } @@ -3580,17 +3559,7 @@ Function modeled after x_draw_glyph_string_box (). struct glyph *last_glyph; NSRect r; int hthickness, vthickness; - struct face *face; - - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = s->face; + struct face *face = s->face; vthickness = face->box_vertical_line_width; hthickness = face->box_horizontal_line_width; @@ -3664,34 +3633,26 @@ Function modeled after x_draw_glyph_string_box (). || FONT_TOO_HIGH (s->font) || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) { - struct face *face; - if (s->hl == DRAW_MOUSE_FACE) - { - face - = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + struct face *face = s->face; if (!face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set]; } - if (s->hl != DRAW_CURSOR) - { - NSRect r = NSMakeRect (s->x, s->y + box_line_width, - s->background_width, - s->height-2*box_line_width); - NSRectFill (r); - } + NSRect r = NSMakeRect (s->x, s->y + box_line_width, + s->background_width, + s->height-2*box_line_width); + NSRectFill (r); s->background_filled_p = 1; } @@ -3712,7 +3673,7 @@ Function modeled after x_draw_glyph_string_box (). int th; char raised_p; NSRect br; - struct face *face; + struct face *face = s->face; NSColor *tdCol; NSTRACE ("ns_dumpglyphs_image"); @@ -3733,15 +3694,6 @@ Function modeled after x_draw_glyph_string_box (). /* Draw BG: if we need larger area than image itself cleared, do that, otherwise, since we composite the image under NS (instead of mucking with its background color), we must clear just the image area. */ - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set]; @@ -3812,16 +3764,8 @@ Function modeled after x_draw_glyph_string_box (). if (s->hl == DRAW_CURSOR) { - [FRAME_CURSOR_COLOR (s->f) set]; - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) + [FRAME_CURSOR_COLOR (s->f) set]; tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); - else - /* Currently on NS img->mask is always 0. Since - get_window_cursor_type specifies a hollow box cursor when on - a non-masked image we never reach this clause. But we put it - in, in anticipation of better support for image masks on - NS. */ - tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); } else { @@ -3873,66 +3817,35 @@ Function modeled after x_draw_glyph_string_box (). static void ns_dumpglyphs_stretch (struct glyph_string *s) { - NSRect r[2]; NSRect glyphRect; - int n; - struct face *face; + struct face *face = s->face; NSColor *fgCol, *bgCol; if (!s->background_filled_p) { - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + face = s->face; bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); - glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); - - [bgCol set]; - - /* NOTE: under NS this is NOT used to draw cursors, but we must avoid - overwriting cursor (usually when cursor on a tab) */ if (s->hl == DRAW_CURSOR) - { - CGFloat x, width; + { + fgCol = bgCol; + bgCol = FRAME_CURSOR_COLOR (s->f); + } - /* FIXME: This looks like it will only work for left to - right languages. */ - x = NSMinX (glyphRect); - width = s->w->phys_cursor_width; - glyphRect.size.width -= width; - glyphRect.origin.x += width; + glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); - NSRectFill (glyphRect); + [bgCol set]; - /* Draw overlining, etc. on the cursor. */ - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) - ns_draw_text_decoration (s, face, bgCol, width, x); - else - ns_draw_text_decoration (s, face, fgCol, width, x); - } - else - { - NSRectFill (glyphRect); - } + NSRectFill (glyphRect); /* Draw overlining, etc. on the stretch glyph (or the part of the stretch glyph after the cursor). */ ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect), NSMinX (glyphRect)); - ns_unfocus (s->f); s->background_filled_p = 1; } } @@ -3941,7 +3854,7 @@ overwriting cursor (usually when cursor on a tab) */ static void ns_draw_glyph_string_foreground (struct glyph_string *s) { - int x, flags; + int x; struct font *font = s->font; /* If first glyph of S has a left box line, start drawing the text @@ -3952,15 +3865,9 @@ overwriting cursor (usually when cursor on a tab) */ else x = s->x; - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - font->driver->draw (s, s->cmp_from, s->nchars, x, s->ybase, - (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p) - || flags == NS_DUMPGLYPH_MOUSEFACE); + !s->for_overlaps && !s->background_filled_p); } @@ -4067,9 +3974,9 @@ overwriting cursor (usually when cursor on a tab) */ struct font *font = s->face->font; if (! font) font = FRAME_FONT (s->f); - NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string"); + NSTRACE ("ns_draw_glyph_string (hl = %u)", s->hl); - if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/) + if (s->next && s->right_overhang && !s->for_overlaps) { int width; struct glyph_string *next; @@ -4106,14 +4013,21 @@ overwriting cursor (usually when cursor on a tab) */ box_drawn_p = 1; } + n = ns_get_glyph_string_clip_rect (s, r); + + if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */ + && !s->clip_tail + && ((s->prev && s->prev->hl != s->hl && s->left_overhang) + || (s->next && s->next->hl != s->hl && s->right_overhang))) + r[0] = NSIntersectionRect (r[0], NSMakeRect (s->x, s->y, s->width, s->height)); + + ns_focus (s->f, r, n); + switch (s->first_glyph->type) { case IMAGE_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); ns_dumpglyphs_image (s, r[0]); - ns_unfocus (s->f); break; case XWIDGET_GLYPH: @@ -4126,57 +4040,36 @@ overwriting cursor (usually when cursor on a tab) */ case CHAR_GLYPH: case COMPOSITE_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - - if (s->for_overlaps || (s->cmp_from > 0 - && ! s->first_glyph->u.cmp.automatic)) - s->background_filled_p = 1; - else - ns_maybe_dumpglyphs_background - (s, s->first_glyph->type == COMPOSITE_GLYPH); - - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - { - BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + if (s->for_overlaps || (isComposite + && (s->cmp_from > 0 + && ! s->first_glyph->u.cmp.automatic))) + s->background_filled_p = 1; + else + ns_maybe_dumpglyphs_background + (s, s->first_glyph->type == COMPOSITE_GLYPH); - if (isComposite) - ns_draw_composite_glyph_string_foreground (s); - else - ns_draw_glyph_string_foreground (s); - } + if (isComposite) + ns_draw_composite_glyph_string_foreground (s); + else + ns_draw_glyph_string_foreground (s); - { - NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), - s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - [col set]; - - /* Draw underline, overline, strike-through. */ - ns_draw_text_decoration (s, s->face, col, s->width, s->x); + { + NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), + s->f) + : FRAME_FOREGROUND_COLOR (s->f)); + [col set]; + + /* Draw underline, overline, strike-through. */ + ns_draw_text_decoration (s, s->face, col, s->width, s->x); + } } - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - - ns_unfocus (s->f); break; case GLYPHLESS_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - if (s->for_overlaps || (s->cmp_from > 0 && ! s->first_glyph->u.cmp.automatic)) s->background_filled_p = 1; @@ -4186,7 +4079,6 @@ overwriting cursor (usually when cursor on a tab) */ /* ... */ /* Not yet implemented. */ /* ... */ - ns_unfocus (s->f); break; default: @@ -4195,13 +4087,92 @@ overwriting cursor (usually when cursor on a tab) */ /* Draw box if not done already. */ if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) + ns_dumpglyphs_box_or_relief (s); + + ns_unfocus (s->f); + + /* Draw surrounding overhangs. */ + if (s->prev) { - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - ns_dumpglyphs_box_or_relief (s); + ns_focus (s->f, NULL, 0); + struct glyph_string *prev; + + for (prev = s->prev; prev; prev = prev->prev) + if (prev->hl != s->hl + && prev->x + prev->width + prev->right_overhang > s->x) + { + /* As prev was drawn while clipped to its own area, we + must draw the right_overhang part using s->hl now. */ + enum draw_glyphs_face save = prev->hl; + struct face *save_face = prev->face; + + prev->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + prev->num_clips = 1; + prev->hl = s->hl; + if (prev->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (prev); + else + ns_draw_composite_glyph_string_foreground (prev); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + [[NSGraphicsContext currentContext] restoreGraphicsState]; + prev->hl = save; + prev->face = save_face; + prev->num_clips = 0; + } ns_unfocus (s->f); } + if (s->next) + { + ns_focus (s->f, NULL, 0); + struct glyph_string *next; + + for (next = s->next; next; next = next->next) + if (next->hl != s->hl + && next->x - next->left_overhang < s->x + s->width) + { + /* As next will be drawn while clipped to its own area, + we must draw the left_overhang part using s->hl now. */ + enum draw_glyphs_face save = next->hl; + struct face *save_face = next->face; + + next->hl = s->hl; + next->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + next->num_clips = 1; + if (next->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (next); + else + ns_draw_composite_glyph_string_foreground (next); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + [[NSGraphicsContext currentContext] restoreGraphicsState]; + next->hl = save; + next->num_clips = 0; + next->face = save_face; + next->clip_head = next; + next->background_filled_p = 0; + } + ns_unfocus (s->f); + } s->num_clips = 0; } diff --git a/src/xdisp.c b/src/xdisp.c index dffbdb8d1e..0d95e70212 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -29298,7 +29298,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, for (s = head; s; s = s->next) FRAME_RIF (f)->draw_glyph_string (s); -#ifndef HAVE_NS /* When focus a sole frame and move horizontally, this clears on_p causing a failure to erase prev cursor position. */ if (area == TEXT_AREA @@ -29317,7 +29316,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, notice_overwritten_cursor (w, TEXT_AREA, x0, x1, row->y, MATRIX_ROW_BOTTOM_Y (row)); } -#endif /* Value is the x-position up to which drawn, relative to AREA of W. This doesn't include parts drawn because of overhangs. */ -- 2.31.1 --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Sun Oct 31 06:59:46 2021 Received: (at 51411) by debbugs.gnu.org; 31 Oct 2021 10:59:46 +0000 Received: from localhost ([127.0.0.1]:59106 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh8Z0-0002mK-GK for submit@debbugs.gnu.org; Sun, 31 Oct 2021 06:59:46 -0400 Received: from outbound.soverin.net ([116.202.126.228]:57955) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh8Yy-0002mC-Jl for 51411@debbugs.gnu.org; Sun, 31 Oct 2021 06:59:45 -0400 Received: from smtp.soverin.net (unknown [10.10.3.24]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by outbound.soverin.net (Postfix) with ESMTPS id 0E4A092; Sun, 31 Oct 2021 10:59:43 +0000 (UTC) Received: from smtp.soverin.net (smtp.soverin.net [159.69.232.138]) by soverin.net DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=idiocy.org; s=soverin; t=1635677982; bh=LBrdcWId1Y1cGLIMnRQ3fB1Szd+jf2cDsDMc8tcP3dQ=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=EUvwCqtSs9DZp4Uw+GI4siesD5iC/LHccD2aYCwponK8dxGw215PsGMV3ompiOpbD s4B2j1cMCED3HkxPvs1Y9ROzgG8U2zuvVZb+TDLRsSBbQZ6JtKmqXGn7svg9OwJSB8 sH0FRMvcgLjnR/pPXmVwPqJ29uGrY0jS/PAWwD+mZ349jWUHGYshqsl6dFhkL8rqIU v7qoT7HESkyYN3Bwh8bKv3U+uhnPzRSo6c1OZkh2o+riYFYrGGYX1FUpa9xq9zk/j+ ToIX3wKw0PHf/0sTVUWawH0Q1rK7EqrgJgmBaHmBwOTkGdm1jcaRnFo1Gct1PVtAMM jOyCWFwbugCEA== Received: from alan by faroe.holly.idiocy.org with local (Exim 4.95-RC2) (envelope-from ) id 1mh8Yu-00033T-AL; Sun, 31 Oct 2021 10:59:40 +0000 Date: Sun, 31 Oct 2021 10:59:40 +0000 From: Alan Third To: Po Lu Subject: Re: bug#51411: NS port cleanups Message-ID: Mail-Followup-To: Alan Third , Po Lu , 51411@debbugs.gnu.org References: <87mtmwt3mc.fsf.ref@yahoo.com> <87mtmwt3mc.fsf@yahoo.com> <87h7d4t0er.fsf@yahoo.com> <87ee86q7jm.fsf@yahoo.com> <87ilxhmlwc.fsf@yahoo.com> <87lf29jxeg.fsf@yahoo.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <87lf29jxeg.fsf@yahoo.com> X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) On Sun, Oct 31, 2021 at 06:34:15PM +0800, Po Lu wrote: > Alan Third writes: > > > I think what you'll need to do is union the two rectangles and then > > clip to that, rather than clipping them both separately. That will > > then provide the same clipping as the NSClipRect code does. > > I meant to say that DPSrectclip intersects (IOW, behaves just as > NSClipRect does). Unless that's incorrect, I think what I'm doing right > now should work fine. When there are two rectangles we use NSRectClipList, which behaves a little differently. It uses the union of the two rectangles to intersect with the existing clipping. So you'll have to do something like u = NSUnionRect (r[0], r[1]); DPSrectclip (ctx, NSMinX (u), NSMinY (u), NSWidth (u), NSHeight (u)); > > I must be failing to communicate well, we keep seeming to > > misunderstand each other. > > It could be my problem as well: my reading comprehension is nowhere near > as good as I would rather it be. Thanks a lot for tolerating it. It turns out in this case I'm getting confused over what's changed in each patch! Entirely my fault. > > You still need to focus, however you don't have to clip when you > > focus. > > After I unfocus here: > > /* Draw box if not done already. */ > if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) > ns_dumpglyphs_box_or_relief (s); > > -> ns_unfocus (s->f); > > I make sure to focus again if an overhang might be drawn again (inside > if (s->prev) and if (s->next)), like so: > > /* Draw surrounding overhangs. */ > if (s->prev) > { > -> ns_focus (s->f, NULL, 0); > struct glyph_string *prev; > > There is, of course, a matching unfocus. Is that not adequate, and if > so, could you please explain how? Sorry, I've got confused. What you're doing here now is good. I noticed that you removed all calls to ns_focus in ns_draw_window_cursor and thought you'd removed all calls to ns_focus, but now I see that's an older change. Is that a good idea? I think ns_draw_window_cursor is sometimes called without matching ns_update_begin/end calls, so it needs to focus, or am I misunderstanding the flow? -- Alan Third From debbugs-submit-bounces@debbugs.gnu.org Sun Oct 31 07:20:58 2021 Received: (at 51411) by debbugs.gnu.org; 31 Oct 2021 11:20:58 +0000 Received: from localhost ([127.0.0.1]:59126 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh8tW-0003Ia-B5 for submit@debbugs.gnu.org; Sun, 31 Oct 2021 07:20:58 -0400 Received: from sonic314-20.consmr.mail.ne1.yahoo.com ([66.163.189.146]:36859) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh8tU-0003IH-6P for 51411@debbugs.gnu.org; Sun, 31 Oct 2021 07:20:57 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635679249; bh=eo6G/WQ6lSXKBXRlAV6QRqqiA21sK7SNjuZvsC/Nq9M=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=gcHMZ+VisBlLJhGgvxekfcp1ttpY2ZduReia9kF1CAKtxNiphriwdjjHzqSlos0XdT1mTHVjBup2xys0pf4jGQ5rLVIDsMKlk0FE4qgjuOCD0Erg7V0Tt5LpsSkrRkp7nKeoT7Ljxp0s1+oMyCzu39M9yp0pgiknDReSTkPWanE6VZnY1wBF3rk4f71nJd7fmzZePGaoAohrMNPD/z+C/oZTdPGDBEN35/SDLLpYRP3mybgBeLLnvFBV4U3ojVdB9e/Gn1pNZQ1V+FAeCKKlVcpKzOayv3OxZGMHww8yrvcZ7Cerf2XwKaNB1AdH5czu6UwfIlAE/huUlNkPxAzSRQ== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635679249; bh=uNuBuE0oHkUvB1kVzlOYfmQtvm9SEgsV5EldTHY7hMF=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=Bbuxk2GciY+xrP9XqNS9GdOjX1/M2qolcbndAOWMcdEQ/cygJvpn17AJXxXM1Bbs6hmMfLvhHT5rP26tI8VVW62vVnLOxtahd2MfXzsGdYIpvUf85tu21t4iEBRLAzbs4A0gQ45f7crJOlqdiZdU4ceskW31NBlwiKYX4grGnFQ3n2tIpox1CKuJkHbBoscOguqP01SRJaRV/mbV6qt3Uz21/tKB3N0uV3LEsEBDbttqRcd06oMavkupMDSTj2k39kjvOp/ThR8HSXlYIkYqJ8M9pTiTlvXDtDH6BzQXz0SLdujAPIdaZAszjDlMaochDfo1COMw50+1CdYKG4vl8A== X-YMail-OSG: .8pYfIoVM1lb4jXvlxhbpztQfaRaPQqKb7aQcaA0GtMN.c.AwVCQqWBSrJgOph4 viSAzpuFeDNwIUOk274UZkY8uBAuLDIeeUNuJvsfSiuoo9r.ji1X0UTGgSlh0lfUO_8IX2yEMk1e dLH9h8IR4NROLJ7FxCqUxpwqnOlf_ogK67nBEn6vzaweuNqg73jBSq.HMMnvnMeAYV0yMxoQ15l9 yMR1LvnhFOJrHxUa6iFJ.MJuRrT.SyZSPN42g3C7pa3MKonhZeRnUX_bXfWXlvZo3w5kHrg639o4 jZvaWz7z.ktJ1WMP52T9KiHlZsVgyUP4xfSOYdQssoMx2L_XlNvv1IgwVpTzHmI339rurzwazD45 QioQD64cNZlS.e8xNEXEMPIsYFUL80nKk9kD8yQIxcvZjozu8ok7C35.7eLWJZD_wRr6_b75p.NR LufSwq4V1g0LQuBFEkcd7m0CfynXjwnP1azCXkVzBy.yCAjCGoDQROCU2BhuVV9_6vLJTJYtegSu p6T5yYz.OU9tghnyRd1aIuYtIVjw34u95KJhK1xdN.3IjH5KwOaXfEgenJYfxNsMx98_UOKk6._L oAk_7S.6VvutCB3Am9EMNYQhYezkZWrOlShdsPksfKI4C7RDS2h78PJNn4K9HCRhoKDHKHOM1g7X BxqyV1.8UHqsb6gzltezuSr04KgiWFz1o6Qeyyb_N63fGQ3MQWuwW8RdRBfipH7vB30z9INHC2R7 j6n6wjph8g0lUOjOZfnL42WbkR9Rft5OiZ6GIoZCvsFmGyx50f9P81rGdsi8dmt5hxKFALqM6WUU lqXgZORE.xWAOW5vkKNaZTOYv8Arbkuo_.mSOKFR5HUbLVFuJTzTrXH5qzhRnOyLp7_YEsL8az8i pfvnhuKZef3FQd3vhPRm44Ryyhk28zQ9DvcHQ0k3kmmiwpxDCi4m19mkN5jHCh5w_tAj5nZZiVJ5 8KZCQr8fpDlsFGGoMdbOFJaXe8SfWVD0mhsI45VXJhr4VevDazVUtlyBxOxnPgJxwZ.PEALPlvoL vaatMmqH9PTfoeWx81y.flnw4GpwAdlLEhbIw0haVI7t7iVwoXUCloDvmDyrhI8._DgpLmpq52Yt a1GW.tMYTwWmQ.zYfyYVJGmhhn2cSoPO2y4DeYRctvjSPh4cEVJ8LLbaRwGkbjXt4qzS8rxW.tyJ lq7ksJyMAgVZqC.Xdh2qb9Rrpyi5f_h2c2qjgilw7.4g0siEsjkBnN7J108iGD8LcpunOxeo3AId pbSjZMKeQwUP_aC3XcFwjqBkP6x7sYYsr8UGkttlnK6okZbrkiEFcKLwhxQ7T_rMNp5X9u718G4O lgHk2t_V952IFnztvyvxgKX_1qzz.td5YIQo7T5xYiM5D3WiuUCmRNFHqRFKAzXeoGPWcwkpPNp. d.p6vn0uGFNf0.aEEQVpH1FmfIRUxulaI_UYkJT.NN7x_ZA.1eAbyHPgjX6NCHYr0AsnLivuUhoe ouyVTIlVRWG5YKje0nSxrP8ChlQMsm.8On54mRntx_QcNu2hAS_72y.EVBMavKci7A_54_AZlg8i tJm_FMrmg8VWy60f0QTy9lxT5t0uU9se63e1H1FDukt6JqjKAKL.S332NeO54nZbHm_ZlyZv5eo6 ShckKA5P7NufedzLKURYA_hftkqwYeJzQqd97M1lSQD2nMtS08bu9jxmo.4LVjxJ6x9VLpMEKKe2 7dyN3C2fsTqoPIkAZg4HlvQtToNUed5j9B.hZDRs60Xcjq18NaHjc6hpQmzCi64v1gBNtN7Zqgv9 tjtPjM_tZmsSRfa4JcEKb9tPkW3BbqK.6H6OpfksGMeOfGP9Vc63viLCjFUSlS1ARMabkj_TIrVo AQrtacq.5YusGT63grndevR2RYat0uHICWxTggptsZBd5PPKGSwIyPSVdq6pRp7lk99wyAqqXvvG DtTqCSYTff04KMN9t26lyZ2dyjnGmqvdCHcGgPpKbI0FwSYtDZSJxnpibOGE7zG3xOnb5ORUMR86 OPCA2EzQHZqpihhgmSxP5iTwitsz4POWA5VhKNwJFH2tzju4oCNrTZzpnG2vBOP2CNWIJsAXIDEU XuTGIUAU2hnGcr9ESTtdJKkKLaKHRkreNKNCpvaHavKXUrscIqBNnBrx6KJWXQgEHpv2iBcP8BSj GSc2E3s2hf35wASPdBPdzBdDkECCajS2MPtKi8FtnH0z6iU7_nilS3TU.oKEH5MXQYCmVsbSKlnG cnBREMpGPduPv_4ilYEwrg71yfv8g6L5MeU26rujJ2DPEGP4Yr9tP6RjHRw-- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic314.consmr.mail.ne1.yahoo.com with HTTP; Sun, 31 Oct 2021 11:20:49 +0000 Received: by kubenode512.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 48f3485be79a5087061babb6c97d3e38; Sun, 31 Oct 2021 11:20:42 +0000 (UTC) From: Po Lu To: Alan Third Subject: Re: bug#51411: NS port cleanups References: <87mtmwt3mc.fsf.ref@yahoo.com> <87mtmwt3mc.fsf@yahoo.com> <87h7d4t0er.fsf@yahoo.com> <87ee86q7jm.fsf@yahoo.com> <87ilxhmlwc.fsf@yahoo.com> <87lf29jxeg.fsf@yahoo.com> Date: Sun, 31 Oct 2021 19:20:38 +0800 In-Reply-To: (Alan Third's message of "Sun, 31 Oct 2021 10:59:40 +0000") Message-ID: <875ytdjv95.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 422 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Alan Third writes: > When there are two rectangles we use NSRectClipList, which behaves a > little differently. It uses the union of the two rectangles to > intersect with the existing clipping. So you'll have to do something > like > > u = NSUnionRect (r[0], r[1]); > DPSrectclip (ctx, NSMinX (u), NSMinY (u), > NSWidth (u), NSHeight (u)); Yes, thanks, please see my other mail. Thanks! From debbugs-submit-bounces@debbugs.gnu.org Sun Oct 31 07:26:26 2021 Received: (at 51411) by debbugs.gnu.org; 31 Oct 2021 11:26:26 +0000 Received: from localhost ([127.0.0.1]:59135 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh8yo-0003Qz-25 for submit@debbugs.gnu.org; Sun, 31 Oct 2021 07:26:26 -0400 Received: from sonic316-22.consmr.mail.ne1.yahoo.com ([66.163.187.148]:39803) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mh8yl-0003Ql-TO for 51411@debbugs.gnu.org; Sun, 31 Oct 2021 07:26:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635679577; bh=qcRkW/rKtm8M0moeMBwzCaTKr7ks77EtvzN6p4n0QOA=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=Z6K6Lw0V2ezTKM71nc47T9IhQ2zO9NSgeKJD/1AVKXVO1K8KuTnvPtNyn/V4eA3Ac2gmirIyvG90c2w8zDbDl88VEDRUkJPvQkxzvSNF4bZiuA4i/OrpNaYDa4ribRdwIeoAx2JEvP9kiWiKV/KG47KsQYzcEEcoIuIje+zMzBKpd7LwVceCU85pAkZB43WMPGpubATkdCyYBKEoBvlCH1m40F8iPIofMn7u5a/uQ23UCFwlFaxJFcRwT1KNdAzA/KxxlxXT1PKU1LWVBbNBvjLAdUVQdHpOjymTSXr56CGn+Wc1SHzcnSC+9gW/T8XoYr9cH21Ta3Th2exjoLJSwg== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635679577; bh=xZ0V4dEzDkeBR7KJKGozDDK4foGuL+kzCrisxw8cQOw=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=grKignXeut8nZfG8iVDCZhug9Gr339WS/w7lvF6BwXBaN/14pZ6fAE1GMU6UEzIL5lRhakaKmGSUZEDTJfLDJAnLVw6DqPMTiISdXAGMy0LRm/3ICzXEbx6MPX241uimkLaQLKCTvsTQc91CsTAT3qxDk8fVaQTbiQvZBjoCkgBGNY7WRE4S8UUfiE4YtmmQmE2HLi4zojFDzwWXurYgJ7/vN/U5xZkJkn1WWAz2CpvSdDo1qF4KVt6Imouz5KIzh0yVmCl1bNQcDcjiiTBWxIAmE55wGXbc+MRDoddR+CgPnIEAo2qokQhg9F3IgMUYV7oNx7ST1fd4XRsjhHwsaw== X-YMail-OSG: zPVRwGwVM1ne1oWgiRJ44ZvAYR8KxMzQWpPeoWbtA9I4SHiQho_ydepi59B6lGg EbKnLqI2kixF5CH06PBMlGhw9rhFogSuEr_q97KdmpOq5cI7Ugec4ZP2r53g8qD2IpqiTyaR27gp A7567ZVIe6xX_ST_xDLFXiSORojgQU76_V9Bu6QmwhOuQwjVD61AXqVKjgEvPXiA.3vUyllTcqI2 UjBd9XcwA27QwQcHN2JoB7kILQU4HW9FMKxSPVBhhyfPHhFs.6mzICCZ5zwD9E5vfBlUZ7KNYZcG OX_iNmQEOpqMEa665wGblSJHZEok2IvCD_Dnl1Zf70.TI9QC3DvPSVuwjU.TKhpmx7HX5eOK4.O9 ruTK3dtCt2M1Ja6bA.kBacWCYPGLmQ1wx3qnGttSMqR.doKRHV3OvHx.7EjEQ9afgxQxG68rMInT Uxyhyr7n3Ko4_fKbFPFOklvRsHIor29kZ2GXfpX8JBFqE.3nV7EXtKr2n1nv0CMM698Ij7QvVuxm y55t72q6qgt5awVpPVk3Xqyjfb_veyLazGFiPyeGx2_jdJL9POkYs0q2jav.b8QlAzsbffFEcpxC 5Y6GvBv.cg_QaDra3v7ADbeofBaY47_gKSWFEOpioTBlvwi4LFrdGCP0mCCWC1TtA5m2Al0k4YJa ZobGttxCLXLvSoRkXhL3.yEg782F6SVGMy96mwuyHuXan2zAhFJeBuLEnTk6GbvR9RH09bzUZx1D I7oXbt6u9fDiypZeNcE8aOwa7QxbA3KxltqbnbVjXTBQTElr1aU8kFH17VPQQfR8vpmKkP7rX5IL UB.kyZ.o1b7IyapWRgiIRKQDicZ9IR1Lb6.uHrPoRQdjazSfu8Yj3iZBcEgE.s8AacbnWbPXsAnw 6YemhSUgoq1wpwMKzSvuKk.JRlX2q_yNLLdYiU5BD5aTHJOsRLOCpJVqWMYy1nvvVJwIySFQMeXV _42cijhYRnUl9furFWcAVJOFEcqndzsDLTrjR9uTrGDN6LXicFzrQCtTw9JRHr0AvSFtFjYgQwtO AAKyKFQQ6ZTmdOpjcrk.qN9m1IqhWd9RklHnbKYoy95DZnIP9sw1OBJ5j1rohTzpT8HwCtUsZmL5 8NY0FwtozSAEC6PMNC2lo0Xl3S90fJH0sxqnla._dFmUI9Vs7TppuA6UjtRiRPPjd6niTIso6Txn u6EN4GEdRz2B3rKNDBk_0yLv2XtuarbrepGKthEjA_JzXPKCDydHRmz8gkYJZ2zpPmtn7u8LBv93 VNFNj83aVB6ppjRlRokfm7yAFT.eqIxqKWGLPH.Uiqyd.dY.CzU35vDAhcy2VGNGwivkK9pg9qfV yLae38yRcb4ZLzVlcnXqFNmXQ17NNU8hB7_yczHfZlDj9Qzrp5RVg0oLMQMWl0PmUBh70sTY6gn9 YoOy3g1CztAtC503DbSEbZ8NlkL2xzud_s4tGu20TZgvokSb1p3.vKtp.EHxgwpoX3gk7yZtpgdG Fs6yF1cOWdwNpuWfu4TSivNXu.jOTtmnaxCHcnm2ZDwO4OoQPyQVlWAN.wZtZeTBEjSIwbFdaotH 2gyxQ0rQy3F1FtvdLP2dcvguVDf39pyWGLV_B6sJy5rdVumH1.sK_1DLqRWuPTfHkdMxwjdk56tq Bz023Ri3glyntne0ATVOQmgnd2Y9Al_z14CWM4iAG5g2f1PTTXjZAg72nP3faMiVw80pUuep2DrH 3hMlCcB89cMTS_HVDC19Q8EzlHjTDLIKgCUgYX5GAwnO7bTd2KdZU5c3qY5LRwmFvcugJMP0D6Wx YCOi7CiWAaUWmrDw5kDzAoNkq5hQOk5TyH66BcwShP80CaXI_NUFE6C77E8h95ydK6O.TFDJryZb 5HDD8bPIMmXydu9OMj2M0FI_PnXsOGZyJS8tjqdeipd6g7mfW3ul8G8CceXF5J1.lQ82pD2Ew5jZ zyptchWUUeMZuCg2QtnUcEJCmc4AjmEG8Ywg8eOkt7qTFDXwNkrK.q2z91tUPcBW7E9LZ1sTZufD 6XTISPnA2fqeA_NR7kj_mO2Mv1VMzJwgsnkX.n_bDjgfKOAc0ncRF10Tnmp74mea9cvXX1rvrMIc qC5YmBEv48UwPflwMxa7xLxA9sGyNaYtYtLoocYjN74KwcGW44vbv.gzA_rhpW.EXvZuhmXQS2Pm xXt7TwC4NOBTXLJjGDnO.YLBdyUEYy10BX1ftnK0wlokNUErCq9_KpN37JfasQ8zPA5FR3wq5.Hw 6J540a4erhM0JKwoKqA1JiZkCPjK1t6KjIi9lHYr41M6ekYzq56VSrcKbhvY- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic316.consmr.mail.ne1.yahoo.com with HTTP; Sun, 31 Oct 2021 11:26:17 +0000 Received: by kubenode512.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID d9c1bdb9a9eb2dc171e9f68fa0b3a273; Sun, 31 Oct 2021 11:26:09 +0000 (UTC) From: Po Lu To: Alan Third Subject: Re: bug#51411: NS port cleanups References: <87mtmwt3mc.fsf.ref@yahoo.com> <87mtmwt3mc.fsf@yahoo.com> <87h7d4t0er.fsf@yahoo.com> <87ee86q7jm.fsf@yahoo.com> <87ilxhmlwc.fsf@yahoo.com> <87lf29jxeg.fsf@yahoo.com> Date: Sun, 31 Oct 2021 19:26:05 +0800 In-Reply-To: (Alan Third's message of "Sun, 31 Oct 2021 10:59:40 +0000") Message-ID: <87v91digfm.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 575 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Alan Third writes: > I noticed that you removed all calls to ns_focus in > ns_draw_window_cursor and thought you'd removed all calls to ns_focus, > but now I see that's an older change. > > Is that a good idea? I think ns_draw_window_cursor is sometimes called > without matching ns_update_begin/end calls, so it needs to focus, or am I > misunderstanding the flow? I don't know if ns_draw_window_cursor is called outside ns_update_begin/end, but if that's the case then I'm not sure how, for instance, double buffering would work on the X port. Thanks. From debbugs-submit-bounces@debbugs.gnu.org Sun Oct 31 08:55:21 2021 Received: (at 51411) by debbugs.gnu.org; 31 Oct 2021 12:55:21 +0000 Received: from localhost ([127.0.0.1]:59215 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mhAMq-0007pC-Ko for submit@debbugs.gnu.org; Sun, 31 Oct 2021 08:55:20 -0400 Received: from outbound.soverin.net ([116.202.126.228]:39929) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mhAMo-0007p2-6U for 51411@debbugs.gnu.org; Sun, 31 Oct 2021 08:55:19 -0400 Received: from smtp.soverin.net (unknown [10.10.3.24]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by outbound.soverin.net (Postfix) with ESMTPS id 69D4692; Sun, 31 Oct 2021 12:55:16 +0000 (UTC) Received: from smtp.soverin.net (smtp.soverin.net [159.69.232.138]) by soverin.net DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=idiocy.org; s=soverin; t=1635684915; bh=tT5koUmHYT6dU9yYJpavbgxB/xmmG9Bli9e/xD9wGJc=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=Wy+y8opFL0TkJeY2L1wKPFN6tQh2zEMdzgIVL3svQAk/WxjQjzv5Vmf0bkvj+y/5V jBisUdokhPBdRH6WDW+LS+SSBJE7rcYcRzUMia7Impy1qJiWBeZBdAN798CKpXaQeq hI4MAobo3hAHDPjz/9LFC/zZuU1YNeiJdWjBBWFC4669gsFSSB5ooZ7siPqz74mxHn 3B81ue0gjiiBrhVl87fqpzvw5SriyQiHLV4PAOgmErcFqb6jVP2j0z2EVC8QLUQ/Fc Yr+aTBQDSJU4/sxQx5mcMlfX3/YPIAGjlAcS2ONc2mr/vnZaOLUV1XwHC6wJ3tFFuF Zhv7iWU1epKaw== Received: from alan by faroe.holly.idiocy.org with local (Exim 4.95-RC2) (envelope-from ) id 1mhAMh-0003UF-7a; Sun, 31 Oct 2021 12:55:11 +0000 Date: Sun, 31 Oct 2021 12:55:11 +0000 From: Alan Third To: Po Lu Subject: Re: bug#51411: NS port cleanups Message-ID: Mail-Followup-To: Alan Third , Po Lu , 51411@debbugs.gnu.org References: <87h7d4t0er.fsf@yahoo.com> <87ee86q7jm.fsf@yahoo.com> <87ilxhmlwc.fsf@yahoo.com> <87lf29jxeg.fsf@yahoo.com> <87v91digfm.fsf@yahoo.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <87v91digfm.fsf@yahoo.com> X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) On Sun, Oct 31, 2021 at 07:26:05PM +0800, Po Lu wrote: > Alan Third writes: > > > I noticed that you removed all calls to ns_focus in > > ns_draw_window_cursor and thought you'd removed all calls to ns_focus, > > but now I see that's an older change. > > > > Is that a good idea? I think ns_draw_window_cursor is sometimes called > > without matching ns_update_begin/end calls, so it needs to focus, or am I > > misunderstanding the flow? > > I don't know if ns_draw_window_cursor is called outside > ns_update_begin/end, but if that's the case then I'm not sure how, for > instance, double buffering would work on the X port. Some drawing functions are definitely used outside ns_update_begin/end, at least in the NS port. Could you please put ns_focus calls back into ns_draw_window_cursor, just in case they are needed, and we can get these changes put into master and then maybe look at whether we need all these ns_focus calls as a separate task (it would certainly be nice if we could get rid of a few of them!). -- Alan Third From debbugs-submit-bounces@debbugs.gnu.org Sun Oct 31 09:12:27 2021 Received: (at 51411) by debbugs.gnu.org; 31 Oct 2021 13:12:27 +0000 Received: from localhost ([127.0.0.1]:59231 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mhAdL-0008FO-Oz for submit@debbugs.gnu.org; Sun, 31 Oct 2021 09:12:27 -0400 Received: from sonic311-23.consmr.mail.ne1.yahoo.com ([66.163.188.204]:40696) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mhAdF-0008F6-OK for 51411@debbugs.gnu.org; Sun, 31 Oct 2021 09:12:22 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635685931; bh=izQG00Qt0d46vhRoKbZFH0YLs/I1b3zX6ZqrVhHJH1g=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=Fdxet2lsDt8uciJ00o/FGEm6p1lzbYouNfKrPWsPFntn0MCvqRfPp/ewdyAbsFHYU4nEbUrKuy7tcRXp2PLzQbdp8Cy+grJ6iRHvPf2WqCL2r+5rI1R0ezOZOfd19Frwot0vTEhyvsSJThozoBiCj5H6tqjZWKO9jL2VuIYgaTIR24Ci6TWJ4d09S5H8vwwjyQ1JdPYI74UPjvFTg3Eb8IzbseNTtP+Ntk8+C/agfUzY2Tu3UK5f2WaH5r4es/ZEYNCAC7mi24Z9P8FuLMKWgo0iQv0BbEAxCwmx61V4a6KV/DlJ78iXXzItrtaLvGnHwQrb1vlk2RMoOeOdlV3FBA== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635685931; bh=itqBpaWaDu7F2GGcKteEbmnhVCOyWsFm1LZ2khgvphI=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=ZNOXcr1pP08btCf8XsdVessg8OQ8Oa8+qs6xU79Qk14gs9N6NGDIQUEp3Lb9G55FnmfXVk46UkZOcvDfu3C0vQhS6/Aq5M47eZFG7dkwEHRnq//WaAEOmTZb4PtF1+DshZoqpXHseKXkuh1dmKo/iypTx4J9okaWtD2NSX6FojXH8Nio+lH1KFeQXC+Nej/+Gdu0qgRNeK0JUHQ6aw4nZ5JRMnxXZQhBPOqZSarJB7G0lu2M7aMxj5L/LS722QF8odtuF4NgtHlEDxfOBB6k0iC7aVSWDfrSDM/Bs30SyspbETlJmGsYW++ES83trOBdTYD62LSAU2cCzgLGOVD+rw== X-YMail-OSG: rsmKpIAVM1k_d61xMKhgShBkUfh7pK65xqdoZQduCimXFjaEo3bmAMVp5wDIclt fu3FG3atGCWV237CY681DmXa81IM1m1LUz93Od8Kk_3Ln78aVDTowyK9DaM93CrgBb4kgvKSS6Ua F6bc25aAiHkjegzGVp_HM4HTSCDQl7TNtvY9u.YhwT8A0pbkbiD7EA0HbNPiby.wJpsLOr0fcPNA AadyzJyJbvwGzWu4XYO4g9Lot5qpQTYLGDygpKu0dB.65k5FYM.JvprrBBEwvnBkAyxD_NCTmu_q V2_AnuC5PD6R3m2i98T9pqiBCpl9plpgThePlbZxtEmh5taRMdcu0rJHj0EArKtdPdSBlGuGqR11 NwJ1UG7sbZ_aT2xZOIIF7n45tKgrJvBmjYUZLt.ybNVQ1PJYpakOfh7V0.0daNung0ALWyDP_92u z61SQ09TyR8AxbrJ5dmLv8_8jxnJpT42HeYBCnj_adlUgTP1Ojcj9_ONc.FLDqiTamKAznALud3Y L5k0pAxuYAS7fqvAbcBz6fVPZugAepGjBj800AmYdgbvDt02jVcFGc0XOKLaLb5cBHF5YrA9dg1a 1HC5Z7T3iCrR3QknSUB24tdu3Og0WRxt0avNu3DaNAoRPz1sHpLoQXnyYDQUHTxFegsjPbnOtHwY 5m2OHvUxVl2igd0eRV4bWhAjQgGgsFL52kGCClEu04AbRE5E3vMKtO0vYxJoQlWdZUtPGMpaN_jZ 6ztVKGOkHVq_xBY7V83S4bfGWgHDbriZo2ASgcZGNiAKiNlbsVpw5xPQvAUKbZ0efpoiTGdl5EmJ 4JEHjUXjkH6XlsWp3DYydYEPVAv.CqInbI8e2AyoY5SuIVNr3Y4WxOlgElsdz67fMMaP1TteVwjp .QQUZcrOAao2siNm1ARV_4EgKxES4vtwZsvA0F8syUA1uNnBD5fRMdwtLbsiRLZII0rlAngIQcsS _vxZLXEthwu_4XoCE1aGfUl84pmpQe7rrvYjX9M.G3NW_wLJtxHU6nEX0AwxAgCZjRI6ddFzeySW oFxtYCtk4k44NK5m.J7E_sT.9NCxFRUrdVGd6pIYta5ECUzqiQk6YeTLY5RbyepcqDlRsVyoTvVW w1W0mIRHYzBzo9ewZu2uNuBomTr_OXo_QDEgSZln4VydW1vBwmIe9yDdOqJybBKwRuD_9zc40n55 sp.drrfGj.hgoezDCBnkg4GqXnC.5qXmaUXqhgg5K0tf2B6y3X76G3f2xPKmJv6nPeT_0nTWMSIZ GR9qmDTFrzyizpgssKLaTM55D9Jt4HGoYP0Xakh4ZQ4gwddwxjtnjTcm2KjgxFjIrnNLCyE7tZVi CieMDtnKMfBcTFFtRA_3g.G.RaPk857.cL8EWmt9_XksD0S.npO.6wN3C.7x0PdFt2iRPnixpH34 FI11PzRW4giA2ZFdEnmKwN5cHm5rC_mIPkgHm47GLSwM9t3IuKEbXBdL9CVlKRejht2amJz5ScHy Wumey6GEWXiYCsa8IfAdeVFEuXopJnhb1h8C3OZkS.x5VQTiUo2q.x2X39G0hcz5dlFVGta_KcO2 5WfGZLTo1aOjibWeF80LtDK7nVPHF0piE4xC7_Xyt090evJsnCRnx.8etXyCKVGWRCSrvZFTPMYA mc0H8PpW1dUOPgnYbAUJBOWhDzjPfFlevGxfThyta9l5rtykSh2ch5tAXhHUeMD1UAcz9uA_ebXS DCGmsiRXmPBg9LWTpPdaK1kT6gWPLwAPqv5M_gx34CdvyAFafZbOwez2X.pF9YOt5I0ApLfj0qfI WoqZHXa8LKPZ4HIkdE4oawmjcTEyAtJRqvtSwDNYkPr.uAFpgg0yes.GyIo4Ytemjmd87Q4OhX2J oJVsgyhwFhBrdD0l3AcDyrJw8jEzMmx7SYRxSOsLS8jRZ5kwIm6luux07ACwwCMAdoeWokgZSaBg a2jikxN51Ho_QfDwHCprxXd3x8qm3C0VM7ETNBURIlRq5ZW8MjFPnA4eoyo_MQzFfM80whTuM8LI RhgixbuuprJc7ulOUXWODJG_1fOctIXeED9eBlacxrikRfXaQDOPxNNRCVI7vtTr.tSxch9eivsK kE8xO_v.Sef0l3U2LMAdz13zEOAz4w9.9cCQJn29uAxMj7ihugXf0ufcHbBkyLaI993LNDglCVWb 1Giv4KV6HMHQJyfApdEimm8ZLLtPH_N.QxM8VJpOxuCUM1J2ytFsFU92hnbXuyymYS_fNkqNy._f ZwCBYr9hwOuK1NZ5QYEfq09rtqbIX_CDl10NC8s9QsN6Zian7muE7mlBfF9eI X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic311.consmr.mail.ne1.yahoo.com with HTTP; Sun, 31 Oct 2021 13:12:11 +0000 Received: by kubenode514.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 5d5ff3ca5c4349edb6c90c7447567481; Sun, 31 Oct 2021 13:12:06 +0000 (UTC) From: Po Lu To: Alan Third Subject: Re: bug#51411: NS port cleanups References: <87h7d4t0er.fsf@yahoo.com> <87ee86q7jm.fsf@yahoo.com> <87ilxhmlwc.fsf@yahoo.com> <87lf29jxeg.fsf@yahoo.com> <87v91digfm.fsf@yahoo.com> Date: Sun, 31 Oct 2021 21:12:03 +0800 In-Reply-To: (Alan Third's message of "Sun, 31 Oct 2021 12:55:11 +0000") Message-ID: <87pmrlibj0.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 91639 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Alan Third writes: > Some drawing functions are definitely used outside > ns_update_begin/end, at least in the NS port. > > Could you please put ns_focus calls back into ns_draw_window_cursor, > just in case they are needed, and we can get these changes put into > master and then maybe look at whether we need all these ns_focus calls > as a separate task (it would certainly be nice if we could get rid of > a few of them!). Thanks, here's the updated patch (along with the other patch for the improvements not related to text display). I will be sure to take a look at the rest of the ns_focus calls later, if I get the time. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Improve-font-display-on-NS-port.patch >From 63b5b710b88d9cf3092a8fda33966c97704767d2 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 23 Oct 2021 19:44:03 +0800 Subject: [PATCH 1/2] Improve font display on NS port * src/nsfns.m (Fx_create_frame): Use "fixed" for the default font on GNUstep. * src/nsfont.m (LCD_SMOOTHING_MARGIN, ns_escape_name) (ns_unescape_name, ns_attribute_fvalue) (STYLE_REF): Remove unused defines and functions. (struct ns_glyph_layout, enum lgstring_direction). (enum gs_font_slant, enum gs_font_weight, enum gs_font_width) (enum gs_specified, struct gs_font_data): New enumerators and structures. (ns_font_descs_match_p) (ns_done_font_data, ns_get_font_data): New functions. (ns_glyph_metrics): Stop escaping names. (ns_spec_to_descriptor): Fix font descriptor creation for symbolic font spec entires. (ns_descriptor_to_entity): Create entries with the correct symbolic styles. (ns_fallback_entity): Fix fallback entity selection. (ns_findfonts): Use our own font matcher instead of the broken GNUstep matcher. (ns_list_family): Remove obsolete comment. (nsfont_open): Remove obsolete code, comments, and synthItal logic which doesn't work on GNUstep. (nsfont_encode_char): Use a type that can fit NSGlyph (nsfont_draw): Chose correct font, remove obsolete mouse face logic, obsolete comments, and switch to using glyph-based drawing instead of character-based drawing. (ns_font_shape, nsfont_shape): New functions. (ns_uni_to_glyphs_1): New function. (ns_uni_to_glyphs): Return glyphs instead of unicode codepoints. (ns_glyph_metrics): Use NSGlyphs instead of unicode codepoints and fix left bearing, right bearing, ascent and descent computation. (struct nsfont_driver): Add shaping capability. * src/nsterm.h (struct nsfont_info): Use unsigned int for glyph cache. * src/nsterm.c (ns_focus): Set DPS clipping on GNUstep. (ns_compute_glyph_string_overhangs): Fix overhang computation by using xterm code. (ns_draw_window_cursor): Simplify cursor drawing. (ns_maybe_dumpglyphs_background): Test for cursor HL and remove obsolete mouse face logic. (ns_dumpglyphs_image) (ns_dumpglyphs_box_or_relief): Rectify for new cursor logic. (ns_dumpglyphs_stretch): Rectify for new cursor logic and rely on ns_draw_glyph_string to set focus. (ns_draw_glyph_string_foreground): Remove mouse face logic. (ns_draw_glyph_strings): Implement overhangs, remove obsolete comment, and always focus before dumping glyphs. (ns_draw_text_decoration): Add condition for DRAW_CURSOR and simplify color selection. (ns_define_frame_cursor): Remove nonsensical code (define_frame_cursor has nothing to do with the text cursor, aka caret). * src/xdisp.c (draw_glyphs): Enable code for NS port to fix mouse face cursor display. * src/macfont.m (get_cgcolor_from_nscolor): New function. (macfont_draw): Remove obsolete mouse-face code and enable cursor display. --- src/macfont.m | 36 +- src/nsfns.m | 6 + src/nsfont.m | 1215 +++++++++++++++++++++++++++++++++++-------------- src/nsterm.h | 2 +- src/nsterm.m | 416 ++++++++--------- src/xdisp.c | 2 - 6 files changed, 1095 insertions(+), 582 deletions(-) diff --git a/src/macfont.m b/src/macfont.m index 78ed5d53f3..1426cae6dc 100644 --- a/src/macfont.m +++ b/src/macfont.m @@ -613,6 +613,21 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char, return cgColor; } +static CGColorRef +get_cgcolor_from_nscolor (NSColor *nsColor, struct frame *f) +{ + [nsColor set]; + CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace]; + NSInteger noc = [nsColor numberOfComponents]; + CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc)); + CGColorRef cgColor; + + [nsColor getComponents: components]; + cgColor = CGColorCreate (colorSpace, components); + xfree (components); + return cgColor; +} + #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f) \ do { \ CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f); \ @@ -2911,14 +2926,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no if (!CGRectIsNull (background_rect)) { - if (s->hl == DRAW_MOUSE_FACE) + if (s->hl == DRAW_CURSOR) { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_CURSOR_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); } - CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); + else + CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); CGContextFillRects (context, &background_rect, 1); } @@ -2927,7 +2942,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no CGAffineTransform atfm; CGContextScaleCTM (context, 1, -1); - CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); + if (s->hl == DRAW_CURSOR) + { + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_BACKGROUND_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); + } + else + CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); if (macfont_info->synthetic_italic_p) atfm = synthetic_italic_atfm; else diff --git a/src/nsfns.m b/src/nsfns.m index 797d0ce782..f4d8172246 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -1236,6 +1236,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. "fontBackend", "FontBackend", RES_TYPE_STRING); { +#ifdef NS_IMPL_COCOA /* use for default font name */ id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */ gui_default_parameter (f, parms, Qfontsize, @@ -1250,6 +1251,11 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. build_string (fontname), "font", "Font", RES_TYPE_STRING); xfree (fontname); +#else + gui_default_parameter (f, parms, Qfont, + build_string ("fixed"), + "font", "Font", RES_TYPE_STRING); +#endif } unblock_input (); diff --git a/src/nsfont.m b/src/nsfont.m index 5a9cdfebc0..b3224629f0 100644 --- a/src/nsfont.m +++ b/src/nsfont.m @@ -1,4 +1,4 @@ -/* Font back-end driver for the NeXT/Open/GNUstep and macOS window system. +/* Font back-end driver for the GNUstep window system. See font.h Copyright (C) 2006-2021 Free Software Foundation, Inc. @@ -38,47 +38,269 @@ #include "termchar.h" #include "pdumper.h" -/* TODO: Drop once we can assume gnustep-gui 0.17.1. */ +#import #import +#import +#import +#import #define NSFONT_TRACE 0 -#define LCD_SMOOTHING_MARGIN 2 -/* Font glyph and metrics caching functions, implemented at end. */ -static void ns_uni_to_glyphs (struct nsfont_info *font_info, - unsigned char block); -static void ns_glyph_metrics (struct nsfont_info *font_info, - unsigned char block); +/* Structure used by GS `shape' functions for storing layout + information for each glyph. Borrowed from macfont.h. */ +struct ns_glyph_layout +{ + /* Range of indices of the characters composed into the group of + glyphs that share the cursor position with this glyph. The + members `location' and `length' are in UTF-16 indices. */ + NSRange comp_range; -#define INVALID_GLYPH 0xFFFF + /* UTF-16 index in the source string for the first character + associated with this glyph. */ + NSUInteger string_index; -/* ========================================================================== + /* Horizontal and vertical adjustments of glyph position. The + coordinate space is that of Core Text. So, the `baseline_delta' + value is negative if the glyph should be placed below the + baseline. */ + CGFloat advance_delta, baseline_delta; - Utilities + /* Typographical width of the glyph. */ + CGFloat advance; - ========================================================================== */ + /* Glyph ID of the glyph. */ + NSGlyph glyph_id; +}; + + +enum lgstring_direction + { + DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1 + }; + +enum gs_font_slant + { + GS_FONT_SLANT_ITALIC, + GS_FONT_SLANT_REVERSE_ITALIC, + GS_FONT_SLANT_NORMAL + }; + +enum gs_font_weight + { + GS_FONT_WEIGHT_LIGHT, + GS_FONT_WEIGHT_BOLD, + GS_FONT_WEIGHT_NORMAL + }; + +enum gs_font_width + { + GS_FONT_WIDTH_CONDENSED, + GS_FONT_WIDTH_EXPANDED, + GS_FONT_WIDTH_NORMAL + }; + +enum gs_specified + { + GS_SPECIFIED_SLANT = 1, + GS_SPECIFIED_WEIGHT = 1 << 1, + GS_SPECIFIED_WIDTH = 1 << 2, + GS_SPECIFIED_FAMILY = 1 << 3, + GS_SPECIFIED_SPACING = 1 << 4 + }; +struct gs_font_data +{ + int specified; + enum gs_font_slant slant; + enum gs_font_weight weight; + enum gs_font_width width; + bool monospace_p; + char *family_name; +}; -/* Replace spaces w/another character so emacs core font parsing routines - aren't thrown off. */ static void -ns_escape_name (char *name) +ns_done_font_data (struct gs_font_data *data) { - for (; *name; name++) - if (*name == ' ') - *name = '_'; + if (data->specified & GS_SPECIFIED_FAMILY) + xfree (data->family_name); } - -/* Reconstruct spaces in a font family name passed through emacs. */ static void -ns_unescape_name (char *name) +ns_get_font_data (NSFontDescriptor *desc, struct gs_font_data *dat) { - for (; *name; name++) - if (*name == '_') - *name = ' '; + NSNumber *tem; + NSFontSymbolicTraits traits = [desc symbolicTraits]; + NSDictionary *dict = [desc objectForKey: NSFontTraitsAttribute]; + NSString *family = [desc objectForKey: NSFontFamilyAttribute]; + + dat->specified = 0; + + if (family != nil) + { + dat->specified |= GS_SPECIFIED_FAMILY; + dat->family_name = xstrdup ([family cStringUsingEncoding: NSUTF8StringEncoding]); + } + + tem = [desc objectForKey: NSFontFixedAdvanceAttribute]; + + if ((tem != nil && [tem boolValue] != NO) + || (traits & NSFontMonoSpaceTrait)) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = true; + } + else if (tem != nil && [tem boolValue] == NO) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = false; + } + + if (traits & NSFontBoldTrait) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + dat->weight = GS_FONT_WEIGHT_BOLD; + } + + if (traits & NSFontItalicTrait) + { + dat->specified |= GS_SPECIFIED_SLANT; + dat->slant = GS_FONT_SLANT_ITALIC; + } + + if (traits & NSFontCondensedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_CONDENSED; + } + else if (traits & NSFontExpandedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_EXPANDED; + } + + if (dict != nil) + { + tem = [dict objectForKey: NSFontSlantTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_SLANT; + + dat->slant = [tem floatValue] > 0 + ? GS_FONT_SLANT_ITALIC + : ([tem floatValue] < 0 + ? GS_FONT_SLANT_REVERSE_ITALIC + : GS_FONT_SLANT_NORMAL); + } + + tem = [dict objectForKey: NSFontWeightTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + + dat->weight = [tem floatValue] > 0 + ? GS_FONT_WEIGHT_BOLD + : ([tem floatValue] < -0.4f + ? GS_FONT_WEIGHT_LIGHT + : GS_FONT_WEIGHT_NORMAL); + } + + tem = [dict objectForKey: NSFontWidthTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WIDTH; + + dat->width = [tem floatValue] > 0 + ? GS_FONT_WIDTH_EXPANDED + : ([tem floatValue] < 0 + ? GS_FONT_WIDTH_NORMAL + : GS_FONT_WIDTH_CONDENSED); + } + } +} + +static bool +ns_font_descs_match_p (NSFontDescriptor *desc, NSFontDescriptor *target) +{ + struct gs_font_data dat; + struct gs_font_data t; + + ns_get_font_data (desc, &dat); + ns_get_font_data (target, &t); + + if (!(t.specified & GS_SPECIFIED_WIDTH)) + t.width = GS_FONT_WIDTH_NORMAL; + if (!(t.specified & GS_SPECIFIED_WEIGHT)) + t.weight = GS_FONT_WEIGHT_NORMAL; + if (!(t.specified & GS_SPECIFIED_SPACING)) + t.monospace_p = false; + if (!(t.specified & GS_SPECIFIED_SLANT)) + t.slant = GS_FONT_SLANT_NORMAL; + + if (!(t.specified & GS_SPECIFIED_FAMILY)) + emacs_abort (); + + bool match_p = true; + + if (dat.specified & GS_SPECIFIED_WIDTH + && dat.width != t.width) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_WEIGHT + && dat.weight != t.weight) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SPACING + && dat.monospace_p != t.monospace_p) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SLANT + && dat.monospace_p != t.monospace_p) + { + if (NSFONT_TRACE) + printf ("Matching monospace for %s: %d %d\n", + t.family_name, dat.monospace_p, + t.monospace_p); + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_FAMILY + && strcmp (dat.family_name, t.family_name)) + match_p = false; + + gout: + ns_done_font_data (&dat); + ns_done_font_data (&t); + + return match_p; } +/* Font glyph and metrics caching functions, implemented at end. */ +static void ns_uni_to_glyphs (struct nsfont_info *font_info, + unsigned char block); +static void ns_glyph_metrics (struct nsfont_info *font_info, + unsigned int block); + +#define INVALID_GLYPH 0xFFFF + +/* ========================================================================== + + Utilities + + ========================================================================== */ + /* Extract family name from a font spec. */ static NSString * @@ -91,66 +313,116 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, { char *tmp = xlispstrdup (SYMBOL_NAME (tem)); NSString *family; - ns_unescape_name (tmp); family = [NSString stringWithUTF8String: tmp]; xfree (tmp); return family; } } - -/* Return 0 if attr not set, else value (which might also be 0). - On Leopard 0 gets returned even on descriptors where the attribute - was never set, so there's no way to distinguish between unspecified - and set to not have. Callers should assume 0 means unspecified. */ -static float -ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait) -{ - NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute]; - NSNumber *val = [tdict objectForKey: trait]; - return val == nil ? 0.0F : [val floatValue]; -} - - /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang to NSFont descriptor. Information under extra only needed for matching. */ -#define STYLE_REF 100 static NSFontDescriptor * ns_spec_to_descriptor (Lisp_Object font_spec) { NSFontDescriptor *fdesc; NSMutableDictionary *fdAttrs = [NSMutableDictionary new]; - NSMutableDictionary *tdict = [NSMutableDictionary new]; NSString *family = ns_get_family (font_spec); - float n; - - /* Add each attr in font_spec to fdAttrs. */ - n = min (FONT_WEIGHT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWeightTrait]; - n = min (FONT_SLANT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontSlantTrait]; - n = min (FONT_WIDTH_NUMERIC (font_spec), 200); - if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10)) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWidthTrait]; - if ([tdict count] > 0) - [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + NSMutableDictionary *tdict = [NSMutableDictionary new]; - fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] - retain] autorelease]; + Lisp_Object tem; + + tem = FONT_SLANT_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qitalic) || EQ (tem, Qoblique)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontSlantTrait]; + else if (EQ (tem, intern ("reverse-italic")) || + EQ (tem, intern ("reverse-oblique"))) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontSlantTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontSlantTrait]; + } + + tem = FONT_WIDTH_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qcondensed)) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWidthTrait]; + else if (EQ (tem, Qexpanded)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWidthTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWidthTrait]; + } + + tem = FONT_WEIGHT_SYMBOLIC (font_spec); + + if (!NILP (tem)) + { + if (EQ (tem, Qbold)) + { + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWeightTrait]; + } + else if (EQ (tem, Qlight)) + { + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWeightTrait]; + } + else + { + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWeightTrait]; + } + } + + tem = AREF (font_spec, FONT_SPACING_INDEX); if (family != nil) { - NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family]; - fdesc = [[fdesc2 retain] autorelease]; + [fdAttrs setObject: family + forKey: NSFontFamilyAttribute]; } - [fdAttrs release]; + if (FIXNUMP (tem)) + { + if (XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL) + { + [fdAttrs setObject: [NSNumber numberWithBool:YES] + forKey: NSFontFixedAdvanceAttribute]; + } + else + { + [fdAttrs setObject: [NSNumber numberWithBool:NO] + forKey: NSFontFixedAdvanceAttribute]; + } + } + + /* Handle special families such as ``fixed'' or ``Sans Serif''. */ + + if ([family isEqualToString: @"fixed"]) + { + [fdAttrs setObject: [[NSFont userFixedPitchFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + else if ([family isEqualToString: @"Sans Serif"]) + { + [fdAttrs setObject: [[NSFont userFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + + [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + + fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] + retain] autorelease]; + [tdict release]; + [fdAttrs release]; return fdesc; } @@ -161,61 +433,64 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, Lisp_Object extra, const char *style) { - Lisp_Object font_entity = font_make_entity (); - /* NSString *psName = [desc postscriptName]; */ - NSString *family = [desc objectForKey: NSFontFamilyAttribute]; - unsigned int traits = [desc symbolicTraits]; - char *escapedFamily; - - /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */ - if (family == nil) - family = [desc objectForKey: NSFontNameAttribute]; - if (family == nil) - family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - - escapedFamily = xstrdup ([family UTF8String]); - ns_escape_name (escapedFamily); - - ASET (font_entity, FONT_TYPE_INDEX, Qns); - ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple); - ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily)); - ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); - ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); - - FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - traits & NSFontBoldTrait ? Qbold : Qmedium); -/* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - traits & NSFontItalicTrait ? Qitalic : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - traits & NSFontCondensedTrait ? Qcondensed : - traits & NSFontExpandedTrait ? Qexpanded : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/ - - ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_SPACING_INDEX, - make_fixnum([desc symbolicTraits] & NSFontMonoSpaceTrait - ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); - - ASET (font_entity, FONT_EXTRA_INDEX, extra); - ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + Lisp_Object font_entity = font_make_entity (); + struct gs_font_data data; + ns_get_font_data (desc, &data); + + ASET (font_entity, FONT_TYPE_INDEX, Qns); + ASET (font_entity, FONT_FOUNDRY_INDEX, Qns); + if (data.specified & GS_SPECIFIED_FAMILY) + ASET (font_entity, FONT_FAMILY_INDEX, intern (data.family_name)); + ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); + ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); + + if (data.specified & GS_SPECIFIED_WEIGHT) + { + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, + data.weight == GS_FONT_WEIGHT_BOLD + ? Qbold : (data.weight == GS_FONT_WEIGHT_LIGHT + ? Qlight : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, Qnormal); - if (NSFONT_TRACE) - { - fputs ("created font_entity:\n ", stderr); - debug_print (font_entity); - } + if (data.specified & GS_SPECIFIED_SLANT) + { + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, + data.slant == GS_FONT_SLANT_ITALIC + ? Qitalic : (data.slant == GS_FONT_SLANT_REVERSE_ITALIC + ? intern ("reverse-italic") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, Qnormal); + + if (data.specified & GS_SPECIFIED_WIDTH) + { + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, + data.width == GS_FONT_WIDTH_CONDENSED + ? Qcondensed : (data.width == GS_FONT_WIDTH_EXPANDED + ? intern ("expanded") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, Qnormal); - xfree (escapedFamily); - return font_entity; + ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_SPACING_INDEX, + make_fixnum ((data.specified & GS_SPECIFIED_WIDTH && data.monospace_p) + ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); + + ASET (font_entity, FONT_EXTRA_INDEX, extra); + ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + + if (NSFONT_TRACE) + { + fputs ("created font_entity:\n ", stderr); + debug_print (font_entity); + } + + ns_done_font_data (&data); + return font_entity; } @@ -223,8 +498,7 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, static Lisp_Object ns_fallback_entity (void) { - return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0] - fontDescriptor], Qnil, NULL); + return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 1] fontDescriptor], Qnil, NULL); } @@ -510,21 +784,20 @@ but also for ascii (which causes unnecessary font substitution). */ return families; } +/* GNUstep font matching is very mediocre (it can't even compare + symbolic styles correctly), which is why our own font matching + mechanism must be implemented. */ -/* Implementation for list() and match(). List() can return nil, match() -must return something. Strategy is to drop family name from attribute -matching set for match. */ +/* Implementation for list and match. */ static Lisp_Object ns_findfonts (Lisp_Object font_spec, BOOL isMatch) { Lisp_Object tem, list = Qnil; - NSFontDescriptor *fdesc, *desc; - NSMutableSet *fkeys; - NSArray *matchingDescs; - NSEnumerator *dEnum; - NSString *family; + NSFontDescriptor *fdesc; + NSArray *all_descs; + GSFontEnumerator *enumerator = [GSFontEnumerator sharedEnumerator]; + NSSet *cFamilies; - BOOL foundItal = NO; block_input (); if (NSFONT_TRACE) @@ -537,43 +810,22 @@ but also for ascii (which causes unnecessary font substitution). */ cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90); fdesc = ns_spec_to_descriptor (font_spec); - fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]]; - if (isMatch) - [fkeys removeObject: NSFontFamilyAttribute]; - - matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys]; + all_descs = [enumerator availableFontDescriptors]; - if (NSFONT_TRACE) - NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc, - (unsigned long)[matchingDescs count]); - - for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);) + for (NSFontDescriptor *desc in all_descs) { if (![cFamilies containsObject: [desc objectForKey: NSFontFamilyAttribute]]) continue; + if (!ns_font_descs_match_p (fdesc, desc)) + continue; + tem = ns_descriptor_to_entity (desc, - AREF (font_spec, FONT_EXTRA_INDEX), + AREF (font_spec, FONT_EXTRA_INDEX), NULL); if (isMatch) return tem; list = Fcons (tem, list); - if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05) - foundItal = YES; - } - - /* Add synthItal member if needed. */ - family = [fdesc objectForKey: NSFontFamilyAttribute]; - if (family != nil && !foundItal && !NILP (list)) - { - NSFontDescriptor *s1 = [NSFontDescriptor new]; - NSFontDescriptor *sDesc - = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait] - fontDescriptorWithFamily: family]; - list = Fcons (ns_descriptor_to_entity (sDesc, - AREF (font_spec, FONT_EXTRA_INDEX), - "synthItal"), list); - [s1 release]; } unblock_input (); @@ -652,7 +904,6 @@ Properties to be considered are same as for list(). */ objectEnumerator]; while ((family = [families nextObject])) list = Fcons (intern ([family UTF8String]), list); - /* FIXME: escape the name? */ if (NSFONT_TRACE) fprintf (stderr, "nsfont: list families returning %"pD"d entries\n", @@ -668,18 +919,15 @@ Properties to be considered are same as for list(). */ static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size) { - BOOL synthItal; - unsigned int traits = 0; struct nsfont_info *font_info; struct font *font; NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity); NSFontManager *fontMgr = [NSFontManager sharedFontManager]; NSString *family; NSFont *nsfont, *sfont; - Lisp_Object tem; NSRect brect; Lisp_Object font_object; - int fixLeopardBug; + Lisp_Object tem; block_input (); @@ -692,42 +940,20 @@ Properties to be considered are same as for list(). */ if (pixel_size <= 0) { /* try to get it out of frame params */ - Lisp_Object tem = get_frame_param (f, Qfontsize); - pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); + tem = get_frame_param (f, Qfontsize); + pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); } tem = AREF (font_entity, FONT_ADSTYLE_INDEX); - synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)), - 9); family = ns_get_family (font_entity); if (family == nil) family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that - when setting family in ns_spec_to_descriptor(). */ - if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F) - traits |= NSBoldFontMask; - if (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F) - traits |= NSItalicFontMask; - - /* see https://web.archive.org/web/20100201175731/http://cocoadev.com/forums/comments.php?DiscussionID=74 */ - fixLeopardBug = traits & NSBoldFontMask ? 10 : 5; - nsfont = [fontMgr fontWithFamily: family - traits: traits weight: fixLeopardBug - size: pixel_size]; - /* if didn't find, try synthetic italic */ - if (nsfont == nil && synthItal) - { - nsfont = [fontMgr fontWithFamily: family - traits: traits & ~NSItalicFontMask - weight: fixLeopardBug size: pixel_size]; - } + + nsfont = [NSFont fontWithDescriptor: fontDesc + size: pixel_size]; if (nsfont == nil) - { - message_with_string ("*** Warning: font in family `%s' not found", - build_string ([family UTF8String]), 1); - nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; - } + nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; if (NSFONT_TRACE) NSLog (@"%@\n", nsfont); @@ -740,7 +966,7 @@ when setting family in ns_spec_to_descriptor(). */ if (!font) { unblock_input (); - return Qnil; /* FIXME: other terms do, but returning Qnil causes segfault. */ + return Qnil; } font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs); @@ -781,7 +1007,7 @@ when setting family in ns_spec_to_descriptor(). */ font_info->name = xstrdup (fontName); font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask; font_info->ital = - synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); + ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); /* Metrics etc.; some fonts return an unusually large max advance, so we only use it for fonts that have wide characters. */ @@ -808,8 +1034,6 @@ when setting family in ns_spec_to_descriptor(). */ lrint (brect.size.width - (CGFloat) font_info->width); /* set up metrics portion of font struct */ - font->ascent = lrint([sfont ascender]); - font->descent = -lrint(floor(adjusted_descender)); font->space_width = lrint (ns_char_width (sfont, ' ')); font->max_width = lrint (font_info->max_bounds.width); font->min_width = font->space_width; /* Approximate. */ @@ -871,7 +1095,7 @@ when setting family in ns_spec_to_descriptor(). */ { struct nsfont_info *font_info = (struct nsfont_info *)font; unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff; - unsigned short g; + unsigned int g; if (c > 0xFFFF) return FONT_INVALID_CODE; @@ -934,51 +1158,23 @@ is false when (FROM > 0 || TO < S->nchars). */ static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, bool with_background) -/* NOTE: focus and clip must be set. */ { - static unsigned char cbuf[1024]; - unsigned char *c = cbuf; -#if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22 - static CGFloat advances[1024]; - CGFloat *adv = advances; -#else - static float advances[1024]; - float *adv = advances; -#endif + NSGlyph *c = alloca ((to - from) * sizeof *c); + struct face *face; NSRect r; struct nsfont_info *font; - NSColor *col, *bgCol; - unsigned *t = s->char2b; - int i, len, flags; + NSColor *col; + int len = to - from; char isComposite = s->first_glyph->type == COMPOSITE_GLYPH; block_input (); - font = (struct nsfont_info *)s->face->font; + font = (struct nsfont_info *) s->font; if (font == NULL) font = (struct nsfont_info *)FRAME_FONT (s->f); - /* Select face based on input flags. */ - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - - switch (flags) - { - case NS_DUMPGLYPH_CURSOR: - face = s->face; - break; - case NS_DUMPGLYPH_MOUSEFACE: - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - break; - default: - face = s->face; - } + face = s->face; r.origin.x = s->x; if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p) @@ -987,91 +1183,24 @@ is false when (FROM > 0 || TO < S->nchars). */ r.origin.y = s->y; r.size.height = FONT_HEIGHT (font); - /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask - NS to render the string, it will come out differently from the individual - character widths added up because of layout processing. */ - { - int cwidth, twidth = 0; - int hi, lo; - /* FIXME: composition: no vertical displacement is considered. */ - t += from; /* advance into composition */ - for (i = from; i < to; i++, t++) - { - hi = (*t & 0xFF00) >> 8; - lo = *t & 0x00FF; - if (isComposite) - { - if (!s->first_glyph->u.cmp.automatic) - cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth; - else - { - Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); - Lisp_Object glyph = LGSTRING_GLYPH (gstring, i); - if (NILP (LGLYPH_ADJUSTMENT (glyph))) - cwidth = LGLYPH_WIDTH (glyph); - else - { - cwidth = LGLYPH_WADJUST (glyph); - *(adv-1) += LGLYPH_XOFF (glyph); - } - } - } - else - { - if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */ - ns_glyph_metrics (font, hi); - cwidth = font->metrics[hi][lo].width; - } - twidth += cwidth; - *adv++ = cwidth; - c += CHAR_STRING (*t, c); /* This converts the char to UTF-8. */ - } - len = adv - advances; - r.size.width = twidth; - *c = 0; - } + for (int i = from; i < to; ++i) + c[i] = s->char2b[i]; /* Fill background if requested. */ if (with_background && !isComposite) { - NSRect br = r; - int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); - int mbox_line_width = max (s->face->box_vertical_line_width, 0); - - if (s->row->full_width_p) - { - if (br.origin.x <= fibw + 1 + mbox_line_width) - { - br.size.width += br.origin.x - mbox_line_width; - br.origin.x = mbox_line_width; - } - if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) - <= fibw+1) - br.size.width += fibw; - } - if (s->face->box == FACE_NO_BOX) - { - /* Expand unboxed top row over internal border. */ - if (br.origin.y <= fibw + 1 + mbox_line_width) - { - br.size.height += br.origin.y; - br.origin.y = 0; - } - } - else - { - int correction = abs (s->face->box_horizontal_line_width)+1; - br.origin.y += correction; - br.size.height -= 2*correction; - correction = abs (s->face->box_vertical_line_width)+1; - br.origin.x += correction; - br.size.width -= 2*correction; - } + NSRect br = NSMakeRect (x, y - FONT_BASE (s->font), + s->width, FONT_HEIGHT (s->font)); if (!s->face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); @@ -1080,43 +1209,32 @@ is false when (FROM > 0 || TO < S->nchars). */ NSRectFill (br); } - /* set up for character rendering */ r.origin.y = y; - col = (NS_FACE_FOREGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - - bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil - : (NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f))); + if (s->hl == DRAW_CURSOR) + col = FRAME_BACKGROUND_COLOR (s->f); + else + col = (NS_FACE_FOREGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) + : FRAME_FOREGROUND_COLOR (s->f)); /* render under GNUstep using DPS */ { - NSGraphicsContext *context = GSCurrentContext (); - + NSGraphicsContext *context = [NSGraphicsContext currentContext]; DPSgsave (context); - [font->nsfont set]; - - /* do erase if "foreground" mode */ - if (bgCol != nil) + if (s->clip_head) { - [bgCol set]; - DPSmoveto (context, r.origin.x, r.origin.y); -/*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */ - DPSxshow (context, (const char *) cbuf, advances, len); - DPSstroke (context); - [col set]; -/*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */ + DPSrectclip (context, s->clip_head->x, 0, + FRAME_PIXEL_WIDTH (s->f), + FRAME_PIXEL_HEIGHT (s->f)); } + [font->nsfont set]; [col set]; - /* draw with DPSxshow () */ DPSmoveto (context, r.origin.x, r.origin.y); - DPSxshow (context, (const char *) cbuf, advances, len); + GSShowGlyphs (context, c, len); DPSstroke (context); DPSgrestore (context); @@ -1126,6 +1244,360 @@ is false when (FROM > 0 || TO < S->nchars). */ return to-from; } +static NSUInteger +ns_font_shape (NSFont *font, NSString *string, + struct ns_glyph_layout *glyph_layouts, NSUInteger glyph_len, + enum lgstring_direction dir) +{ + NSUInteger i; + NSUInteger result = 0; + NSTextStorage *textStorage; + NSLayoutManager *layoutManager; + NSTextContainer *textContainer; + NSUInteger stringLength; + NSPoint spaceLocation; + /* numberOfGlyphs can't actually be 0, but this pacifies GCC */ + NSUInteger used, numberOfGlyphs = 0; + + textStorage = [[NSTextStorage alloc] initWithString:string]; + layoutManager = [[NSLayoutManager alloc] init]; + textContainer = [[NSTextContainer alloc] init]; + + /* Append a trailing space to measure baseline position. */ + [textStorage appendAttributedString:([[[NSAttributedString alloc] + initWithString:@" "] autorelease])]; + [textStorage setFont:font]; + [textContainer setLineFragmentPadding:0]; + + [layoutManager addTextContainer:textContainer]; + [textContainer release]; + [textStorage addLayoutManager:layoutManager]; + [layoutManager release]; + + if (!(textStorage && layoutManager && textContainer)) + emacs_abort (); + + stringLength = [string length]; + + /* Force layout. */ + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength]; + + /* Remove the appended trailing space because otherwise it may + generate a wrong result for a right-to-left text. */ + [textStorage beginEditing]; + [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))]; + [textStorage endEditing]; + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + i = 0; + while (i < stringLength) + { + NSRange range; + NSFont *fontInTextStorage = + [textStorage attribute: NSFontAttributeName + atIndex:i + longestEffectiveRange: &range + inRange: NSMakeRange (0, stringLength)]; + + if (!(fontInTextStorage == font + || [[fontInTextStorage fontName] isEqualToString:[font fontName]])) + break; + i = NSMaxRange (range); + } + if (i < stringLength) + /* Make the test `used <= glyph_len' below fail if textStorage + contained some fonts other than the specified one. */ + used = glyph_len + 1; + else + { + NSRange range = NSMakeRange (0, stringLength); + + range = [layoutManager glyphRangeForCharacterRange:range + actualCharacterRange:NULL]; + numberOfGlyphs = NSMaxRange (range); + used = numberOfGlyphs; + for (i = 0; i < numberOfGlyphs; i++) + if ([layoutManager notShownAttributeForGlyphAtIndex:i]) + used--; + } + + if (0 < used && used <= glyph_len) + { + NSUInteger glyphIndex, prevGlyphIndex; + NSUInteger *permutation; + NSRange compRange, range; + CGFloat totalAdvance; + + glyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + permutation = NULL; +#define RIGHT_TO_LEFT_P permutation + + /* Fill the `comp_range' member of struct mac_glyph_layout, and + setup a permutation for right-to-left text. */ + compRange = NSMakeRange (0, 0); + for (range = NSMakeRange (0, 0); NSMaxRange (range) < used; + range.length++) + { + struct ns_glyph_layout *gl = glyph_layouts + NSMaxRange (range); + NSUInteger characterIndex = + [layoutManager characterIndexForGlyphAtIndex:glyphIndex]; + + gl->string_index = characterIndex; + + if (characterIndex >= NSMaxRange (compRange)) + { + compRange.location = NSMaxRange (compRange); + do + { + NSRange characterRange = + [string + rangeOfComposedCharacterSequenceAtIndex:characterIndex]; + + compRange.length = + NSMaxRange (characterRange) - compRange.location; + [layoutManager glyphRangeForCharacterRange:compRange + actualCharacterRange:&characterRange]; + characterIndex = NSMaxRange (characterRange) - 1; + } + while (characterIndex >= NSMaxRange (compRange)); + + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + range = NSMakeRange (NSMaxRange (range), 0); + } + + gl->comp_range.location = compRange.location; + gl->comp_range.length = compRange.length; + + while (++glyphIndex < numberOfGlyphs) + if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + break; + } + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + /* Then fill the remaining members. */ + glyphIndex = prevGlyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + if (!RIGHT_TO_LEFT_P) + totalAdvance = 0; + else + { + NSUInteger nrects; + NSRect *glyphRects = + [layoutManager + rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs)) + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + + totalAdvance = NSMaxX (glyphRects[0]); + } + + for (i = 0; i < used; i++) + { + struct ns_glyph_layout *gl; + NSPoint location; + NSUInteger nextGlyphIndex; + NSRange glyphRange; + NSRect *glyphRects; + NSUInteger nrects; + + if (!RIGHT_TO_LEFT_P) + gl = glyph_layouts + i; + else + { + NSUInteger dest = permutation[i]; + + gl = glyph_layouts + dest; + if (i < dest) + { + NSUInteger tmp = gl->string_index; + + gl->string_index = glyph_layouts[i].string_index; + glyph_layouts[i].string_index = tmp; + } + } + gl->glyph_id = [layoutManager glyphAtIndex: glyphIndex]; + + location = [layoutManager locationForGlyphAtIndex:glyphIndex]; + gl->baseline_delta = spaceLocation.y - location.y; + + for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs; + nextGlyphIndex++) + if (![layoutManager + notShownAttributeForGlyphAtIndex:nextGlyphIndex]) + break; + + if (!RIGHT_TO_LEFT_P) + { + CGFloat maxX; + + if (prevGlyphIndex == 0) + glyphRange = NSMakeRange (0, nextGlyphIndex); + else + glyphRange = NSMakeRange (glyphIndex, + nextGlyphIndex - glyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + maxX = max (NSMaxX (glyphRects[0]), totalAdvance); + gl->advance_delta = location.x - totalAdvance; + gl->advance = maxX - totalAdvance; + totalAdvance = maxX; + } + else + { + CGFloat minX; + + if (nextGlyphIndex == numberOfGlyphs) + glyphRange = NSMakeRange (prevGlyphIndex, + numberOfGlyphs - prevGlyphIndex); + else + glyphRange = NSMakeRange (prevGlyphIndex, + glyphIndex + 1 - prevGlyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + minX = min (NSMinX (glyphRects[0]), totalAdvance); + gl->advance = totalAdvance - minX; + totalAdvance = minX; + gl->advance_delta = location.x - totalAdvance; + } + + prevGlyphIndex = glyphIndex + 1; + glyphIndex = nextGlyphIndex; + } + + if (RIGHT_TO_LEFT_P) + xfree (permutation); + +#undef RIGHT_TO_LEFT_P + + result = used; + } + [textStorage release]; + + return result; +} + +static Lisp_Object +nsfont_shape (Lisp_Object lgstring, Lisp_Object direction) +{ + struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring)); + struct nsfont_info *font_info = (struct nsfont_info *) font; + struct ns_glyph_layout *glyph_layouts; + NSFont *nsfont = font_info->nsfont; + ptrdiff_t glyph_len, len, i; + Lisp_Object tem; + unichar *mb_buf; + NSUInteger used; + + glyph_len = LGSTRING_GLYPH_LEN (lgstring); + for (i = 0; i < glyph_len; ++i) + { + tem = LGSTRING_GLYPH (lgstring, i); + + if (NILP (tem)) + break; + } + + len = i; + + if (INT_MAX / 2 < len) + memory_full (SIZE_MAX); + + block_input (); + + mb_buf = alloca (len * sizeof *mb_buf); + + for (i = 0; i < len; ++i) + { + uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i)); + mb_buf[i] = (unichar) c; + } + + NSString *string = [NSString stringWithCharacters: mb_buf + length: len]; + unblock_input (); + + if (!string) + return Qnil; + + block_input (); + + enum lgstring_direction dir = DIR_UNKNOWN; + + if (EQ (direction, QL2R)) + dir = DIR_L2R; + else if (EQ (direction, QR2L)) + dir = DIR_R2L; + glyph_layouts = alloca (sizeof (struct ns_glyph_layout) * glyph_len); + used = ns_font_shape (nsfont, string, glyph_layouts, glyph_len, dir); + + for (i = 0; i < used; i++) + { + Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i); + struct ns_glyph_layout *gl = glyph_layouts + i; + EMACS_INT from, to; + struct font_metrics metrics; + + if (NILP (lglyph)) + { + lglyph = LGLYPH_NEW (); + LGSTRING_SET_GLYPH (lgstring, i, lglyph); + } + + from = gl->comp_range.location; + LGLYPH_SET_FROM (lglyph, from); + + to = gl->comp_range.location + gl->comp_range.length; + LGLYPH_SET_TO (lglyph, to - 1); + + /* LGLYPH_CHAR is used in `describe-char' for checking whether + the composition is trivial. */ + { + UTF32Char c; + + if (mb_buf[gl->string_index] >= 0xD800 + && mb_buf[gl->string_index] < 0xDC00) + c = (((mb_buf[gl->string_index] - 0xD800) << 10) + + (mb_buf[gl->string_index + 1] - 0xDC00) + 0x10000); + else + c = mb_buf[gl->string_index]; + + LGLYPH_SET_CHAR (lglyph, c); + } + + { + unsigned long cc = gl->glyph_id; + LGLYPH_SET_CODE (lglyph, cc); + } + + nsfont_text_extents (font, &gl->glyph_id, 1, &metrics); + LGLYPH_SET_WIDTH (lglyph, metrics.width); + LGLYPH_SET_LBEARING (lglyph, metrics.lbearing); + LGLYPH_SET_RBEARING (lglyph, metrics.rbearing); + LGLYPH_SET_ASCENT (lglyph, metrics.ascent); + LGLYPH_SET_DESCENT (lglyph, metrics.descent); + } + unblock_input (); + + return make_fixnum (used); +} /* ========================================================================== @@ -1134,6 +1606,50 @@ is false when (FROM > 0 || TO < S->nchars). */ ========================================================================== */ +static NSGlyph +ns_uni_to_glyphs_1 (struct nsfont_info *info, unsigned int c) +{ + unichar characters[] = { c }; + NSString *string = + [NSString stringWithCharacters: characters + length: 1]; + NSDictionary *attributes = + [NSDictionary dictionaryWithObjectsAndKeys: + info->nsfont, NSFontAttributeName, nil]; + NSTextStorage *storage = [[NSTextStorage alloc] initWithString: string + attributes: attributes]; + NSTextContainer *text_container = [[NSTextContainer alloc] init]; + NSLayoutManager *manager = [[NSLayoutManager alloc] init]; + + [manager addTextContainer: text_container]; + [text_container release]; /* Retained by manager */ + [storage addLayoutManager: manager]; + [manager release]; /* Retained by storage */ + + NSFont *font_in_storage = [storage attribute: NSFontAttributeName + atIndex:0 + effectiveRange: NULL]; + NSGlyph glyph = FONT_INVALID_CODE; + + if ((font_in_storage == info->nsfont + || [[font_in_storage fontName] isEqualToString: [info->nsfont fontName]])) + { + @try + { + glyph = [manager glyphAtIndex: 0]; + } + @catch (NSException *e) + { + /* GNUstep bug? */ + glyph = 'X'; + } + } + + [storage release]; + + return glyph; +} + /* Find and cache corresponding glyph codes for unicode values in given hi-byte block of 256. */ static void @@ -1141,7 +1657,7 @@ is false when (FROM > 0 || TO < S->nchars). */ { unichar *unichars = xmalloc (0x101 * sizeof (unichar)); unsigned int i, g, idx; - unsigned short *glyphs; + unsigned int *glyphs; if (NSFONT_TRACE) fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n", @@ -1149,7 +1665,7 @@ is false when (FROM > 0 || TO < S->nchars). */ block_input (); - font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short)); + font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned int)); if (!unichars || !(font_info->glyphs[block])) emacs_abort (); @@ -1166,7 +1682,8 @@ is false when (FROM > 0 || TO < S->nchars). */ for (i = 0; i < 0x100; i++, glyphs++) { g = unichars[i]; - *glyphs = g; + NSGlyph glyph = ns_uni_to_glyphs_1 (font_info, g); + *glyphs = glyph; } } @@ -1175,18 +1692,19 @@ is false when (FROM > 0 || TO < S->nchars). */ } -/* Determine and cache metrics for corresponding glyph codes in given - hi-byte block of 256. */ +/* Determine and cache metrics for glyphs in given hi-byte block of + 256. */ static void -ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block) +ns_glyph_metrics (struct nsfont_info *font_info, unsigned int block) { - unsigned int i, g; + unsigned int i; + NSGlyph g; unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs]; NSFont *sfont; struct font_metrics *metrics; if (NSFONT_TRACE) - fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n", + fprintf (stderr, "%p\tComputing metrics for glyphs in block %u\n", font_info, block); /* not implemented yet (as of startup 0.18), so punt */ @@ -1209,19 +1727,14 @@ is false when (FROM > 0 || TO < S->nchars). */ w = max ([sfont advancementForGlyph: g].width, 2.0); metrics->width = lrint (w); - lb = r.origin.x; - rb = r.size.width - w; - // Add to bearing for LCD smoothing. We don't know if it is there. - if (lb < 0) - metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN); - if (font_info->ital) - rb += (CGFloat) (0.22F * font_info->height); - metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN); - - metrics->descent = r.origin.y < 0 ? -r.origin.y : 0; - /* lrint (hshrink * [sfont ascender] + expand * hd/2); */ - metrics->ascent = r.size.height - metrics->descent; - /* -lrint (hshrink* [sfont descender] - expand * hd/2); */ + lb = NSMinX (r); + rb = NSMaxX (r); + + metrics->rbearing = lrint (rb); + metrics->lbearing = lrint (lb); + + metrics->descent = NSMinY (r); + metrics->ascent = NSMaxY (r); } unblock_input (); } @@ -1257,6 +1770,7 @@ is false when (FROM > 0 || TO < S->nchars). */ .has_char = nsfont_has_char, .encode_char = nsfont_encode_char, .text_extents = nsfont_text_extents, + .shape = nsfont_shape, .draw = nsfont_draw, }; @@ -1265,7 +1779,6 @@ is false when (FROM > 0 || TO < S->nchars). */ { DEFSYM (Qcondensed, "condensed"); DEFSYM (Qexpanded, "expanded"); - DEFSYM (Qapple, "apple"); DEFSYM (Qmedium, "medium"); DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script, doc: /* Internal use: maps font registry to Unicode script. */); diff --git a/src/nsterm.h b/src/nsterm.h index 4bbcf43973..944dbd727c 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -820,7 +820,7 @@ #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) XCharStruct max_bounds; /* We compute glyph codes and metrics on-demand in blocks of 256 indexed by hibyte, lobyte. */ - unsigned short **glyphs; /* map Unicode index to glyph */ + unsigned int **glyphs; /* map Unicode index to glyph */ struct font_metrics **metrics; }; #endif diff --git a/src/nsterm.m b/src/nsterm.m index e8848b39b7..37580c39ef 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1077,11 +1077,16 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) /* clipping */ if (r) { - [[NSGraphicsContext currentContext] saveGraphicsState]; + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; +#ifdef NS_IMPL_COCOA if (n == 2) NSRectClipList (r, 2); else NSRectClip (*r); +#else + GSRectClipList (ctx, r, n); +#endif gsaved = YES; } } @@ -2433,9 +2438,6 @@ Hide the window (X11 semantics) EmacsView *view = FRAME_NS_VIEW (f); FRAME_POINTER_TYPE (f) = cursor; [[view window] invalidateCursorRectsForView: view]; - /* Redisplay assumes this function also draws the changed frame - cursor, but this function doesn't, so do it explicitly. */ - gui_update_cursor (f, 1); } } @@ -2847,31 +2849,31 @@ Hide the window (X11 semantics) External (RIF); compute left/right overhang of whole string and set in s -------------------------------------------------------------------------- */ { - struct font *font = s->font; - - if (s->char2b) + if (s->cmp == NULL + && (s->first_glyph->type == CHAR_GLYPH + || s->first_glyph->type == COMPOSITE_GLYPH)) { struct font_metrics metrics; - unsigned int codes[2]; - codes[0] = *(s->char2b); - codes[1] = *(s->char2b + s->nchars - 1); - font->driver->text_extents (font, codes, 2, &metrics); - s->left_overhang = -metrics.lbearing; - s->right_overhang - = metrics.rbearing > metrics.width - ? metrics.rbearing - metrics.width : 0; + if (s->first_glyph->type == CHAR_GLYPH) + { + struct font *font = s->font; + font->driver->text_extents (font, s->char2b, s->nchars, &metrics); + } + else + { + Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); + + composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); + } + s->right_overhang = (metrics.rbearing > metrics.width + ? metrics.rbearing - metrics.width : 0); + s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0; } - else + else if (s->cmp) { - s->left_overhang = 0; -#ifdef NS_IMPL_GNUSTEP - if (EQ (font->driver->type, Qns)) - s->right_overhang = ((struct nsfont_info *)font)->ital ? - FONT_HEIGHT (font) * 0.2 : 0; - else -#endif - s->right_overhang = 0; + s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width; + s->left_overhang = - s->cmp->lbearing; } } @@ -3011,14 +3013,13 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. struct frame *f = WINDOW_XFRAME (w); struct glyph *phys_cursor_glyph; struct glyph *cursor_glyph; - struct face *face; - NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f); /* If cursor is out of bounds, don't draw garbage. This can happen in mini-buffer windows when switching between echo area glyphs and mini-buffer. */ - NSTRACE ("ns_draw_window_cursor"); + NSTRACE ("ns_draw_window_cursor (on = %d, cursor_type = %d)", + on_p, cursor_type); if (!on_p) return; @@ -3034,6 +3035,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL) { + NSTRACE_MSG ("No phys cursor glyph was found!"); + if (glyph_row->exact_window_width_line_p && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) { @@ -3043,10 +3046,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. return; } - /* We draw the cursor (with NSRectFill), then draw the glyph on top - (other terminals do it the other way round). We must set - w->phys_cursor_width to the cursor width. For bar cursors, that - is CURSOR_WIDTH; for box cursors, it is the glyph width. */ get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h); /* The above get_phys_cursor_geometry call set w->phys_cursor_width @@ -3078,17 +3077,17 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. /* Prevent the cursor from being drawn outside the text area. */ r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA)); - ns_focus (f, &r, 1); + ns_focus (f, NULL, 0); - face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id); - if (face && NS_FACE_BACKGROUND (face) - == ns_index_color (FRAME_CURSOR_COLOR (f), f)) - { - [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set]; - hollow_color = FRAME_CURSOR_COLOR (f); - } - else - [FRAME_CURSOR_COLOR (f) set]; + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; +#ifdef NS_IMPL_GNUSTEP + GSRectClipList (ctx, &r, 1); +#else + NSRectClip (r); +#endif + + [FRAME_CURSOR_COLOR (f) set]; switch (cursor_type) { @@ -3096,13 +3095,11 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. case NO_CURSOR: break; case FILLED_BOX_CURSOR: - NSRectFill (r); + draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); break; case HOLLOW_BOX_CURSOR: - NSRectFill (r); - [hollow_color set]; - NSRectFill (NSInsetRect (r, 1, 1)); - [FRAME_CURSOR_COLOR (f) set]; + draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT); + [NSBezierPath strokeRect: r]; break; case HBAR_CURSOR: NSRectFill (r); @@ -3118,12 +3115,9 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. NSRectFill (s); break; } - ns_unfocus (f); - /* Draw the character under the cursor. Other terms only draw - the character on top of box cursors, so do the same here. */ - if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR) - draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); + [ctx restoreGraphicsState]; + ns_unfocus (f); } @@ -3303,16 +3297,18 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if (s->for_overlaps) return; + if (s->hl == DRAW_CURSOR) + [FRAME_BACKGROUND_COLOR (s->f) set]; + else if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + /* Do underline. */ if (face->underline) { if (s->face->underline == FACE_UNDER_WAVE) { - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; - ns_draw_underwave (s, width, x); } else if (s->face->underline == FACE_UNDER_LINE) @@ -3383,11 +3379,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. s->underline_position = position; r = NSMakeRect (x, s->ybase + position, width, thickness); - - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; NSRectFill (r); } } @@ -3397,11 +3388,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. { NSRect r; r = NSMakeRect (x, s->y, width, 1); - - if (face->overline_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->overline_color, s->f) set]; NSRectFill (r); } @@ -3424,10 +3410,6 @@ larger if there are taller display elements (e.g., characters dy = lrint ((glyph_height - h) / 2); r = NSMakeRect (x, glyph_y + dy, width, 1); - if (face->strike_through_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->strike_through_color, s->f) set]; NSRectFill (r); } } @@ -3575,17 +3557,7 @@ Function modeled after x_draw_glyph_string_box (). struct glyph *last_glyph; NSRect r; int hthickness, vthickness; - struct face *face; - - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = s->face; + struct face *face = s->face; vthickness = face->box_vertical_line_width; hthickness = face->box_horizontal_line_width; @@ -3659,34 +3631,26 @@ Function modeled after x_draw_glyph_string_box (). || FONT_TOO_HIGH (s->font) || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) { - struct face *face; - if (s->hl == DRAW_MOUSE_FACE) - { - face - = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + struct face *face = s->face; if (!face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set]; } - if (s->hl != DRAW_CURSOR) - { - NSRect r = NSMakeRect (s->x, s->y + box_line_width, - s->background_width, - s->height-2*box_line_width); - NSRectFill (r); - } + NSRect r = NSMakeRect (s->x, s->y + box_line_width, + s->background_width, + s->height-2*box_line_width); + NSRectFill (r); s->background_filled_p = 1; } @@ -3707,7 +3671,7 @@ Function modeled after x_draw_glyph_string_box (). int th; char raised_p; NSRect br; - struct face *face; + struct face *face = s->face; NSColor *tdCol; NSTRACE ("ns_dumpglyphs_image"); @@ -3728,15 +3692,6 @@ Function modeled after x_draw_glyph_string_box (). /* Draw BG: if we need larger area than image itself cleared, do that, otherwise, since we composite the image under NS (instead of mucking with its background color), we must clear just the image area. */ - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set]; @@ -3807,16 +3762,8 @@ Function modeled after x_draw_glyph_string_box (). if (s->hl == DRAW_CURSOR) { - [FRAME_CURSOR_COLOR (s->f) set]; - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) + [FRAME_CURSOR_COLOR (s->f) set]; tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); - else - /* Currently on NS img->mask is always 0. Since - get_window_cursor_type specifies a hollow box cursor when on - a non-masked image we never reach this clause. But we put it - in, in anticipation of better support for image masks on - NS. */ - tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); } else { @@ -3868,66 +3815,35 @@ Function modeled after x_draw_glyph_string_box (). static void ns_dumpglyphs_stretch (struct glyph_string *s) { - NSRect r[2]; NSRect glyphRect; - int n; - struct face *face; + struct face *face = s->face; NSColor *fgCol, *bgCol; if (!s->background_filled_p) { - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + face = s->face; bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); - glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); - - [bgCol set]; - - /* NOTE: under NS this is NOT used to draw cursors, but we must avoid - overwriting cursor (usually when cursor on a tab) */ if (s->hl == DRAW_CURSOR) - { - CGFloat x, width; + { + fgCol = bgCol; + bgCol = FRAME_CURSOR_COLOR (s->f); + } - /* FIXME: This looks like it will only work for left to - right languages. */ - x = NSMinX (glyphRect); - width = s->w->phys_cursor_width; - glyphRect.size.width -= width; - glyphRect.origin.x += width; + glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); - NSRectFill (glyphRect); + [bgCol set]; - /* Draw overlining, etc. on the cursor. */ - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) - ns_draw_text_decoration (s, face, bgCol, width, x); - else - ns_draw_text_decoration (s, face, fgCol, width, x); - } - else - { - NSRectFill (glyphRect); - } + NSRectFill (glyphRect); /* Draw overlining, etc. on the stretch glyph (or the part of the stretch glyph after the cursor). */ ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect), NSMinX (glyphRect)); - ns_unfocus (s->f); s->background_filled_p = 1; } } @@ -3936,7 +3852,7 @@ overwriting cursor (usually when cursor on a tab) */ static void ns_draw_glyph_string_foreground (struct glyph_string *s) { - int x, flags; + int x; struct font *font = s->font; /* If first glyph of S has a left box line, start drawing the text @@ -3947,15 +3863,9 @@ overwriting cursor (usually when cursor on a tab) */ else x = s->x; - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - font->driver->draw (s, s->cmp_from, s->nchars, x, s->ybase, - (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p) - || flags == NS_DUMPGLYPH_MOUSEFACE); + !s->for_overlaps && !s->background_filled_p); } @@ -4062,9 +3972,9 @@ overwriting cursor (usually when cursor on a tab) */ struct font *font = s->face->font; if (! font) font = FRAME_FONT (s->f); - NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string"); + NSTRACE ("ns_draw_glyph_string (hl = %u)", s->hl); - if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/) + if (s->next && s->right_overhang && !s->for_overlaps) { int width; struct glyph_string *next; @@ -4101,14 +4011,21 @@ overwriting cursor (usually when cursor on a tab) */ box_drawn_p = 1; } + n = ns_get_glyph_string_clip_rect (s, r); + + if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */ + && !s->clip_tail + && ((s->prev && s->prev->hl != s->hl && s->left_overhang) + || (s->next && s->next->hl != s->hl && s->right_overhang))) + r[0] = NSIntersectionRect (r[0], NSMakeRect (s->x, s->y, s->width, s->height)); + + ns_focus (s->f, r, n); + switch (s->first_glyph->type) { case IMAGE_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); ns_dumpglyphs_image (s, r[0]); - ns_unfocus (s->f); break; case XWIDGET_GLYPH: @@ -4121,57 +4038,36 @@ overwriting cursor (usually when cursor on a tab) */ case CHAR_GLYPH: case COMPOSITE_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - - if (s->for_overlaps || (s->cmp_from > 0 - && ! s->first_glyph->u.cmp.automatic)) - s->background_filled_p = 1; - else - ns_maybe_dumpglyphs_background - (s, s->first_glyph->type == COMPOSITE_GLYPH); - - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - { - BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + if (s->for_overlaps || (isComposite + && (s->cmp_from > 0 + && ! s->first_glyph->u.cmp.automatic))) + s->background_filled_p = 1; + else + ns_maybe_dumpglyphs_background + (s, s->first_glyph->type == COMPOSITE_GLYPH); - if (isComposite) - ns_draw_composite_glyph_string_foreground (s); - else - ns_draw_glyph_string_foreground (s); - } + if (isComposite) + ns_draw_composite_glyph_string_foreground (s); + else + ns_draw_glyph_string_foreground (s); - { - NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), - s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - [col set]; - - /* Draw underline, overline, strike-through. */ - ns_draw_text_decoration (s, s->face, col, s->width, s->x); + { + NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), + s->f) + : FRAME_FOREGROUND_COLOR (s->f)); + [col set]; + + /* Draw underline, overline, strike-through. */ + ns_draw_text_decoration (s, s->face, col, s->width, s->x); + } } - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - - ns_unfocus (s->f); break; case GLYPHLESS_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - if (s->for_overlaps || (s->cmp_from > 0 && ! s->first_glyph->u.cmp.automatic)) s->background_filled_p = 1; @@ -4181,7 +4077,6 @@ overwriting cursor (usually when cursor on a tab) */ /* ... */ /* Not yet implemented. */ /* ... */ - ns_unfocus (s->f); break; default: @@ -4190,13 +4085,92 @@ overwriting cursor (usually when cursor on a tab) */ /* Draw box if not done already. */ if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) + ns_dumpglyphs_box_or_relief (s); + + ns_unfocus (s->f); + + /* Draw surrounding overhangs. */ + if (s->prev) { - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - ns_dumpglyphs_box_or_relief (s); + ns_focus (s->f, NULL, 0); + struct glyph_string *prev; + + for (prev = s->prev; prev; prev = prev->prev) + if (prev->hl != s->hl + && prev->x + prev->width + prev->right_overhang > s->x) + { + /* As prev was drawn while clipped to its own area, we + must draw the right_overhang part using s->hl now. */ + enum draw_glyphs_face save = prev->hl; + struct face *save_face = prev->face; + + prev->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + prev->num_clips = 1; + prev->hl = s->hl; + if (prev->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (prev); + else + ns_draw_composite_glyph_string_foreground (prev); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + [[NSGraphicsContext currentContext] restoreGraphicsState]; + prev->hl = save; + prev->face = save_face; + prev->num_clips = 0; + } ns_unfocus (s->f); } + if (s->next) + { + ns_focus (s->f, NULL, 0); + struct glyph_string *next; + + for (next = s->next; next; next = next->next) + if (next->hl != s->hl + && next->x - next->left_overhang < s->x + s->width) + { + /* As next will be drawn while clipped to its own area, + we must draw the left_overhang part using s->hl now. */ + enum draw_glyphs_face save = next->hl; + struct face *save_face = next->face; + + next->hl = s->hl; + next->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + next->num_clips = 1; + if (next->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (next); + else + ns_draw_composite_glyph_string_foreground (next); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + [[NSGraphicsContext currentContext] restoreGraphicsState]; + next->hl = save; + next->num_clips = 0; + next->face = save_face; + next->clip_head = next; + next->background_filled_p = 0; + } + ns_unfocus (s->f); + } s->num_clips = 0; } diff --git a/src/xdisp.c b/src/xdisp.c index aa01db210b..67c6c74567 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -29300,7 +29300,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, for (s = head; s; s = s->next) FRAME_RIF (f)->draw_glyph_string (s); -#ifndef HAVE_NS /* When focus a sole frame and move horizontally, this clears on_p causing a failure to erase prev cursor position. */ if (area == TEXT_AREA @@ -29319,7 +29318,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, notice_overwritten_cursor (w, TEXT_AREA, x0, x1, row->y, MATRIX_ROW_BOTTOM_Y (row)); } -#endif /* Value is the x-position up to which drawn, relative to AREA of W. This doesn't include parts drawn because of overhangs. */ -- 2.31.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-General-improvements-to-NS-port.patch >From 7266c4c407f618716f5289057de8c8555d0a81aa Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 23 Oct 2021 19:51:31 +0800 Subject: [PATCH 2/2] General improvements to NS port * src/dispextern.h: Remove some !HAVE_NS conditionals around grab related code. * src/frame.c (gui_mouse_grabbed, gui_redo_mouse_highlight): Remove !HAVE_NS conditionals around code. * src/nsmenu.m (ns_update_menubar): Prevent recursive calls and enable shallow updates on GNUstep. (menuNeedsUpdate): Prevent recursive calls. (ns_menu_show): Fix mysterious GC-related bug. (update_frame_tool_bar_1): Work around mysterious toolbar sizing bug on GNUstep. * src/nsterm.h (struct ns_output): New field for tracking toolbar visibility changes. * src/nsterm.m (frame_set_mouse_pixel_position): Implement for GNUstep. (ns_redraw_scroll_bars): Enable for GNUstep. (ns_clear_frame): Redraw scrollbars on GNUstep. (ns_update_window_end): New function. (ns_redisplay_interface): Add ns_update_window_end on GNUstep. (- keyDown): Remove debug code that doesn't work on GNUstep. (- mouseDown): Enable grab tracking on NS port. (- resizeWithOldSuperviewSize): Fix build with NSTRACE. * src/xdisp.c (note_tab_bar_highlight): Enable some code for NS port. --- src/dispextern.h | 2 -- src/frame.c | 4 --- src/nsmenu.m | 76 +++++++++++++++++++++++++++++++++++++++--------- src/nsterm.h | 6 ++++ src/nsterm.m | 42 +++++++++++++++++++++----- src/xdisp.c | 2 -- 6 files changed, 102 insertions(+), 30 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index e03e21fddc..5b28fe7666 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3722,10 +3722,8 @@ #define IMAGE_BACKGROUND_TRANSPARENT(img, f, mask) \ const char *, const char *, enum resource_types); -#ifndef HAVE_NS /* These both used on W32 and X only. */ extern bool gui_mouse_grabbed (Display_Info *); extern void gui_redo_mouse_highlight (Display_Info *); -#endif /* HAVE_NS */ #endif /* HAVE_WINDOW_SYSTEM */ diff --git a/src/frame.c b/src/frame.c index 2b1cb452ef..79a7c89e0d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -5028,8 +5028,6 @@ gui_set_no_special_glyphs (struct frame *f, Lisp_Object new_value, Lisp_Object o } -#ifndef HAVE_NS - /* Non-zero if mouse is grabbed on DPYINFO and we know the frame where it is. */ @@ -5054,8 +5052,6 @@ gui_redo_mouse_highlight (Display_Info *dpyinfo) dpyinfo->last_mouse_motion_y); } -#endif /* HAVE_NS */ - /* Subroutines of creating an X frame. */ /* Make sure that Vx_resource_name is set to a reasonable value. diff --git a/src/nsmenu.m b/src/nsmenu.m index 05b89c2f56..b93d3a79bd 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -101,6 +101,15 @@ static void ns_update_menubar (struct frame *f, bool deep_p) { +#ifdef NS_IMPL_GNUSTEP + static int inside = 0; + + if (inside) + return; + + inside++; +#endif + BOOL needsSet = NO; id menu = [NSApp mainMenu]; bool owfi; @@ -120,7 +129,12 @@ NSTRACE ("ns_update_menubar"); if (f != SELECTED_FRAME () || FRAME_EXTERNAL_MENU_BAR (f) == 0) + { +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif return; + } XSETFRAME (Vmenu_updating_frame, f); /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */ @@ -144,10 +158,6 @@ t = -(1000*tb.time+tb.millitm); #endif -#ifdef NS_IMPL_GNUSTEP - deep_p = 1; /* See comment in menuNeedsUpdate. */ -#endif - if (deep_p) { /* Make a widget-value tree representing the entire menu trees. */ @@ -275,6 +285,9 @@ free_menubar_widget_value_tree (first_wv); discard_menu_items (); unbind_to (specpdl_count, Qnil); +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif return; } @@ -408,6 +421,10 @@ if (needsSet) [NSApp setMainMenu: menu]; +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif + unblock_input (); } @@ -490,17 +507,34 @@ - (instancetype)initWithTitle: (NSString *)title call to ns_update_menubar. */ - (void)menuNeedsUpdate: (NSMenu *)menu { +#ifdef NS_IMPL_GNUSTEP + static int inside = 0; +#endif + if (!FRAME_LIVE_P (SELECTED_FRAME ())) return; -#ifdef NS_IMPL_COCOA -/* TODO: GNUstep calls this method when the menu is still being built - which results in a recursive stack overflow. One possible solution - is to use menuWillOpen instead, but the Apple docs explicitly warn - against changing the contents of the menu in it. I don't know what - the right thing to do for GNUstep is. */ +#ifdef NS_IMPL_GNUSTEP + /* GNUstep calls this method when the menu is still being built + which results in a recursive stack overflow, which this variable + prevents. */ + + if (!inside) + ++inside; + else + return; +#endif + if (needsUpdate) - ns_update_menubar (SELECTED_FRAME (), true); + { +#ifdef NS_IMPL_GNUSTEP + needsUpdate = NO; +#endif + ns_update_menubar (SELECTED_FRAME (), true); + } + +#ifdef NS_IMPL_GNUSTEP + --inside; #endif } @@ -827,6 +861,9 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item p.x = x; p.y = y; + /* Don't GC due to a mysterious bug. */ + inhibit_garbage_collection (); + /* now parse stage 2 as in ns_update_menubar */ wv = make_widget_value ("contextmenu", NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; @@ -998,15 +1035,17 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item pmenu = [[EmacsMenu alloc] initWithTitle: NILP (title) ? @"" : [NSString stringWithLispString: title]]; + /* On GNUstep, this call makes menu_items nil for whatever reason + when displaying a context menu from `context-menu-mode'. */ + Lisp_Object items = menu_items; [pmenu fillWithWidgetValue: first_wv->contents]; + menu_items = items; free_menubar_widget_value_tree (first_wv); - unbind_to (specpdl_count, Qnil); - popup_activated_flag = 1; tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps]; popup_activated_flag = 0; [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; - + unbind_to (specpdl_count, Qnil); unblock_input (); return tem; } @@ -1057,6 +1096,15 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item [toolbar clearActive]; #else [toolbar clearAll]; + /* It takes at least 3 such adjustments to fix an issue where the + tool bar is 2x too tall when a frame's tool bar is first shown. + This is ugly, but I have no other solution for this problem. */ + if (FRAME_OUTPUT_DATA (f)->tool_bar_adjusted < 3) + { + [toolbar setVisible: NO]; + FRAME_OUTPUT_DATA (f)->tool_bar_adjusted++; + [toolbar setVisible: YES]; + } #endif /* Update EmacsToolbar as in GtkUtils, build items list. */ diff --git a/src/nsterm.h b/src/nsterm.h index 944dbd727c..8175f99664 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -978,6 +978,12 @@ #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) /* Non-zero if we are doing an animation, e.g. toggling the tool bar. */ int in_animation; + +#ifdef NS_IMPL_GNUSTEP + /* Zero if this is the first time a toolbar has been updated on this + frame. */ + int tool_bar_adjusted; +#endif }; /* This dummy declaration needed to support TTYs. */ diff --git a/src/nsterm.m b/src/nsterm.m index 37580c39ef..469f867579 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -65,6 +65,7 @@ Updated by Christian Limpach (chris@nice.ch) #ifdef NS_IMPL_GNUSTEP #include "process.h" +#import #endif #ifdef NS_IMPL_COCOA @@ -2254,13 +2255,19 @@ Hide the window (X11 semantics) { NSTRACE ("frame_set_mouse_pixel_position"); - /* FIXME: what about GNUstep? */ #ifdef NS_IMPL_COCOA CGPoint mouse_pos = CGPointMake(f->left_pos + pix_x, f->top_pos + pix_y + FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f)); CGWarpMouseCursorPosition (mouse_pos); +#else + GSDisplayServer *server = GSServerForWindow ([FRAME_NS_VIEW (f) window]); + [server setMouseLocation: NSMakePoint (f->left_pos + pix_x, + f->top_pos + pix_y + + FRAME_NS_TITLEBAR_HEIGHT(f) + + FRAME_TOOLBAR_HEIGHT(f)) + onScreen: [[[FRAME_NS_VIEW (f) window] screen] screenNumber]]; #endif } @@ -2573,8 +2580,7 @@ Hide the window (X11 semantics) ========================================================================== */ -#if 0 -/* FIXME: Remove this function. */ +#ifdef NS_IMPL_GNUSTEP static void ns_redraw_scroll_bars (struct frame *f) { @@ -2619,10 +2625,9 @@ Hide the window (X11 semantics) NSRectFill (r); ns_unfocus (f); - /* as of 2006/11 or so this is now needed */ - /* FIXME: I don't see any reason for this and removing it makes no - difference here. Do we need it for GNUstep? */ - //ns_redraw_scroll_bars (f); +#ifdef NS_IMPL_GNUSTEP + ns_redraw_scroll_bars (f); +#endif unblock_input (); } @@ -4920,6 +4925,17 @@ static Lisp_Object ns_string_to_lispmod (const char *s) { } +#ifdef NS_IMPL_GNUSTEP +static void +ns_update_window_end (struct window *w, bool cursor_on_p, + bool mouse_face_overwritten_p) +{ + NSTRACE ("ns_update_window_end (cursor_on_p = %d)", cursor_on_p); + + ns_redraw_scroll_bars (WINDOW_XFRAME (w)); +} +#endif + /* This and next define (many of the) public functions in this file. */ /* gui_* are generic versions in xdisp.c that we, and other terms, get away with using despite presence in the "system dependent" redisplay @@ -4936,7 +4952,11 @@ static Lisp_Object ns_string_to_lispmod (const char *s) ns_scroll_run, ns_after_update_window_line, NULL, /* update_window_begin */ +#ifndef NS_IMPL_GNUSTEP NULL, /* update_window_end */ +#else + ns_update_window_end, +#endif 0, /* flush_display */ gui_clear_window_mouse_face, gui_get_glyph_overhangs, @@ -6164,9 +6184,11 @@ In that case we use UCKeyTranslate (ns_get_shifted_character) Lisp_Object kind = fnKeysym ? QCfunction : QCordinary; emacs_event->modifiers = EV_MODIFIERS2 (flags, kind); +#ifndef NS_IMPL_GNUSTEP if (NS_KEYLOG) fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n", code, fnKeysym, flags, emacs_event->modifiers); +#endif /* If it was a function key or had control-like modifiers, pass it directly to Emacs. */ @@ -6679,6 +6701,11 @@ - (void)mouseDown: (NSEvent *)theEvent emacs_event->code = EV_BUTTON (theEvent); emacs_event->modifiers = EV_MODIFIERS (theEvent) | EV_UDMODIFIERS (theEvent); + + if (emacs_event->modifiers & down_modifier) + FRAME_DISPLAY_INFO (emacsframe)->grabbed |= 1 << EV_BUTTON (theEvent); + else + FRAME_DISPLAY_INFO (emacsframe)->grabbed &= ~(1 << EV_BUTTON (theEvent)); } XSETINT (emacs_event->x, lrint (p.x)); @@ -6979,7 +7006,6 @@ - (void)resizeWithOldSuperviewSize: (NSSize)oldSize height = (int)NSHeight (frame); NSTRACE_SIZE ("New size", NSMakeSize (width, height)); - NSTRACE_SIZE ("Original size", size); /* Reset the frame size to match the bounds of the superview (the NSWindow's contentView). We need to do this as sometimes the diff --git a/src/xdisp.c b/src/xdisp.c index 67c6c74567..0d95e70212 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -13894,7 +13894,6 @@ note_tab_bar_highlight (struct frame *f, int x, int y) clear_mouse_face (hlinfo); bool mouse_down_p = false; -#ifndef HAVE_NS /* Mouse is down, but on different tab-bar item? Or alternatively, the mouse might've been pressed somewhere we don't know about, and then have moved onto the tab bar. In this case, @@ -13907,7 +13906,6 @@ note_tab_bar_highlight (struct frame *f, int x, int y) if (mouse_down_p && f->last_tab_bar_item != prop_idx && f->last_tab_bar_item != -1) return; -#endif draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; /* If tab-bar item is not enabled, don't highlight it. */ -- 2.31.1 --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Fri Nov 05 03:45:20 2021 Received: (at 51411) by debbugs.gnu.org; 5 Nov 2021 07:45:21 +0000 Received: from localhost ([127.0.0.1]:44749 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mituX-0001Mn-6z for submit@debbugs.gnu.org; Fri, 05 Nov 2021 03:45:20 -0400 Received: from sonic303-20.consmr.mail.ne1.yahoo.com ([66.163.188.146]:42669) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mituR-0001MO-6B for 51411@debbugs.gnu.org; Fri, 05 Nov 2021 03:45:16 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636098305; bh=zqHnum476SWqoeu8z4B5UNx8vYJc5w/vptFNU1VMz80=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=mwaw2Aj9PBt+FoH3wf2++OQ4Zcr8VyfxbFitIIAr0PP3wAq/vd4iNYmTU9JzczDxtHH0h5JYfsbmw+3qsdYxPSSIk0eejfgWc2wTIbqQ9SJsla6HguVQYL6QQZBeX0cQcY8DBQ13h8t17pnptDaqXXHab8sKy6rrpvkVwT6tVZBwcnOQfp/ezIYNd7MhYbyqwfrxhU18ZT245bgWo5zvbEMOuag+IKOpj0WVfJZeTJruOmi/OkEz8yeEwaNtRL2OULUPlhHvLBwXSiKBfAUD7vwltERPl74XxzWlvAgT2AsYk5OdgtLwWaz/AqpfxPqLVcu45CfM2yff0Cep6LoojQ== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636098305; bh=LfMeuPE17esbUlEiHyVaB1ycSo9QGEA3aQzUOTKeDKz=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=U19sllRqywt3AiOjeVY0qTW6YGGICZ1xwaBjFOhPv2ztDVyjRyqw+kYFMzdOf6bHZuWQcBq/OnE/5QyNxigXb0PXDS387q3tcBzI/hIXX9jEk+vqKBrQROG6GGsBbezVKlqQDws6N+Syw3jd+QiRiQ/aQZQdD9Y5mn9pk3vkCwP00wrNFwCOzhl1mdcNhCsMhW9hHGE09ASGHFDgc/URgrHCFWDp1G1iLoRLYfIif2pNG7/w8r/GpCk2ge2F3Z0nm2CauYeckRIj662vqdjAJ0Zx5+YXQF4s1KWueYDi18egtSgfK3XOgjPk+GU1HI5lS2B2Gk8VlxttyzL6Zf32iw== X-YMail-OSG: CnZCXgYVM1lqqo8PHeHjzg1GDdyXorZdOk3aP4LSOQQZUB7xDU.yt0QGhww6Wq2 nr1am4TZXc0vV2CLMdD8_GPMb2iVonpuqHJiKmJN_iFJu7gaTNrK..8UEl42DqAJu3ajHDQqztjr kJl7Eefz_lmY37eGN2Lc_KQiYNP9TrrZ5TaYBK3a8m7UJQRPQhw_L5UgwcHjvHKhoGpd8NLxKIdl JJx6tqlwM2Ikgir.7o1N7wh3ADGPGk1yQSjokrFlbgnNQJ_RD8K8YEL.quj0alogDV.BjgP8ukbb VtrUEgyzodYOI8BjtIkMWd0CWlDrQnT.2MWNz.BwkaOjPa4wXN85Iu212FXgSLOtnKiA1eb8uhc8 IzYHpcD61uzY78YwQXlkGjiLyMsgMjzjWLNY1GQCt0TkljaJqQ.yLB_5CKwwIhN5mnDDpDeMLNEh YPKkpEWazQZVOqLuBwvGrgBW9tsfIcrjdSLNxIZtjsfM2TPysZiv6.Whqf3Rkqh4OpGQv5W5NdIV o0m7bekkeHFmFFXCjlQsGOpJVmxkrHOZGv05NvL2xh44mEexbkb4OuROSpReYmdWlHSkIXv6bIm8 0j.5GcGLzv61WNec5Z_cR7lFA5.AzX_sJg9EHWlcm8pKzT6yYiLmD7Q6n9TpyE3Xrj.Mue5ULyl. CjhVtrl6.fy_.2dUDZ3I7J9eXveB9z9rXCZgfSMWAz0z8EqEvJkOnXrwiQcbJUjO7YDSJbOQflUh GoeukEX_SQLj99PMM1JLOzbOJus7_z81SWYRMh0ui3bQfdJWgqrh3KaAEvIhRD3SYUwnOnqAtYsG cWnkrl6Oju0pKeTOooG4R9bpW1iPYazSyud3M7I8n332yq_SPBvYQMYQ3Oh5O7z5D7ykR.W6kRw. 6WjJDo6VyUjKA0srFY3sW50ZH5Nm1zCIlFirCBGJoLzzAL.kTbHCthZ9bQpIorIos1qJVo4RQjsu P3AN8zpwWlVeLd5kIjOMVjSaIa6p44ufZagW6ki0ptiL8uFNipqVyRtDJDYeVrqgNKZZX_165FrJ vbJMpNwovTNNu3cihe8BtrxziEaH6DO6Mn_EE2E4AthJFi6DvEHN6IiABKhLdObcQXKU.yTWQwwQ lfYTYQp7i3Rjwoj.eVi7yCAaKIO8GqIZE4nFB6oo2nbt2NfZohqb6NP1SlT4I5hCI.5hKtYTDJ9J ZiyhSEv4z4tFO9HAdkXu6Wi5.4Pr79d9CY00OGDA_YOqA858.Ivtfw4.dt.rKOx0XM2yybsP_RMf fyb2Aa9A_9_kwVi4wn2cphcpxlRE6hMVh1jnOqoQmhc1YNDAlyW_VkQ4xZ65M5L3jpBcs8YkYtCY DlxQaBym7.43UApuqa49CHB6eM3vuSczB2Yy7LHgnXgisjcbZETsoaXa6hnuoZI_3DYJn6OcmmEw sT1P1l1Qh2VdaN.c5bud53BiigpdlGRPdaJ8H3BoYpckq.wy0qav1EB8gJ3BY39qiObHWD5sAC2x B0rmTfitsjV4gfDMYZfzbRYFohqFdhbbCxEOvkdepigr8kJg69uuJRhHrL8e.j4qov53.Yyco4zQ YTMpaw7TYtVMMIvtDd7OKcznKN2HKvfjYg6M8Q.dw9voLvNn.y29VMMNqYmOWyACzTv5obm035An 2ecdvM_OTFam4c5AhwVBcHnIwU1sLITZf1jSbsuDBUJL_Zyc8PS67txTPcUrW9MRxHQIASPHDi5W Qt_18JuOlcksYBNUswYl8Ufnv1UrdfyyVCedUyAZczX7DEf.sRwqpsq8IC4rtZFHgVxT8FyMorKp upfA6OQD4aS_yQiqb4qCnNEL5DIKGu6X9tooL0NZQpBeSmk3IcEGrvrvidDg2aSwE43Ki2YAdMtp QneKm04b_hQk.n6qMgfCNA72n0jNMgaYVG2x5N.eH9DJPHM7pLr3M6xWhx7lNd7u5hWYRQ9IFbHz w1IH90xGSAvf._hNN7j9YzXBzl5u7_z.mFC6rvTMMWoXm0A9Wq8Bf9FHb6.jnTJgKfF08oAFe_zJ ce_N8jIWLq.wt5s3i.b4ucHi5qVdAAO1BNu3iccjIMFIBEXmXLeEtkT7sKKqoOGdRvvl7UqKkn0G _jrBx5nWnhauAW7.9RL7bWsarAuJu3Z0FSVJxEf6FUDZurQLly2geyLLOMhNhnzR5Ua4I_VS.8fq tBGgmvtKR83GwOZ_1ud._uao.MV8kVpmGP7NkkMhJz0PA8XA2zRLdrFFAmrqKaxG1ygGtqlbD_eu YTHCvmo4kZ6NjESzFZBMBhJmNxD.ntn0tsUmU3QVZI7bUl9iDss8d9sP2Dw-- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic303.consmr.mail.ne1.yahoo.com with HTTP; Fri, 5 Nov 2021 07:45:05 +0000 Received: by kubenode508.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID d88b379ceb599b39efea503c13273ef8; Fri, 05 Nov 2021 07:44:54 +0000 (UTC) From: Po Lu To: Alan Third Subject: Re: bug#51411: NS port cleanups References: <87h7d4t0er.fsf@yahoo.com> <87ee86q7jm.fsf@yahoo.com> <87ilxhmlwc.fsf@yahoo.com> <87lf29jxeg.fsf@yahoo.com> <87v91digfm.fsf@yahoo.com> <87pmrlibj0.fsf@yahoo.com> Date: Fri, 05 Nov 2021 15:44:48 +0800 In-Reply-To: <87pmrlibj0.fsf@yahoo.com> (Po Lu's message of "Sun, 31 Oct 2021 21:12:03 +0800") Message-ID: <87fssb9hcf.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 91967 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Po Lu writes: > Thanks, here's the updated patch (along with the other patch for the > improvements not related to text display). I will be sure to take a > look at the rest of the ns_focus calls later, if I get the time. As of 48af19c1 those patches don't apply anymore. Here's a version that does. (I kept my version of the overhang computation code instead of Daniel's, because the xterm code computes overhangs correctly, and bug#51105 doesn't apply to it AFAIU.) --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Improve-font-display-on-NS-port.patch >From 12ff5156b755a3654404328171045f13bcaec901 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 23 Oct 2021 19:44:03 +0800 Subject: [PATCH 1/2] Improve font display on NS port * src/nsfns.m (Fx_create_frame): Use "fixed" for the default font on GNUstep. * src/nsfont.m (LCD_SMOOTHING_MARGIN, ns_escape_name) (ns_unescape_name, ns_attribute_fvalue) (STYLE_REF): Remove unused defines and functions. (struct ns_glyph_layout, enum lgstring_direction). (enum gs_font_slant, enum gs_font_weight, enum gs_font_width) (enum gs_specified, struct gs_font_data): New enumerators and structures. (ns_font_descs_match_p) (ns_done_font_data, ns_get_font_data): New functions. (ns_glyph_metrics): Stop escaping names. (ns_spec_to_descriptor): Fix font descriptor creation for symbolic font spec entires. (ns_descriptor_to_entity): Create entries with the correct symbolic styles. (ns_fallback_entity): Fix fallback entity selection. (ns_findfonts): Use our own font matcher instead of the broken GNUstep matcher. (ns_list_family): Remove obsolete comment. (nsfont_open): Remove obsolete code, comments, and synthItal logic which doesn't work on GNUstep. (nsfont_encode_char): Use a type that can fit NSGlyph (nsfont_draw): Chose correct font, remove obsolete mouse face logic, obsolete comments, and switch to using glyph-based drawing instead of character-based drawing. (ns_font_shape, nsfont_shape): New functions. (ns_uni_to_glyphs_1): New function. (ns_uni_to_glyphs): Return glyphs instead of unicode codepoints. (ns_glyph_metrics): Use NSGlyphs instead of unicode codepoints and fix left bearing, right bearing, ascent and descent computation. (struct nsfont_driver): Add shaping capability. * src/nsterm.h (struct nsfont_info): Use unsigned int for glyph cache. * src/nsterm.c (ns_focus): Set DPS clipping on GNUstep. (ns_compute_glyph_string_overhangs): Fix overhang computation by using xterm code. (ns_draw_window_cursor): Simplify cursor drawing. (ns_maybe_dumpglyphs_background): Test for cursor HL and remove obsolete mouse face logic. (ns_dumpglyphs_image) (ns_dumpglyphs_box_or_relief): Rectify for new cursor logic. (ns_dumpglyphs_stretch): Rectify for new cursor logic and rely on ns_draw_glyph_string to set focus. (ns_draw_glyph_string_foreground): Remove mouse face logic. (ns_draw_glyph_strings): Implement overhangs, remove obsolete comment, and always focus before dumping glyphs. (ns_draw_text_decoration): Add condition for DRAW_CURSOR and simplify color selection. (ns_define_frame_cursor): Remove nonsensical code (define_frame_cursor has nothing to do with the text cursor, aka caret). * src/xdisp.c (draw_glyphs): Enable code for NS port to fix mouse face cursor display. * src/macfont.m (get_cgcolor_from_nscolor): New function. (macfont_draw): Remove obsolete mouse-face code and enable cursor display. --- src/macfont.m | 36 +- src/nsfns.m | 6 + src/nsfont.m | 1215 +++++++++++++++++++++++++++++++++++-------------- src/nsterm.h | 2 +- src/nsterm.m | 423 ++++++++--------- src/xdisp.c | 2 - 6 files changed, 1095 insertions(+), 589 deletions(-) diff --git a/src/macfont.m b/src/macfont.m index 78ed5d53f3..1426cae6dc 100644 --- a/src/macfont.m +++ b/src/macfont.m @@ -613,6 +613,21 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char, return cgColor; } +static CGColorRef +get_cgcolor_from_nscolor (NSColor *nsColor, struct frame *f) +{ + [nsColor set]; + CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace]; + NSInteger noc = [nsColor numberOfComponents]; + CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc)); + CGColorRef cgColor; + + [nsColor getComponents: components]; + cgColor = CGColorCreate (colorSpace, components); + xfree (components); + return cgColor; +} + #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f) \ do { \ CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f); \ @@ -2911,14 +2926,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no if (!CGRectIsNull (background_rect)) { - if (s->hl == DRAW_MOUSE_FACE) + if (s->hl == DRAW_CURSOR) { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_CURSOR_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); } - CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); + else + CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); CGContextFillRects (context, &background_rect, 1); } @@ -2927,7 +2942,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no CGAffineTransform atfm; CGContextScaleCTM (context, 1, -1); - CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); + if (s->hl == DRAW_CURSOR) + { + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_BACKGROUND_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); + } + else + CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); if (macfont_info->synthetic_italic_p) atfm = synthetic_italic_atfm; else diff --git a/src/nsfns.m b/src/nsfns.m index 797d0ce782..f4d8172246 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -1236,6 +1236,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. "fontBackend", "FontBackend", RES_TYPE_STRING); { +#ifdef NS_IMPL_COCOA /* use for default font name */ id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */ gui_default_parameter (f, parms, Qfontsize, @@ -1250,6 +1251,11 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. build_string (fontname), "font", "Font", RES_TYPE_STRING); xfree (fontname); +#else + gui_default_parameter (f, parms, Qfont, + build_string ("fixed"), + "font", "Font", RES_TYPE_STRING); +#endif } unblock_input (); diff --git a/src/nsfont.m b/src/nsfont.m index 5a9cdfebc0..b3224629f0 100644 --- a/src/nsfont.m +++ b/src/nsfont.m @@ -1,4 +1,4 @@ -/* Font back-end driver for the NeXT/Open/GNUstep and macOS window system. +/* Font back-end driver for the GNUstep window system. See font.h Copyright (C) 2006-2021 Free Software Foundation, Inc. @@ -38,47 +38,269 @@ #include "termchar.h" #include "pdumper.h" -/* TODO: Drop once we can assume gnustep-gui 0.17.1. */ +#import #import +#import +#import +#import #define NSFONT_TRACE 0 -#define LCD_SMOOTHING_MARGIN 2 -/* Font glyph and metrics caching functions, implemented at end. */ -static void ns_uni_to_glyphs (struct nsfont_info *font_info, - unsigned char block); -static void ns_glyph_metrics (struct nsfont_info *font_info, - unsigned char block); +/* Structure used by GS `shape' functions for storing layout + information for each glyph. Borrowed from macfont.h. */ +struct ns_glyph_layout +{ + /* Range of indices of the characters composed into the group of + glyphs that share the cursor position with this glyph. The + members `location' and `length' are in UTF-16 indices. */ + NSRange comp_range; -#define INVALID_GLYPH 0xFFFF + /* UTF-16 index in the source string for the first character + associated with this glyph. */ + NSUInteger string_index; -/* ========================================================================== + /* Horizontal and vertical adjustments of glyph position. The + coordinate space is that of Core Text. So, the `baseline_delta' + value is negative if the glyph should be placed below the + baseline. */ + CGFloat advance_delta, baseline_delta; - Utilities + /* Typographical width of the glyph. */ + CGFloat advance; - ========================================================================== */ + /* Glyph ID of the glyph. */ + NSGlyph glyph_id; +}; + + +enum lgstring_direction + { + DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1 + }; + +enum gs_font_slant + { + GS_FONT_SLANT_ITALIC, + GS_FONT_SLANT_REVERSE_ITALIC, + GS_FONT_SLANT_NORMAL + }; + +enum gs_font_weight + { + GS_FONT_WEIGHT_LIGHT, + GS_FONT_WEIGHT_BOLD, + GS_FONT_WEIGHT_NORMAL + }; + +enum gs_font_width + { + GS_FONT_WIDTH_CONDENSED, + GS_FONT_WIDTH_EXPANDED, + GS_FONT_WIDTH_NORMAL + }; + +enum gs_specified + { + GS_SPECIFIED_SLANT = 1, + GS_SPECIFIED_WEIGHT = 1 << 1, + GS_SPECIFIED_WIDTH = 1 << 2, + GS_SPECIFIED_FAMILY = 1 << 3, + GS_SPECIFIED_SPACING = 1 << 4 + }; +struct gs_font_data +{ + int specified; + enum gs_font_slant slant; + enum gs_font_weight weight; + enum gs_font_width width; + bool monospace_p; + char *family_name; +}; -/* Replace spaces w/another character so emacs core font parsing routines - aren't thrown off. */ static void -ns_escape_name (char *name) +ns_done_font_data (struct gs_font_data *data) { - for (; *name; name++) - if (*name == ' ') - *name = '_'; + if (data->specified & GS_SPECIFIED_FAMILY) + xfree (data->family_name); } - -/* Reconstruct spaces in a font family name passed through emacs. */ static void -ns_unescape_name (char *name) +ns_get_font_data (NSFontDescriptor *desc, struct gs_font_data *dat) { - for (; *name; name++) - if (*name == '_') - *name = ' '; + NSNumber *tem; + NSFontSymbolicTraits traits = [desc symbolicTraits]; + NSDictionary *dict = [desc objectForKey: NSFontTraitsAttribute]; + NSString *family = [desc objectForKey: NSFontFamilyAttribute]; + + dat->specified = 0; + + if (family != nil) + { + dat->specified |= GS_SPECIFIED_FAMILY; + dat->family_name = xstrdup ([family cStringUsingEncoding: NSUTF8StringEncoding]); + } + + tem = [desc objectForKey: NSFontFixedAdvanceAttribute]; + + if ((tem != nil && [tem boolValue] != NO) + || (traits & NSFontMonoSpaceTrait)) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = true; + } + else if (tem != nil && [tem boolValue] == NO) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = false; + } + + if (traits & NSFontBoldTrait) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + dat->weight = GS_FONT_WEIGHT_BOLD; + } + + if (traits & NSFontItalicTrait) + { + dat->specified |= GS_SPECIFIED_SLANT; + dat->slant = GS_FONT_SLANT_ITALIC; + } + + if (traits & NSFontCondensedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_CONDENSED; + } + else if (traits & NSFontExpandedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_EXPANDED; + } + + if (dict != nil) + { + tem = [dict objectForKey: NSFontSlantTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_SLANT; + + dat->slant = [tem floatValue] > 0 + ? GS_FONT_SLANT_ITALIC + : ([tem floatValue] < 0 + ? GS_FONT_SLANT_REVERSE_ITALIC + : GS_FONT_SLANT_NORMAL); + } + + tem = [dict objectForKey: NSFontWeightTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + + dat->weight = [tem floatValue] > 0 + ? GS_FONT_WEIGHT_BOLD + : ([tem floatValue] < -0.4f + ? GS_FONT_WEIGHT_LIGHT + : GS_FONT_WEIGHT_NORMAL); + } + + tem = [dict objectForKey: NSFontWidthTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WIDTH; + + dat->width = [tem floatValue] > 0 + ? GS_FONT_WIDTH_EXPANDED + : ([tem floatValue] < 0 + ? GS_FONT_WIDTH_NORMAL + : GS_FONT_WIDTH_CONDENSED); + } + } +} + +static bool +ns_font_descs_match_p (NSFontDescriptor *desc, NSFontDescriptor *target) +{ + struct gs_font_data dat; + struct gs_font_data t; + + ns_get_font_data (desc, &dat); + ns_get_font_data (target, &t); + + if (!(t.specified & GS_SPECIFIED_WIDTH)) + t.width = GS_FONT_WIDTH_NORMAL; + if (!(t.specified & GS_SPECIFIED_WEIGHT)) + t.weight = GS_FONT_WEIGHT_NORMAL; + if (!(t.specified & GS_SPECIFIED_SPACING)) + t.monospace_p = false; + if (!(t.specified & GS_SPECIFIED_SLANT)) + t.slant = GS_FONT_SLANT_NORMAL; + + if (!(t.specified & GS_SPECIFIED_FAMILY)) + emacs_abort (); + + bool match_p = true; + + if (dat.specified & GS_SPECIFIED_WIDTH + && dat.width != t.width) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_WEIGHT + && dat.weight != t.weight) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SPACING + && dat.monospace_p != t.monospace_p) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SLANT + && dat.monospace_p != t.monospace_p) + { + if (NSFONT_TRACE) + printf ("Matching monospace for %s: %d %d\n", + t.family_name, dat.monospace_p, + t.monospace_p); + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_FAMILY + && strcmp (dat.family_name, t.family_name)) + match_p = false; + + gout: + ns_done_font_data (&dat); + ns_done_font_data (&t); + + return match_p; } +/* Font glyph and metrics caching functions, implemented at end. */ +static void ns_uni_to_glyphs (struct nsfont_info *font_info, + unsigned char block); +static void ns_glyph_metrics (struct nsfont_info *font_info, + unsigned int block); + +#define INVALID_GLYPH 0xFFFF + +/* ========================================================================== + + Utilities + + ========================================================================== */ + /* Extract family name from a font spec. */ static NSString * @@ -91,66 +313,116 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, { char *tmp = xlispstrdup (SYMBOL_NAME (tem)); NSString *family; - ns_unescape_name (tmp); family = [NSString stringWithUTF8String: tmp]; xfree (tmp); return family; } } - -/* Return 0 if attr not set, else value (which might also be 0). - On Leopard 0 gets returned even on descriptors where the attribute - was never set, so there's no way to distinguish between unspecified - and set to not have. Callers should assume 0 means unspecified. */ -static float -ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait) -{ - NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute]; - NSNumber *val = [tdict objectForKey: trait]; - return val == nil ? 0.0F : [val floatValue]; -} - - /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang to NSFont descriptor. Information under extra only needed for matching. */ -#define STYLE_REF 100 static NSFontDescriptor * ns_spec_to_descriptor (Lisp_Object font_spec) { NSFontDescriptor *fdesc; NSMutableDictionary *fdAttrs = [NSMutableDictionary new]; - NSMutableDictionary *tdict = [NSMutableDictionary new]; NSString *family = ns_get_family (font_spec); - float n; - - /* Add each attr in font_spec to fdAttrs. */ - n = min (FONT_WEIGHT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWeightTrait]; - n = min (FONT_SLANT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontSlantTrait]; - n = min (FONT_WIDTH_NUMERIC (font_spec), 200); - if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10)) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWidthTrait]; - if ([tdict count] > 0) - [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + NSMutableDictionary *tdict = [NSMutableDictionary new]; - fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] - retain] autorelease]; + Lisp_Object tem; + + tem = FONT_SLANT_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qitalic) || EQ (tem, Qoblique)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontSlantTrait]; + else if (EQ (tem, intern ("reverse-italic")) || + EQ (tem, intern ("reverse-oblique"))) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontSlantTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontSlantTrait]; + } + + tem = FONT_WIDTH_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qcondensed)) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWidthTrait]; + else if (EQ (tem, Qexpanded)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWidthTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWidthTrait]; + } + + tem = FONT_WEIGHT_SYMBOLIC (font_spec); + + if (!NILP (tem)) + { + if (EQ (tem, Qbold)) + { + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWeightTrait]; + } + else if (EQ (tem, Qlight)) + { + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWeightTrait]; + } + else + { + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWeightTrait]; + } + } + + tem = AREF (font_spec, FONT_SPACING_INDEX); if (family != nil) { - NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family]; - fdesc = [[fdesc2 retain] autorelease]; + [fdAttrs setObject: family + forKey: NSFontFamilyAttribute]; } - [fdAttrs release]; + if (FIXNUMP (tem)) + { + if (XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL) + { + [fdAttrs setObject: [NSNumber numberWithBool:YES] + forKey: NSFontFixedAdvanceAttribute]; + } + else + { + [fdAttrs setObject: [NSNumber numberWithBool:NO] + forKey: NSFontFixedAdvanceAttribute]; + } + } + + /* Handle special families such as ``fixed'' or ``Sans Serif''. */ + + if ([family isEqualToString: @"fixed"]) + { + [fdAttrs setObject: [[NSFont userFixedPitchFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + else if ([family isEqualToString: @"Sans Serif"]) + { + [fdAttrs setObject: [[NSFont userFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + + [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + + fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] + retain] autorelease]; + [tdict release]; + [fdAttrs release]; return fdesc; } @@ -161,61 +433,64 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, Lisp_Object extra, const char *style) { - Lisp_Object font_entity = font_make_entity (); - /* NSString *psName = [desc postscriptName]; */ - NSString *family = [desc objectForKey: NSFontFamilyAttribute]; - unsigned int traits = [desc symbolicTraits]; - char *escapedFamily; - - /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */ - if (family == nil) - family = [desc objectForKey: NSFontNameAttribute]; - if (family == nil) - family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - - escapedFamily = xstrdup ([family UTF8String]); - ns_escape_name (escapedFamily); - - ASET (font_entity, FONT_TYPE_INDEX, Qns); - ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple); - ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily)); - ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); - ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); - - FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - traits & NSFontBoldTrait ? Qbold : Qmedium); -/* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - traits & NSFontItalicTrait ? Qitalic : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - traits & NSFontCondensedTrait ? Qcondensed : - traits & NSFontExpandedTrait ? Qexpanded : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/ - - ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_SPACING_INDEX, - make_fixnum([desc symbolicTraits] & NSFontMonoSpaceTrait - ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); - - ASET (font_entity, FONT_EXTRA_INDEX, extra); - ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + Lisp_Object font_entity = font_make_entity (); + struct gs_font_data data; + ns_get_font_data (desc, &data); + + ASET (font_entity, FONT_TYPE_INDEX, Qns); + ASET (font_entity, FONT_FOUNDRY_INDEX, Qns); + if (data.specified & GS_SPECIFIED_FAMILY) + ASET (font_entity, FONT_FAMILY_INDEX, intern (data.family_name)); + ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); + ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); + + if (data.specified & GS_SPECIFIED_WEIGHT) + { + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, + data.weight == GS_FONT_WEIGHT_BOLD + ? Qbold : (data.weight == GS_FONT_WEIGHT_LIGHT + ? Qlight : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, Qnormal); - if (NSFONT_TRACE) - { - fputs ("created font_entity:\n ", stderr); - debug_print (font_entity); - } + if (data.specified & GS_SPECIFIED_SLANT) + { + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, + data.slant == GS_FONT_SLANT_ITALIC + ? Qitalic : (data.slant == GS_FONT_SLANT_REVERSE_ITALIC + ? intern ("reverse-italic") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, Qnormal); + + if (data.specified & GS_SPECIFIED_WIDTH) + { + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, + data.width == GS_FONT_WIDTH_CONDENSED + ? Qcondensed : (data.width == GS_FONT_WIDTH_EXPANDED + ? intern ("expanded") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, Qnormal); - xfree (escapedFamily); - return font_entity; + ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_SPACING_INDEX, + make_fixnum ((data.specified & GS_SPECIFIED_WIDTH && data.monospace_p) + ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); + + ASET (font_entity, FONT_EXTRA_INDEX, extra); + ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + + if (NSFONT_TRACE) + { + fputs ("created font_entity:\n ", stderr); + debug_print (font_entity); + } + + ns_done_font_data (&data); + return font_entity; } @@ -223,8 +498,7 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, static Lisp_Object ns_fallback_entity (void) { - return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0] - fontDescriptor], Qnil, NULL); + return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 1] fontDescriptor], Qnil, NULL); } @@ -510,21 +784,20 @@ but also for ascii (which causes unnecessary font substitution). */ return families; } +/* GNUstep font matching is very mediocre (it can't even compare + symbolic styles correctly), which is why our own font matching + mechanism must be implemented. */ -/* Implementation for list() and match(). List() can return nil, match() -must return something. Strategy is to drop family name from attribute -matching set for match. */ +/* Implementation for list and match. */ static Lisp_Object ns_findfonts (Lisp_Object font_spec, BOOL isMatch) { Lisp_Object tem, list = Qnil; - NSFontDescriptor *fdesc, *desc; - NSMutableSet *fkeys; - NSArray *matchingDescs; - NSEnumerator *dEnum; - NSString *family; + NSFontDescriptor *fdesc; + NSArray *all_descs; + GSFontEnumerator *enumerator = [GSFontEnumerator sharedEnumerator]; + NSSet *cFamilies; - BOOL foundItal = NO; block_input (); if (NSFONT_TRACE) @@ -537,43 +810,22 @@ but also for ascii (which causes unnecessary font substitution). */ cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90); fdesc = ns_spec_to_descriptor (font_spec); - fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]]; - if (isMatch) - [fkeys removeObject: NSFontFamilyAttribute]; - - matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys]; + all_descs = [enumerator availableFontDescriptors]; - if (NSFONT_TRACE) - NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc, - (unsigned long)[matchingDescs count]); - - for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);) + for (NSFontDescriptor *desc in all_descs) { if (![cFamilies containsObject: [desc objectForKey: NSFontFamilyAttribute]]) continue; + if (!ns_font_descs_match_p (fdesc, desc)) + continue; + tem = ns_descriptor_to_entity (desc, - AREF (font_spec, FONT_EXTRA_INDEX), + AREF (font_spec, FONT_EXTRA_INDEX), NULL); if (isMatch) return tem; list = Fcons (tem, list); - if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05) - foundItal = YES; - } - - /* Add synthItal member if needed. */ - family = [fdesc objectForKey: NSFontFamilyAttribute]; - if (family != nil && !foundItal && !NILP (list)) - { - NSFontDescriptor *s1 = [NSFontDescriptor new]; - NSFontDescriptor *sDesc - = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait] - fontDescriptorWithFamily: family]; - list = Fcons (ns_descriptor_to_entity (sDesc, - AREF (font_spec, FONT_EXTRA_INDEX), - "synthItal"), list); - [s1 release]; } unblock_input (); @@ -652,7 +904,6 @@ Properties to be considered are same as for list(). */ objectEnumerator]; while ((family = [families nextObject])) list = Fcons (intern ([family UTF8String]), list); - /* FIXME: escape the name? */ if (NSFONT_TRACE) fprintf (stderr, "nsfont: list families returning %"pD"d entries\n", @@ -668,18 +919,15 @@ Properties to be considered are same as for list(). */ static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size) { - BOOL synthItal; - unsigned int traits = 0; struct nsfont_info *font_info; struct font *font; NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity); NSFontManager *fontMgr = [NSFontManager sharedFontManager]; NSString *family; NSFont *nsfont, *sfont; - Lisp_Object tem; NSRect brect; Lisp_Object font_object; - int fixLeopardBug; + Lisp_Object tem; block_input (); @@ -692,42 +940,20 @@ Properties to be considered are same as for list(). */ if (pixel_size <= 0) { /* try to get it out of frame params */ - Lisp_Object tem = get_frame_param (f, Qfontsize); - pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); + tem = get_frame_param (f, Qfontsize); + pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); } tem = AREF (font_entity, FONT_ADSTYLE_INDEX); - synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)), - 9); family = ns_get_family (font_entity); if (family == nil) family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that - when setting family in ns_spec_to_descriptor(). */ - if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F) - traits |= NSBoldFontMask; - if (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F) - traits |= NSItalicFontMask; - - /* see https://web.archive.org/web/20100201175731/http://cocoadev.com/forums/comments.php?DiscussionID=74 */ - fixLeopardBug = traits & NSBoldFontMask ? 10 : 5; - nsfont = [fontMgr fontWithFamily: family - traits: traits weight: fixLeopardBug - size: pixel_size]; - /* if didn't find, try synthetic italic */ - if (nsfont == nil && synthItal) - { - nsfont = [fontMgr fontWithFamily: family - traits: traits & ~NSItalicFontMask - weight: fixLeopardBug size: pixel_size]; - } + + nsfont = [NSFont fontWithDescriptor: fontDesc + size: pixel_size]; if (nsfont == nil) - { - message_with_string ("*** Warning: font in family `%s' not found", - build_string ([family UTF8String]), 1); - nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; - } + nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; if (NSFONT_TRACE) NSLog (@"%@\n", nsfont); @@ -740,7 +966,7 @@ when setting family in ns_spec_to_descriptor(). */ if (!font) { unblock_input (); - return Qnil; /* FIXME: other terms do, but returning Qnil causes segfault. */ + return Qnil; } font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs); @@ -781,7 +1007,7 @@ when setting family in ns_spec_to_descriptor(). */ font_info->name = xstrdup (fontName); font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask; font_info->ital = - synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); + ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); /* Metrics etc.; some fonts return an unusually large max advance, so we only use it for fonts that have wide characters. */ @@ -808,8 +1034,6 @@ when setting family in ns_spec_to_descriptor(). */ lrint (brect.size.width - (CGFloat) font_info->width); /* set up metrics portion of font struct */ - font->ascent = lrint([sfont ascender]); - font->descent = -lrint(floor(adjusted_descender)); font->space_width = lrint (ns_char_width (sfont, ' ')); font->max_width = lrint (font_info->max_bounds.width); font->min_width = font->space_width; /* Approximate. */ @@ -871,7 +1095,7 @@ when setting family in ns_spec_to_descriptor(). */ { struct nsfont_info *font_info = (struct nsfont_info *)font; unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff; - unsigned short g; + unsigned int g; if (c > 0xFFFF) return FONT_INVALID_CODE; @@ -934,51 +1158,23 @@ is false when (FROM > 0 || TO < S->nchars). */ static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, bool with_background) -/* NOTE: focus and clip must be set. */ { - static unsigned char cbuf[1024]; - unsigned char *c = cbuf; -#if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22 - static CGFloat advances[1024]; - CGFloat *adv = advances; -#else - static float advances[1024]; - float *adv = advances; -#endif + NSGlyph *c = alloca ((to - from) * sizeof *c); + struct face *face; NSRect r; struct nsfont_info *font; - NSColor *col, *bgCol; - unsigned *t = s->char2b; - int i, len, flags; + NSColor *col; + int len = to - from; char isComposite = s->first_glyph->type == COMPOSITE_GLYPH; block_input (); - font = (struct nsfont_info *)s->face->font; + font = (struct nsfont_info *) s->font; if (font == NULL) font = (struct nsfont_info *)FRAME_FONT (s->f); - /* Select face based on input flags. */ - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - - switch (flags) - { - case NS_DUMPGLYPH_CURSOR: - face = s->face; - break; - case NS_DUMPGLYPH_MOUSEFACE: - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - break; - default: - face = s->face; - } + face = s->face; r.origin.x = s->x; if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p) @@ -987,91 +1183,24 @@ is false when (FROM > 0 || TO < S->nchars). */ r.origin.y = s->y; r.size.height = FONT_HEIGHT (font); - /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask - NS to render the string, it will come out differently from the individual - character widths added up because of layout processing. */ - { - int cwidth, twidth = 0; - int hi, lo; - /* FIXME: composition: no vertical displacement is considered. */ - t += from; /* advance into composition */ - for (i = from; i < to; i++, t++) - { - hi = (*t & 0xFF00) >> 8; - lo = *t & 0x00FF; - if (isComposite) - { - if (!s->first_glyph->u.cmp.automatic) - cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth; - else - { - Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); - Lisp_Object glyph = LGSTRING_GLYPH (gstring, i); - if (NILP (LGLYPH_ADJUSTMENT (glyph))) - cwidth = LGLYPH_WIDTH (glyph); - else - { - cwidth = LGLYPH_WADJUST (glyph); - *(adv-1) += LGLYPH_XOFF (glyph); - } - } - } - else - { - if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */ - ns_glyph_metrics (font, hi); - cwidth = font->metrics[hi][lo].width; - } - twidth += cwidth; - *adv++ = cwidth; - c += CHAR_STRING (*t, c); /* This converts the char to UTF-8. */ - } - len = adv - advances; - r.size.width = twidth; - *c = 0; - } + for (int i = from; i < to; ++i) + c[i] = s->char2b[i]; /* Fill background if requested. */ if (with_background && !isComposite) { - NSRect br = r; - int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); - int mbox_line_width = max (s->face->box_vertical_line_width, 0); - - if (s->row->full_width_p) - { - if (br.origin.x <= fibw + 1 + mbox_line_width) - { - br.size.width += br.origin.x - mbox_line_width; - br.origin.x = mbox_line_width; - } - if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) - <= fibw+1) - br.size.width += fibw; - } - if (s->face->box == FACE_NO_BOX) - { - /* Expand unboxed top row over internal border. */ - if (br.origin.y <= fibw + 1 + mbox_line_width) - { - br.size.height += br.origin.y; - br.origin.y = 0; - } - } - else - { - int correction = abs (s->face->box_horizontal_line_width)+1; - br.origin.y += correction; - br.size.height -= 2*correction; - correction = abs (s->face->box_vertical_line_width)+1; - br.origin.x += correction; - br.size.width -= 2*correction; - } + NSRect br = NSMakeRect (x, y - FONT_BASE (s->font), + s->width, FONT_HEIGHT (s->font)); if (!s->face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); @@ -1080,43 +1209,32 @@ is false when (FROM > 0 || TO < S->nchars). */ NSRectFill (br); } - /* set up for character rendering */ r.origin.y = y; - col = (NS_FACE_FOREGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - - bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil - : (NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f))); + if (s->hl == DRAW_CURSOR) + col = FRAME_BACKGROUND_COLOR (s->f); + else + col = (NS_FACE_FOREGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) + : FRAME_FOREGROUND_COLOR (s->f)); /* render under GNUstep using DPS */ { - NSGraphicsContext *context = GSCurrentContext (); - + NSGraphicsContext *context = [NSGraphicsContext currentContext]; DPSgsave (context); - [font->nsfont set]; - - /* do erase if "foreground" mode */ - if (bgCol != nil) + if (s->clip_head) { - [bgCol set]; - DPSmoveto (context, r.origin.x, r.origin.y); -/*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */ - DPSxshow (context, (const char *) cbuf, advances, len); - DPSstroke (context); - [col set]; -/*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */ + DPSrectclip (context, s->clip_head->x, 0, + FRAME_PIXEL_WIDTH (s->f), + FRAME_PIXEL_HEIGHT (s->f)); } + [font->nsfont set]; [col set]; - /* draw with DPSxshow () */ DPSmoveto (context, r.origin.x, r.origin.y); - DPSxshow (context, (const char *) cbuf, advances, len); + GSShowGlyphs (context, c, len); DPSstroke (context); DPSgrestore (context); @@ -1126,6 +1244,360 @@ is false when (FROM > 0 || TO < S->nchars). */ return to-from; } +static NSUInteger +ns_font_shape (NSFont *font, NSString *string, + struct ns_glyph_layout *glyph_layouts, NSUInteger glyph_len, + enum lgstring_direction dir) +{ + NSUInteger i; + NSUInteger result = 0; + NSTextStorage *textStorage; + NSLayoutManager *layoutManager; + NSTextContainer *textContainer; + NSUInteger stringLength; + NSPoint spaceLocation; + /* numberOfGlyphs can't actually be 0, but this pacifies GCC */ + NSUInteger used, numberOfGlyphs = 0; + + textStorage = [[NSTextStorage alloc] initWithString:string]; + layoutManager = [[NSLayoutManager alloc] init]; + textContainer = [[NSTextContainer alloc] init]; + + /* Append a trailing space to measure baseline position. */ + [textStorage appendAttributedString:([[[NSAttributedString alloc] + initWithString:@" "] autorelease])]; + [textStorage setFont:font]; + [textContainer setLineFragmentPadding:0]; + + [layoutManager addTextContainer:textContainer]; + [textContainer release]; + [textStorage addLayoutManager:layoutManager]; + [layoutManager release]; + + if (!(textStorage && layoutManager && textContainer)) + emacs_abort (); + + stringLength = [string length]; + + /* Force layout. */ + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength]; + + /* Remove the appended trailing space because otherwise it may + generate a wrong result for a right-to-left text. */ + [textStorage beginEditing]; + [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))]; + [textStorage endEditing]; + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + i = 0; + while (i < stringLength) + { + NSRange range; + NSFont *fontInTextStorage = + [textStorage attribute: NSFontAttributeName + atIndex:i + longestEffectiveRange: &range + inRange: NSMakeRange (0, stringLength)]; + + if (!(fontInTextStorage == font + || [[fontInTextStorage fontName] isEqualToString:[font fontName]])) + break; + i = NSMaxRange (range); + } + if (i < stringLength) + /* Make the test `used <= glyph_len' below fail if textStorage + contained some fonts other than the specified one. */ + used = glyph_len + 1; + else + { + NSRange range = NSMakeRange (0, stringLength); + + range = [layoutManager glyphRangeForCharacterRange:range + actualCharacterRange:NULL]; + numberOfGlyphs = NSMaxRange (range); + used = numberOfGlyphs; + for (i = 0; i < numberOfGlyphs; i++) + if ([layoutManager notShownAttributeForGlyphAtIndex:i]) + used--; + } + + if (0 < used && used <= glyph_len) + { + NSUInteger glyphIndex, prevGlyphIndex; + NSUInteger *permutation; + NSRange compRange, range; + CGFloat totalAdvance; + + glyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + permutation = NULL; +#define RIGHT_TO_LEFT_P permutation + + /* Fill the `comp_range' member of struct mac_glyph_layout, and + setup a permutation for right-to-left text. */ + compRange = NSMakeRange (0, 0); + for (range = NSMakeRange (0, 0); NSMaxRange (range) < used; + range.length++) + { + struct ns_glyph_layout *gl = glyph_layouts + NSMaxRange (range); + NSUInteger characterIndex = + [layoutManager characterIndexForGlyphAtIndex:glyphIndex]; + + gl->string_index = characterIndex; + + if (characterIndex >= NSMaxRange (compRange)) + { + compRange.location = NSMaxRange (compRange); + do + { + NSRange characterRange = + [string + rangeOfComposedCharacterSequenceAtIndex:characterIndex]; + + compRange.length = + NSMaxRange (characterRange) - compRange.location; + [layoutManager glyphRangeForCharacterRange:compRange + actualCharacterRange:&characterRange]; + characterIndex = NSMaxRange (characterRange) - 1; + } + while (characterIndex >= NSMaxRange (compRange)); + + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + range = NSMakeRange (NSMaxRange (range), 0); + } + + gl->comp_range.location = compRange.location; + gl->comp_range.length = compRange.length; + + while (++glyphIndex < numberOfGlyphs) + if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + break; + } + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + /* Then fill the remaining members. */ + glyphIndex = prevGlyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + if (!RIGHT_TO_LEFT_P) + totalAdvance = 0; + else + { + NSUInteger nrects; + NSRect *glyphRects = + [layoutManager + rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs)) + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + + totalAdvance = NSMaxX (glyphRects[0]); + } + + for (i = 0; i < used; i++) + { + struct ns_glyph_layout *gl; + NSPoint location; + NSUInteger nextGlyphIndex; + NSRange glyphRange; + NSRect *glyphRects; + NSUInteger nrects; + + if (!RIGHT_TO_LEFT_P) + gl = glyph_layouts + i; + else + { + NSUInteger dest = permutation[i]; + + gl = glyph_layouts + dest; + if (i < dest) + { + NSUInteger tmp = gl->string_index; + + gl->string_index = glyph_layouts[i].string_index; + glyph_layouts[i].string_index = tmp; + } + } + gl->glyph_id = [layoutManager glyphAtIndex: glyphIndex]; + + location = [layoutManager locationForGlyphAtIndex:glyphIndex]; + gl->baseline_delta = spaceLocation.y - location.y; + + for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs; + nextGlyphIndex++) + if (![layoutManager + notShownAttributeForGlyphAtIndex:nextGlyphIndex]) + break; + + if (!RIGHT_TO_LEFT_P) + { + CGFloat maxX; + + if (prevGlyphIndex == 0) + glyphRange = NSMakeRange (0, nextGlyphIndex); + else + glyphRange = NSMakeRange (glyphIndex, + nextGlyphIndex - glyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + maxX = max (NSMaxX (glyphRects[0]), totalAdvance); + gl->advance_delta = location.x - totalAdvance; + gl->advance = maxX - totalAdvance; + totalAdvance = maxX; + } + else + { + CGFloat minX; + + if (nextGlyphIndex == numberOfGlyphs) + glyphRange = NSMakeRange (prevGlyphIndex, + numberOfGlyphs - prevGlyphIndex); + else + glyphRange = NSMakeRange (prevGlyphIndex, + glyphIndex + 1 - prevGlyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + minX = min (NSMinX (glyphRects[0]), totalAdvance); + gl->advance = totalAdvance - minX; + totalAdvance = minX; + gl->advance_delta = location.x - totalAdvance; + } + + prevGlyphIndex = glyphIndex + 1; + glyphIndex = nextGlyphIndex; + } + + if (RIGHT_TO_LEFT_P) + xfree (permutation); + +#undef RIGHT_TO_LEFT_P + + result = used; + } + [textStorage release]; + + return result; +} + +static Lisp_Object +nsfont_shape (Lisp_Object lgstring, Lisp_Object direction) +{ + struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring)); + struct nsfont_info *font_info = (struct nsfont_info *) font; + struct ns_glyph_layout *glyph_layouts; + NSFont *nsfont = font_info->nsfont; + ptrdiff_t glyph_len, len, i; + Lisp_Object tem; + unichar *mb_buf; + NSUInteger used; + + glyph_len = LGSTRING_GLYPH_LEN (lgstring); + for (i = 0; i < glyph_len; ++i) + { + tem = LGSTRING_GLYPH (lgstring, i); + + if (NILP (tem)) + break; + } + + len = i; + + if (INT_MAX / 2 < len) + memory_full (SIZE_MAX); + + block_input (); + + mb_buf = alloca (len * sizeof *mb_buf); + + for (i = 0; i < len; ++i) + { + uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i)); + mb_buf[i] = (unichar) c; + } + + NSString *string = [NSString stringWithCharacters: mb_buf + length: len]; + unblock_input (); + + if (!string) + return Qnil; + + block_input (); + + enum lgstring_direction dir = DIR_UNKNOWN; + + if (EQ (direction, QL2R)) + dir = DIR_L2R; + else if (EQ (direction, QR2L)) + dir = DIR_R2L; + glyph_layouts = alloca (sizeof (struct ns_glyph_layout) * glyph_len); + used = ns_font_shape (nsfont, string, glyph_layouts, glyph_len, dir); + + for (i = 0; i < used; i++) + { + Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i); + struct ns_glyph_layout *gl = glyph_layouts + i; + EMACS_INT from, to; + struct font_metrics metrics; + + if (NILP (lglyph)) + { + lglyph = LGLYPH_NEW (); + LGSTRING_SET_GLYPH (lgstring, i, lglyph); + } + + from = gl->comp_range.location; + LGLYPH_SET_FROM (lglyph, from); + + to = gl->comp_range.location + gl->comp_range.length; + LGLYPH_SET_TO (lglyph, to - 1); + + /* LGLYPH_CHAR is used in `describe-char' for checking whether + the composition is trivial. */ + { + UTF32Char c; + + if (mb_buf[gl->string_index] >= 0xD800 + && mb_buf[gl->string_index] < 0xDC00) + c = (((mb_buf[gl->string_index] - 0xD800) << 10) + + (mb_buf[gl->string_index + 1] - 0xDC00) + 0x10000); + else + c = mb_buf[gl->string_index]; + + LGLYPH_SET_CHAR (lglyph, c); + } + + { + unsigned long cc = gl->glyph_id; + LGLYPH_SET_CODE (lglyph, cc); + } + + nsfont_text_extents (font, &gl->glyph_id, 1, &metrics); + LGLYPH_SET_WIDTH (lglyph, metrics.width); + LGLYPH_SET_LBEARING (lglyph, metrics.lbearing); + LGLYPH_SET_RBEARING (lglyph, metrics.rbearing); + LGLYPH_SET_ASCENT (lglyph, metrics.ascent); + LGLYPH_SET_DESCENT (lglyph, metrics.descent); + } + unblock_input (); + + return make_fixnum (used); +} /* ========================================================================== @@ -1134,6 +1606,50 @@ is false when (FROM > 0 || TO < S->nchars). */ ========================================================================== */ +static NSGlyph +ns_uni_to_glyphs_1 (struct nsfont_info *info, unsigned int c) +{ + unichar characters[] = { c }; + NSString *string = + [NSString stringWithCharacters: characters + length: 1]; + NSDictionary *attributes = + [NSDictionary dictionaryWithObjectsAndKeys: + info->nsfont, NSFontAttributeName, nil]; + NSTextStorage *storage = [[NSTextStorage alloc] initWithString: string + attributes: attributes]; + NSTextContainer *text_container = [[NSTextContainer alloc] init]; + NSLayoutManager *manager = [[NSLayoutManager alloc] init]; + + [manager addTextContainer: text_container]; + [text_container release]; /* Retained by manager */ + [storage addLayoutManager: manager]; + [manager release]; /* Retained by storage */ + + NSFont *font_in_storage = [storage attribute: NSFontAttributeName + atIndex:0 + effectiveRange: NULL]; + NSGlyph glyph = FONT_INVALID_CODE; + + if ((font_in_storage == info->nsfont + || [[font_in_storage fontName] isEqualToString: [info->nsfont fontName]])) + { + @try + { + glyph = [manager glyphAtIndex: 0]; + } + @catch (NSException *e) + { + /* GNUstep bug? */ + glyph = 'X'; + } + } + + [storage release]; + + return glyph; +} + /* Find and cache corresponding glyph codes for unicode values in given hi-byte block of 256. */ static void @@ -1141,7 +1657,7 @@ is false when (FROM > 0 || TO < S->nchars). */ { unichar *unichars = xmalloc (0x101 * sizeof (unichar)); unsigned int i, g, idx; - unsigned short *glyphs; + unsigned int *glyphs; if (NSFONT_TRACE) fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n", @@ -1149,7 +1665,7 @@ is false when (FROM > 0 || TO < S->nchars). */ block_input (); - font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short)); + font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned int)); if (!unichars || !(font_info->glyphs[block])) emacs_abort (); @@ -1166,7 +1682,8 @@ is false when (FROM > 0 || TO < S->nchars). */ for (i = 0; i < 0x100; i++, glyphs++) { g = unichars[i]; - *glyphs = g; + NSGlyph glyph = ns_uni_to_glyphs_1 (font_info, g); + *glyphs = glyph; } } @@ -1175,18 +1692,19 @@ is false when (FROM > 0 || TO < S->nchars). */ } -/* Determine and cache metrics for corresponding glyph codes in given - hi-byte block of 256. */ +/* Determine and cache metrics for glyphs in given hi-byte block of + 256. */ static void -ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block) +ns_glyph_metrics (struct nsfont_info *font_info, unsigned int block) { - unsigned int i, g; + unsigned int i; + NSGlyph g; unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs]; NSFont *sfont; struct font_metrics *metrics; if (NSFONT_TRACE) - fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n", + fprintf (stderr, "%p\tComputing metrics for glyphs in block %u\n", font_info, block); /* not implemented yet (as of startup 0.18), so punt */ @@ -1209,19 +1727,14 @@ is false when (FROM > 0 || TO < S->nchars). */ w = max ([sfont advancementForGlyph: g].width, 2.0); metrics->width = lrint (w); - lb = r.origin.x; - rb = r.size.width - w; - // Add to bearing for LCD smoothing. We don't know if it is there. - if (lb < 0) - metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN); - if (font_info->ital) - rb += (CGFloat) (0.22F * font_info->height); - metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN); - - metrics->descent = r.origin.y < 0 ? -r.origin.y : 0; - /* lrint (hshrink * [sfont ascender] + expand * hd/2); */ - metrics->ascent = r.size.height - metrics->descent; - /* -lrint (hshrink* [sfont descender] - expand * hd/2); */ + lb = NSMinX (r); + rb = NSMaxX (r); + + metrics->rbearing = lrint (rb); + metrics->lbearing = lrint (lb); + + metrics->descent = NSMinY (r); + metrics->ascent = NSMaxY (r); } unblock_input (); } @@ -1257,6 +1770,7 @@ is false when (FROM > 0 || TO < S->nchars). */ .has_char = nsfont_has_char, .encode_char = nsfont_encode_char, .text_extents = nsfont_text_extents, + .shape = nsfont_shape, .draw = nsfont_draw, }; @@ -1265,7 +1779,6 @@ is false when (FROM > 0 || TO < S->nchars). */ { DEFSYM (Qcondensed, "condensed"); DEFSYM (Qexpanded, "expanded"); - DEFSYM (Qapple, "apple"); DEFSYM (Qmedium, "medium"); DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script, doc: /* Internal use: maps font registry to Unicode script. */); diff --git a/src/nsterm.h b/src/nsterm.h index 4bbcf43973..944dbd727c 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -820,7 +820,7 @@ #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) XCharStruct max_bounds; /* We compute glyph codes and metrics on-demand in blocks of 256 indexed by hibyte, lobyte. */ - unsigned short **glyphs; /* map Unicode index to glyph */ + unsigned int **glyphs; /* map Unicode index to glyph */ struct font_metrics **metrics; }; #endif diff --git a/src/nsterm.m b/src/nsterm.m index 641f3f548b..4c915dac5d 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1079,11 +1079,16 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) /* clipping */ if (r) { - [[NSGraphicsContext currentContext] saveGraphicsState]; + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; +#ifdef NS_IMPL_COCOA if (n == 2) NSRectClipList (r, 2); else NSRectClip (*r); +#else + GSRectClipList (ctx, r, n); +#endif gsaved = YES; } } @@ -2435,9 +2440,6 @@ Hide the window (X11 semantics) EmacsView *view = FRAME_NS_VIEW (f); FRAME_POINTER_TYPE (f) = cursor; [[view window] invalidateCursorRectsForView: view]; - /* Redisplay assumes this function also draws the changed frame - cursor, but this function doesn't, so do it explicitly. */ - gui_update_cursor (f, 1); } } @@ -2849,38 +2851,31 @@ Hide the window (X11 semantics) External (RIF); compute left/right overhang of whole string and set in s -------------------------------------------------------------------------- */ { - if (s->char2b) + if (s->cmp == NULL + && (s->first_glyph->type == CHAR_GLYPH + || s->first_glyph->type == COMPOSITE_GLYPH)) { struct font_metrics metrics; - if (s->first_glyph->type == CHAR_GLYPH && !s->font_not_found_p) - { - struct font *font = s->font; - font->driver->text_extents (font, s->char2b, s->nchars, &metrics); - s->left_overhang = -metrics.lbearing; - s->right_overhang - = metrics.rbearing > metrics.width - ? metrics.rbearing - metrics.width : 0; - } - else if (s->first_glyph->type == COMPOSITE_GLYPH) - { - Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); - composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); - s->right_overhang = (metrics.rbearing > metrics.width - ? metrics.rbearing - metrics.width : 0); - s->left_overhang = metrics.lbearing < 0 ? -metrics.lbearing : 0; - } + if (s->first_glyph->type == CHAR_GLYPH) + { + struct font *font = s->font; + font->driver->text_extents (font, s->char2b, s->nchars, &metrics); + } + else + { + Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); + + composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); + } + s->right_overhang = (metrics.rbearing > metrics.width + ? metrics.rbearing - metrics.width : 0); + s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0; } - else + else if (s->cmp) { - s->left_overhang = 0; -#ifdef NS_IMPL_GNUSTEP - if (EQ (font->driver->type, Qns)) - s->right_overhang = ((struct nsfont_info *)font)->ital ? - FONT_HEIGHT (font) * 0.2 : 0; - else -#endif - s->right_overhang = 0; + s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width; + s->left_overhang = - s->cmp->lbearing; } } @@ -3020,14 +3015,13 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. struct frame *f = WINDOW_XFRAME (w); struct glyph *phys_cursor_glyph; struct glyph *cursor_glyph; - struct face *face; - NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f); /* If cursor is out of bounds, don't draw garbage. This can happen in mini-buffer windows when switching between echo area glyphs and mini-buffer. */ - NSTRACE ("ns_draw_window_cursor"); + NSTRACE ("ns_draw_window_cursor (on = %d, cursor_type = %d)", + on_p, cursor_type); if (!on_p) return; @@ -3043,6 +3037,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL) { + NSTRACE_MSG ("No phys cursor glyph was found!"); + if (glyph_row->exact_window_width_line_p && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) { @@ -3052,10 +3048,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. return; } - /* We draw the cursor (with NSRectFill), then draw the glyph on top - (other terminals do it the other way round). We must set - w->phys_cursor_width to the cursor width. For bar cursors, that - is CURSOR_WIDTH; for box cursors, it is the glyph width. */ get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h); /* The above get_phys_cursor_geometry call set w->phys_cursor_width @@ -3087,17 +3079,17 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. /* Prevent the cursor from being drawn outside the text area. */ r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA)); - ns_focus (f, &r, 1); + ns_focus (f, NULL, 0); - face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id); - if (face && NS_FACE_BACKGROUND (face) - == ns_index_color (FRAME_CURSOR_COLOR (f), f)) - { - [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set]; - hollow_color = FRAME_CURSOR_COLOR (f); - } - else - [FRAME_CURSOR_COLOR (f) set]; + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; +#ifdef NS_IMPL_GNUSTEP + GSRectClipList (ctx, &r, 1); +#else + NSRectClip (r); +#endif + + [FRAME_CURSOR_COLOR (f) set]; switch (cursor_type) { @@ -3105,13 +3097,11 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. case NO_CURSOR: break; case FILLED_BOX_CURSOR: - NSRectFill (r); + draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); break; case HOLLOW_BOX_CURSOR: - NSRectFill (r); - [hollow_color set]; - NSRectFill (NSInsetRect (r, 1, 1)); - [FRAME_CURSOR_COLOR (f) set]; + draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT); + [NSBezierPath strokeRect: r]; break; case HBAR_CURSOR: NSRectFill (r); @@ -3127,12 +3117,9 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. NSRectFill (s); break; } - ns_unfocus (f); - /* Draw the character under the cursor. Other terms only draw - the character on top of box cursors, so do the same here. */ - if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR) - draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); + [ctx restoreGraphicsState]; + ns_unfocus (f); } @@ -3312,16 +3299,18 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if (s->for_overlaps) return; + if (s->hl == DRAW_CURSOR) + [FRAME_BACKGROUND_COLOR (s->f) set]; + else if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + /* Do underline. */ if (face->underline) { if (s->face->underline == FACE_UNDER_WAVE) { - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; - ns_draw_underwave (s, width, x); } else if (s->face->underline == FACE_UNDER_LINE) @@ -3392,11 +3381,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. s->underline_position = position; r = NSMakeRect (x, s->ybase + position, width, thickness); - - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; NSRectFill (r); } } @@ -3406,11 +3390,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. { NSRect r; r = NSMakeRect (x, s->y, width, 1); - - if (face->overline_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->overline_color, s->f) set]; NSRectFill (r); } @@ -3433,10 +3412,6 @@ larger if there are taller display elements (e.g., characters dy = lrint ((glyph_height - h) / 2); r = NSMakeRect (x, glyph_y + dy, width, 1); - if (face->strike_through_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->strike_through_color, s->f) set]; NSRectFill (r); } } @@ -3584,17 +3559,7 @@ Function modeled after x_draw_glyph_string_box (). struct glyph *last_glyph; NSRect r; int hthickness, vthickness; - struct face *face; - - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = s->face; + struct face *face = s->face; vthickness = face->box_vertical_line_width; hthickness = face->box_horizontal_line_width; @@ -3668,34 +3633,26 @@ Function modeled after x_draw_glyph_string_box (). || FONT_TOO_HIGH (s->font) || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) { - struct face *face; - if (s->hl == DRAW_MOUSE_FACE) - { - face - = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + struct face *face = s->face; if (!face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set]; } - if (s->hl != DRAW_CURSOR) - { - NSRect r = NSMakeRect (s->x, s->y + box_line_width, - s->background_width, - s->height-2*box_line_width); - NSRectFill (r); - } + NSRect r = NSMakeRect (s->x, s->y + box_line_width, + s->background_width, + s->height-2*box_line_width); + NSRectFill (r); s->background_filled_p = 1; } @@ -3716,7 +3673,7 @@ Function modeled after x_draw_glyph_string_box (). int th; char raised_p; NSRect br; - struct face *face; + struct face *face = s->face; NSColor *tdCol; NSTRACE ("ns_dumpglyphs_image"); @@ -3737,15 +3694,6 @@ Function modeled after x_draw_glyph_string_box (). /* Draw BG: if we need larger area than image itself cleared, do that, otherwise, since we composite the image under NS (instead of mucking with its background color), we must clear just the image area. */ - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set]; @@ -3816,16 +3764,8 @@ Function modeled after x_draw_glyph_string_box (). if (s->hl == DRAW_CURSOR) { - [FRAME_CURSOR_COLOR (s->f) set]; - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) + [FRAME_CURSOR_COLOR (s->f) set]; tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); - else - /* Currently on NS img->mask is always 0. Since - get_window_cursor_type specifies a hollow box cursor when on - a non-masked image we never reach this clause. But we put it - in, in anticipation of better support for image masks on - NS. */ - tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); } else { @@ -3877,66 +3817,35 @@ Function modeled after x_draw_glyph_string_box (). static void ns_dumpglyphs_stretch (struct glyph_string *s) { - NSRect r[2]; NSRect glyphRect; - int n; - struct face *face; + struct face *face = s->face; NSColor *fgCol, *bgCol; if (!s->background_filled_p) { - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + face = s->face; bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); - glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); - - [bgCol set]; - - /* NOTE: under NS this is NOT used to draw cursors, but we must avoid - overwriting cursor (usually when cursor on a tab) */ if (s->hl == DRAW_CURSOR) - { - CGFloat x, width; + { + fgCol = bgCol; + bgCol = FRAME_CURSOR_COLOR (s->f); + } - /* FIXME: This looks like it will only work for left to - right languages. */ - x = NSMinX (glyphRect); - width = s->w->phys_cursor_width; - glyphRect.size.width -= width; - glyphRect.origin.x += width; + glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); - NSRectFill (glyphRect); + [bgCol set]; - /* Draw overlining, etc. on the cursor. */ - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) - ns_draw_text_decoration (s, face, bgCol, width, x); - else - ns_draw_text_decoration (s, face, fgCol, width, x); - } - else - { - NSRectFill (glyphRect); - } + NSRectFill (glyphRect); /* Draw overlining, etc. on the stretch glyph (or the part of the stretch glyph after the cursor). */ ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect), NSMinX (glyphRect)); - ns_unfocus (s->f); s->background_filled_p = 1; } } @@ -3945,7 +3854,7 @@ overwriting cursor (usually when cursor on a tab) */ static void ns_draw_glyph_string_foreground (struct glyph_string *s) { - int x, flags; + int x; struct font *font = s->font; /* If first glyph of S has a left box line, start drawing the text @@ -3956,15 +3865,9 @@ overwriting cursor (usually when cursor on a tab) */ else x = s->x; - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - font->driver->draw (s, s->cmp_from, s->nchars, x, s->ybase, - (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p) - || flags == NS_DUMPGLYPH_MOUSEFACE); + !s->for_overlaps && !s->background_filled_p); } @@ -4071,9 +3974,9 @@ overwriting cursor (usually when cursor on a tab) */ struct font *font = s->face->font; if (! font) font = FRAME_FONT (s->f); - NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string"); + NSTRACE ("ns_draw_glyph_string (hl = %u)", s->hl); - if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/) + if (s->next && s->right_overhang && !s->for_overlaps) { int width; struct glyph_string *next; @@ -4110,14 +4013,21 @@ overwriting cursor (usually when cursor on a tab) */ box_drawn_p = 1; } + n = ns_get_glyph_string_clip_rect (s, r); + + if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */ + && !s->clip_tail + && ((s->prev && s->prev->hl != s->hl && s->left_overhang) + || (s->next && s->next->hl != s->hl && s->right_overhang))) + r[0] = NSIntersectionRect (r[0], NSMakeRect (s->x, s->y, s->width, s->height)); + + ns_focus (s->f, r, n); + switch (s->first_glyph->type) { case IMAGE_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); ns_dumpglyphs_image (s, r[0]); - ns_unfocus (s->f); break; case XWIDGET_GLYPH: @@ -4130,57 +4040,36 @@ overwriting cursor (usually when cursor on a tab) */ case CHAR_GLYPH: case COMPOSITE_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - - if (s->for_overlaps || (s->cmp_from > 0 - && ! s->first_glyph->u.cmp.automatic)) - s->background_filled_p = 1; - else - ns_maybe_dumpglyphs_background - (s, s->first_glyph->type == COMPOSITE_GLYPH); - - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - { - BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + if (s->for_overlaps || (isComposite + && (s->cmp_from > 0 + && ! s->first_glyph->u.cmp.automatic))) + s->background_filled_p = 1; + else + ns_maybe_dumpglyphs_background + (s, s->first_glyph->type == COMPOSITE_GLYPH); - if (isComposite) - ns_draw_composite_glyph_string_foreground (s); - else - ns_draw_glyph_string_foreground (s); - } + if (isComposite) + ns_draw_composite_glyph_string_foreground (s); + else + ns_draw_glyph_string_foreground (s); - { - NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), - s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - [col set]; - - /* Draw underline, overline, strike-through. */ - ns_draw_text_decoration (s, s->face, col, s->width, s->x); + { + NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), + s->f) + : FRAME_FOREGROUND_COLOR (s->f)); + [col set]; + + /* Draw underline, overline, strike-through. */ + ns_draw_text_decoration (s, s->face, col, s->width, s->x); + } } - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - - ns_unfocus (s->f); break; case GLYPHLESS_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - if (s->for_overlaps || (s->cmp_from > 0 && ! s->first_glyph->u.cmp.automatic)) s->background_filled_p = 1; @@ -4190,7 +4079,6 @@ overwriting cursor (usually when cursor on a tab) */ /* ... */ /* Not yet implemented. */ /* ... */ - ns_unfocus (s->f); break; default: @@ -4199,13 +4087,92 @@ overwriting cursor (usually when cursor on a tab) */ /* Draw box if not done already. */ if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) + ns_dumpglyphs_box_or_relief (s); + + ns_unfocus (s->f); + + /* Draw surrounding overhangs. */ + if (s->prev) { - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - ns_dumpglyphs_box_or_relief (s); + ns_focus (s->f, NULL, 0); + struct glyph_string *prev; + + for (prev = s->prev; prev; prev = prev->prev) + if (prev->hl != s->hl + && prev->x + prev->width + prev->right_overhang > s->x) + { + /* As prev was drawn while clipped to its own area, we + must draw the right_overhang part using s->hl now. */ + enum draw_glyphs_face save = prev->hl; + struct face *save_face = prev->face; + + prev->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + prev->num_clips = 1; + prev->hl = s->hl; + if (prev->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (prev); + else + ns_draw_composite_glyph_string_foreground (prev); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + [[NSGraphicsContext currentContext] restoreGraphicsState]; + prev->hl = save; + prev->face = save_face; + prev->num_clips = 0; + } ns_unfocus (s->f); } + if (s->next) + { + ns_focus (s->f, NULL, 0); + struct glyph_string *next; + + for (next = s->next; next; next = next->next) + if (next->hl != s->hl + && next->x - next->left_overhang < s->x + s->width) + { + /* As next will be drawn while clipped to its own area, + we must draw the left_overhang part using s->hl now. */ + enum draw_glyphs_face save = next->hl; + struct face *save_face = next->face; + + next->hl = s->hl; + next->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + next->num_clips = 1; + if (next->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (next); + else + ns_draw_composite_glyph_string_foreground (next); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + [[NSGraphicsContext currentContext] restoreGraphicsState]; + next->hl = save; + next->num_clips = 0; + next->face = save_face; + next->clip_head = next; + next->background_filled_p = 0; + } + ns_unfocus (s->f); + } s->num_clips = 0; } diff --git a/src/xdisp.c b/src/xdisp.c index 646beed6f0..9814efd63c 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -29306,7 +29306,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, for (s = head; s; s = s->next) FRAME_RIF (f)->draw_glyph_string (s); -#ifndef HAVE_NS /* When focus a sole frame and move horizontally, this clears on_p causing a failure to erase prev cursor position. */ if (area == TEXT_AREA @@ -29325,7 +29324,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, notice_overwritten_cursor (w, TEXT_AREA, x0, x1, row->y, MATRIX_ROW_BOTTOM_Y (row)); } -#endif /* Value is the x-position up to which drawn, relative to AREA of W. This doesn't include parts drawn because of overhangs. */ -- 2.31.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-General-improvements-to-NS-port.patch >From 27747e0e1b7836aa346572fbac3796ef2c5121c2 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 23 Oct 2021 19:51:31 +0800 Subject: [PATCH 2/2] General improvements to NS port * src/dispextern.h: Remove some !HAVE_NS conditionals around grab related code. * src/frame.c (gui_mouse_grabbed, gui_redo_mouse_highlight): Remove !HAVE_NS conditionals around code. * src/nsmenu.m (ns_update_menubar): Prevent recursive calls and enable shallow updates on GNUstep. (menuNeedsUpdate): Prevent recursive calls. (ns_menu_show): Fix mysterious GC-related bug. (update_frame_tool_bar_1): Work around mysterious toolbar sizing bug on GNUstep. * src/nsterm.h (struct ns_output): New field for tracking toolbar visibility changes. * src/nsterm.m (frame_set_mouse_pixel_position): Implement for GNUstep. (ns_redraw_scroll_bars): Enable for GNUstep. (ns_clear_frame): Redraw scrollbars on GNUstep. (ns_update_window_end): New function. (ns_redisplay_interface): Add ns_update_window_end on GNUstep. (- keyDown): Remove debug code that doesn't work on GNUstep. (- mouseDown): Enable grab tracking on NS port. (- resizeWithOldSuperviewSize): Fix build with NSTRACE. * src/xdisp.c (note_tab_bar_highlight): Enable some code for NS port. --- src/dispextern.h | 2 -- src/frame.c | 4 --- src/nsmenu.m | 76 +++++++++++++++++++++++++++++++++++++++--------- src/nsterm.h | 6 ++++ src/nsterm.m | 42 +++++++++++++++++++++----- src/xdisp.c | 2 -- 6 files changed, 102 insertions(+), 30 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index e03e21fddc..5b28fe7666 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3722,10 +3722,8 @@ #define IMAGE_BACKGROUND_TRANSPARENT(img, f, mask) \ const char *, const char *, enum resource_types); -#ifndef HAVE_NS /* These both used on W32 and X only. */ extern bool gui_mouse_grabbed (Display_Info *); extern void gui_redo_mouse_highlight (Display_Info *); -#endif /* HAVE_NS */ #endif /* HAVE_WINDOW_SYSTEM */ diff --git a/src/frame.c b/src/frame.c index 2b1cb452ef..79a7c89e0d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -5028,8 +5028,6 @@ gui_set_no_special_glyphs (struct frame *f, Lisp_Object new_value, Lisp_Object o } -#ifndef HAVE_NS - /* Non-zero if mouse is grabbed on DPYINFO and we know the frame where it is. */ @@ -5054,8 +5052,6 @@ gui_redo_mouse_highlight (Display_Info *dpyinfo) dpyinfo->last_mouse_motion_y); } -#endif /* HAVE_NS */ - /* Subroutines of creating an X frame. */ /* Make sure that Vx_resource_name is set to a reasonable value. diff --git a/src/nsmenu.m b/src/nsmenu.m index 05b89c2f56..b93d3a79bd 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -101,6 +101,15 @@ static void ns_update_menubar (struct frame *f, bool deep_p) { +#ifdef NS_IMPL_GNUSTEP + static int inside = 0; + + if (inside) + return; + + inside++; +#endif + BOOL needsSet = NO; id menu = [NSApp mainMenu]; bool owfi; @@ -120,7 +129,12 @@ NSTRACE ("ns_update_menubar"); if (f != SELECTED_FRAME () || FRAME_EXTERNAL_MENU_BAR (f) == 0) + { +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif return; + } XSETFRAME (Vmenu_updating_frame, f); /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */ @@ -144,10 +158,6 @@ t = -(1000*tb.time+tb.millitm); #endif -#ifdef NS_IMPL_GNUSTEP - deep_p = 1; /* See comment in menuNeedsUpdate. */ -#endif - if (deep_p) { /* Make a widget-value tree representing the entire menu trees. */ @@ -275,6 +285,9 @@ free_menubar_widget_value_tree (first_wv); discard_menu_items (); unbind_to (specpdl_count, Qnil); +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif return; } @@ -408,6 +421,10 @@ if (needsSet) [NSApp setMainMenu: menu]; +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif + unblock_input (); } @@ -490,17 +507,34 @@ - (instancetype)initWithTitle: (NSString *)title call to ns_update_menubar. */ - (void)menuNeedsUpdate: (NSMenu *)menu { +#ifdef NS_IMPL_GNUSTEP + static int inside = 0; +#endif + if (!FRAME_LIVE_P (SELECTED_FRAME ())) return; -#ifdef NS_IMPL_COCOA -/* TODO: GNUstep calls this method when the menu is still being built - which results in a recursive stack overflow. One possible solution - is to use menuWillOpen instead, but the Apple docs explicitly warn - against changing the contents of the menu in it. I don't know what - the right thing to do for GNUstep is. */ +#ifdef NS_IMPL_GNUSTEP + /* GNUstep calls this method when the menu is still being built + which results in a recursive stack overflow, which this variable + prevents. */ + + if (!inside) + ++inside; + else + return; +#endif + if (needsUpdate) - ns_update_menubar (SELECTED_FRAME (), true); + { +#ifdef NS_IMPL_GNUSTEP + needsUpdate = NO; +#endif + ns_update_menubar (SELECTED_FRAME (), true); + } + +#ifdef NS_IMPL_GNUSTEP + --inside; #endif } @@ -827,6 +861,9 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item p.x = x; p.y = y; + /* Don't GC due to a mysterious bug. */ + inhibit_garbage_collection (); + /* now parse stage 2 as in ns_update_menubar */ wv = make_widget_value ("contextmenu", NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; @@ -998,15 +1035,17 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item pmenu = [[EmacsMenu alloc] initWithTitle: NILP (title) ? @"" : [NSString stringWithLispString: title]]; + /* On GNUstep, this call makes menu_items nil for whatever reason + when displaying a context menu from `context-menu-mode'. */ + Lisp_Object items = menu_items; [pmenu fillWithWidgetValue: first_wv->contents]; + menu_items = items; free_menubar_widget_value_tree (first_wv); - unbind_to (specpdl_count, Qnil); - popup_activated_flag = 1; tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps]; popup_activated_flag = 0; [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; - + unbind_to (specpdl_count, Qnil); unblock_input (); return tem; } @@ -1057,6 +1096,15 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item [toolbar clearActive]; #else [toolbar clearAll]; + /* It takes at least 3 such adjustments to fix an issue where the + tool bar is 2x too tall when a frame's tool bar is first shown. + This is ugly, but I have no other solution for this problem. */ + if (FRAME_OUTPUT_DATA (f)->tool_bar_adjusted < 3) + { + [toolbar setVisible: NO]; + FRAME_OUTPUT_DATA (f)->tool_bar_adjusted++; + [toolbar setVisible: YES]; + } #endif /* Update EmacsToolbar as in GtkUtils, build items list. */ diff --git a/src/nsterm.h b/src/nsterm.h index 944dbd727c..8175f99664 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -978,6 +978,12 @@ #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) /* Non-zero if we are doing an animation, e.g. toggling the tool bar. */ int in_animation; + +#ifdef NS_IMPL_GNUSTEP + /* Zero if this is the first time a toolbar has been updated on this + frame. */ + int tool_bar_adjusted; +#endif }; /* This dummy declaration needed to support TTYs. */ diff --git a/src/nsterm.m b/src/nsterm.m index 4c915dac5d..a63883cd08 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -65,6 +65,7 @@ Updated by Christian Limpach (chris@nice.ch) #ifdef NS_IMPL_GNUSTEP #include "process.h" +#import #endif #ifdef NS_IMPL_COCOA @@ -2256,13 +2257,19 @@ Hide the window (X11 semantics) { NSTRACE ("frame_set_mouse_pixel_position"); - /* FIXME: what about GNUstep? */ #ifdef NS_IMPL_COCOA CGPoint mouse_pos = CGPointMake(f->left_pos + pix_x, f->top_pos + pix_y + FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f)); CGWarpMouseCursorPosition (mouse_pos); +#else + GSDisplayServer *server = GSServerForWindow ([FRAME_NS_VIEW (f) window]); + [server setMouseLocation: NSMakePoint (f->left_pos + pix_x, + f->top_pos + pix_y + + FRAME_NS_TITLEBAR_HEIGHT(f) + + FRAME_TOOLBAR_HEIGHT(f)) + onScreen: [[[FRAME_NS_VIEW (f) window] screen] screenNumber]]; #endif } @@ -2575,8 +2582,7 @@ Hide the window (X11 semantics) ========================================================================== */ -#if 0 -/* FIXME: Remove this function. */ +#ifdef NS_IMPL_GNUSTEP static void ns_redraw_scroll_bars (struct frame *f) { @@ -2621,10 +2627,9 @@ Hide the window (X11 semantics) NSRectFill (r); ns_unfocus (f); - /* as of 2006/11 or so this is now needed */ - /* FIXME: I don't see any reason for this and removing it makes no - difference here. Do we need it for GNUstep? */ - //ns_redraw_scroll_bars (f); +#ifdef NS_IMPL_GNUSTEP + ns_redraw_scroll_bars (f); +#endif unblock_input (); } @@ -4922,6 +4927,17 @@ static Lisp_Object ns_string_to_lispmod (const char *s) { } +#ifdef NS_IMPL_GNUSTEP +static void +ns_update_window_end (struct window *w, bool cursor_on_p, + bool mouse_face_overwritten_p) +{ + NSTRACE ("ns_update_window_end (cursor_on_p = %d)", cursor_on_p); + + ns_redraw_scroll_bars (WINDOW_XFRAME (w)); +} +#endif + /* This and next define (many of the) public functions in this file. */ /* gui_* are generic versions in xdisp.c that we, and other terms, get away with using despite presence in the "system dependent" redisplay @@ -4938,7 +4954,11 @@ static Lisp_Object ns_string_to_lispmod (const char *s) ns_scroll_run, ns_after_update_window_line, NULL, /* update_window_begin */ +#ifndef NS_IMPL_GNUSTEP NULL, /* update_window_end */ +#else + ns_update_window_end, +#endif 0, /* flush_display */ gui_clear_window_mouse_face, gui_get_glyph_overhangs, @@ -6166,9 +6186,11 @@ In that case we use UCKeyTranslate (ns_get_shifted_character) Lisp_Object kind = fnKeysym ? QCfunction : QCordinary; emacs_event->modifiers = EV_MODIFIERS2 (flags, kind); +#ifndef NS_IMPL_GNUSTEP if (NS_KEYLOG) fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n", code, fnKeysym, flags, emacs_event->modifiers); +#endif /* If it was a function key or had control-like modifiers, pass it directly to Emacs. */ @@ -6681,6 +6703,11 @@ - (void)mouseDown: (NSEvent *)theEvent emacs_event->code = EV_BUTTON (theEvent); emacs_event->modifiers = EV_MODIFIERS (theEvent) | EV_UDMODIFIERS (theEvent); + + if (emacs_event->modifiers & down_modifier) + FRAME_DISPLAY_INFO (emacsframe)->grabbed |= 1 << EV_BUTTON (theEvent); + else + FRAME_DISPLAY_INFO (emacsframe)->grabbed &= ~(1 << EV_BUTTON (theEvent)); } XSETINT (emacs_event->x, lrint (p.x)); @@ -6981,7 +7008,6 @@ - (void)resizeWithOldSuperviewSize: (NSSize)oldSize height = (int)NSHeight (frame); NSTRACE_SIZE ("New size", NSMakeSize (width, height)); - NSTRACE_SIZE ("Original size", size); /* Reset the frame size to match the bounds of the superview (the NSWindow's contentView). We need to do this as sometimes the diff --git a/src/xdisp.c b/src/xdisp.c index 9814efd63c..86c4e704d5 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -13894,7 +13894,6 @@ note_tab_bar_highlight (struct frame *f, int x, int y) clear_mouse_face (hlinfo); bool mouse_down_p = false; -#ifndef HAVE_NS /* Mouse is down, but on different tab-bar item? Or alternatively, the mouse might've been pressed somewhere we don't know about, and then have moved onto the tab bar. In this case, @@ -13907,7 +13906,6 @@ note_tab_bar_highlight (struct frame *f, int x, int y) if (mouse_down_p && f->last_tab_bar_item != prop_idx && f->last_tab_bar_item != -1) return; -#endif draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; /* If tab-bar item is not enabled, don't highlight it. */ -- 2.31.1 --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Fri Nov 05 20:21:20 2021 Received: (at 51411) by debbugs.gnu.org; 6 Nov 2021 00:21:20 +0000 Received: from localhost ([127.0.0.1]:47699 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mj9SJ-0004a3-Vc for submit@debbugs.gnu.org; Fri, 05 Nov 2021 20:21:20 -0400 Received: from sonic307-10.consmr.mail.ne1.yahoo.com ([66.163.190.33]:40697) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mj9SE-0004Z6-D5 for 51411@debbugs.gnu.org; Fri, 05 Nov 2021 20:21:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636158059; bh=flxZ58qn3Gxsp7iJ2OynAEAbatBUqU2einusN6opp7k=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=Kp49lPnZHBCHxAqctBYaRBS/ZLA0cJH8ua4gMrbOcdVATXU+Do0aB5T3bp9SFo5754UZet79ngMPxTpBoxjjApjK2dufs2+fnBHdAIt18U+ID0y6iZOp1Rbs1+ctVHqTgCYcrQSBmjIhwclBnExtFM2Bg0kVhzSLP2fGxsy0mzWLM5UqatdkeByq4IGJBuL3dVeVA1T4pvDjemzjuJqjZYaUDUfPBiPWmpHZr8CQs7EELIC36dljGtkWFGdB4dY2VUE1DwHtzo0+fwaG3X9kn3NBiEvRWJiRYIi+yVPlNlQ21gx+X0PNDEkH7TqFrmrRwFuly/JNQEVffyyunZdjRg== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636158059; bh=/Gpw83m5wsmSepPRz4R1aVA0/JmDsUNJxd5J1KvDzoi=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=lDHyTu6cxcgbNTFytOlxV8T1de6c+mOP85NuCzJiaXVckpapRI7pJWeb6Jn4iKxNf7O1DeWcGGpn6RLfcjiZ9qLlqe26MOmcaZTCS+0gLNu5bn0JsZuDNfoEkdZ5GHOKJM4Xz7WlkyJdvhbBR9gm58C3I0Eca+WPCxa4TjMJL7qLs3GFzc9sTq7mZEXZzKi38k/foVmuMau9ly0D1mCnuDQ368bVgA3fO+dgjbfHNWhBAcXvIrlz0H5vVCw6gYZAnkilQr1T4abycMFxGvLWa4FyUMpORgnmu30Qz42dIKug5hIbm0vGVjDt6mmtTLKnolNAVAq2W6ljPXBBjMz6pw== X-YMail-OSG: 7yi5aBoVM1m88atNqTkKldtn2KSnoPrbuP0xZCt4nOI_7eu50qy6BEUlxMSDZ2j pwasUqqp6VqbLcluwFHty_VDlRyj4_aPO7KdSx3Jzy2PGr6LFNW.7DyS5J0EkhdQx86J4ZV7YBNV rbrYuSGiRkJgmTAFtuGAiTbaDjwMSjePCIfRuQ72ExFi8QvRDx6OXi0gfOgTKaA9Q1N.1KIfkKMr WBUOghJ1cxOsqsbyMJM37laOZoxXRNrm0rXUrdJf4ZyBqIoekRBBKd9YG8ULK.HhiHgcGtV9.UQd .gFzE6rx6mWCjZUW.7SThe9m.53Ot509u0.b20m35Kfx1Bk99fFK65XYOjfYzp2W..wIhlkatxdZ AJikvgL0kjc5UaMlJLEhdbkfmHm2L12DEcPcP8Y.o23_VcD.SZI4Q.db0eXetdkdPqY00y7w8Gx5 kbJz6mXmrtLHOpRMqCm_1VdgIDZ936UndhPYyGij_MYoP0_my2eaKYFaOCBq4k5RiBocprYPtEOH 8ba3xOJQCOw2vENRXojK2t0tX85qyqi8EaFdIJ0H8WSb7RFIrEzGHctVe2w98hM8lgKhrsbrpiY_ 9p447f_.qM25As9Z4PT9VEFGfNteXcEdyYyo2r3H9C07GmezS049zuJdav1VLPbO9Y7SAc8rQb_i 3PIGsWuScVVL8WDN77eXQeTraEC3lsz8n3NaLFz2JKxlV18BZXEwwybcp8ORb6FW0GdCVTN7p7RF IBkofUWbCbHNy5lKgIou.X5j0GP5svZc61CoD9yhzLWAGBWuPtFgRExBz0L87nEFjSrR1Zdhadc. zTjEb69NYSiqy2ixPSxCnHMyhzhgoqfYQVlsPjk2PmMxkuLZ5kaiMy26FXXD2BKpA8p9qPWtR8mm 0mP4ohTA2ku8eYK5LVqjSyFhybA1V8BGmY_b5qxkB7mWVKqJwjMH8LvrDbugVZHqr1OpOUlZDY2c XPFwT03pZtW9f7Qy_x2aKExwcxNgmQPAkdbBcw7HSgM9wz2lQmdOQgNhzlwlnODgUkrZLBNU.j2Q xpdXZ0pDHKSE.bvh0ZQj8_KnsDV_7TZA4fe9oYbdSeWbmZGuYUMSs5kvyaQjX7.VIK1lHhi3Go8. a61vGPcKw.Ykl5DZ25.sI.2YF2_xXEbr8GTNOl6Y3hvL44hN6Z2PmICIMJ_ZZ8P1wJl7_.B2zRr5 _CYSiLe9cPm03iZs3EYSyJ9x2L0vOKzUjDQOiJXmnp9YSujW2SqauPIFcwKk7V4CjRzHxJSAMW_b YdPM4z6skQpfKkKWAlgDvR8rCIDbgLSHYLQPcly1nFB6.t1tUKxmB.R6z34o5cZSwb_LnppM_ABz lskCb4hSgpaSo6jBsGvQntvp58t8IE67O6R4MtH5t5WDHZoyMo6NRWiKrQj.zsQJj9jK6Z7rTiWh MHcBOA8rf4qbVSS6qvj.EWqZLOHV59vC3_l7Bagqd0egOh7Wq0.K4dXRPI0qUNbRfzL9Aby3etYj E2seNtrbSOKy0_8vwte_BTjIwh4ev8sFMMBMozYJWi1GQMfDYgvyl28xvPYDfCZiQfvKfrRPbHbb BhcswKWDHR9mTk2tB5sVa80JNV_u9AiNqnoxhlGgt4coDO4xhVaifFvD61pj7O6P_TA1n5wuVOhZ JzUfNTTMsWUW2zwrpttyzjeLoG4PPKStRRJTx7bRDJonLXp3RudrOKfDYjV4GQXBl_jBt6ptP9qx 4PXck6T54faLbithdf1D4i7e60YwpGQMmxeWbX6Pa9M1yq8pGu8el80A94el2lq6T65xmHddGmKB 8Vhras9dKiLbCt1WfdeZ3jiglV7GbVB.LwsRHRv4hYtly8zxI1llmyCBjl.yY9ha0R8OxaiAUO45 dZV_r0xX9SVep9IY1pswEO1oXAiKtseANbqGDB37V704XDSR30gNF0j7BFtjd_UwuGvf_QXzrijb 0seZ5dGU8zHT4_G6IBgMRmm1RA6YyOGM2iZcxaFThq71Sh9nPwIJHFbXAnagZWUefuMZVmVefkfX Xb6oYf0hPAoeyr3DF02.xZPLo6iwhyUM_ZSTljQWYRVKQNWPGTziCmsF40D6YXzv18.DArFvKpzq 35ar4.LZ1mGqona66XZ0lon1F5JaApLK3x2yAliAKcSJhvGVQvcJgM9cYjx5Xs3Kh0SDVHLo.7V5 qnvWqxcDdEabQx0uDWTKho9GEln1vmLmDrI3R4GV10g1BOQZ.4qsOJipfSRngY7VdpcDUp3ulKSI OL1qf0wnkoTbYskMjUGGLIswbkVaHSpWjj81C1KnZYKy7x_TLQ5eU X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic307.consmr.mail.ne1.yahoo.com with HTTP; Sat, 6 Nov 2021 00:20:59 +0000 Received: by kubenode503.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID a40f74b6160130cfeaf3013aaedb3bdf; Sat, 06 Nov 2021 00:20:54 +0000 (UTC) From: Po Lu To: Alan Third Subject: Re: bug#51411: NS port cleanups References: <87h7d4t0er.fsf@yahoo.com> <87ee86q7jm.fsf@yahoo.com> <87ilxhmlwc.fsf@yahoo.com> <87lf29jxeg.fsf@yahoo.com> <87v91digfm.fsf@yahoo.com> <87pmrlibj0.fsf@yahoo.com> <87fssb9hcf.fsf@yahoo.com> Date: Sat, 06 Nov 2021 08:20:49 +0800 In-Reply-To: <87fssb9hcf.fsf@yahoo.com> (Po Lu's message of "Fri, 05 Nov 2021 15:44:48 +0800") Message-ID: <877ddm878e.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 91847 X-Spam-Score: 0.0 (/) X-Debbugs-Envelope-To: 51411 Cc: 51411@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Po Lu writes: > As of 48af19c1 those patches don't apply anymore. Here's a version that > does. (I kept my version of the overhang computation code instead of > Daniel's, because the xterm code computes overhangs correctly, and > bug#51105 doesn't apply to it AFAIU.) And it doesn't apply, again. This should: --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Improve-font-display-on-NS-port.patch >From 075d3d8dc020c5991c4a758d66c58dfd04f70964 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 23 Oct 2021 19:44:03 +0800 Subject: [PATCH 1/2] Improve font display on NS port * src/nsfns.m (Fx_create_frame): Use "fixed" for the default font on GNUstep. * src/nsfont.m (LCD_SMOOTHING_MARGIN, ns_escape_name) (ns_unescape_name, ns_attribute_fvalue) (STYLE_REF): Remove unused defines and functions. (struct ns_glyph_layout, enum lgstring_direction). (enum gs_font_slant, enum gs_font_weight, enum gs_font_width) (enum gs_specified, struct gs_font_data): New enumerators and structures. (ns_font_descs_match_p) (ns_done_font_data, ns_get_font_data): New functions. (ns_glyph_metrics): Stop escaping names. (ns_spec_to_descriptor): Fix font descriptor creation for symbolic font spec entires. (ns_descriptor_to_entity): Create entries with the correct symbolic styles. (ns_fallback_entity): Fix fallback entity selection. (ns_findfonts): Use our own font matcher instead of the broken GNUstep matcher. (ns_list_family): Remove obsolete comment. (nsfont_open): Remove obsolete code, comments, and synthItal logic which doesn't work on GNUstep. (nsfont_encode_char): Use a type that can fit NSGlyph (nsfont_draw): Chose correct font, remove obsolete mouse face logic, obsolete comments, and switch to using glyph-based drawing instead of character-based drawing. (ns_font_shape, nsfont_shape): New functions. (ns_uni_to_glyphs_1): New function. (ns_uni_to_glyphs): Return glyphs instead of unicode codepoints. (ns_glyph_metrics): Use NSGlyphs instead of unicode codepoints and fix left bearing, right bearing, ascent and descent computation. (struct nsfont_driver): Add shaping capability. * src/nsterm.h (struct nsfont_info): Use unsigned int for glyph cache. * src/nsterm.c (ns_focus): Set DPS clipping on GNUstep. (ns_compute_glyph_string_overhangs): Fix overhang computation by using xterm code. (ns_draw_window_cursor): Simplify cursor drawing. (ns_maybe_dumpglyphs_background): Test for cursor HL and remove obsolete mouse face logic. (ns_dumpglyphs_image) (ns_dumpglyphs_box_or_relief): Rectify for new cursor logic. (ns_dumpglyphs_stretch): Rectify for new cursor logic and rely on ns_draw_glyph_string to set focus. (ns_draw_glyph_string_foreground): Remove mouse face logic. (ns_draw_glyph_strings): Implement overhangs, remove obsolete comment, and always focus before dumping glyphs. (ns_draw_text_decoration): Add condition for DRAW_CURSOR and simplify color selection. (ns_define_frame_cursor): Remove nonsensical code (define_frame_cursor has nothing to do with the text cursor, aka caret). * src/xdisp.c (draw_glyphs): Enable code for NS port to fix mouse face cursor display. * src/macfont.m (get_cgcolor_from_nscolor): New function. (macfont_draw): Remove obsolete mouse-face code and enable cursor display. --- src/macfont.m | 36 +- src/nsfns.m | 6 + src/nsfont.m | 1215 +++++++++++++++++++++++++++++++++++-------------- src/nsterm.h | 2 +- src/nsterm.m | 424 ++++++++--------- src/xdisp.c | 2 - 6 files changed, 1095 insertions(+), 590 deletions(-) diff --git a/src/macfont.m b/src/macfont.m index 78ed5d53f3..1426cae6dc 100644 --- a/src/macfont.m +++ b/src/macfont.m @@ -613,6 +613,21 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char, return cgColor; } +static CGColorRef +get_cgcolor_from_nscolor (NSColor *nsColor, struct frame *f) +{ + [nsColor set]; + CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace]; + NSInteger noc = [nsColor numberOfComponents]; + CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc)); + CGColorRef cgColor; + + [nsColor getComponents: components]; + cgColor = CGColorCreate (colorSpace, components); + xfree (components); + return cgColor; +} + #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f) \ do { \ CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f); \ @@ -2911,14 +2926,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no if (!CGRectIsNull (background_rect)) { - if (s->hl == DRAW_MOUSE_FACE) + if (s->hl == DRAW_CURSOR) { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_CURSOR_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); } - CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); + else + CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f); CGContextFillRects (context, &background_rect, 1); } @@ -2927,7 +2942,14 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no CGAffineTransform atfm; CGContextScaleCTM (context, 1, -1); - CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); + if (s->hl == DRAW_CURSOR) + { + CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_BACKGROUND_COLOR (f), f); + CGContextSetFillColorWithColor (context, colorref); + CGColorRelease (colorref); + } + else + CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f); if (macfont_info->synthetic_italic_p) atfm = synthetic_italic_atfm; else diff --git a/src/nsfns.m b/src/nsfns.m index 797d0ce782..f4d8172246 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -1236,6 +1236,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. "fontBackend", "FontBackend", RES_TYPE_STRING); { +#ifdef NS_IMPL_COCOA /* use for default font name */ id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */ gui_default_parameter (f, parms, Qfontsize, @@ -1250,6 +1251,11 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. build_string (fontname), "font", "Font", RES_TYPE_STRING); xfree (fontname); +#else + gui_default_parameter (f, parms, Qfont, + build_string ("fixed"), + "font", "Font", RES_TYPE_STRING); +#endif } unblock_input (); diff --git a/src/nsfont.m b/src/nsfont.m index 5a9cdfebc0..b3224629f0 100644 --- a/src/nsfont.m +++ b/src/nsfont.m @@ -1,4 +1,4 @@ -/* Font back-end driver for the NeXT/Open/GNUstep and macOS window system. +/* Font back-end driver for the GNUstep window system. See font.h Copyright (C) 2006-2021 Free Software Foundation, Inc. @@ -38,47 +38,269 @@ #include "termchar.h" #include "pdumper.h" -/* TODO: Drop once we can assume gnustep-gui 0.17.1. */ +#import #import +#import +#import +#import #define NSFONT_TRACE 0 -#define LCD_SMOOTHING_MARGIN 2 -/* Font glyph and metrics caching functions, implemented at end. */ -static void ns_uni_to_glyphs (struct nsfont_info *font_info, - unsigned char block); -static void ns_glyph_metrics (struct nsfont_info *font_info, - unsigned char block); +/* Structure used by GS `shape' functions for storing layout + information for each glyph. Borrowed from macfont.h. */ +struct ns_glyph_layout +{ + /* Range of indices of the characters composed into the group of + glyphs that share the cursor position with this glyph. The + members `location' and `length' are in UTF-16 indices. */ + NSRange comp_range; -#define INVALID_GLYPH 0xFFFF + /* UTF-16 index in the source string for the first character + associated with this glyph. */ + NSUInteger string_index; -/* ========================================================================== + /* Horizontal and vertical adjustments of glyph position. The + coordinate space is that of Core Text. So, the `baseline_delta' + value is negative if the glyph should be placed below the + baseline. */ + CGFloat advance_delta, baseline_delta; - Utilities + /* Typographical width of the glyph. */ + CGFloat advance; - ========================================================================== */ + /* Glyph ID of the glyph. */ + NSGlyph glyph_id; +}; + + +enum lgstring_direction + { + DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1 + }; + +enum gs_font_slant + { + GS_FONT_SLANT_ITALIC, + GS_FONT_SLANT_REVERSE_ITALIC, + GS_FONT_SLANT_NORMAL + }; + +enum gs_font_weight + { + GS_FONT_WEIGHT_LIGHT, + GS_FONT_WEIGHT_BOLD, + GS_FONT_WEIGHT_NORMAL + }; + +enum gs_font_width + { + GS_FONT_WIDTH_CONDENSED, + GS_FONT_WIDTH_EXPANDED, + GS_FONT_WIDTH_NORMAL + }; + +enum gs_specified + { + GS_SPECIFIED_SLANT = 1, + GS_SPECIFIED_WEIGHT = 1 << 1, + GS_SPECIFIED_WIDTH = 1 << 2, + GS_SPECIFIED_FAMILY = 1 << 3, + GS_SPECIFIED_SPACING = 1 << 4 + }; +struct gs_font_data +{ + int specified; + enum gs_font_slant slant; + enum gs_font_weight weight; + enum gs_font_width width; + bool monospace_p; + char *family_name; +}; -/* Replace spaces w/another character so emacs core font parsing routines - aren't thrown off. */ static void -ns_escape_name (char *name) +ns_done_font_data (struct gs_font_data *data) { - for (; *name; name++) - if (*name == ' ') - *name = '_'; + if (data->specified & GS_SPECIFIED_FAMILY) + xfree (data->family_name); } - -/* Reconstruct spaces in a font family name passed through emacs. */ static void -ns_unescape_name (char *name) +ns_get_font_data (NSFontDescriptor *desc, struct gs_font_data *dat) { - for (; *name; name++) - if (*name == '_') - *name = ' '; + NSNumber *tem; + NSFontSymbolicTraits traits = [desc symbolicTraits]; + NSDictionary *dict = [desc objectForKey: NSFontTraitsAttribute]; + NSString *family = [desc objectForKey: NSFontFamilyAttribute]; + + dat->specified = 0; + + if (family != nil) + { + dat->specified |= GS_SPECIFIED_FAMILY; + dat->family_name = xstrdup ([family cStringUsingEncoding: NSUTF8StringEncoding]); + } + + tem = [desc objectForKey: NSFontFixedAdvanceAttribute]; + + if ((tem != nil && [tem boolValue] != NO) + || (traits & NSFontMonoSpaceTrait)) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = true; + } + else if (tem != nil && [tem boolValue] == NO) + { + dat->specified |= GS_SPECIFIED_SPACING; + dat->monospace_p = false; + } + + if (traits & NSFontBoldTrait) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + dat->weight = GS_FONT_WEIGHT_BOLD; + } + + if (traits & NSFontItalicTrait) + { + dat->specified |= GS_SPECIFIED_SLANT; + dat->slant = GS_FONT_SLANT_ITALIC; + } + + if (traits & NSFontCondensedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_CONDENSED; + } + else if (traits & NSFontExpandedTrait) + { + dat->specified |= GS_SPECIFIED_WIDTH; + dat->width = GS_FONT_WIDTH_EXPANDED; + } + + if (dict != nil) + { + tem = [dict objectForKey: NSFontSlantTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_SLANT; + + dat->slant = [tem floatValue] > 0 + ? GS_FONT_SLANT_ITALIC + : ([tem floatValue] < 0 + ? GS_FONT_SLANT_REVERSE_ITALIC + : GS_FONT_SLANT_NORMAL); + } + + tem = [dict objectForKey: NSFontWeightTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WEIGHT; + + dat->weight = [tem floatValue] > 0 + ? GS_FONT_WEIGHT_BOLD + : ([tem floatValue] < -0.4f + ? GS_FONT_WEIGHT_LIGHT + : GS_FONT_WEIGHT_NORMAL); + } + + tem = [dict objectForKey: NSFontWidthTrait]; + + if (tem != nil) + { + dat->specified |= GS_SPECIFIED_WIDTH; + + dat->width = [tem floatValue] > 0 + ? GS_FONT_WIDTH_EXPANDED + : ([tem floatValue] < 0 + ? GS_FONT_WIDTH_NORMAL + : GS_FONT_WIDTH_CONDENSED); + } + } +} + +static bool +ns_font_descs_match_p (NSFontDescriptor *desc, NSFontDescriptor *target) +{ + struct gs_font_data dat; + struct gs_font_data t; + + ns_get_font_data (desc, &dat); + ns_get_font_data (target, &t); + + if (!(t.specified & GS_SPECIFIED_WIDTH)) + t.width = GS_FONT_WIDTH_NORMAL; + if (!(t.specified & GS_SPECIFIED_WEIGHT)) + t.weight = GS_FONT_WEIGHT_NORMAL; + if (!(t.specified & GS_SPECIFIED_SPACING)) + t.monospace_p = false; + if (!(t.specified & GS_SPECIFIED_SLANT)) + t.slant = GS_FONT_SLANT_NORMAL; + + if (!(t.specified & GS_SPECIFIED_FAMILY)) + emacs_abort (); + + bool match_p = true; + + if (dat.specified & GS_SPECIFIED_WIDTH + && dat.width != t.width) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_WEIGHT + && dat.weight != t.weight) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SPACING + && dat.monospace_p != t.monospace_p) + { + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_SLANT + && dat.monospace_p != t.monospace_p) + { + if (NSFONT_TRACE) + printf ("Matching monospace for %s: %d %d\n", + t.family_name, dat.monospace_p, + t.monospace_p); + match_p = false; + goto gout; + } + + if (dat.specified & GS_SPECIFIED_FAMILY + && strcmp (dat.family_name, t.family_name)) + match_p = false; + + gout: + ns_done_font_data (&dat); + ns_done_font_data (&t); + + return match_p; } +/* Font glyph and metrics caching functions, implemented at end. */ +static void ns_uni_to_glyphs (struct nsfont_info *font_info, + unsigned char block); +static void ns_glyph_metrics (struct nsfont_info *font_info, + unsigned int block); + +#define INVALID_GLYPH 0xFFFF + +/* ========================================================================== + + Utilities + + ========================================================================== */ + /* Extract family name from a font spec. */ static NSString * @@ -91,66 +313,116 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, { char *tmp = xlispstrdup (SYMBOL_NAME (tem)); NSString *family; - ns_unescape_name (tmp); family = [NSString stringWithUTF8String: tmp]; xfree (tmp); return family; } } - -/* Return 0 if attr not set, else value (which might also be 0). - On Leopard 0 gets returned even on descriptors where the attribute - was never set, so there's no way to distinguish between unspecified - and set to not have. Callers should assume 0 means unspecified. */ -static float -ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait) -{ - NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute]; - NSNumber *val = [tdict objectForKey: trait]; - return val == nil ? 0.0F : [val floatValue]; -} - - /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang to NSFont descriptor. Information under extra only needed for matching. */ -#define STYLE_REF 100 static NSFontDescriptor * ns_spec_to_descriptor (Lisp_Object font_spec) { NSFontDescriptor *fdesc; NSMutableDictionary *fdAttrs = [NSMutableDictionary new]; - NSMutableDictionary *tdict = [NSMutableDictionary new]; NSString *family = ns_get_family (font_spec); - float n; - - /* Add each attr in font_spec to fdAttrs. */ - n = min (FONT_WEIGHT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWeightTrait]; - n = min (FONT_SLANT_NUMERIC (font_spec), 200); - if (n != -1 && n != STYLE_REF) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontSlantTrait]; - n = min (FONT_WIDTH_NUMERIC (font_spec), 200); - if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10)) - [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F] - forKey: NSFontWidthTrait]; - if ([tdict count] > 0) - [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + NSMutableDictionary *tdict = [NSMutableDictionary new]; - fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] - retain] autorelease]; + Lisp_Object tem; + + tem = FONT_SLANT_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qitalic) || EQ (tem, Qoblique)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontSlantTrait]; + else if (EQ (tem, intern ("reverse-italic")) || + EQ (tem, intern ("reverse-oblique"))) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontSlantTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontSlantTrait]; + } + + tem = FONT_WIDTH_SYMBOLIC (font_spec); + if (!NILP (tem)) + { + if (EQ (tem, Qcondensed)) + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWidthTrait]; + else if (EQ (tem, Qexpanded)) + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWidthTrait]; + else + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWidthTrait]; + } + + tem = FONT_WEIGHT_SYMBOLIC (font_spec); + + if (!NILP (tem)) + { + if (EQ (tem, Qbold)) + { + [tdict setObject: [NSNumber numberWithFloat: 1.0] + forKey: NSFontWeightTrait]; + } + else if (EQ (tem, Qlight)) + { + [tdict setObject: [NSNumber numberWithFloat: -1.0] + forKey: NSFontWeightTrait]; + } + else + { + [tdict setObject: [NSNumber numberWithFloat: 0.0] + forKey: NSFontWeightTrait]; + } + } + + tem = AREF (font_spec, FONT_SPACING_INDEX); if (family != nil) { - NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family]; - fdesc = [[fdesc2 retain] autorelease]; + [fdAttrs setObject: family + forKey: NSFontFamilyAttribute]; } - [fdAttrs release]; + if (FIXNUMP (tem)) + { + if (XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL) + { + [fdAttrs setObject: [NSNumber numberWithBool:YES] + forKey: NSFontFixedAdvanceAttribute]; + } + else + { + [fdAttrs setObject: [NSNumber numberWithBool:NO] + forKey: NSFontFixedAdvanceAttribute]; + } + } + + /* Handle special families such as ``fixed'' or ``Sans Serif''. */ + + if ([family isEqualToString: @"fixed"]) + { + [fdAttrs setObject: [[NSFont userFixedPitchFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + else if ([family isEqualToString: @"Sans Serif"]) + { + [fdAttrs setObject: [[NSFont userFontOfSize: 0] familyName] + forKey: NSFontFamilyAttribute]; + } + + [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; + + fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs] + retain] autorelease]; + [tdict release]; + [fdAttrs release]; return fdesc; } @@ -161,61 +433,64 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, Lisp_Object extra, const char *style) { - Lisp_Object font_entity = font_make_entity (); - /* NSString *psName = [desc postscriptName]; */ - NSString *family = [desc objectForKey: NSFontFamilyAttribute]; - unsigned int traits = [desc symbolicTraits]; - char *escapedFamily; - - /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */ - if (family == nil) - family = [desc objectForKey: NSFontNameAttribute]; - if (family == nil) - family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - - escapedFamily = xstrdup ([family UTF8String]); - ns_escape_name (escapedFamily); - - ASET (font_entity, FONT_TYPE_INDEX, Qns); - ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple); - ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily)); - ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); - ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); - - FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - traits & NSFontBoldTrait ? Qbold : Qmedium); -/* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - traits & NSFontItalicTrait ? Qitalic : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/ - FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - traits & NSFontCondensedTrait ? Qcondensed : - traits & NSFontExpandedTrait ? Qexpanded : Qnormal); -/* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, - make_fixnum (100 + 100 - * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/ - - ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); - ASET (font_entity, FONT_SPACING_INDEX, - make_fixnum([desc symbolicTraits] & NSFontMonoSpaceTrait - ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); - - ASET (font_entity, FONT_EXTRA_INDEX, extra); - ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + Lisp_Object font_entity = font_make_entity (); + struct gs_font_data data; + ns_get_font_data (desc, &data); + + ASET (font_entity, FONT_TYPE_INDEX, Qns); + ASET (font_entity, FONT_FOUNDRY_INDEX, Qns); + if (data.specified & GS_SPECIFIED_FAMILY) + ASET (font_entity, FONT_FAMILY_INDEX, intern (data.family_name)); + ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); + ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); + + if (data.specified & GS_SPECIFIED_WEIGHT) + { + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, + data.weight == GS_FONT_WEIGHT_BOLD + ? Qbold : (data.weight == GS_FONT_WEIGHT_LIGHT + ? Qlight : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, Qnormal); - if (NSFONT_TRACE) - { - fputs ("created font_entity:\n ", stderr); - debug_print (font_entity); - } + if (data.specified & GS_SPECIFIED_SLANT) + { + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, + data.slant == GS_FONT_SLANT_ITALIC + ? Qitalic : (data.slant == GS_FONT_SLANT_REVERSE_ITALIC + ? intern ("reverse-italic") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, Qnormal); + + if (data.specified & GS_SPECIFIED_WIDTH) + { + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, + data.width == GS_FONT_WIDTH_CONDENSED + ? Qcondensed : (data.width == GS_FONT_WIDTH_EXPANDED + ? intern ("expanded") : Qnormal)); + } + else + FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, Qnormal); - xfree (escapedFamily); - return font_entity; + ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0)); + ASET (font_entity, FONT_SPACING_INDEX, + make_fixnum ((data.specified & GS_SPECIFIED_WIDTH && data.monospace_p) + ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); + + ASET (font_entity, FONT_EXTRA_INDEX, extra); + ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); + + if (NSFONT_TRACE) + { + fputs ("created font_entity:\n ", stderr); + debug_print (font_entity); + } + + ns_done_font_data (&data); + return font_entity; } @@ -223,8 +498,7 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, static Lisp_Object ns_fallback_entity (void) { - return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0] - fontDescriptor], Qnil, NULL); + return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 1] fontDescriptor], Qnil, NULL); } @@ -510,21 +784,20 @@ but also for ascii (which causes unnecessary font substitution). */ return families; } +/* GNUstep font matching is very mediocre (it can't even compare + symbolic styles correctly), which is why our own font matching + mechanism must be implemented. */ -/* Implementation for list() and match(). List() can return nil, match() -must return something. Strategy is to drop family name from attribute -matching set for match. */ +/* Implementation for list and match. */ static Lisp_Object ns_findfonts (Lisp_Object font_spec, BOOL isMatch) { Lisp_Object tem, list = Qnil; - NSFontDescriptor *fdesc, *desc; - NSMutableSet *fkeys; - NSArray *matchingDescs; - NSEnumerator *dEnum; - NSString *family; + NSFontDescriptor *fdesc; + NSArray *all_descs; + GSFontEnumerator *enumerator = [GSFontEnumerator sharedEnumerator]; + NSSet *cFamilies; - BOOL foundItal = NO; block_input (); if (NSFONT_TRACE) @@ -537,43 +810,22 @@ but also for ascii (which causes unnecessary font substitution). */ cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90); fdesc = ns_spec_to_descriptor (font_spec); - fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]]; - if (isMatch) - [fkeys removeObject: NSFontFamilyAttribute]; - - matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys]; + all_descs = [enumerator availableFontDescriptors]; - if (NSFONT_TRACE) - NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc, - (unsigned long)[matchingDescs count]); - - for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);) + for (NSFontDescriptor *desc in all_descs) { if (![cFamilies containsObject: [desc objectForKey: NSFontFamilyAttribute]]) continue; + if (!ns_font_descs_match_p (fdesc, desc)) + continue; + tem = ns_descriptor_to_entity (desc, - AREF (font_spec, FONT_EXTRA_INDEX), + AREF (font_spec, FONT_EXTRA_INDEX), NULL); if (isMatch) return tem; list = Fcons (tem, list); - if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05) - foundItal = YES; - } - - /* Add synthItal member if needed. */ - family = [fdesc objectForKey: NSFontFamilyAttribute]; - if (family != nil && !foundItal && !NILP (list)) - { - NSFontDescriptor *s1 = [NSFontDescriptor new]; - NSFontDescriptor *sDesc - = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait] - fontDescriptorWithFamily: family]; - list = Fcons (ns_descriptor_to_entity (sDesc, - AREF (font_spec, FONT_EXTRA_INDEX), - "synthItal"), list); - [s1 release]; } unblock_input (); @@ -652,7 +904,6 @@ Properties to be considered are same as for list(). */ objectEnumerator]; while ((family = [families nextObject])) list = Fcons (intern ([family UTF8String]), list); - /* FIXME: escape the name? */ if (NSFONT_TRACE) fprintf (stderr, "nsfont: list families returning %"pD"d entries\n", @@ -668,18 +919,15 @@ Properties to be considered are same as for list(). */ static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size) { - BOOL synthItal; - unsigned int traits = 0; struct nsfont_info *font_info; struct font *font; NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity); NSFontManager *fontMgr = [NSFontManager sharedFontManager]; NSString *family; NSFont *nsfont, *sfont; - Lisp_Object tem; NSRect brect; Lisp_Object font_object; - int fixLeopardBug; + Lisp_Object tem; block_input (); @@ -692,42 +940,20 @@ Properties to be considered are same as for list(). */ if (pixel_size <= 0) { /* try to get it out of frame params */ - Lisp_Object tem = get_frame_param (f, Qfontsize); - pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); + tem = get_frame_param (f, Qfontsize); + pixel_size = NILP (tem) ? 0 : XFIXNAT (tem); } tem = AREF (font_entity, FONT_ADSTYLE_INDEX); - synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)), - 9); family = ns_get_family (font_entity); if (family == nil) family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; - /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that - when setting family in ns_spec_to_descriptor(). */ - if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F) - traits |= NSBoldFontMask; - if (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F) - traits |= NSItalicFontMask; - - /* see https://web.archive.org/web/20100201175731/http://cocoadev.com/forums/comments.php?DiscussionID=74 */ - fixLeopardBug = traits & NSBoldFontMask ? 10 : 5; - nsfont = [fontMgr fontWithFamily: family - traits: traits weight: fixLeopardBug - size: pixel_size]; - /* if didn't find, try synthetic italic */ - if (nsfont == nil && synthItal) - { - nsfont = [fontMgr fontWithFamily: family - traits: traits & ~NSItalicFontMask - weight: fixLeopardBug size: pixel_size]; - } + + nsfont = [NSFont fontWithDescriptor: fontDesc + size: pixel_size]; if (nsfont == nil) - { - message_with_string ("*** Warning: font in family `%s' not found", - build_string ([family UTF8String]), 1); - nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; - } + nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; if (NSFONT_TRACE) NSLog (@"%@\n", nsfont); @@ -740,7 +966,7 @@ when setting family in ns_spec_to_descriptor(). */ if (!font) { unblock_input (); - return Qnil; /* FIXME: other terms do, but returning Qnil causes segfault. */ + return Qnil; } font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs); @@ -781,7 +1007,7 @@ when setting family in ns_spec_to_descriptor(). */ font_info->name = xstrdup (fontName); font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask; font_info->ital = - synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); + ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); /* Metrics etc.; some fonts return an unusually large max advance, so we only use it for fonts that have wide characters. */ @@ -808,8 +1034,6 @@ when setting family in ns_spec_to_descriptor(). */ lrint (brect.size.width - (CGFloat) font_info->width); /* set up metrics portion of font struct */ - font->ascent = lrint([sfont ascender]); - font->descent = -lrint(floor(adjusted_descender)); font->space_width = lrint (ns_char_width (sfont, ' ')); font->max_width = lrint (font_info->max_bounds.width); font->min_width = font->space_width; /* Approximate. */ @@ -871,7 +1095,7 @@ when setting family in ns_spec_to_descriptor(). */ { struct nsfont_info *font_info = (struct nsfont_info *)font; unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff; - unsigned short g; + unsigned int g; if (c > 0xFFFF) return FONT_INVALID_CODE; @@ -934,51 +1158,23 @@ is false when (FROM > 0 || TO < S->nchars). */ static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, bool with_background) -/* NOTE: focus and clip must be set. */ { - static unsigned char cbuf[1024]; - unsigned char *c = cbuf; -#if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22 - static CGFloat advances[1024]; - CGFloat *adv = advances; -#else - static float advances[1024]; - float *adv = advances; -#endif + NSGlyph *c = alloca ((to - from) * sizeof *c); + struct face *face; NSRect r; struct nsfont_info *font; - NSColor *col, *bgCol; - unsigned *t = s->char2b; - int i, len, flags; + NSColor *col; + int len = to - from; char isComposite = s->first_glyph->type == COMPOSITE_GLYPH; block_input (); - font = (struct nsfont_info *)s->face->font; + font = (struct nsfont_info *) s->font; if (font == NULL) font = (struct nsfont_info *)FRAME_FONT (s->f); - /* Select face based on input flags. */ - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - - switch (flags) - { - case NS_DUMPGLYPH_CURSOR: - face = s->face; - break; - case NS_DUMPGLYPH_MOUSEFACE: - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - break; - default: - face = s->face; - } + face = s->face; r.origin.x = s->x; if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p) @@ -987,91 +1183,24 @@ is false when (FROM > 0 || TO < S->nchars). */ r.origin.y = s->y; r.size.height = FONT_HEIGHT (font); - /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask - NS to render the string, it will come out differently from the individual - character widths added up because of layout processing. */ - { - int cwidth, twidth = 0; - int hi, lo; - /* FIXME: composition: no vertical displacement is considered. */ - t += from; /* advance into composition */ - for (i = from; i < to; i++, t++) - { - hi = (*t & 0xFF00) >> 8; - lo = *t & 0x00FF; - if (isComposite) - { - if (!s->first_glyph->u.cmp.automatic) - cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth; - else - { - Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); - Lisp_Object glyph = LGSTRING_GLYPH (gstring, i); - if (NILP (LGLYPH_ADJUSTMENT (glyph))) - cwidth = LGLYPH_WIDTH (glyph); - else - { - cwidth = LGLYPH_WADJUST (glyph); - *(adv-1) += LGLYPH_XOFF (glyph); - } - } - } - else - { - if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */ - ns_glyph_metrics (font, hi); - cwidth = font->metrics[hi][lo].width; - } - twidth += cwidth; - *adv++ = cwidth; - c += CHAR_STRING (*t, c); /* This converts the char to UTF-8. */ - } - len = adv - advances; - r.size.width = twidth; - *c = 0; - } + for (int i = from; i < to; ++i) + c[i] = s->char2b[i]; /* Fill background if requested. */ if (with_background && !isComposite) { - NSRect br = r; - int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); - int mbox_line_width = max (s->face->box_vertical_line_width, 0); - - if (s->row->full_width_p) - { - if (br.origin.x <= fibw + 1 + mbox_line_width) - { - br.size.width += br.origin.x - mbox_line_width; - br.origin.x = mbox_line_width; - } - if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) - <= fibw+1) - br.size.width += fibw; - } - if (s->face->box == FACE_NO_BOX) - { - /* Expand unboxed top row over internal border. */ - if (br.origin.y <= fibw + 1 + mbox_line_width) - { - br.size.height += br.origin.y; - br.origin.y = 0; - } - } - else - { - int correction = abs (s->face->box_horizontal_line_width)+1; - br.origin.y += correction; - br.size.height -= 2*correction; - correction = abs (s->face->box_vertical_line_width)+1; - br.origin.x += correction; - br.size.width -= 2*correction; - } + NSRect br = NSMakeRect (x, y - FONT_BASE (s->font), + s->width, FONT_HEIGHT (s->font)); if (!s->face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); @@ -1080,43 +1209,32 @@ is false when (FROM > 0 || TO < S->nchars). */ NSRectFill (br); } - /* set up for character rendering */ r.origin.y = y; - col = (NS_FACE_FOREGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - - bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil - : (NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f))); + if (s->hl == DRAW_CURSOR) + col = FRAME_BACKGROUND_COLOR (s->f); + else + col = (NS_FACE_FOREGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f) + : FRAME_FOREGROUND_COLOR (s->f)); /* render under GNUstep using DPS */ { - NSGraphicsContext *context = GSCurrentContext (); - + NSGraphicsContext *context = [NSGraphicsContext currentContext]; DPSgsave (context); - [font->nsfont set]; - - /* do erase if "foreground" mode */ - if (bgCol != nil) + if (s->clip_head) { - [bgCol set]; - DPSmoveto (context, r.origin.x, r.origin.y); -/*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */ - DPSxshow (context, (const char *) cbuf, advances, len); - DPSstroke (context); - [col set]; -/*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */ + DPSrectclip (context, s->clip_head->x, 0, + FRAME_PIXEL_WIDTH (s->f), + FRAME_PIXEL_HEIGHT (s->f)); } + [font->nsfont set]; [col set]; - /* draw with DPSxshow () */ DPSmoveto (context, r.origin.x, r.origin.y); - DPSxshow (context, (const char *) cbuf, advances, len); + GSShowGlyphs (context, c, len); DPSstroke (context); DPSgrestore (context); @@ -1126,6 +1244,360 @@ is false when (FROM > 0 || TO < S->nchars). */ return to-from; } +static NSUInteger +ns_font_shape (NSFont *font, NSString *string, + struct ns_glyph_layout *glyph_layouts, NSUInteger glyph_len, + enum lgstring_direction dir) +{ + NSUInteger i; + NSUInteger result = 0; + NSTextStorage *textStorage; + NSLayoutManager *layoutManager; + NSTextContainer *textContainer; + NSUInteger stringLength; + NSPoint spaceLocation; + /* numberOfGlyphs can't actually be 0, but this pacifies GCC */ + NSUInteger used, numberOfGlyphs = 0; + + textStorage = [[NSTextStorage alloc] initWithString:string]; + layoutManager = [[NSLayoutManager alloc] init]; + textContainer = [[NSTextContainer alloc] init]; + + /* Append a trailing space to measure baseline position. */ + [textStorage appendAttributedString:([[[NSAttributedString alloc] + initWithString:@" "] autorelease])]; + [textStorage setFont:font]; + [textContainer setLineFragmentPadding:0]; + + [layoutManager addTextContainer:textContainer]; + [textContainer release]; + [textStorage addLayoutManager:layoutManager]; + [layoutManager release]; + + if (!(textStorage && layoutManager && textContainer)) + emacs_abort (); + + stringLength = [string length]; + + /* Force layout. */ + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength]; + + /* Remove the appended trailing space because otherwise it may + generate a wrong result for a right-to-left text. */ + [textStorage beginEditing]; + [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))]; + [textStorage endEditing]; + (void) [layoutManager glyphRangeForTextContainer:textContainer]; + + i = 0; + while (i < stringLength) + { + NSRange range; + NSFont *fontInTextStorage = + [textStorage attribute: NSFontAttributeName + atIndex:i + longestEffectiveRange: &range + inRange: NSMakeRange (0, stringLength)]; + + if (!(fontInTextStorage == font + || [[fontInTextStorage fontName] isEqualToString:[font fontName]])) + break; + i = NSMaxRange (range); + } + if (i < stringLength) + /* Make the test `used <= glyph_len' below fail if textStorage + contained some fonts other than the specified one. */ + used = glyph_len + 1; + else + { + NSRange range = NSMakeRange (0, stringLength); + + range = [layoutManager glyphRangeForCharacterRange:range + actualCharacterRange:NULL]; + numberOfGlyphs = NSMaxRange (range); + used = numberOfGlyphs; + for (i = 0; i < numberOfGlyphs; i++) + if ([layoutManager notShownAttributeForGlyphAtIndex:i]) + used--; + } + + if (0 < used && used <= glyph_len) + { + NSUInteger glyphIndex, prevGlyphIndex; + NSUInteger *permutation; + NSRange compRange, range; + CGFloat totalAdvance; + + glyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + permutation = NULL; +#define RIGHT_TO_LEFT_P permutation + + /* Fill the `comp_range' member of struct mac_glyph_layout, and + setup a permutation for right-to-left text. */ + compRange = NSMakeRange (0, 0); + for (range = NSMakeRange (0, 0); NSMaxRange (range) < used; + range.length++) + { + struct ns_glyph_layout *gl = glyph_layouts + NSMaxRange (range); + NSUInteger characterIndex = + [layoutManager characterIndexForGlyphAtIndex:glyphIndex]; + + gl->string_index = characterIndex; + + if (characterIndex >= NSMaxRange (compRange)) + { + compRange.location = NSMaxRange (compRange); + do + { + NSRange characterRange = + [string + rangeOfComposedCharacterSequenceAtIndex:characterIndex]; + + compRange.length = + NSMaxRange (characterRange) - compRange.location; + [layoutManager glyphRangeForCharacterRange:compRange + actualCharacterRange:&characterRange]; + characterIndex = NSMaxRange (characterRange) - 1; + } + while (characterIndex >= NSMaxRange (compRange)); + + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + range = NSMakeRange (NSMaxRange (range), 0); + } + + gl->comp_range.location = compRange.location; + gl->comp_range.length = compRange.length; + + while (++glyphIndex < numberOfGlyphs) + if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + break; + } + if (RIGHT_TO_LEFT_P) + for (i = 0; i < range.length; i++) + permutation[range.location + i] = NSMaxRange (range) - i - 1; + + /* Then fill the remaining members. */ + glyphIndex = prevGlyphIndex = 0; + while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex]) + glyphIndex++; + + if (!RIGHT_TO_LEFT_P) + totalAdvance = 0; + else + { + NSUInteger nrects; + NSRect *glyphRects = + [layoutManager + rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs)) + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + + totalAdvance = NSMaxX (glyphRects[0]); + } + + for (i = 0; i < used; i++) + { + struct ns_glyph_layout *gl; + NSPoint location; + NSUInteger nextGlyphIndex; + NSRange glyphRange; + NSRect *glyphRects; + NSUInteger nrects; + + if (!RIGHT_TO_LEFT_P) + gl = glyph_layouts + i; + else + { + NSUInteger dest = permutation[i]; + + gl = glyph_layouts + dest; + if (i < dest) + { + NSUInteger tmp = gl->string_index; + + gl->string_index = glyph_layouts[i].string_index; + glyph_layouts[i].string_index = tmp; + } + } + gl->glyph_id = [layoutManager glyphAtIndex: glyphIndex]; + + location = [layoutManager locationForGlyphAtIndex:glyphIndex]; + gl->baseline_delta = spaceLocation.y - location.y; + + for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs; + nextGlyphIndex++) + if (![layoutManager + notShownAttributeForGlyphAtIndex:nextGlyphIndex]) + break; + + if (!RIGHT_TO_LEFT_P) + { + CGFloat maxX; + + if (prevGlyphIndex == 0) + glyphRange = NSMakeRange (0, nextGlyphIndex); + else + glyphRange = NSMakeRange (glyphIndex, + nextGlyphIndex - glyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + maxX = max (NSMaxX (glyphRects[0]), totalAdvance); + gl->advance_delta = location.x - totalAdvance; + gl->advance = maxX - totalAdvance; + totalAdvance = maxX; + } + else + { + CGFloat minX; + + if (nextGlyphIndex == numberOfGlyphs) + glyphRange = NSMakeRange (prevGlyphIndex, + numberOfGlyphs - prevGlyphIndex); + else + glyphRange = NSMakeRange (prevGlyphIndex, + glyphIndex + 1 - prevGlyphIndex); + glyphRects = + [layoutManager + rectArrayForGlyphRange:glyphRange + withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0)) + inTextContainer:textContainer rectCount:&nrects]; + minX = min (NSMinX (glyphRects[0]), totalAdvance); + gl->advance = totalAdvance - minX; + totalAdvance = minX; + gl->advance_delta = location.x - totalAdvance; + } + + prevGlyphIndex = glyphIndex + 1; + glyphIndex = nextGlyphIndex; + } + + if (RIGHT_TO_LEFT_P) + xfree (permutation); + +#undef RIGHT_TO_LEFT_P + + result = used; + } + [textStorage release]; + + return result; +} + +static Lisp_Object +nsfont_shape (Lisp_Object lgstring, Lisp_Object direction) +{ + struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring)); + struct nsfont_info *font_info = (struct nsfont_info *) font; + struct ns_glyph_layout *glyph_layouts; + NSFont *nsfont = font_info->nsfont; + ptrdiff_t glyph_len, len, i; + Lisp_Object tem; + unichar *mb_buf; + NSUInteger used; + + glyph_len = LGSTRING_GLYPH_LEN (lgstring); + for (i = 0; i < glyph_len; ++i) + { + tem = LGSTRING_GLYPH (lgstring, i); + + if (NILP (tem)) + break; + } + + len = i; + + if (INT_MAX / 2 < len) + memory_full (SIZE_MAX); + + block_input (); + + mb_buf = alloca (len * sizeof *mb_buf); + + for (i = 0; i < len; ++i) + { + uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i)); + mb_buf[i] = (unichar) c; + } + + NSString *string = [NSString stringWithCharacters: mb_buf + length: len]; + unblock_input (); + + if (!string) + return Qnil; + + block_input (); + + enum lgstring_direction dir = DIR_UNKNOWN; + + if (EQ (direction, QL2R)) + dir = DIR_L2R; + else if (EQ (direction, QR2L)) + dir = DIR_R2L; + glyph_layouts = alloca (sizeof (struct ns_glyph_layout) * glyph_len); + used = ns_font_shape (nsfont, string, glyph_layouts, glyph_len, dir); + + for (i = 0; i < used; i++) + { + Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i); + struct ns_glyph_layout *gl = glyph_layouts + i; + EMACS_INT from, to; + struct font_metrics metrics; + + if (NILP (lglyph)) + { + lglyph = LGLYPH_NEW (); + LGSTRING_SET_GLYPH (lgstring, i, lglyph); + } + + from = gl->comp_range.location; + LGLYPH_SET_FROM (lglyph, from); + + to = gl->comp_range.location + gl->comp_range.length; + LGLYPH_SET_TO (lglyph, to - 1); + + /* LGLYPH_CHAR is used in `describe-char' for checking whether + the composition is trivial. */ + { + UTF32Char c; + + if (mb_buf[gl->string_index] >= 0xD800 + && mb_buf[gl->string_index] < 0xDC00) + c = (((mb_buf[gl->string_index] - 0xD800) << 10) + + (mb_buf[gl->string_index + 1] - 0xDC00) + 0x10000); + else + c = mb_buf[gl->string_index]; + + LGLYPH_SET_CHAR (lglyph, c); + } + + { + unsigned long cc = gl->glyph_id; + LGLYPH_SET_CODE (lglyph, cc); + } + + nsfont_text_extents (font, &gl->glyph_id, 1, &metrics); + LGLYPH_SET_WIDTH (lglyph, metrics.width); + LGLYPH_SET_LBEARING (lglyph, metrics.lbearing); + LGLYPH_SET_RBEARING (lglyph, metrics.rbearing); + LGLYPH_SET_ASCENT (lglyph, metrics.ascent); + LGLYPH_SET_DESCENT (lglyph, metrics.descent); + } + unblock_input (); + + return make_fixnum (used); +} /* ========================================================================== @@ -1134,6 +1606,50 @@ is false when (FROM > 0 || TO < S->nchars). */ ========================================================================== */ +static NSGlyph +ns_uni_to_glyphs_1 (struct nsfont_info *info, unsigned int c) +{ + unichar characters[] = { c }; + NSString *string = + [NSString stringWithCharacters: characters + length: 1]; + NSDictionary *attributes = + [NSDictionary dictionaryWithObjectsAndKeys: + info->nsfont, NSFontAttributeName, nil]; + NSTextStorage *storage = [[NSTextStorage alloc] initWithString: string + attributes: attributes]; + NSTextContainer *text_container = [[NSTextContainer alloc] init]; + NSLayoutManager *manager = [[NSLayoutManager alloc] init]; + + [manager addTextContainer: text_container]; + [text_container release]; /* Retained by manager */ + [storage addLayoutManager: manager]; + [manager release]; /* Retained by storage */ + + NSFont *font_in_storage = [storage attribute: NSFontAttributeName + atIndex:0 + effectiveRange: NULL]; + NSGlyph glyph = FONT_INVALID_CODE; + + if ((font_in_storage == info->nsfont + || [[font_in_storage fontName] isEqualToString: [info->nsfont fontName]])) + { + @try + { + glyph = [manager glyphAtIndex: 0]; + } + @catch (NSException *e) + { + /* GNUstep bug? */ + glyph = 'X'; + } + } + + [storage release]; + + return glyph; +} + /* Find and cache corresponding glyph codes for unicode values in given hi-byte block of 256. */ static void @@ -1141,7 +1657,7 @@ is false when (FROM > 0 || TO < S->nchars). */ { unichar *unichars = xmalloc (0x101 * sizeof (unichar)); unsigned int i, g, idx; - unsigned short *glyphs; + unsigned int *glyphs; if (NSFONT_TRACE) fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n", @@ -1149,7 +1665,7 @@ is false when (FROM > 0 || TO < S->nchars). */ block_input (); - font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short)); + font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned int)); if (!unichars || !(font_info->glyphs[block])) emacs_abort (); @@ -1166,7 +1682,8 @@ is false when (FROM > 0 || TO < S->nchars). */ for (i = 0; i < 0x100; i++, glyphs++) { g = unichars[i]; - *glyphs = g; + NSGlyph glyph = ns_uni_to_glyphs_1 (font_info, g); + *glyphs = glyph; } } @@ -1175,18 +1692,19 @@ is false when (FROM > 0 || TO < S->nchars). */ } -/* Determine and cache metrics for corresponding glyph codes in given - hi-byte block of 256. */ +/* Determine and cache metrics for glyphs in given hi-byte block of + 256. */ static void -ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block) +ns_glyph_metrics (struct nsfont_info *font_info, unsigned int block) { - unsigned int i, g; + unsigned int i; + NSGlyph g; unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs]; NSFont *sfont; struct font_metrics *metrics; if (NSFONT_TRACE) - fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n", + fprintf (stderr, "%p\tComputing metrics for glyphs in block %u\n", font_info, block); /* not implemented yet (as of startup 0.18), so punt */ @@ -1209,19 +1727,14 @@ is false when (FROM > 0 || TO < S->nchars). */ w = max ([sfont advancementForGlyph: g].width, 2.0); metrics->width = lrint (w); - lb = r.origin.x; - rb = r.size.width - w; - // Add to bearing for LCD smoothing. We don't know if it is there. - if (lb < 0) - metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN); - if (font_info->ital) - rb += (CGFloat) (0.22F * font_info->height); - metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN); - - metrics->descent = r.origin.y < 0 ? -r.origin.y : 0; - /* lrint (hshrink * [sfont ascender] + expand * hd/2); */ - metrics->ascent = r.size.height - metrics->descent; - /* -lrint (hshrink* [sfont descender] - expand * hd/2); */ + lb = NSMinX (r); + rb = NSMaxX (r); + + metrics->rbearing = lrint (rb); + metrics->lbearing = lrint (lb); + + metrics->descent = NSMinY (r); + metrics->ascent = NSMaxY (r); } unblock_input (); } @@ -1257,6 +1770,7 @@ is false when (FROM > 0 || TO < S->nchars). */ .has_char = nsfont_has_char, .encode_char = nsfont_encode_char, .text_extents = nsfont_text_extents, + .shape = nsfont_shape, .draw = nsfont_draw, }; @@ -1265,7 +1779,6 @@ is false when (FROM > 0 || TO < S->nchars). */ { DEFSYM (Qcondensed, "condensed"); DEFSYM (Qexpanded, "expanded"); - DEFSYM (Qapple, "apple"); DEFSYM (Qmedium, "medium"); DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script, doc: /* Internal use: maps font registry to Unicode script. */); diff --git a/src/nsterm.h b/src/nsterm.h index 4bbcf43973..944dbd727c 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -820,7 +820,7 @@ #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) XCharStruct max_bounds; /* We compute glyph codes and metrics on-demand in blocks of 256 indexed by hibyte, lobyte. */ - unsigned short **glyphs; /* map Unicode index to glyph */ + unsigned int **glyphs; /* map Unicode index to glyph */ struct font_metrics **metrics; }; #endif diff --git a/src/nsterm.m b/src/nsterm.m index 418931eeee..4c915dac5d 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1079,11 +1079,16 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) /* clipping */ if (r) { - [[NSGraphicsContext currentContext] saveGraphicsState]; + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; +#ifdef NS_IMPL_COCOA if (n == 2) NSRectClipList (r, 2); else NSRectClip (*r); +#else + GSRectClipList (ctx, r, n); +#endif gsaved = YES; } } @@ -2435,9 +2440,6 @@ Hide the window (X11 semantics) EmacsView *view = FRAME_NS_VIEW (f); FRAME_POINTER_TYPE (f) = cursor; [[view window] invalidateCursorRectsForView: view]; - /* Redisplay assumes this function also draws the changed frame - cursor, but this function doesn't, so do it explicitly. */ - gui_update_cursor (f, 1); } } @@ -2849,39 +2851,31 @@ Hide the window (X11 semantics) External (RIF); compute left/right overhang of whole string and set in s -------------------------------------------------------------------------- */ { - struct font *font = s->font; - - if (s->char2b) + if (s->cmp == NULL + && (s->first_glyph->type == CHAR_GLYPH + || s->first_glyph->type == COMPOSITE_GLYPH)) { struct font_metrics metrics; - if (s->first_glyph->type == CHAR_GLYPH && !s->font_not_found_p) - { - font->driver->text_extents (font, s->char2b, s->nchars, &metrics); - s->left_overhang = -metrics.lbearing; - s->right_overhang - = metrics.rbearing > metrics.width - ? metrics.rbearing - metrics.width : 0; - } - else if (s->first_glyph->type == COMPOSITE_GLYPH) - { - Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); - composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); - s->right_overhang = (metrics.rbearing > metrics.width - ? metrics.rbearing - metrics.width : 0); - s->left_overhang = metrics.lbearing < 0 ? -metrics.lbearing : 0; - } + if (s->first_glyph->type == CHAR_GLYPH) + { + struct font *font = s->font; + font->driver->text_extents (font, s->char2b, s->nchars, &metrics); + } + else + { + Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); + + composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); + } + s->right_overhang = (metrics.rbearing > metrics.width + ? metrics.rbearing - metrics.width : 0); + s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0; } - else + else if (s->cmp) { - s->left_overhang = 0; -#ifdef NS_IMPL_GNUSTEP - if (EQ (font->driver->type, Qns)) - s->right_overhang = ((struct nsfont_info *)font)->ital ? - FONT_HEIGHT (font) * 0.2 : 0; - else -#endif - s->right_overhang = 0; + s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width; + s->left_overhang = - s->cmp->lbearing; } } @@ -3021,14 +3015,13 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. struct frame *f = WINDOW_XFRAME (w); struct glyph *phys_cursor_glyph; struct glyph *cursor_glyph; - struct face *face; - NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f); /* If cursor is out of bounds, don't draw garbage. This can happen in mini-buffer windows when switching between echo area glyphs and mini-buffer. */ - NSTRACE ("ns_draw_window_cursor"); + NSTRACE ("ns_draw_window_cursor (on = %d, cursor_type = %d)", + on_p, cursor_type); if (!on_p) return; @@ -3044,6 +3037,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL) { + NSTRACE_MSG ("No phys cursor glyph was found!"); + if (glyph_row->exact_window_width_line_p && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) { @@ -3053,10 +3048,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. return; } - /* We draw the cursor (with NSRectFill), then draw the glyph on top - (other terminals do it the other way round). We must set - w->phys_cursor_width to the cursor width. For bar cursors, that - is CURSOR_WIDTH; for box cursors, it is the glyph width. */ get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h); /* The above get_phys_cursor_geometry call set w->phys_cursor_width @@ -3088,17 +3079,17 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. /* Prevent the cursor from being drawn outside the text area. */ r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA)); - ns_focus (f, &r, 1); + ns_focus (f, NULL, 0); - face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id); - if (face && NS_FACE_BACKGROUND (face) - == ns_index_color (FRAME_CURSOR_COLOR (f), f)) - { - [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set]; - hollow_color = FRAME_CURSOR_COLOR (f); - } - else - [FRAME_CURSOR_COLOR (f) set]; + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; +#ifdef NS_IMPL_GNUSTEP + GSRectClipList (ctx, &r, 1); +#else + NSRectClip (r); +#endif + + [FRAME_CURSOR_COLOR (f) set]; switch (cursor_type) { @@ -3106,13 +3097,11 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. case NO_CURSOR: break; case FILLED_BOX_CURSOR: - NSRectFill (r); + draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); break; case HOLLOW_BOX_CURSOR: - NSRectFill (r); - [hollow_color set]; - NSRectFill (NSInsetRect (r, 1, 1)); - [FRAME_CURSOR_COLOR (f) set]; + draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT); + [NSBezierPath strokeRect: r]; break; case HBAR_CURSOR: NSRectFill (r); @@ -3128,12 +3117,9 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. NSRectFill (s); break; } - ns_unfocus (f); - /* Draw the character under the cursor. Other terms only draw - the character on top of box cursors, so do the same here. */ - if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR) - draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); + [ctx restoreGraphicsState]; + ns_unfocus (f); } @@ -3313,16 +3299,18 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if (s->for_overlaps) return; + if (s->hl == DRAW_CURSOR) + [FRAME_BACKGROUND_COLOR (s->f) set]; + else if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + /* Do underline. */ if (face->underline) { if (s->face->underline == FACE_UNDER_WAVE) { - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; - ns_draw_underwave (s, width, x); } else if (s->face->underline == FACE_UNDER_LINE) @@ -3393,11 +3381,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. s->underline_position = position; r = NSMakeRect (x, s->ybase + position, width, thickness); - - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; NSRectFill (r); } } @@ -3407,11 +3390,6 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. { NSRect r; r = NSMakeRect (x, s->y, width, 1); - - if (face->overline_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->overline_color, s->f) set]; NSRectFill (r); } @@ -3434,10 +3412,6 @@ larger if there are taller display elements (e.g., characters dy = lrint ((glyph_height - h) / 2); r = NSMakeRect (x, glyph_y + dy, width, 1); - if (face->strike_through_color_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->strike_through_color, s->f) set]; NSRectFill (r); } } @@ -3585,17 +3559,7 @@ Function modeled after x_draw_glyph_string_box (). struct glyph *last_glyph; NSRect r; int hthickness, vthickness; - struct face *face; - - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = s->face; + struct face *face = s->face; vthickness = face->box_vertical_line_width; hthickness = face->box_horizontal_line_width; @@ -3669,34 +3633,26 @@ Function modeled after x_draw_glyph_string_box (). || FONT_TOO_HIGH (s->font) || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) { - struct face *face; - if (s->hl == DRAW_MOUSE_FACE) - { - face - = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + struct face *face = s->face; if (!face->stipple) - [(NS_FACE_BACKGROUND (face) != 0 - ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) - : FRAME_BACKGROUND_COLOR (s->f)) set]; + { + if (s->hl != DRAW_CURSOR) + [(NS_FACE_BACKGROUND (face) != 0 + ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) + : FRAME_BACKGROUND_COLOR (s->f)) set]; + else + [FRAME_CURSOR_COLOR (s->f) set]; + } else { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set]; } - if (s->hl != DRAW_CURSOR) - { - NSRect r = NSMakeRect (s->x, s->y + box_line_width, - s->background_width, - s->height-2*box_line_width); - NSRectFill (r); - } + NSRect r = NSMakeRect (s->x, s->y + box_line_width, + s->background_width, + s->height-2*box_line_width); + NSRectFill (r); s->background_filled_p = 1; } @@ -3717,7 +3673,7 @@ Function modeled after x_draw_glyph_string_box (). int th; char raised_p; NSRect br; - struct face *face; + struct face *face = s->face; NSColor *tdCol; NSTRACE ("ns_dumpglyphs_image"); @@ -3738,15 +3694,6 @@ Function modeled after x_draw_glyph_string_box (). /* Draw BG: if we need larger area than image itself cleared, do that, otherwise, since we composite the image under NS (instead of mucking with its background color), we must clear just the image area. */ - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set]; @@ -3817,16 +3764,8 @@ Function modeled after x_draw_glyph_string_box (). if (s->hl == DRAW_CURSOR) { - [FRAME_CURSOR_COLOR (s->f) set]; - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) + [FRAME_CURSOR_COLOR (s->f) set]; tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); - else - /* Currently on NS img->mask is always 0. Since - get_window_cursor_type specifies a hollow box cursor when on - a non-masked image we never reach this clause. But we put it - in, in anticipation of better support for image masks on - NS. */ - tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); } else { @@ -3878,66 +3817,35 @@ Function modeled after x_draw_glyph_string_box (). static void ns_dumpglyphs_stretch (struct glyph_string *s) { - NSRect r[2]; NSRect glyphRect; - int n; - struct face *face; + struct face *face = s->face; NSColor *fgCol, *bgCol; if (!s->background_filled_p) { - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID_OR_NULL (s->f, - MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + face = s->face; bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); - glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); - - [bgCol set]; - - /* NOTE: under NS this is NOT used to draw cursors, but we must avoid - overwriting cursor (usually when cursor on a tab) */ if (s->hl == DRAW_CURSOR) - { - CGFloat x, width; + { + fgCol = bgCol; + bgCol = FRAME_CURSOR_COLOR (s->f); + } - /* FIXME: This looks like it will only work for left to - right languages. */ - x = NSMinX (glyphRect); - width = s->w->phys_cursor_width; - glyphRect.size.width -= width; - glyphRect.origin.x += width; + glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); - NSRectFill (glyphRect); + [bgCol set]; - /* Draw overlining, etc. on the cursor. */ - if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) - ns_draw_text_decoration (s, face, bgCol, width, x); - else - ns_draw_text_decoration (s, face, fgCol, width, x); - } - else - { - NSRectFill (glyphRect); - } + NSRectFill (glyphRect); /* Draw overlining, etc. on the stretch glyph (or the part of the stretch glyph after the cursor). */ ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect), NSMinX (glyphRect)); - ns_unfocus (s->f); s->background_filled_p = 1; } } @@ -3946,7 +3854,7 @@ overwriting cursor (usually when cursor on a tab) */ static void ns_draw_glyph_string_foreground (struct glyph_string *s) { - int x, flags; + int x; struct font *font = s->font; /* If first glyph of S has a left box line, start drawing the text @@ -3957,15 +3865,9 @@ overwriting cursor (usually when cursor on a tab) */ else x = s->x; - flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR : - (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE : - (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND : - NS_DUMPGLYPH_NORMAL)); - font->driver->draw (s, s->cmp_from, s->nchars, x, s->ybase, - (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p) - || flags == NS_DUMPGLYPH_MOUSEFACE); + !s->for_overlaps && !s->background_filled_p); } @@ -4072,9 +3974,9 @@ overwriting cursor (usually when cursor on a tab) */ struct font *font = s->face->font; if (! font) font = FRAME_FONT (s->f); - NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string"); + NSTRACE ("ns_draw_glyph_string (hl = %u)", s->hl); - if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/) + if (s->next && s->right_overhang && !s->for_overlaps) { int width; struct glyph_string *next; @@ -4111,14 +4013,21 @@ overwriting cursor (usually when cursor on a tab) */ box_drawn_p = 1; } + n = ns_get_glyph_string_clip_rect (s, r); + + if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */ + && !s->clip_tail + && ((s->prev && s->prev->hl != s->hl && s->left_overhang) + || (s->next && s->next->hl != s->hl && s->right_overhang))) + r[0] = NSIntersectionRect (r[0], NSMakeRect (s->x, s->y, s->width, s->height)); + + ns_focus (s->f, r, n); + switch (s->first_glyph->type) { case IMAGE_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); ns_dumpglyphs_image (s, r[0]); - ns_unfocus (s->f); break; case XWIDGET_GLYPH: @@ -4131,57 +4040,36 @@ overwriting cursor (usually when cursor on a tab) */ case CHAR_GLYPH: case COMPOSITE_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - - if (s->for_overlaps || (s->cmp_from > 0 - && ! s->first_glyph->u.cmp.automatic)) - s->background_filled_p = 1; - else - ns_maybe_dumpglyphs_background - (s, s->first_glyph->type == COMPOSITE_GLYPH); - - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - { - BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; + if (s->for_overlaps || (isComposite + && (s->cmp_from > 0 + && ! s->first_glyph->u.cmp.automatic))) + s->background_filled_p = 1; + else + ns_maybe_dumpglyphs_background + (s, s->first_glyph->type == COMPOSITE_GLYPH); - if (isComposite) - ns_draw_composite_glyph_string_foreground (s); - else - ns_draw_glyph_string_foreground (s); - } + if (isComposite) + ns_draw_composite_glyph_string_foreground (s); + else + ns_draw_glyph_string_foreground (s); - { - NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 - ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), - s->f) - : FRAME_FOREGROUND_COLOR (s->f)); - [col set]; - - /* Draw underline, overline, strike-through. */ - ns_draw_text_decoration (s, s->face, col, s->width, s->x); + { + NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 + ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face), + s->f) + : FRAME_FOREGROUND_COLOR (s->f)); + [col set]; + + /* Draw underline, overline, strike-through. */ + ns_draw_text_decoration (s, s->face, col, s->width, s->x); + } } - if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR) - { - unsigned long tmp = NS_FACE_BACKGROUND (s->face); - NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face); - NS_FACE_FOREGROUND (s->face) = tmp; - } - - ns_unfocus (s->f); break; case GLYPHLESS_GLYPH: - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - if (s->for_overlaps || (s->cmp_from > 0 && ! s->first_glyph->u.cmp.automatic)) s->background_filled_p = 1; @@ -4191,7 +4079,6 @@ overwriting cursor (usually when cursor on a tab) */ /* ... */ /* Not yet implemented. */ /* ... */ - ns_unfocus (s->f); break; default: @@ -4200,13 +4087,92 @@ overwriting cursor (usually when cursor on a tab) */ /* Draw box if not done already. */ if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) + ns_dumpglyphs_box_or_relief (s); + + ns_unfocus (s->f); + + /* Draw surrounding overhangs. */ + if (s->prev) { - n = ns_get_glyph_string_clip_rect (s, r); - ns_focus (s->f, r, n); - ns_dumpglyphs_box_or_relief (s); + ns_focus (s->f, NULL, 0); + struct glyph_string *prev; + + for (prev = s->prev; prev; prev = prev->prev) + if (prev->hl != s->hl + && prev->x + prev->width + prev->right_overhang > s->x) + { + /* As prev was drawn while clipped to its own area, we + must draw the right_overhang part using s->hl now. */ + enum draw_glyphs_face save = prev->hl; + struct face *save_face = prev->face; + + prev->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + prev->num_clips = 1; + prev->hl = s->hl; + if (prev->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (prev); + else + ns_draw_composite_glyph_string_foreground (prev); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + [[NSGraphicsContext currentContext] restoreGraphicsState]; + prev->hl = save; + prev->face = save_face; + prev->num_clips = 0; + } ns_unfocus (s->f); } + if (s->next) + { + ns_focus (s->f, NULL, 0); + struct glyph_string *next; + + for (next = s->next; next; next = next->next) + if (next->hl != s->hl + && next->x - next->left_overhang < s->x + s->width) + { + /* As next will be drawn while clipped to its own area, + we must draw the left_overhang part using s->hl now. */ + enum draw_glyphs_face save = next->hl; + struct face *save_face = next->face; + + next->hl = s->hl; + next->face = s->face; + NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (r); +#ifdef NS_IMPL_GNUSTEP + DPSgsave ([NSGraphicsContext currentContext]); + DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, + s->width, s->height); +#endif + next->num_clips = 1; + if (next->first_glyph->type == CHAR_GLYPH) + ns_draw_glyph_string_foreground (next); + else + ns_draw_composite_glyph_string_foreground (next); +#ifdef NS_IMPL_GNUSTEP + DPSgrestore ([NSGraphicsContext currentContext]); +#endif + [[NSGraphicsContext currentContext] restoreGraphicsState]; + next->hl = save; + next->num_clips = 0; + next->face = save_face; + next->clip_head = next; + next->background_filled_p = 0; + } + ns_unfocus (s->f); + } s->num_clips = 0; } diff --git a/src/xdisp.c b/src/xdisp.c index 646beed6f0..9814efd63c 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -29306,7 +29306,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, for (s = head; s; s = s->next) FRAME_RIF (f)->draw_glyph_string (s); -#ifndef HAVE_NS /* When focus a sole frame and move horizontally, this clears on_p causing a failure to erase prev cursor position. */ if (area == TEXT_AREA @@ -29325,7 +29324,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, notice_overwritten_cursor (w, TEXT_AREA, x0, x1, row->y, MATRIX_ROW_BOTTOM_Y (row)); } -#endif /* Value is the x-position up to which drawn, relative to AREA of W. This doesn't include parts drawn because of overhangs. */ -- 2.31.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-General-improvements-to-NS-port.patch >From f2a724811cfe11165eef4ec7a3dc12b14e31b2dc Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 23 Oct 2021 19:51:31 +0800 Subject: [PATCH 2/2] General improvements to NS port * src/dispextern.h: Remove some !HAVE_NS conditionals around grab related code. * src/frame.c (gui_mouse_grabbed, gui_redo_mouse_highlight): Remove !HAVE_NS conditionals around code. * src/nsmenu.m (ns_update_menubar): Prevent recursive calls and enable shallow updates on GNUstep. (menuNeedsUpdate): Prevent recursive calls. (ns_menu_show): Fix mysterious GC-related bug. (update_frame_tool_bar_1): Work around mysterious toolbar sizing bug on GNUstep. * src/nsterm.h (struct ns_output): New field for tracking toolbar visibility changes. * src/nsterm.m (frame_set_mouse_pixel_position): Implement for GNUstep. (ns_redraw_scroll_bars): Enable for GNUstep. (ns_clear_frame): Redraw scrollbars on GNUstep. (ns_update_window_end): New function. (ns_redisplay_interface): Add ns_update_window_end on GNUstep. (- keyDown): Remove debug code that doesn't work on GNUstep. (- mouseDown): Enable grab tracking on NS port. (- resizeWithOldSuperviewSize): Fix build with NSTRACE. * src/xdisp.c (note_tab_bar_highlight): Enable some code for NS port. --- src/dispextern.h | 2 -- src/frame.c | 4 --- src/nsmenu.m | 76 +++++++++++++++++++++++++++++++++++++++--------- src/nsterm.h | 6 ++++ src/nsterm.m | 42 +++++++++++++++++++++----- src/xdisp.c | 2 -- 6 files changed, 102 insertions(+), 30 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index e03e21fddc..5b28fe7666 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3722,10 +3722,8 @@ #define IMAGE_BACKGROUND_TRANSPARENT(img, f, mask) \ const char *, const char *, enum resource_types); -#ifndef HAVE_NS /* These both used on W32 and X only. */ extern bool gui_mouse_grabbed (Display_Info *); extern void gui_redo_mouse_highlight (Display_Info *); -#endif /* HAVE_NS */ #endif /* HAVE_WINDOW_SYSTEM */ diff --git a/src/frame.c b/src/frame.c index 2b1cb452ef..79a7c89e0d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -5028,8 +5028,6 @@ gui_set_no_special_glyphs (struct frame *f, Lisp_Object new_value, Lisp_Object o } -#ifndef HAVE_NS - /* Non-zero if mouse is grabbed on DPYINFO and we know the frame where it is. */ @@ -5054,8 +5052,6 @@ gui_redo_mouse_highlight (Display_Info *dpyinfo) dpyinfo->last_mouse_motion_y); } -#endif /* HAVE_NS */ - /* Subroutines of creating an X frame. */ /* Make sure that Vx_resource_name is set to a reasonable value. diff --git a/src/nsmenu.m b/src/nsmenu.m index 05b89c2f56..b93d3a79bd 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -101,6 +101,15 @@ static void ns_update_menubar (struct frame *f, bool deep_p) { +#ifdef NS_IMPL_GNUSTEP + static int inside = 0; + + if (inside) + return; + + inside++; +#endif + BOOL needsSet = NO; id menu = [NSApp mainMenu]; bool owfi; @@ -120,7 +129,12 @@ NSTRACE ("ns_update_menubar"); if (f != SELECTED_FRAME () || FRAME_EXTERNAL_MENU_BAR (f) == 0) + { +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif return; + } XSETFRAME (Vmenu_updating_frame, f); /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, deep_p, submenu); */ @@ -144,10 +158,6 @@ t = -(1000*tb.time+tb.millitm); #endif -#ifdef NS_IMPL_GNUSTEP - deep_p = 1; /* See comment in menuNeedsUpdate. */ -#endif - if (deep_p) { /* Make a widget-value tree representing the entire menu trees. */ @@ -275,6 +285,9 @@ free_menubar_widget_value_tree (first_wv); discard_menu_items (); unbind_to (specpdl_count, Qnil); +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif return; } @@ -408,6 +421,10 @@ if (needsSet) [NSApp setMainMenu: menu]; +#ifdef NS_IMPL_GNUSTEP + inside--; +#endif + unblock_input (); } @@ -490,17 +507,34 @@ - (instancetype)initWithTitle: (NSString *)title call to ns_update_menubar. */ - (void)menuNeedsUpdate: (NSMenu *)menu { +#ifdef NS_IMPL_GNUSTEP + static int inside = 0; +#endif + if (!FRAME_LIVE_P (SELECTED_FRAME ())) return; -#ifdef NS_IMPL_COCOA -/* TODO: GNUstep calls this method when the menu is still being built - which results in a recursive stack overflow. One possible solution - is to use menuWillOpen instead, but the Apple docs explicitly warn - against changing the contents of the menu in it. I don't know what - the right thing to do for GNUstep is. */ +#ifdef NS_IMPL_GNUSTEP + /* GNUstep calls this method when the menu is still being built + which results in a recursive stack overflow, which this variable + prevents. */ + + if (!inside) + ++inside; + else + return; +#endif + if (needsUpdate) - ns_update_menubar (SELECTED_FRAME (), true); + { +#ifdef NS_IMPL_GNUSTEP + needsUpdate = NO; +#endif + ns_update_menubar (SELECTED_FRAME (), true); + } + +#ifdef NS_IMPL_GNUSTEP + --inside; #endif } @@ -827,6 +861,9 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item p.x = x; p.y = y; + /* Don't GC due to a mysterious bug. */ + inhibit_garbage_collection (); + /* now parse stage 2 as in ns_update_menubar */ wv = make_widget_value ("contextmenu", NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; @@ -998,15 +1035,17 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item pmenu = [[EmacsMenu alloc] initWithTitle: NILP (title) ? @"" : [NSString stringWithLispString: title]]; + /* On GNUstep, this call makes menu_items nil for whatever reason + when displaying a context menu from `context-menu-mode'. */ + Lisp_Object items = menu_items; [pmenu fillWithWidgetValue: first_wv->contents]; + menu_items = items; free_menubar_widget_value_tree (first_wv); - unbind_to (specpdl_count, Qnil); - popup_activated_flag = 1; tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps]; popup_activated_flag = 0; [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; - + unbind_to (specpdl_count, Qnil); unblock_input (); return tem; } @@ -1057,6 +1096,15 @@ - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item [toolbar clearActive]; #else [toolbar clearAll]; + /* It takes at least 3 such adjustments to fix an issue where the + tool bar is 2x too tall when a frame's tool bar is first shown. + This is ugly, but I have no other solution for this problem. */ + if (FRAME_OUTPUT_DATA (f)->tool_bar_adjusted < 3) + { + [toolbar setVisible: NO]; + FRAME_OUTPUT_DATA (f)->tool_bar_adjusted++; + [toolbar setVisible: YES]; + } #endif /* Update EmacsToolbar as in GtkUtils, build items list. */ diff --git a/src/nsterm.h b/src/nsterm.h index 944dbd727c..8175f99664 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -978,6 +978,12 @@ #define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) /* Non-zero if we are doing an animation, e.g. toggling the tool bar. */ int in_animation; + +#ifdef NS_IMPL_GNUSTEP + /* Zero if this is the first time a toolbar has been updated on this + frame. */ + int tool_bar_adjusted; +#endif }; /* This dummy declaration needed to support TTYs. */ diff --git a/src/nsterm.m b/src/nsterm.m index 4c915dac5d..a63883cd08 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -65,6 +65,7 @@ Updated by Christian Limpach (chris@nice.ch) #ifdef NS_IMPL_GNUSTEP #include "process.h" +#import #endif #ifdef NS_IMPL_COCOA @@ -2256,13 +2257,19 @@ Hide the window (X11 semantics) { NSTRACE ("frame_set_mouse_pixel_position"); - /* FIXME: what about GNUstep? */ #ifdef NS_IMPL_COCOA CGPoint mouse_pos = CGPointMake(f->left_pos + pix_x, f->top_pos + pix_y + FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f)); CGWarpMouseCursorPosition (mouse_pos); +#else + GSDisplayServer *server = GSServerForWindow ([FRAME_NS_VIEW (f) window]); + [server setMouseLocation: NSMakePoint (f->left_pos + pix_x, + f->top_pos + pix_y + + FRAME_NS_TITLEBAR_HEIGHT(f) + + FRAME_TOOLBAR_HEIGHT(f)) + onScreen: [[[FRAME_NS_VIEW (f) window] screen] screenNumber]]; #endif } @@ -2575,8 +2582,7 @@ Hide the window (X11 semantics) ========================================================================== */ -#if 0 -/* FIXME: Remove this function. */ +#ifdef NS_IMPL_GNUSTEP static void ns_redraw_scroll_bars (struct frame *f) { @@ -2621,10 +2627,9 @@ Hide the window (X11 semantics) NSRectFill (r); ns_unfocus (f); - /* as of 2006/11 or so this is now needed */ - /* FIXME: I don't see any reason for this and removing it makes no - difference here. Do we need it for GNUstep? */ - //ns_redraw_scroll_bars (f); +#ifdef NS_IMPL_GNUSTEP + ns_redraw_scroll_bars (f); +#endif unblock_input (); } @@ -4922,6 +4927,17 @@ static Lisp_Object ns_string_to_lispmod (const char *s) { } +#ifdef NS_IMPL_GNUSTEP +static void +ns_update_window_end (struct window *w, bool cursor_on_p, + bool mouse_face_overwritten_p) +{ + NSTRACE ("ns_update_window_end (cursor_on_p = %d)", cursor_on_p); + + ns_redraw_scroll_bars (WINDOW_XFRAME (w)); +} +#endif + /* This and next define (many of the) public functions in this file. */ /* gui_* are generic versions in xdisp.c that we, and other terms, get away with using despite presence in the "system dependent" redisplay @@ -4938,7 +4954,11 @@ static Lisp_Object ns_string_to_lispmod (const char *s) ns_scroll_run, ns_after_update_window_line, NULL, /* update_window_begin */ +#ifndef NS_IMPL_GNUSTEP NULL, /* update_window_end */ +#else + ns_update_window_end, +#endif 0, /* flush_display */ gui_clear_window_mouse_face, gui_get_glyph_overhangs, @@ -6166,9 +6186,11 @@ In that case we use UCKeyTranslate (ns_get_shifted_character) Lisp_Object kind = fnKeysym ? QCfunction : QCordinary; emacs_event->modifiers = EV_MODIFIERS2 (flags, kind); +#ifndef NS_IMPL_GNUSTEP if (NS_KEYLOG) fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n", code, fnKeysym, flags, emacs_event->modifiers); +#endif /* If it was a function key or had control-like modifiers, pass it directly to Emacs. */ @@ -6681,6 +6703,11 @@ - (void)mouseDown: (NSEvent *)theEvent emacs_event->code = EV_BUTTON (theEvent); emacs_event->modifiers = EV_MODIFIERS (theEvent) | EV_UDMODIFIERS (theEvent); + + if (emacs_event->modifiers & down_modifier) + FRAME_DISPLAY_INFO (emacsframe)->grabbed |= 1 << EV_BUTTON (theEvent); + else + FRAME_DISPLAY_INFO (emacsframe)->grabbed &= ~(1 << EV_BUTTON (theEvent)); } XSETINT (emacs_event->x, lrint (p.x)); @@ -6981,7 +7008,6 @@ - (void)resizeWithOldSuperviewSize: (NSSize)oldSize height = (int)NSHeight (frame); NSTRACE_SIZE ("New size", NSMakeSize (width, height)); - NSTRACE_SIZE ("Original size", size); /* Reset the frame size to match the bounds of the superview (the NSWindow's contentView). We need to do this as sometimes the diff --git a/src/xdisp.c b/src/xdisp.c index 9814efd63c..86c4e704d5 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -13894,7 +13894,6 @@ note_tab_bar_highlight (struct frame *f, int x, int y) clear_mouse_face (hlinfo); bool mouse_down_p = false; -#ifndef HAVE_NS /* Mouse is down, but on different tab-bar item? Or alternatively, the mouse might've been pressed somewhere we don't know about, and then have moved onto the tab bar. In this case, @@ -13907,7 +13906,6 @@ note_tab_bar_highlight (struct frame *f, int x, int y) if (mouse_down_p && f->last_tab_bar_item != prop_idx && f->last_tab_bar_item != -1) return; -#endif draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; /* If tab-bar item is not enabled, don't highlight it. */ -- 2.31.1 --=-=-= Content-Type: text/plain Thanks. --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Sat Nov 06 09:02:18 2021 Received: (at 51411-done) by debbugs.gnu.org; 6 Nov 2021 13:02:18 +0000 Received: from localhost ([127.0.0.1]:48695 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjLKs-0003pr-Aj for submit@debbugs.gnu.org; Sat, 06 Nov 2021 09:02:18 -0400 Received: from outbound.soverin.net ([116.202.126.228]:44165) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjLKp-0003pd-Rh for 51411-done@debbugs.gnu.org; Sat, 06 Nov 2021 09:02:16 -0400 Received: from smtp.soverin.net (unknown [10.10.3.28]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by outbound.soverin.net (Postfix) with ESMTPS id CDFA24D3; Sat, 6 Nov 2021 13:02:09 +0000 (UTC) Received: from smtp.soverin.net (smtp.soverin.net [159.69.232.142]) by soverin.net DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=idiocy.org; s=soverin; t=1636203729; bh=kL5MTp67WhTR6qKMXeunjcJpqvRC8uUB/3Ej935ZCRg=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=FRL3+mwLt6vLMMuWg3KxM5FEvRKIIj7lNDcuYlnQVNjRJFPlp2uXUsy71YReYG3VT vqkU6O38ePs7B//4kdS6lYTnMdzRvvmZiRA7IOGGnixfGV7C/0avAuuLmBMore4adF Tzr99snEmqb0sk6d7erQFB3azqbcQzIZHgd4A8K0hRRXXTa4pOBc4prgQKjhqMxkeA bD44IKhZX5SLtcamvunHLoCf2Gb+PmIisCGJHYkdRDeQqpWZPHm7KT+uCG8tSetY+J 7o39gsU9ue2V+eV5KJ51BFsim7YiWqgxb2UbAVaCcWMoTZ1B2G3rdJn9K5BPBdPOyt ldae/Fw+Bw76g== Received: from alan by faroe.holly.idiocy.org with local (Exim 4.95-RC2) (envelope-from ) id 1mjLKd-000D2B-ID; Sat, 06 Nov 2021 13:02:03 +0000 Date: Sat, 6 Nov 2021 13:02:03 +0000 From: Alan Third To: Po Lu Subject: Re: bug#51411: NS port cleanups Message-ID: Mail-Followup-To: Alan Third , Po Lu , 51411-done@debbugs.gnu.org References: <87ilxhmlwc.fsf@yahoo.com> <87lf29jxeg.fsf@yahoo.com> <87v91digfm.fsf@yahoo.com> <87pmrlibj0.fsf@yahoo.com> <87fssb9hcf.fsf@yahoo.com> <877ddm878e.fsf@yahoo.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <877ddm878e.fsf@yahoo.com> X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 51411-done Cc: 51411-done@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) On Sat, Nov 06, 2021 at 08:20:49AM +0800, Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors wrote: > Po Lu writes: > > > As of 48af19c1 those patches don't apply anymore. Here's a version that > > does. (I kept my version of the overhang computation code instead of > > Daniel's, because the xterm code computes overhangs correctly, and > > bug#51105 doesn't apply to it AFAIU.) > > And it doesn't apply, again. This should: Sorry, I've not been very attentive to Emacs stuff recently. I've pushed these changes to master. Thank you! -- Alan Third From unknown Wed Jun 18 23:16:38 2025 Received: (at fakecontrol) by fakecontrolmessage; To: internal_control@debbugs.gnu.org From: Debbugs Internal Request Subject: Internal Control Message-Id: bug archived. Date: Sun, 05 Dec 2021 12:24:06 +0000 User-Agent: Fakemail v42.6.9 # This is a fake control message. # # The action: # bug archived. thanks # This fakemail brought to you by your local debbugs # administrator