From 6608a7d8fb941119faeb8873df0f56eea0ac1764 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Wed, 26 Jan 2011 13:10:04 -0500 Subject: [PATCH] * src/font.c (font_parse_fcname): Rewrite GTK font name parser. * test/font-parse-testsuite.el (test-font-parse-data): New file. --- src/ChangeLog | 4 ++ src/font.c | 134 ++++++++++++++-------------------- test/ChangeLog | 4 ++ test/font-parse-testsuite.el | 135 +++++++++++++++++++++++++++++++++++ 4 files changed, 197 insertions(+), 80 deletions(-) create mode 100644 test/font-parse-testsuite.el diff --git a/src/ChangeLog b/src/ChangeLog index 76f81d6135..2041b5bb45 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2011-01-26 Chong Yidong + + * font.c (font_parse_fcname): Rewrite GTK font name parser. + 2011-01-25 Stefan Monnier * xdisp.c (handle_fontified_prop): Be careful with font-lock changing diff --git a/src/font.c b/src/font.c index eb217c6f60..52b239569b 100644 --- a/src/font.c +++ b/src/font.c @@ -1448,109 +1448,83 @@ font_parse_fcname (char *name, Lisp_Object font) /* Either a fontconfig-style name with no size and property data, or a GTK-style name. */ Lisp_Object prop; - int word_len, prop_found = 0; + Lisp_Object weight = Qnil, slant = Qnil; + Lisp_Object width = Qnil, size = Qnil; + char *word_start; + int word_len; + int size_found = 0; + + /* Scan backwards from the end, looking for a size. */ + for (p = name + len - 1; p >= name; p--) + if (!isdigit (*p)) + break; + + if ((p < name + len - 1) && ((p + 1 == name) || *p == ' ')) + /* Found a font size. */ + size = make_float (strtod (p + 1, NULL)); + else + p = name + len; - for (p = name; *p; p = *q ? q + 1 : q) + /* Now P points to the termination of the string, sans size. + Scan backwards, looking for font properties. */ + for (; p > name; p = q) { - if (isdigit (*p)) + for (q = p - 1; q >= name; q--) { - int size_found = 1; - - for (q = p + 1; *q && *q != ' '; q++) - if (! isdigit (*q) && *q != '.') - { - size_found = 0; - break; - } - if (size_found) - { - double point_size = strtod (p, &q); - ASET (font, FONT_SIZE_INDEX, make_float (point_size)); - continue; - } + if (q > name && *(q-1) == '\\') + --q; /* Skip quoting backslashes. */ + else if (*q == ' ') + break; } - for (q = p + 1; *q && *q != ' '; q++) - if (*q == '\\' && q[1]) - q++; - word_len = q - p; + word_start = q + 1; + word_len = p - word_start; -#define PROP_MATCH(STR,N) ((word_len == N) && memcmp (p, STR, N) == 0) +#define PROP_MATCH(STR,N) \ + ((word_len == N) && memcmp (word_start, STR, N) == 0) +#define PROP_SAVE(VAR,STR,N) \ + (VAR = NILP (VAR) ? font_intern_prop (STR, N, 1) : VAR) if (PROP_MATCH ("Ultra-Light", 11)) - { - prop_found = 1; - prop = font_intern_prop ("ultra-light", 11, 1); - FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop); - } + PROP_SAVE (weight, "ultra-light", 11); else if (PROP_MATCH ("Light", 5)) - { - prop_found = 1; - prop = font_intern_prop ("light", 5, 1); - FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop); - } + PROP_SAVE (weight, "light", 5); else if (PROP_MATCH ("Book", 4)) - { - prop_found = 1; - prop = font_intern_prop ("book", 4, 1); - FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop); - } + PROP_SAVE (weight, "book", 4); else if (PROP_MATCH ("Medium", 6)) - { - prop_found = 1; - prop = font_intern_prop ("medium", 6, 1); - FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop); - } + PROP_SAVE (weight, "medium", 6); else if (PROP_MATCH ("Semi-Bold", 9)) - { - prop_found = 1; - prop = font_intern_prop ("semi-bold", 9, 1); - FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop); - } + PROP_SAVE (weight, "semi-bold", 9); else if (PROP_MATCH ("Bold", 4)) - { - prop_found = 1; - prop = font_intern_prop ("bold", 4, 1); - FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, prop); - } + PROP_SAVE (weight, "bold", 4); else if (PROP_MATCH ("Italic", 6)) - { - prop_found = 1; - prop = font_intern_prop ("italic", 4, 1); - FONT_SET_STYLE (font, FONT_SLANT_INDEX, prop); - } + PROP_SAVE (slant, "italic", 6); else if (PROP_MATCH ("Oblique", 7)) - { - prop_found = 1; - prop = font_intern_prop ("oblique", 7, 1); - FONT_SET_STYLE (font, FONT_SLANT_INDEX, prop); - } + PROP_SAVE (slant, "oblique", 7); else if (PROP_MATCH ("Semi-Condensed", 14)) - { - prop_found = 1; - prop = font_intern_prop ("semi-condensed", 14, 1); - FONT_SET_STYLE (font, FONT_WIDTH_INDEX, prop); - } + PROP_SAVE (width, "semi-condensed", 14); else if (PROP_MATCH ("Condensed", 9)) + PROP_SAVE (width, "condensed", 9); + /* An unknown word must be part of the font name. */ + else { - prop_found = 1; - prop = font_intern_prop ("condensed", 9, 1); - FONT_SET_STYLE (font, FONT_WIDTH_INDEX, prop); + family_end = p; + break; } - else { - if (prop_found) - return -1; /* Unknown property in GTK-style font name. */ - family_end = q; - } } #undef PROP_MATCH if (family_end) - { - Lisp_Object family; - family = font_intern_prop (name, family_end - name, 1); - ASET (font, FONT_FAMILY_INDEX, family); - } + ASET (font, FONT_FAMILY_INDEX, + font_intern_prop (name, family_end - name, 1)); + if (!NILP (size)) + ASET (font, FONT_SIZE_INDEX, size); + if (!NILP (weight)) + FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, weight); + if (!NILP (slant)) + FONT_SET_STYLE (font, FONT_SLANT_INDEX, slant); + if (!NILP (width)) + FONT_SET_STYLE (font, FONT_WIDTH_INDEX, width); } return 0; diff --git a/test/ChangeLog b/test/ChangeLog index 7b0de7e9e1..b03e372b8b 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,7 @@ +2011-01-26 Chong Yidong + + * font-parse-testsuite.el (test-font-parse-data): New file. + 2011-01-13 Stefan Monnier * indent/prolog.prolog: Add tokenizing tests. diff --git a/test/font-parse-testsuite.el b/test/font-parse-testsuite.el new file mode 100644 index 0000000000..02923159e8 --- /dev/null +++ b/test/font-parse-testsuite.el @@ -0,0 +1,135 @@ +;;; redisplay-testsuite.el --- Test suite for redisplay. + +;; Copyright (C) 2011 Free Software Foundation, Inc. + +;; Author: Chong Yidong +;; Keywords: internal +;; Human-Keywords: internal + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; Type M-x test-font-parse RET to generate the test buffer. + +;; TODO: Convert to ERT format. + +;;; Code: + +(defvar test-font-parse-data + '((" " " " nil nil nil nil) + ("Monospace" "Monospace" nil nil nil nil) + ("Foo1" "Foo1" nil nil nil nil) + ("12" "nil" 12.0 nil nil nil) + ("12 " "12 " nil nil nil nil) + ;; Fontconfig format + ("Foo:" "Foo" nil nil nil nil) + ("Foo-8" "Foo" 8.0 nil nil nil) + ("Foo-18:" "Foo" 18.0 nil nil nil) + ("Foo-18:light" "Foo" 18.0 light nil nil) + ("Foo 10:weight=bold" "Foo 10" nil bold nil nil) + ("Foo-12:weight=bold" "Foo" 12.0 bold nil nil) + ("Foo 8-20:slant=oblique" "Foo 8" 20.0 nil oblique nil) + ("Foo:light:roman" "Foo" nil light roman nil) + ("Foo:italic:roman" "Foo" nil nil roman nil) + ("Foo 12:light:oblique" "Foo 12" nil light oblique nil) + ("Foo-12:demibold:oblique" "Foo" 12.0 demibold oblique nil) + ("Foo:black:proportional" "Foo" nil black nil 0) + ("Foo-10:black:proportional" "Foo" 10.0 black nil 0) + ("Foo:weight=normal" "Foo" nil normal nil nil) + ("Foo:weight=bold" "Foo" nil bold nil nil) + ("Foo:weight=bold:slant=italic" "Foo" nil bold italic) + ("Foo:weight=bold:slant=italic:mono" "Foo" nil bold italic 100) + ("Foo-10:demibold:slant=normal" "Foo" 10.0 demibold normal nil) + ("Foo 11-16:oblique:weight=bold" "Foo 11" 16.0 bold oblique nil) + ("Foo:oblique:randomprop=randomtag:weight=bold" + "Foo" nil bold oblique nil) + ("Foo:randomprop=randomtag:bar=baz" "Foo" nil nil nil nil) + ("Foo Book Light:bar=baz" "Foo Book Light" nil nil nil nil) + ("Foo Book Light 10:bar=baz" "Foo Book Light 10" nil nil nil nil) + ("Foo Book Light-10:bar=baz" "Foo Book Light" 10.0 nil nil nil) + ;; GTK format + ("Oblique" "nil" nil nil oblique nil) + ("Bold 17" "nil" 17.0 bold nil nil) + ("17 Bold" "17" nil bold nil nil) + ("Book Oblique 2" "nil" 2.0 book oblique nil) + ("Bar 7" "Bar" 7.0 nil nil nil) + ("Bar Ultra-Light" "Bar" nil ultra-light nil nil) + ("Bar Light 8" "Bar" 8.0 light nil nil) + ("Bar Book Medium 9" "Bar" 9.0 medium nil nil) + ("Bar Semi-Bold Italic 10" "Bar" 10.0 semi-bold italic nil) + ("Bar Semi-Condensed Bold Italic 11" "Bar" 11.0 bold italic nil) + ("Foo 10 11" "Foo 10" 11.0 nil nil nil) + ("Foo 1985 Book" "Foo 1985" nil book nil nil) + ("Foo 1985 A Book" "Foo 1985 A" nil book nil nil) + ("Foo A Book 12 A" "Foo A Book 12 A" nil nil nil nil) + ("Foo 1985 Book 12 Oblique" "Foo 1985 Book 12" nil nil oblique nil) + ("Foo 1985 Book 12 Italic 10" "Foo 1985 Book 12" 10.0 nil italic nil) + ("Foo Book Bar 6 Italic" "Foo Book Bar 6" nil nil italic nil) + ("Foo Book Bar Bold" "Foo Book Bar" nil bold nil nil)) + "List of font names parse data. +Each element should have the form + (NAME FAMILY SIZE WEIGHT SLANT SPACING) +where NAME is the name to parse, and the remainder are the +expected font properties from parsing NAME.") + +(defun test-font-parse () + "Test font name parsing." + (interactive) + (switch-to-buffer (generate-new-buffer "*Font Pase Test*")) + (setq show-trailing-whitespace nil) + (let ((pass-face '((t :foreground "green"))) + (fail-face '((t :foreground "red")))) + (dolist (test test-font-parse-data) + (let* ((name (nth 0 test)) + (fs (font-spec :name name)) + (family (symbol-name (font-get fs :family))) + (size (font-get fs :size)) + (weight (font-get fs :weight)) + (slant (font-get fs :slant)) + (spacing (font-get fs :spacing))) + (insert name) + (if (> (current-column) 20) + (insert "\n")) + (indent-to-column 21) + (insert (propertize family + 'face (if (equal family (nth 1 test)) + pass-face + fail-face))) + (indent-to-column 40) + (insert (propertize (format "%s" size) + 'face (if (equal size (nth 2 test)) + pass-face + fail-face))) + (indent-to-column 48) + (insert (propertize (format "%s" weight) + 'face (if (eq weight (nth 3 test)) + pass-face + fail-face))) + (indent-to-column 60) + (insert (propertize (format "%s" slant) + 'face (if (eq slant (nth 4 test)) + pass-face + fail-face))) + (indent-to-column 69) + (insert (propertize (format "%s" spacing) + 'face (if (eq spacing (nth 5 test)) + pass-face + fail-face))) + (insert "\n")))) + (goto-char (point-min))) + +;;; font-parse-testsuite.el ends here. -- 2.20.1