aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorPo Lu2023-09-14 09:57:09 +0800
committerPo Lu2023-09-14 09:59:45 +0800
commit921c0a16ce20828043b3a9df3e0fb6c3a4ecbd74 (patch)
tree47849b6044689807759a949cd6472d0226e5a0a7 /java
parentef2bd5e48751ac3b1abe9a0a4865a62a1c51a419 (diff)
downloademacs-921c0a16ce20828043b3a9df3e0fb6c3a4ecbd74.tar.gz
emacs-921c0a16ce20828043b3a9df3e0fb6c3a4ecbd74.zip
Improve the Android last resort font driver
* java/org/gnu/emacs/EmacsSdk7FontDriver.java (Sdk7Typeface): Rename fileName to familyName and cease attempting to infer a style from it. (EmacsSdk7FontDriver): Employ preset typefaces rather than enumerating each typeface within the system fonts directory. (draw): Circumvent kerning difficulties by advancing past each character individually.
Diffstat (limited to 'java')
-rw-r--r--java/org/gnu/emacs/EmacsSdk7FontDriver.java194
1 files changed, 71 insertions, 123 deletions
diff --git a/java/org/gnu/emacs/EmacsSdk7FontDriver.java b/java/org/gnu/emacs/EmacsSdk7FontDriver.java
index 97969585d16..b8aecbe7c2d 100644
--- a/java/org/gnu/emacs/EmacsSdk7FontDriver.java
+++ b/java/org/gnu/emacs/EmacsSdk7FontDriver.java
@@ -31,6 +31,19 @@ import android.graphics.Canvas;
31 31
32import android.util.Log; 32import android.util.Log;
33 33
34
35
36/* EmacsSdk7FontDriver implements a fallback font driver under
37 Android. This font driver is enabled when the SFNT font driver (in
38 sfntfont-android.c) proves incapable of locating any fonts, which
39 has hitherto not been observed in practice.
40
41 This font driver does not supply each font installed on the system,
42 in lieu of which it provides a list of fonts for each conceivable
43 style and sub-type of the system's own Typefaces, which arises from
44 Android's absence of suitable APIs for loading individual font
45 files. */
46
34public class EmacsSdk7FontDriver extends EmacsFontDriver 47public class EmacsSdk7FontDriver extends EmacsFontDriver
35{ 48{
36 private static final String TOFU_STRING = "\uDB3F\uDFFD"; 49 private static final String TOFU_STRING = "\uDB3F\uDFFD";
@@ -46,106 +59,26 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
46 public int slant, width, weight, spacing; 59 public int slant, width, weight, spacing;
47 60
48 public 61 public
49 Sdk7Typeface (String fileName, Typeface typeface) 62 Sdk7Typeface (String familyName, Typeface typeface)
50 { 63 {
51 String style, testString; 64 String style, testString;
52 int index, measured, i; 65 int index, measured, i;
53 float[] widths; 66 float[] widths;
54 67
68 /* Initialize the font style fields and create a paint object
69 linked with that typeface. */
70
55 slant = NORMAL; 71 slant = NORMAL;
56 weight = REGULAR; 72 weight = REGULAR;
57 width = UNSPECIFIED; 73 width = UNSPECIFIED;
58 spacing = PROPORTIONAL; 74 spacing = PROPORTIONAL;
59 75
60 this.typeface = typeface; 76 this.typeface = typeface;
77 this.familyName = familyName;
61 78
62 typefacePaint = new Paint (); 79 typefacePaint = new Paint ();
63 typefacePaint.setAntiAlias (true); 80 typefacePaint.setAntiAlias (true);
64 typefacePaint.setTypeface (typeface); 81 typefacePaint.setTypeface (typeface);
65
66 /* For the calls to measureText below. */
67 typefacePaint.setTextSize (10.0f);
68
69 /* Parse the file name into some useful data. First, strip off
70 the extension. */
71 fileName = fileName.split ("\\.", 2)[0];
72
73 /* Next, split the file name by dashes. Everything before the
74 last dash is part of the family name. */
75 index = fileName.lastIndexOf ("-");
76
77 if (index > 0)
78 {
79 style = fileName.substring (index + 1, fileName.length ());
80 familyName = fileName.substring (0, index);
81
82 /* Look for something describing the weight. */
83 if (style.contains ("Thin"))
84 weight = THIN;
85 else if (style.contains ("UltraLight"))
86 weight = ULTRA_LIGHT;
87 else if (style.contains ("SemiLight"))
88 weight = SEMI_LIGHT;
89 else if (style.contains ("Light"))
90 weight = LIGHT;
91 else if (style.contains ("Medium"))
92 weight = MEDIUM;
93 else if (style.contains ("SemiBold"))
94 weight = SEMI_BOLD;
95 else if (style.contains ("ExtraBold"))
96 weight = EXTRA_BOLD;
97 else if (style.contains ("Bold"))
98 weight = BOLD;
99 else if (style.contains ("Black"))
100 weight = BLACK;
101 else if (style.contains ("UltraHeavy"))
102 weight = ULTRA_HEAVY;
103
104 /* And the slant. */
105 if (style.contains ("ReverseOblique"))
106 slant = OBLIQUE;
107 else if (style.contains ("ReverseItalic"))
108 slant = REVERSE_ITALIC;
109 else if (style.contains ("Italic"))
110 slant = ITALIC;
111 else if (style.contains ("Oblique"))
112 slant = OBLIQUE;
113
114 /* Finally, the width. */
115 if (style.contains ("UltraCondensed"))
116 width = ULTRA_CONDENSED;
117 else if (style.contains ("ExtraCondensed"))
118 width = EXTRA_CONDENSED;
119 else if (style.contains ("SemiCondensed"))
120 width = SEMI_CONDENSED;
121 else if (style.contains ("Condensed"))
122 width = CONDENSED;
123 else if (style.contains ("SemiExpanded"))
124 width = SEMI_EXPANDED;
125 else if (style.contains ("ExtraExpanded"))
126 width = EXTRA_EXPANDED;
127 else if (style.contains ("UltraExpanded"))
128 width = ULTRA_EXPANDED;
129 else if (style.contains ("Expanded"))
130 width = EXPANDED;
131
132 /* Guess the spacing information. */
133 testString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
134 widths = new float[testString.length ()];
135
136 measured = typefacePaint.getTextWidths (testString,
137 0, testString.length (),
138 widths);
139 spacing = MONO;
140 for (i = 0; i < measured; ++i)
141 {
142 if (i != 0 && widths[i - 1] != widths[i])
143 /* This isn't a monospace font. */
144 spacing = PROPORTIONAL;
145 }
146 }
147 else
148 familyName = fileName;
149 } 82 }
150 83
151 @Override 84 @Override
@@ -244,43 +177,42 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
244 EmacsSdk7FontDriver () 177 EmacsSdk7FontDriver ()
245 { 178 {
246 int i; 179 int i;
247 File systemFontsDirectory, fontFile;
248 Typeface typeface; 180 Typeface typeface;
249 181
250 systemFontsDirectory = new File ("/system/fonts"); 182 typefaceList = new Sdk7Typeface[5];
251
252 fontFamilyList = systemFontsDirectory.list ();
253
254 /* If that returned null, replace it with an empty array. */
255 fontFamilyList = new String[0];
256 183
257 typefaceList = new Sdk7Typeface[fontFamilyList.length + 3]; 184 /* Initialize the default monospace and Sans Serif typefaces.
258 185 Initialize the same typeface with various distinct styles. */
259 /* It would be nice to avoid opening each and every font upon 186 fallbackTypeface = new Sdk7Typeface ("Sans Serif",
260 startup. But that doesn't seem to be possible on 187 Typeface.DEFAULT);
261 Android. */ 188 typefaceList[1] = fallbackTypeface;
262 189
263 for (i = 0; i < fontFamilyList.length; ++i) 190 fallbackTypeface = new Sdk7Typeface ("Sans Serif",
264 { 191 Typeface.create (Typeface.DEFAULT,
265 fontFile = new File (systemFontsDirectory, 192 Typeface.BOLD));
266 fontFamilyList[i]); 193 fallbackTypeface.weight = BOLD;
267 typeface = Typeface.createFromFile (fontFile); 194 typefaceList[2] = fallbackTypeface;
268 typefaceList[i] = new Sdk7Typeface (fontFile.getName (),
269 typeface);
270 }
271 195
272 /* Initialize the default monospace and serif typefaces. */ 196 fallbackTypeface = new Sdk7Typeface ("Sans Serif",
273 fallbackTypeface = new Sdk7Typeface ("monospace", 197 Typeface.create (Typeface.DEFAULT,
274 Typeface.MONOSPACE); 198 Typeface.ITALIC));
275 typefaceList[fontFamilyList.length] = fallbackTypeface; 199 fallbackTypeface.slant = ITALIC;
200 typefaceList[3] = fallbackTypeface;
201
202 fallbackTypeface
203 = new Sdk7Typeface ("Sans Serif",
204 Typeface.create (Typeface.DEFAULT,
205 Typeface.BOLD_ITALIC));
206 fallbackTypeface.weight = BOLD;
207 fallbackTypeface.slant = ITALIC;
208 typefaceList[4] = fallbackTypeface;
276 209
277 fallbackTypeface = new Sdk7Typeface ("Monospace", 210 fallbackTypeface = new Sdk7Typeface ("Monospace",
278 Typeface.MONOSPACE); 211 Typeface.MONOSPACE);
279 typefaceList[fontFamilyList.length + 1] = fallbackTypeface; 212 fallbackTypeface.spacing = MONO;
213 typefaceList[0] = fallbackTypeface;
280 214
281 fallbackTypeface = new Sdk7Typeface ("Sans Serif", 215 fontFamilyList = new String[] { "Monospace", "Sans Serif", };
282 Typeface.DEFAULT);
283 typefaceList[fontFamilyList.length + 2] = fallbackTypeface;
284 } 216 }
285 217
286 private boolean 218 private boolean
@@ -491,16 +423,12 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
491 { 423 {
492 Rect backgroundRect, bounds; 424 Rect backgroundRect, bounds;
493 Sdk7FontObject sdk7FontObject; 425 Sdk7FontObject sdk7FontObject;
494 char[] charsArray;
495 int i; 426 int i;
496 Canvas canvas; 427 Canvas canvas;
497 Paint paint; 428 Paint paint;
429 char[] array;
498 430
499 sdk7FontObject = (Sdk7FontObject) fontObject; 431 sdk7FontObject = (Sdk7FontObject) fontObject;
500 charsArray = new char[chars.length];
501
502 for (i = 0; i < chars.length; ++i)
503 charsArray[i] = (char) chars[i];
504 432
505 backgroundRect = new Rect (); 433 backgroundRect = new Rect ();
506 backgroundRect.top = y - sdk7FontObject.ascent; 434 backgroundRect.top = y - sdk7FontObject.ascent;
@@ -526,13 +454,33 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
526 paint.setTextSize (sdk7FontObject.pixelSize); 454 paint.setTextSize (sdk7FontObject.pixelSize);
527 paint.setTypeface (sdk7FontObject.typeface.typeface); 455 paint.setTypeface (sdk7FontObject.typeface.typeface);
528 paint.setAntiAlias (true); 456 paint.setAntiAlias (true);
529 canvas.drawText (charsArray, 0, chars.length, x, y, paint); 457
458 /* Android applies kerning to non-monospaced fonts by default,
459 which brings the dimensions of strings drawn via `drawText' out
460 of agreement with measurements previously provided to redisplay
461 by textExtents. To avert such disaster, draw each character
462 individually, advancing the origin point by hand. */
530 463
531 bounds = new Rect (); 464 bounds = new Rect ();
532 paint.getTextBounds (charsArray, 0, chars.length, bounds); 465 array = new char[1];
533 bounds.offset (x, y); 466
534 bounds.union (backgroundRect); 467 for (i = 0; i < chars.length; ++i)
535 drawable.damageRect (bounds); 468 {
469 /* Retrieve the text bounds for this character so as to
470 compute the damage rectangle. */
471 array[0] = (char) chars[i];
472 paint.getTextBounds (array, 0, 1, bounds);
473 bounds.offset (x, y);
474 backgroundRect.union (bounds);
475
476 /* Draw this character. */
477 canvas.drawText (array, 0, 1, x, y, paint);
478
479 /* Advance the origin point by that much. */
480 x += paint.measureText ("" + array[0]);
481 }
482
483 drawable.damageRect (backgroundRect);
536 paint.setAntiAlias (false); 484 paint.setAntiAlias (false);
537 return 1; 485 return 1;
538 } 486 }