aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PuzzleApplet.java2
-rw-r--r--devel.but61
-rw-r--r--drawing.c33
-rw-r--r--gtk.c18
-rw-r--r--nestedvm.c11
-rw-r--r--nullfe.c2
-rw-r--r--osx.m15
-rw-r--r--ps.c74
-rw-r--r--puzzles.h3
-rw-r--r--windows.c26
10 files changed, 227 insertions, 18 deletions
diff --git a/PuzzleApplet.java b/PuzzleApplet.java
index f401ecf..b796aa4 100644
--- a/PuzzleApplet.java
+++ b/PuzzleApplet.java
@@ -373,7 +373,7 @@ public class PuzzleApplet extends JApplet implements Runtime.CallJavaCB {
case 7: // string
gg.setColor(colors[arg2]);
{
- String text = runtime.cstring(arg3);
+ String text = runtime.utfstring(arg3);
Font ft = new Font((xarg3 & 0x10) != 0 ? "Monospaced" : "Dialog",
Font.PLAIN, 100);
int height100 = this.getFontMetrics(ft).getHeight();
diff --git a/devel.but b/devel.but
index 4783b06..c5a2c43 100644
--- a/devel.but
+++ b/devel.but
@@ -1848,6 +1848,54 @@ the back end function \cw{colours()} (\k{backend-colours}).
This function may be used for both drawing and printing.
+The character set used to encode the text passed to this function is
+specified \e{by the drawing object}, although it must be a superset
+of ASCII. If a puzzle wants to display text that is not contained in
+ASCII, it should use the \cw{text_fallback()} function
+(\k{drawing-text-fallback}) to query the drawing object for an
+appropriate representation of the characters it wants.
+
+\S{drawing-text-fallback} \cw{text_fallback()}
+
+\c char *text_fallback(drawing *dr, const char *const *strings,
+\c int nstrings);
+
+This function is used to request a translation of UTF-8 text into
+whatever character encoding is expected by the drawing object's
+implementation of \cw{draw_text()}.
+
+The input is a list of strings encoded in UTF-8: \cw{nstrings} gives
+the number of strings in the list, and \cw{strings[0]},
+\cw{strings[1]}, ..., \cw{strings[nstrings-1]} are the strings
+themselves.
+
+The returned string (which is dynamically allocated and must be
+freed when finished with) is derived from the first string in the
+list that the drawing object expects to be able to display reliably;
+it will consist of that string translated into the character set
+expected by \cw{draw_text()}.
+
+Drawing implementations are not required to handle anything outside
+ASCII, but are permitted to assume that \e{some} string will be
+successfully translated. So every call to this function must include
+a string somewhere in the list (presumably the last element) which
+consists of nothing but ASCII, to be used by any front end which
+cannot handle anything else.
+
+For example, if a puzzle wished to display a string including a
+multiplication sign (U+00D7 in Unicode, represented by the bytes C3
+97 in UTF-8), it might do something like this:
+
+\c static const char *const times_signs[] = { "\xC3\x97", "x" };
+\c char *times_sign = text_fallback(dr, times_signs, 2);
+\c sprintf(buffer, "%d%s%d", width, times_sign, height);
+\c draw_text(dr, x, y, font, size, align, colour, buffer);
+\c sfree(buffer);
+
+which would draw a string with a times sign in the middle on
+platforms that support it, and fall back to a simple ASCII \cq{x}
+where there was no alternative.
+
\S{drawing-clip} \cw{clip()}
\c void clip(drawing *dr, int x, int y, int w, int h);
@@ -2442,6 +2490,19 @@ Implementations of this API which do not provide printing services
may define this function pointer to be \cw{NULL}; it will never be
called unless printing is attempted.
+\S{drawingapi-text-fallback} \cw{text_fallback()}
+
+\c char *(*text_fallback)(void *handle, const char *const *strings,
+\c int nstrings);
+
+This function behaves exactly like the back end \cw{text_fallback()}
+function; see \k{drawing-text-fallback}.
+
+Implementations of this API which do not support any characters
+outside ASCII may define this function pointer to be \cw{NULL}, in
+which case the central code in \cw{drawing.c} will provide a default
+implementation.
+
\H{drawingapi-frontend} The drawing API as called by the front end
There are a small number of functions provided in \cw{drawing.c}
diff --git a/drawing.c b/drawing.c
index 26df1ff..4cbb46d 100644
--- a/drawing.c
+++ b/drawing.c
@@ -127,6 +127,39 @@ void end_draw(drawing *dr)
dr->api->end_draw(dr->handle);
}
+char *text_fallback(drawing *dr, const char *const *strings, int nstrings)
+{
+ int i;
+
+ /*
+ * If the drawing implementation provides one of these, use it.
+ */
+ if (dr && dr->api->text_fallback)
+ return dr->api->text_fallback(dr->handle, strings, nstrings);
+
+ /*
+ * Otherwise, do the simple thing and just pick the first string
+ * that fits in plain ASCII. It will then need no translation
+ * out of UTF-8.
+ */
+ for (i = 0; i < nstrings; i++) {
+ const char *p;
+
+ for (p = strings[i]; *p; p++)
+ if (*p & 0x80)
+ break;
+ if (!*p)
+ return dupstr(strings[i]);
+ }
+
+ /*
+ * The caller was responsible for making sure _some_ string in
+ * the list was in plain ASCII.
+ */
+ assert(!"Should never get here");
+ return NULL; /* placate optimiser */
+}
+
void status_bar(drawing *dr, char *text)
{
char *rewritten;
diff --git a/gtk.c b/gtk.c
index 9c19ab6..0fd351b 100644
--- a/gtk.c
+++ b/gtk.c
@@ -499,6 +499,17 @@ void gtk_end_draw(void *handle)
}
}
+#ifdef USE_PANGO
+char *gtk_text_fallback(void *handle, const char *const *strings, int nstrings)
+{
+ /*
+ * We assume Pango can cope with any UTF-8 likely to be emitted
+ * by a puzzle.
+ */
+ return dupstr(strings[0]);
+}
+#endif
+
const struct drawing_api gtk_drawing = {
gtk_draw_text,
gtk_draw_rect,
@@ -516,7 +527,12 @@ const struct drawing_api gtk_drawing = {
gtk_blitter_save,
gtk_blitter_load,
NULL, NULL, NULL, NULL, NULL, NULL, /* {begin,end}_{doc,page,puzzle} */
- NULL, /* line_width */
+ NULL, NULL, /* line_width, line_dotted */
+#ifdef USE_PANGO
+ gtk_text_fallback,
+#else
+ NULL,
+#endif
};
static void destroy(GtkWidget *widget, gpointer data)
diff --git a/nestedvm.c b/nestedvm.c
index 2bbf4e3..9381b6c 100644
--- a/nestedvm.c
+++ b/nestedvm.c
@@ -167,6 +167,16 @@ void nestedvm_end_draw(void *handle)
_call_java(4,2,0,0);
}
+char *nestedvm_text_fallback(void *handle, const char *const *strings,
+ int nstrings)
+{
+ /*
+ * We assume Java can cope with any UTF-8 likely to be emitted
+ * by a puzzle.
+ */
+ return dupstr(strings[0]);
+}
+
const struct drawing_api nestedvm_drawing = {
nestedvm_draw_text,
nestedvm_draw_rect,
@@ -185,6 +195,7 @@ const struct drawing_api nestedvm_drawing = {
nestedvm_blitter_load,
NULL, NULL, NULL, NULL, NULL, NULL, /* {begin,end}_{doc,page,puzzle} */
NULL, NULL, /* line_width, line_dotted */
+ nestedvm_text_fallback,
};
int jcallback_key_event(int x, int y, int keyval)
diff --git a/nullfe.c b/nullfe.c
index 325fd5a..f80a50c 100644
--- a/nullfe.c
+++ b/nullfe.c
@@ -17,6 +17,8 @@ void draw_polygon(drawing *dr, int *coords, int npoints,
int fillcolour, int outlinecolour) {}
void draw_circle(drawing *dr, int cx, int cy, int radius,
int fillcolour, int outlinecolour) {}
+char *text_fallback(drawing *dr, const char *const *strings, int nstrings)
+{ return dupstr(strings[0]); }
void clip(drawing *dr, int x, int y, int w, int h) {}
void unclip(drawing *dr) {}
void start_draw(drawing *dr) {}
diff --git a/osx.m b/osx.m
index c59ff56..4c3b132 100644
--- a/osx.m
+++ b/osx.m
@@ -1344,7 +1344,8 @@ static void osx_draw_text(void *handle, int x, int y, int fonttype,
int fontsize, int align, int colour, char *text)
{
frontend *fe = (frontend *)handle;
- NSString *string = [NSString stringWithCString:text];
+ NSString *string = [NSString stringWithCString:text
+ encoding:NSUTF8StringEncoding];
NSDictionary *attr;
NSFont *font;
NSSize size;
@@ -1378,6 +1379,15 @@ static void osx_draw_text(void *handle, int x, int y, int fonttype,
[string drawAtPoint:point withAttributes:attr];
}
+static char *osx_text_fallback(void *handle, const char *const *strings,
+ int nstrings)
+{
+ /*
+ * We assume OS X can cope with any UTF-8 likely to be emitted
+ * by a puzzle.
+ */
+ return dupstr(strings[0]);
+}
struct blitter {
int w, h;
int x, y;
@@ -1478,7 +1488,8 @@ const struct drawing_api osx_drawing = {
osx_blitter_save,
osx_blitter_load,
NULL, NULL, NULL, NULL, NULL, NULL, /* {begin,end}_{doc,page,puzzle} */
- NULL, /* line_width */
+ NULL, NULL, /* line_width, line_dotted */
+ osx_text_fallback,
};
void deactivate_timer(frontend *fe)
diff --git a/ps.c b/ps.c
index f6a71bb..2394cc5 100644
--- a/ps.c
+++ b/ps.c
@@ -109,7 +109,7 @@ static void ps_draw_text(void *handle, int x, int y, int fonttype,
y = ps->ytop - y;
ps_setcolour(ps, colour);
ps_printf(ps, "/%s findfont %d scalefont setfont\n",
- fonttype == FONT_FIXED ? "Courier" : "Helvetica",
+ fonttype == FONT_FIXED ? "Courier-L1" : "Helvetica-L1",
fontsize);
if (align & ALIGN_VCENTRE) {
ps_printf(ps, "newpath 0 0 moveto (X) true charpath flattenpath"
@@ -242,6 +242,49 @@ static void ps_line_dotted(void *handle, int dotted)
}
}
+static char *ps_text_fallback(void *handle, const char *const *strings,
+ int nstrings)
+{
+ /*
+ * We can handle anything in ISO 8859-1, and we'll manually
+ * translate it out of UTF-8 for the purpose.
+ */
+ int i, maxlen;
+ char *ret;
+
+ maxlen = 0;
+ for (i = 0; i < nstrings; i++) {
+ int len = strlen(strings[i]);
+ if (maxlen < len) maxlen = len;
+ }
+
+ ret = snewn(maxlen + 1, char);
+
+ for (i = 0; i < nstrings; i++) {
+ const char *p = strings[i];
+ char *q = ret;
+
+ while (*p) {
+ int c = (unsigned char)*p++;
+ if (c < 0x80) {
+ *q++ = c; /* ASCII */
+ } else if ((c == 0xC2 || c == 0xC3) && (*p & 0xC0) == 0x80) {
+ *q++ = (c << 6) | (*p++ & 0x3F); /* top half of 8859-1 */
+ } else {
+ break;
+ }
+ }
+
+ if (!*p) {
+ *q = '\0';
+ return ret;
+ }
+ }
+
+ assert(!"Should never reach here");
+ return NULL;
+}
+
static void ps_begin_doc(void *handle, int pages)
{
psdata *ps = (psdata *)handle;
@@ -259,6 +302,34 @@ static void ps_begin_doc(void *handle, int pages)
fputs("%%IncludeResource: font Helvetica\n", ps->fp);
fputs("%%IncludeResource: font Courier\n", ps->fp);
fputs("%%EndSetup\n", ps->fp);
+ fputs("%%BeginProlog\n", ps->fp);
+ /*
+ * Re-encode Helvetica and Courier into ISO-8859-1, which gives
+ * us times and divide signs - and also (according to the
+ * Language Reference Manual) a bonus in that the ASCII '-' code
+ * point now points to a minus sign instead of a hyphen.
+ */
+ fputs("/Helvetica findfont " /* get the font dictionary */
+ "dup maxlength dict dup begin " /* create and open a new dict */
+ "exch " /* move the original font to top of stack */
+ "{1 index /FID ne {def} {pop pop} ifelse} forall "
+ /* copy everything except FID */
+ "/Encoding ISOLatin1Encoding def "
+ /* set the thing we actually wanted to change */
+ "/FontName /Helvetica-L1 def " /* set a new font name */
+ "FontName end exch definefont" /* and define the font */
+ "\n", ps->fp);
+ fputs("/Courier findfont " /* get the font dictionary */
+ "dup maxlength dict dup begin " /* create and open a new dict */
+ "exch " /* move the original font to top of stack */
+ "{1 index /FID ne {def} {pop pop} ifelse} forall "
+ /* copy everything except FID */
+ "/Encoding ISOLatin1Encoding def "
+ /* set the thing we actually wanted to change */
+ "/FontName /Courier-L1 def " /* set a new font name */
+ "FontName end exch definefont" /* and define the font */
+ "\n", ps->fp);
+ fputs("%%EndProlog\n", ps->fp);
}
static void ps_begin_page(void *handle, int number)
@@ -333,6 +404,7 @@ static const struct drawing_api ps_drawing = {
ps_end_doc,
ps_line_width,
ps_line_dotted,
+ ps_text_fallback,
};
psdata *ps_init(FILE *outfile, int colour)
diff --git a/puzzles.h b/puzzles.h
index bb9bc6d..a97746c 100644
--- a/puzzles.h
+++ b/puzzles.h
@@ -189,6 +189,7 @@ void unclip(drawing *dr);
void start_draw(drawing *dr);
void draw_update(drawing *dr, int x, int y, int w, int h);
void end_draw(drawing *dr);
+char *text_fallback(drawing *dr, const char *const *strings, int nstrings);
void status_bar(drawing *dr, char *text);
blitter *blitter_new(drawing *dr, int w, int h);
void blitter_free(drawing *dr, blitter *bl);
@@ -516,6 +517,8 @@ struct drawing_api {
void (*end_doc)(void *handle);
void (*line_width)(void *handle, float width);
void (*line_dotted)(void *handle, int dotted);
+ char *(*text_fallback)(void *handle, const char *const *strings,
+ int nstrings);
};
/*
diff --git a/windows.c b/windows.c
index 7fe11f3..1fb14b9 100644
--- a/windows.c
+++ b/windows.c
@@ -601,10 +601,8 @@ static void win_draw_text(void *handle, int x, int y, int fonttype,
HFONT oldfont;
TEXTMETRIC tm;
SIZE size;
-#ifdef _WIN32_WCE
TCHAR wText[256];
- MultiByteToWideChar (CP_ACP, 0, text, -1, wText, 256);
-#endif
+ MultiByteToWideChar (CP_UTF8, 0, text, -1, wText, 256);
oldfont = SelectObject(fe->hdc, fe->fonts[i].font);
if (GetTextMetrics(fe->hdc, &tm)) {
@@ -613,11 +611,7 @@ static void win_draw_text(void *handle, int x, int y, int fonttype,
else
xy.y -= tm.tmAscent;
}
-#ifndef _WIN32_WCE
- if (GetTextExtentPoint32(fe->hdc, text, strlen(text), &size))
-#else
- if (GetTextExtentPoint32(fe->hdc, wText, wcslen(wText), &size))
-#endif
+ if (GetTextExtentPoint32W(fe->hdc, wText, wcslen(wText), &size))
{
if (align & ALIGN_HCENTRE)
xy.x -= size.cx / 2;
@@ -626,11 +620,7 @@ static void win_draw_text(void *handle, int x, int y, int fonttype,
}
SetBkMode(fe->hdc, TRANSPARENT);
win_text_colour(fe, colour);
-#ifndef _WIN32_WCE
- TextOut(fe->hdc, xy.x, xy.y, text, strlen(text));
-#else
- ExtTextOut(fe->hdc, xy.x, xy.y, 0, NULL, wText, wcslen(wText), NULL);
-#endif
+ ExtTextOutW(fe->hdc, xy.x, xy.y, 0, NULL, wText, wcslen(wText), NULL);
SelectObject(fe->hdc, oldfont);
}
}
@@ -956,6 +946,15 @@ static void win_end_doc(void *handle)
}
}
+char *win_text_fallback(void *handle, const char *const *strings, int nstrings)
+{
+ /*
+ * We assume Windows can cope with any UTF-8 likely to be
+ * emitted by a puzzle.
+ */
+ return dupstr(strings[0]);
+}
+
const struct drawing_api win_drawing = {
win_draw_text,
win_draw_rect,
@@ -980,6 +979,7 @@ const struct drawing_api win_drawing = {
win_end_doc,
win_line_width,
win_line_dotted,
+ win_text_fallback,
};
void print(frontend *fe)