* src/font.c (font_parse_fcname): Rewrite GTK font name parser.
* test/font-parse-testsuite.el (test-font-parse-data): New file.
This commit is contained in:
parent
e4dbdb0992
commit
6608a7d8fb
4 changed files with 197 additions and 80 deletions
|
@ -1,3 +1,7 @@
|
|||
2011-01-26 Chong Yidong <cyd@stupidchicken.com>
|
||||
|
||||
* font.c (font_parse_fcname): Rewrite GTK font name parser.
|
||||
|
||||
2011-01-25 Stefan Monnier <monnier@iro.umontreal.ca>
|
||||
|
||||
* xdisp.c (handle_fontified_prop): Be careful with font-lock changing
|
||||
|
|
134
src/font.c
134
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;
|
||||
|
||||
for (p = name; *p; p = *q ? q + 1 : q)
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2011-01-26 Chong Yidong <cyd@stupidchicken.com>
|
||||
|
||||
* font-parse-testsuite.el (test-font-parse-data): New file.
|
||||
|
||||
2011-01-13 Stefan Monnier <monnier@iro.umontreal.ca>
|
||||
|
||||
* indent/prolog.prolog: Add tokenizing tests.
|
||||
|
|
135
test/font-parse-testsuite.el
Normal file
135
test/font-parse-testsuite.el
Normal file
|
@ -0,0 +1,135 @@
|
|||
;;; redisplay-testsuite.el --- Test suite for redisplay.
|
||||
|
||||
;; Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Chong Yidong <cyd@stupidchicken.com>
|
||||
;; 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; 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.
|
Loading…
Add table
Reference in a new issue