--- /dev/null
+#
+# Makefile for TrueType Edit
+#
+# Author: James Hammons
+# Copyright: (c) 2006 Underground Software
+#
+
+ifeq "$(OSTYPE)" "msys" # Win32
+
+SYSTYPE = __GCCWIN32__
+EXESUFFIX = .exe
+ICON = obj/icon.o
+MSG = Win32 on MinGW
+
+else
+#ifeq "$(OSTYPE)" "darwin"
+ifeq "darwin" "$(findstring darwin,$(OSTYPE))" # Should catch both 'darwin' and 'darwin7.0'
+
+SYSTYPE = __GCCUNIX__ -D_OSX_
+EXESUFFIX =
+ICON =
+MSG = Mac OS X
+
+else # *nix
+
+SYSTYPE = __GCCUNIX__
+EXESUFFIX =
+ICON =
+MSG = generic Unix/Linux
+
+endif
+endif
+
+# This is ugly, ugly, ugly. Find a way to fix this crap so it's more unified,
+# like the SDL based makefiles are... !!! FIX !!! [made initial stab at it]
+
+### Variables: ###
+
+#EXEEXT = .exe
+RESCOMP = windres
+srcdir = ./src
+top_srcdir = /local
+top_builddir = /local/
+CXX = g++
+TOOLKIT = MSW
+TOOLKIT_LOWERCASE = msw
+WX_RELEASE = 2.6
+WX_VERSION = $(WX_RELEASE).0
+
+# This is OK
+
+# Note that the -MMD flag is what gives us our automagic dependency information (*.d files)
+# Add -g to compile in debuggin information
+CXXFLAGS = -MMD -Wall -Wno-switch -Wno-non-virtual-dtor -O2 `wx-config --cxxflags` -g
+INCS = -I.
+LIBS = `wx-config --libs`
+
+PROGRAM = ttedit
+
+# KO si sihT
+
+OBJECTS = \
+ obj/bezier.o \
+ obj/charnames.o \
+ obj/debug.o \
+ obj/glyphpoints.o \
+ obj/registry.o \
+ obj/ttf.o \
+ obj/vector.o \
+ obj/$(PROGRAM).o \
+ $(ICON)
+
+BIN_PROGRAM = $(PROGRAM)$(EXESUFFIX)
+#Need to fix this shit
+ifneq "" "$(ICON)"
+RES_PROGRAM_OBJ = obj/$(PROGRAM)_resources.o
+else
+RES_PROGRAM_OBJ =
+endif
+BUNDLE = $(BIN_PROGRAM).app/Contents
+
+### Conditionally set variables: ###
+
+COND_TOOLKIT_MAC___MACOSX_RESOURCES_p_1 = $(RESCOMP) -d __DARWIN__ -t APPL -d \
+ __WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) \
+ $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) -i $(srcdir) -d WXUSINGDLL -i \
+ $(srcdir)/../../samples -i $(top_srcdir)/include -o bombs$(EXEEXT) Carbon.r \
+ sample.r
+
+### Targets: ###
+
+all: checkenv message obj $(BIN_PROGRAM) $(__bombs_bundle___depname)
+ @echo
+ @echo "*** Looks like it compiled OK... Give it a whirl!"
+
+obj:
+ @mkdir obj
+
+#install: all
+
+# Check the compilation environment, barf if not appropriate
+
+checkenv:
+ @echo
+ @echo -n "*** Checking compilation environment... "
+ifeq "" "$(shell which wx-config)"
+ @echo
+ @echo
+ @echo "It seems that you don't have the wxWidget development libraries installed."
+ @echo "If you have installed them, make sure that the wx-config file is somewhere"
+ @echo "in your path and is executable."
+ @echo
+#Is there a better way to break out of the makefile?
+# @break
+ @breakola!
+else
+ @echo "OK"
+endif
+
+message:
+# @echo
+ @echo "*** Building TTEdit for $(MSG)..."
+ @echo
+
+clean:
+ @echo -n "*** Cleaning out the garbage..."
+ @rm -rf ./obj
+ @rm -f $(BIN_PROGRAM)
+# rm -rf bombs.app
+ @echo "done!"
+
+## This is only done for Win32 at the moment...
+#
+#ifneq "" "$(ICON)"
+#$(ICON): res/$(TARGET).rc res/$(TARGET).ico
+# @echo "*** Processing icon..."
+# @windres -i res/$(TARGET).rc -o $(ICON) --include-dir=./res
+#endif
+
+# This is only done for Win32 at the moment...
+
+ifneq "" "$(ICON)"
+$(RES_PROGRAM_OBJ): res/$(PROGRAM).rc res/$(PROGRAM).ico
+ @echo "*** Processing icon..."
+ @$(RESCOMP) -i$< -o$@ --define __WX$(TOOLKIT)__ --include-dir ./res --define WXUSINGDLL --include-dir $(top_srcdir)/include/wx-2.6
+endif
+
+obj/%.o: $(srcdir)/%.cpp
+ @echo "*** Compiling $<..."
+ @$(CXX) -c -o $@ $(INCS) $(CXXFLAGS) $<
+
+$(BIN_PROGRAM): $(OBJECTS) $(RES_PROGRAM_OBJ)
+ @echo "*** Linking it all together..."
+ @$(CXX) -o $@ $(OBJECTS) $(RES_PROGRAM_OBJ) $(LIBS)
+# $(_mac_rezcmd)
+# $(_mac_setfilecmd)
+
+# Mac OSX bundling shit (figure out how to condense this so it works!)
+
+bombs.app/Contents/PkgInfo: bombs$(EXEEXT) $(top_srcdir)/src/mac/carbon/Info.plist.in $(top_srcdir)/src/mac/carbon/wxmac.icns
+ mkdir -p bombs.app/Contents
+ mkdir -p bombs.app/Contents/MacOS
+ mkdir -p bombs.app/Contents/Resources
+
+ sed -e "s/IDENTIFIER/`echo $(srcdir) | sed -e 's,\.\./,,g' | sed -e 's,/,.,g'`/" \
+ -e "s/EXECUTABLE/bombs/" \
+ -e "s/VERSION/$(WX_VERSION)/" \
+ $(top_srcdir)/src/mac/carbon/Info.plist.in >bombs.app/Contents/Info.plist
+
+ echo -n "APPL????" >bombs.app/Contents/PkgInfo
+
+ ln -f bombs$(EXEEXT) bombs.app/Contents/MacOS/bombs
+
+ cp -f $(top_srcdir)/src/mac/carbon/wxmac.icns bombs.app/Contents/Resources/wxmac.icns
+
+#bundle: $(_BUNDLE_TGT_REF_DEP)
+
+### Include dependency info, if present:
+
+-include ./obj/*.d
+
+### No idea what this does
+
+#.PHONY: all install uninstall clean distclean bundle
--- /dev/null
+/* XPM */\r
+static char * cur1_xpm[] = {\r
+"32 32 2 1",\r
+" g #000000",\r
+". g #FFFFFF",\r
+" ...............................",\r
+" ..............................",\r
+" .............................",\r
+" ............................",\r
+" ...........................",\r
+" ..........................",\r
+" .........................",\r
+" ........................",\r
+" .......................",\r
+" ......................",\r
+" .....................",\r
+" ....................",\r
+" .........................",\r
+" .........................",\r
+" .. ........................",\r
+" ... ........................",\r
+" ..... .......................",\r
+"...... .......................",\r
+"....... ......................",\r
+"....... .......................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................"};\r
--- /dev/null
+/* XPM */\r
+static char * cur2_xpm[] = {\r
+"32 32 2 1",\r
+" g #000000",\r
+". g #FFFFFF",\r
+" ...............................",\r
+" ..............................",\r
+" .............................",\r
+" ............................",\r
+" ...........................",\r
+" ..........................",\r
+" .........................",\r
+" ........................",\r
+" .......................",\r
+" ......................",\r
+" .....................",\r
+" ....................",\r
+" .........................",\r
+" ...... .............",\r
+" .. ..... ............",\r
+" ... ..... ... ............",\r
+" ..... .... ... ............",\r
+"...... .... ... ............",\r
+"....... ... ............",\r
+"....... .... .............",\r
+"............. .................",\r
+"............. .................",\r
+"............. .................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................"};\r
--- /dev/null
+/* XPM */\r
+static char * cur3_xpm[] = {\r
+"32 32 2 1",\r
+" g #FFFFFF",\r
+". g #000000",\r
+" .. ",\r
+" .. ",\r
+" .... ",\r
+" .... ",\r
+" ...... ",\r
+" . .. . ",\r
+" . .. . ",\r
+" .. ",\r
+" .. .. .. ",\r
+" ... . . ... ",\r
+"......... .. ......... ",\r
+"......... .. ......... ",\r
+" ... . . ... ",\r
+" .. .. .. ",\r
+" .. ",\r
+" . .. . ",\r
+" . .. . ",\r
+" ...... ",\r
+" ..... ",\r
+" .... ",\r
+" .. ",\r
+" .. ",\r
+" ",\r
+" ",\r
+" ",\r
+" ",\r
+" ",\r
+" ",\r
+" ",\r
+" ",\r
+" ",\r
+" "};\r
--- /dev/null
+/* XPM */\r
+static char * cur4_xpm[] = {\r
+"32 32 2 1",\r
+" g #FFFFFF",\r
+". g #000000",\r
+" .. ",\r
+" .. ",\r
+"...... ",\r
+"...... ",\r
+" .. ",\r
+" .. ",\r
+" ... ",\r
+" .. .. .. ",\r
+" .. .. .. ",\r
+" .... . . . ",\r
+" .... . . . ",\r
+"...... . . . ",\r
+". .. . . . . ",\r
+" .. . . ",\r
+" .. . . ",\r
+" .. . . ",\r
+" .. .. .. ",\r
+" .. .. ... ",\r
+" .. ... . ",\r
+". .. . . ",\r
+"...... .. ",\r
+" .... ... ",\r
+" .... ... ",\r
+" .. ... ",\r
+" .. . ",\r
+" ",\r
+" ",\r
+"...... ",\r
+"...... ",\r
+" ",\r
+" ",\r
+" "};\r
--- /dev/null
+/* XPM */\r
+static char * cur5_xpm[] = {\r
+"32 32 2 1",\r
+" g #000000",\r
+". g #FFFFFF",\r
+" ...............................",\r
+" ..............................",\r
+" .............................",\r
+" ............................",\r
+" ...........................",\r
+" ..........................",\r
+" .........................",\r
+" ........................",\r
+" .......................",\r
+" ......................",\r
+" .....................",\r
+" ....................",\r
+" .........................",\r
+" .........................",\r
+" .. ........................",\r
+" ... ........................",\r
+" ..... .......................",\r
+"...... ..... ..............",\r
+"....... ... .............",\r
+"....... .... .. .............",\r
+"............. .. .............",\r
+"............. .............",\r
+".............. ..............",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................"};\r
--- /dev/null
+/* XPM */\r
+static char * cur6_xpm[] = {\r
+"32 32 2 1",\r
+" g #000000",\r
+". g #FFFFFF",\r
+" ...............................",\r
+" ..............................",\r
+" .............................",\r
+" ............................",\r
+" ...........................",\r
+" ..........................",\r
+" .........................",\r
+" ........................",\r
+" .......................",\r
+" ......................",\r
+" .....................",\r
+" ....................",\r
+" ........ ...............",\r
+" ....... ..............",\r
+" .. ...... ..............",\r
+" ... ..... .. .............",\r
+" ..... .... .. .............",\r
+"...... ... .... ............",\r
+"....... .. .... ............",\r
+"....... .. ...... ...........",\r
+"........... ...... ...........",\r
+".......... ........ ..........",\r
+".......... ..........",\r
+"........... ...........",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................"};\r
--- /dev/null
+/* XPM */\r
+static char * cur7_xpm[] = {\r
+"32 32 2 1",\r
+" g #000000",\r
+". g #FFFFFF",\r
+" ...............................",\r
+" ..............................",\r
+" .............................",\r
+" ............................",\r
+" ...........................",\r
+" ..........................",\r
+" .........................",\r
+" ........................",\r
+" .......................",\r
+" ......................",\r
+" .....................",\r
+" ....................",\r
+" .........................",\r
+" .........................",\r
+" .. ........................",\r
+" ... ... ...... ...........",\r
+" ..... .. .... ...........",\r
+"...... ... ............",\r
+"....... ... .............",\r
+"....... .... .............",\r
+"............. .............",\r
+"............. .............",\r
+"............ ............",\r
+"........... .... ...........",\r
+"........... ...... ...........",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................"};\r
--- /dev/null
+/* XPM */\r
+static char * cur8_xpm[] = {\r
+"32 32 2 1",\r
+" g #000000",\r
+". g #FFFFFF",\r
+" ...............................",\r
+" ..............................",\r
+" .............................",\r
+" ............................",\r
+" ...........................",\r
+" ..........................",\r
+" .........................",\r
+" ........................",\r
+" .......................",\r
+" ......................",\r
+" .....................",\r
+" ....................",\r
+" .........................",\r
+" .........................",\r
+" .. ........................",\r
+" ... ... ...... ...........",\r
+" ..... .. .... ...........",\r
+"...... ... ............",\r
+"....... ... .............",\r
+"....... .... .............",\r
+"............. .............",\r
+"............. .............",\r
+"............ ............",\r
+"........... .... ...........",\r
+"........... ...... ...........",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................",\r
+"................................"};\r
--- /dev/null
+/* XPM */\r
+static char * tool1_xpm[] = {\r
+"16 15 3 1",\r
+" c None",\r
+". c #A0A0A0",\r
+"+ c #000000",\r
+" ",\r
+" ",\r
+" ",\r
+" ",\r
+" ++ ",\r
+" ++ ",\r
+" ++++ ",\r
+" ++++++++++++++ ",\r
+" ++++ ",\r
+" ++ ",\r
+" ++ ",\r
+" ",\r
+" ",\r
+" ",\r
+" "};\r
--- /dev/null
+/* XPM */\r
+static char * tool2_xpm[] = {\r
+"16 15 3 1",\r
+" c None",\r
+". c #C0C0C0",\r
+"+ c #000000",\r
+" ",\r
+" ",\r
+" ",\r
+" ",\r
+" ++ ",\r
+" ++ ",\r
+" ++++ ",\r
+" ++++++++++++++ ",\r
+" ++++ ",\r
+" ++ ",\r
+" ++ ",\r
+" ",\r
+" ",\r
+" ",\r
+" "};\r
--- /dev/null
+/* XPM */\r
+static char * tool3_xpm[] = {\r
+"16 15 3 1",\r
+" c None",\r
+". c #C0C0C0",\r
+"+ c #000000",\r
+"++++++++++++++++",\r
+"+ +",\r
+"+ ++++++++ +",\r
+"+ ++++++++++ +",\r
+"+ ++ ++ +",\r
+"+ ++ +",\r
+"+ +++++++++ +",\r
+"+ ++++++++++ +",\r
+"+ ++ ++ +",\r
+"+ ++ ++ +",\r
+"+ ++ +++ +",\r
+"+ ++++++++++ +",\r
+"+ ++++++ ++ +",\r
+"+ +",\r
+"++++++++++++++++"};\r
+\r
--- /dev/null
+/* XPM */\r
+static char * toolpal1_xpm[] = {\r
+"96 48 2 1",\r
+" c #000000",\r
+". c #FFFFFF",\r
+" ",\r
+" .................. .................. .................. .................. ",\r
+" ",\r
+" . .................. . . .................. . . .................. . . .................. . ",\r
+" . .... ............. . . .................. . . ........ ........ . . .................. . ",\r
+" . .... ............ . . .................. . . ........ ........ . . ...... .......... . ",\r
+" . .... ........... . . .. ............... . . ....... ....... . . .... .. ........ . ",\r
+" . .... .......... . . .. .............. . . ....... ....... . . ... ...... ....... . ",\r
+" . .... ......... . . .. ............. . . ...... . . ...... . . ... ...... ....... . ",\r
+" . .... ........ . . .. ............ . . ..... .. .. ..... . . .. ........ ...... . ",\r
+" . .... ....... . . .. ... .. . . ... ... ... ... . . .. ........ ...... . ",\r
+" . .... ...... . . .. .. . . . . . . . ... ...... ....... . ",\r
+" . .... ..... . . .. . ... . . . . . . . ... ...... ....... . ",\r
+" . .... ........ . . .. ... ... . . . ... ... ... ... . . .... .. ...... . ",\r
+" . .... ........ . . .. ... . . . ..... .. .. ..... . . ...... .. ..... . ",\r
+" . .... .. ....... . . .. .. .. .. . . ...... . . ...... . . ........... .... . ",\r
+" . .... ... ....... . . ...... .. ...... . . ....... ....... . . ............ ... . ",\r
+" . ......... ...... . . .......... ...... . . ....... ....... . . ............. .. . ",\r
+" . ......... ...... . . .......... ...... . . ........ ........ . . .............. .. . ",\r
+" . .......... ....... . . .................. . . ........ ........ . . .................. . ",\r
+" . .................. . . .................. . . .................. . . .................. . ",\r
+" ",\r
+" .................. .................. .................. .................. ",\r
+" ",\r
+" ",\r
+" .................. .................. .................. .................. ",\r
+" ",\r
+" . .................. . . .................. . . .................. . . .................. . ",\r
+" . .................. . . .................. . . .................. . . .................. . ",\r
+" . .................. . . ........ ........ . . .. .......... .. . . .. ........... .. . ",\r
+" . .................. . . ....... ....... . . .. ........ .. . . ... . .. .. . ",\r
+" . .................. . . ....... ....... . . ... ...... ... . . .... ... . ",\r
+" . ....... ....... . . ...... .. ...... . . .... .... . . ..... ... .... . ",\r
+" . ...... ...... . . ...... .. ...... . . ..... ..... . . ...... ... ..... . ",\r
+" . ..... ..... . . ..... .... ..... . . ..... ..... . . ...... . ..... . ",\r
+" . ..... .. ..... . . ..... .... ..... . . ..... ..... . . ...... ..... . ",\r
+" . ..... .. ..... . . .... ...... .... . . ..... ..... . . ...... ..... . ",\r
+" . ..... ..... . . .... ...... .... . . ..... ..... . . ...... ...... . ",\r
+" . ...... ...... . . ... ........ ... . . ..... ..... . . ...... ... ..... . ",\r
+" . ....... ....... . . ... ........ ... . . .... .... . . ..... .... .... . ",\r
+" . .................. . . .. .......... .. . . ... ...... ... . . .... ..... ... . ",\r
+" . .................. . . .. .. . . .. ........ .. . . ... . ...... .. . ",\r
+" . .................. . . ... ... . . .. .......... .. . . .. ........... .. . ",\r
+" . .................. . . .................. . . .................. . . .................. . ",\r
+" . .................. . . .................. . . .................. . . .................. . ",\r
+" ",\r
+" .................. .................. .................. .................. ",\r
+" "};\r
--- /dev/null
+/* XPM */
+static char *ttedit_xpm[]={
+"32 32 11 1",
+". c None",
+"d c #0000ff",
+"a c #00ffff",
+"i c #600000",
+"# c #600040",
+"h c #606040",
+"b c #6060ff",
+"g c #a0a080",
+"c c #ff0000",
+"f c #ff6040",
+"e c #ffffff",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................",
+".##############.................",
+".##############.................",
+".##...####...##............aab..",
+".#....####....#..........aabbbb.",
+"......##cc.c.c.c.c.c.c.aabbbbbb.",
+"......##c#c.c...c.c..aabbbbbbdd.",
+"......###c...c.....aabbbbbbdd...",
+"......##c#......c.ebbbbbbdd.....",
+"......####...c...fgbbbbdd.......",
+"......####......fccgbdd.........",
+"......####...c.fccchd...........",
+"......####....ciiii.............",
+"......####...cc.................",
+"......####...cccc...............",
+".....######..cccc...............",
+".............cccc...............",
+".............cccc...............",
+".............cccc...............",
+"............cccccc..............",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................"};
--- /dev/null
+//\r
+// Bezier curve fitter\r
+// by James L. Hammons\r
+// (C) 2005 Underground Software\r
+//\r
+// This function takes three points and draws a curve using a\r
+// second order Bezier function.\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who When What\r
+// --- ---------- -------------------------------------------------------------\r
+// JLH 03/14/1998 Created this file\r
+// JLH 01/20/2005 Converted to use wxWidgets\r
+//\r
+\r
+#include "bezier.h"\r
+\r
+double abs(double n) // Helper function\r
+{\r
+ return (n < 0 ? -n : n);\r
+}\r
+\r
+void Bezier(wxDC &dc, point p1, point p2, point p3)\r
+{\r
+ double step = abs(p1.x - p3.x), tmp = abs(p1.y - p3.y);\r
+ step = (tmp > step ? tmp : step); // Get the larger of the two...\r
+ step = (step > 0 ? 1/step : 1); // & convert to valid step value\r
+\r
+// MoveToEx(hdc, (int)p1.x, (int)p1.y, NULL);\r
+ wxCoord prevX = (wxCoord)p1.x, prevY = (wxCoord)p1.y;\r
+\r
+ for(double u=0; u<=1; u+=step)\r
+ {\r
+ double _2u = 2*u, _uu = u*u, _2uu = 2*_uu,\r
+ x = (p1.x * (1 - _2u + _uu)) + (p2.x * (_2u - _2uu)) + (p3.x * _uu),\r
+ y = (p1.y * (1 - _2u + _uu)) + (p2.y * (_2u - _2uu)) + (p3.y * _uu);\r
+// LineTo(hdc, (int)x, (int)y);\r
+ dc.DrawLine(prevX, prevY, (wxCoord)x, (wxCoord)y);\r
+ prevX = (wxCoord)x, prevY = (wxCoord)y;\r
+ }\r
+\r
+// LineTo(hdc, (int)p3.x, (int)p3.y);\r
+ dc.DrawLine(prevX, prevY, (wxCoord)p3.x, (wxCoord)p3.y);\r
+}\r
--- /dev/null
+// True Type Hack\r
+//\r
+// Bezier Curve fitter header\r
+//\r
+// This function takes three points and draws a curve using a\r
+// second order Bezier function.\r
+\r
+#ifndef __BEZIER_H__\r
+#define __BEZIER_H__\r
+\r
+#include <wx/wx.h> // For device context\r
+\r
+struct point\r
+{\r
+ float x, y;\r
+\r
+ point(float xx = 0, float yy = 0): x(xx), y(yy) {}\r
+};\r
+\r
+void Bezier(wxDC &, point, point, point);\r
+\r
+#endif // __BEZIER_H__\r
--- /dev/null
+//\r
+// CHARNAMES.CPP\r
+//\r
+// A header file that links Unicode character names to character numbers.\r
+// by James L. Hammons\r
+// (C) 2004 Underground Software\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who When What\r
+// --- ---------- -------------------------------------------------------------\r
+// JLH ??/??/200? Created this file\r
+//\r
+\r
+unsigned char macStdNames[] = {\r
+ "\x06""notdef"\r
+ "\x05"".null"\r
+ "\x02""CR"\r
+ "\x05""space"\r
+ "\x06""exclam"\r
+ "\x08""quotedbl"\r
+ "\x0A""numbersign"\r
+ "\x06""dollar"\r
+ "\x07""percent"\r
+ "\x09""ampersand"\r
+ "\x0B""quotesingle"\r
+ "\x09""parenleft"\r
+ "\x0A""parenright"\r
+ "\x08""asterisk"\r
+ "\x04""plus"\r
+ "\x05""comma"\r
+ "\x06""hyphen"\r
+ "\x06""period"\r
+ "\x05""slash"\r
+ "\x04""zero"\r
+ "\x03""one"\r
+ "\x03""two"\r
+ "\x05""three"\r
+ "\x04""four"\r
+ "\x04""five"\r
+ "\x03""six"\r
+ "\x05""seven"\r
+ "\x05""eight"\r
+ "\x04""nine"\r
+ "\x05""colon"\r
+ "\x09""semicolon"\r
+ "\x04""less"\r
+ "\x05""equal"\r
+ "\x07""greater"\r
+ "\x08""question"\r
+ "\x02""at"\r
+ "\x01""A"\r
+ "\x01""B"\r
+ "\x01""C"\r
+ "\x01""D"\r
+ "\x01""E"\r
+ "\x01""F"\r
+ "\x01""G"\r
+ "\x01""H"\r
+ "\x01""I"\r
+ "\x01""J"\r
+ "\x01""K"\r
+ "\x01""L"\r
+ "\x01""M"\r
+ "\x01""N"\r
+ "\x01""O"\r
+ "\x01""P"\r
+ "\x01""Q"\r
+ "\x01""R"\r
+ "\x01""S"\r
+ "\x01""T"\r
+ "\x01""U"\r
+ "\x01""V"\r
+ "\x01""W"\r
+ "\x01""X"\r
+ "\x01""Y"\r
+ "\x01""Z"\r
+ "\x0B""bracketleft"\r
+ "\x09""backslash"\r
+ "\x0C""bracketright"\r
+ "\x0B""asciicircum"\r
+ "\x0A""underscore"\r
+ "\x05""grave"\r
+ "\x01""a"\r
+ "\x01""b"\r
+ "\x01""c"\r
+ "\x01""d"\r
+ "\x01""e"\r
+ "\x01""f"\r
+ "\x01""g"\r
+ "\x01""h"\r
+ "\x01""i"\r
+ "\x01""j"\r
+ "\x01""k"\r
+ "\x01""l"\r
+ "\x01""m"\r
+ "\x01""n"\r
+ "\x01""o"\r
+ "\x01""p"\r
+ "\x01""q"\r
+ "\x01""r"\r
+ "\x01""s"\r
+ "\x01""t"\r
+ "\x01""u"\r
+ "\x01""v"\r
+ "\x01""w"\r
+ "\x01""x"\r
+ "\x01""y"\r
+ "\x01""z"\r
+ "\x09""braceleft"\r
+ "\x03""bar"\r
+ "\x0A""braceright"\r
+ "\x0A""asciitilde"\r
+ "\x09""Adieresis"\r
+ "\x05""Aring"\r
+ "\x08""Ccedilla"\r
+ "\x06""Eacute"\r
+ "\x06""Ntilde"\r
+ "\x09""Odieresis"\r
+ "\x09""Udieresis"\r
+ "\x06""aacute"\r
+ "\x06""agrave"\r
+ "\x0B""acircumflex"\r
+ "\x09""adieresis"\r
+ "\x06""atilde"\r
+ "\x05""aring"\r
+ "\x08""ccedilla"\r
+ "\x06""eacute"\r
+ "\x06""egrave"\r
+ "\x0B""ecircumflex"\r
+ "\x09""edieresis"\r
+ "\x06""iacute"\r
+ "\x06""igrave"\r
+ "\x0B""icircumflex"\r
+ "\x09""idieresis"\r
+ "\x06""ntilde"\r
+ "\x06""oacute"\r
+ "\x06""ograve"\r
+ "\x0B""ocircumflex"\r
+ "\x09""odieresis"\r
+ "\x06""otilde"\r
+ "\x06""uacute"\r
+ "\x06""ugrave"\r
+ "\x0B""ucircumflex"\r
+ "\x09""udieresis"\r
+ "\x06""dagger"\r
+ "\x06""degree"\r
+ "\x04""cent"\r
+ "\x08""sterling"\r
+ "\x07""section"\r
+ "\x06""bullet"\r
+ "\x09""paragraph"\r
+ "\x0A""germandbls"\r
+ "\x0A""registered"\r
+ "\x09""copyright"\r
+ "\x09""trademark"\r
+ "\x05""acute"\r
+ "\x08""dieresis"\r
+ "\x08""notequal"\r
+ "\x02""AE"\r
+ "\x06""Oslash"\r
+ "\x08""infinity"\r
+ "\x09""plusminus"\r
+ "\x09""lessequal"\r
+ "\x0C""greaterequal"\r
+ "\x03""yen"\r
+ "\x03""mu1"\r
+ "\x0B""partialdiff"\r
+ "\x09""summation"\r
+ "\x07""product"\r
+ "\x02""pi"\r
+ "\x08""integral"\r
+ "\x0B""ordfeminine"\r
+ "\x0C""ordmasculine"\r
+ "\x03""Ohm"\r
+ "\x02""ae"\r
+ "\x06""oslash"\r
+ "\x0C""questiondown"\r
+ "\x0A""exclamdown"\r
+ "\x0A""logicalnot"\r
+ "\x07""radical"\r
+ "\x06""florin"\r
+ "\x0B""approxequal"\r
+ "\x09""increment"\r
+ "\x0D""guillemotleft"\r
+ "\x0E""guillemotright"\r
+ "\x08""ellipsis"\r
+ "\x07""nbspace"\r
+ "\x06""Agrave"\r
+ "\x06""Atilde"\r
+ "\x06""Otilde"\r
+ "\x02""OE"\r
+ "\x02""oe"\r
+ "\x06""endash"\r
+ "\x06""emdash"\r
+ "\x0C""quotedblleft"\r
+ "\x0D""quotedblright"\r
+ "\x09""quoteleft"\r
+ "\x0A""quoteright"\r
+ "\x06""divide"\r
+ "\x07""lozenge"\r
+ "\x09""ydieresis"\r
+ "\x09""Ydieresis"\r
+ "\x08""fraction"\r
+ "\x08""currency"\r
+ "\x0D""guilsinglleft"\r
+ "\x0E""guilsinglright"\r
+ "\x02""fi"\r
+ "\x02""fl"\r
+ "\x09""daggerdbl"\r
+ "\x0E""periodcentered"\r
+ "\x0E""quotesinglbase"\r
+ "\x0C""quotedblbase"\r
+ "\x0B""perthousand"\r
+ "\x0B""Acircumflex"\r
+ "\x0B""Ecircumflex"\r
+ "\x06""Aacute"\r
+ "\x09""Edieresis"\r
+ "\x06""Egrave"\r
+ "\x06""Iacute"\r
+ "\x0B""Icircumflex"\r
+ "\x09""Idieresis"\r
+ "\x06""Igrave"\r
+ "\x06""Oacute"\r
+ "\x0B""Ocircumflex"\r
+ "\x09""applelogo"\r
+ "\x06""Ograve"\r
+ "\x06""Uacute"\r
+ "\x0B""Ucircumflex"\r
+ "\x06""Ugrave"\r
+ "\x08""dotlessi"\r
+ "\x0A""circumflex"\r
+ "\x05""tilde"\r
+ "\x09""overscore"\r
+ "\x05""breve"\r
+ "\x09""dotaccent"\r
+ "\x04""ring"\r
+ "\x07""cedilla"\r
+ "\x0C""hungarumlaut"\r
+ "\x06""ogonek"\r
+ "\x05""caron"\r
+ "\x06""Lslash"\r
+ "\x06""lslash"\r
+ "\x06""Scaron"\r
+ "\x06""scaron"\r
+ "\x06""Zcaron"\r
+ "\x06""zcaron"\r
+ "\x09""brokenbar"\r
+ "\x03""Eth"\r
+ "\x03""eth"\r
+ "\x06""Yacute"\r
+ "\x06""yacute"\r
+ "\x05""Thorn"\r
+ "\x05""thorn"\r
+ "\x05""minus"\r
+ "\x08""multiply"\r
+ "\x0B""onesuperior"\r
+ "\x0B""twosuperior"\r
+ "\x0D""threesuperior"\r
+ "\x07""onehalf"\r
+ "\x0A""onequarter"\r
+ "\x0D""threequarters"\r
+ "\x05""franc"\r
+ "\x06""Gbreve"\r
+ "\x06""gbreve"\r
+ "\x04""Idot"\r
+ "\x08""Scedilla"\r
+ "\x08""scedilla"\r
+ "\x06""Cacute"\r
+ "\x06""cacute"\r
+ "\x06""Ccaron"\r
+ "\x06""ccaron"\r
+ "\x07""dmacron"\r
+};\r
+\r
+/*struct unicodeChar\r
+{\r
+ int cNum;\r
+\r
+};*/\r
+\r
+unsigned char unicodeChars[] = {\r
+ "\x00\x20""space\0"\r
+ "\x00\x21""exclamation mark\0"\r
+ "\x00\x22""quotation mark\0"\r
+ "\x00\x23""number sign\0"\r
+\r
+};\r
+\r
+/*\r
+\r
+0023 NUMBER SIGN\r
+ = pound sign, hash, crosshatch, octothorpe\r
+0024 DOLLAR SIGN\r
+ = milreis, escudo\r
+ * glyph may have one or two vertical bars\r
+ * other currency symbol characters: 20A0-20AF\r
+ x (currency sign - 00A4)\r
+0025 PERCENT SIGN\r
+ x (arabic percent sign - 066A)\r
+ x (per mille sign - 2030)\r
+ x (per ten thousand sign - 2031)\r
+0026 AMPERSAND\r
+0027 APOSTROPHE\r
+ = APOSTROPHE-QUOTE\r
+ = APL quote\r
+ * neutral (vertical) glyph having mixed usage\r
+ * preferred character for apostrophe is 2019\r
+ * preferred characters in English for paired quotation marks are 2018 & 2019\r
+ x (modifier letter prime - 02B9)\r
+ x (modifier letter apostrophe - 02BC)\r
+ x (modifier letter vertical line - 02C8)\r
+ x (combining acute accent - 0301)\r
+ x (prime - 2032)\r
+0028 LEFT PARENTHESIS\r
+ = OPENING PARENTHESIS\r
+0029 RIGHT PARENTHESIS\r
+ = CLOSING PARENTHESIS\r
+ * see discussion on semantics of paired bracketing characters\r
+002A ASTERISK\r
+ = star (on phone keypads)\r
+ x (arabic five pointed star - 066D)\r
+ x (asterisk operator - 2217)\r
+ x (heavy asterisk - 2731)\r
+002B PLUS SIGN\r
+002C COMMA\r
+ = decimal separator\r
+ x (arabic comma - 060C)\r
+ x (single low-9 quotation mark - 201A)\r
+ x (ideographic comma - 3001)\r
+002D HYPHEN-MINUS\r
+ = hyphen or minus sign\r
+ * used for either hyphen or minus sign\r
+ x (hyphen - 2010)\r
+ x (non-breaking hyphen - 2011)\r
+ x (figure dash - 2012)\r
+ x (en dash - 2013)\r
+ x (minus sign - 2212)\r
+002E FULL STOP\r
+ = PERIOD\r
+ = dot, decimal point\r
+ * may be rendered as a raised decimal point in old style numbers\r
+ x (arabic full stop - 06D4)\r
+ x (ideographic full stop - 3002)\r
+002F SOLIDUS\r
+ = SLASH\r
+ = virgule, shilling (British)\r
+ x (latin letter dental click - 01C0)\r
+ x (combining long solidus overlay - 0338)\r
+ x (fraction slash - 2044)\r
+ x (division slash - 2215)\r
+0030 DIGIT ZERO\r
+0031 DIGIT ONE\r
+0032 DIGIT TWO\r
+0033 DIGIT THREE\r
+0034 DIGIT FOUR\r
+0035 DIGIT FIVE\r
+0036 DIGIT SIX\r
+0037 DIGIT SEVEN\r
+0038 DIGIT EIGHT\r
+0039 DIGIT NINE\r
+003A COLON\r
+ x (armenian full stop - 0589)\r
+ x (hebrew punctuation sof pasuq - 05C3)\r
+ x (ratio - 2236)\r
+003B SEMICOLON\r
+ x (greek question mark - 037E)\r
+ x (arabic semicolon - 061B)\r
+003C LESS-THAN SIGN\r
+ x (single left-pointing angle quotation mark - 2039)\r
+ x (left-pointing angle bracket - 2329)\r
+ x (left angle bracket - 3008)\r
+003D EQUALS SIGN\r
+ * other related characters: 2241-2263\r
+ x (not equal to - 2260)\r
+ x (identical to - 2261)\r
+003E GREATER-THAN SIGN\r
+ x (single right-pointing angle quotation mark - 203A)\r
+ x (right-pointing angle bracket - 232A)\r
+ x (right angle bracket - 3009)\r
+003F QUESTION MARK\r
+ x (inverted question mark - 00BF)\r
+ x (greek question mark - 037E)\r
+ x (arabic question mark - 061F)\r
+ x (interrobang - 203D)\r
+ x (question exclamation mark - 2048)\r
+ x (exclamation question mark - 2049)\r
+0040 COMMERCIAL AT\r
+0041 LATIN CAPITAL LETTER A\r
+0042 LATIN CAPITAL LETTER B\r
+ x (script capital b - 212C)\r
+0043 LATIN CAPITAL LETTER C\r
+ x (double-struck capital c - 2102)\r
+ x (black-letter capital c - 212D)\r
+0044 LATIN CAPITAL LETTER D\r
+0045 LATIN CAPITAL LETTER E\r
+ x (euler constant - 2107)\r
+ x (script capital e - 2130)\r
+0046 LATIN CAPITAL LETTER F\r
+ x (script capital f - 2131)\r
+ x (turned capital f - 2132)\r
+0047 LATIN CAPITAL LETTER G\r
+0048 LATIN CAPITAL LETTER H\r
+ x (script capital h - 210B)\r
+ x (black-letter capital h - 210C)\r
+ x (double-struck capital h - 210D)\r
+0049 LATIN CAPITAL LETTER I\r
+ * Turkish and Azerbaijani use 0131 for lowercase\r
+ x (latin capital letter i with dot above - 0130)\r
+ x (cyrillic capital letter byelorussian-ukrainian i - 0406)\r
+ x (cyrillic letter palochka - 04C0)\r
+ x (script capital i - 2110)\r
+ x (black-letter capital i - 2111)\r
+ x (roman numeral one - 2160)\r
+004A LATIN CAPITAL LETTER J\r
+004B LATIN CAPITAL LETTER K\r
+ x (kelvin sign - 212A)\r
+004C LATIN CAPITAL LETTER L\r
+ x (script capital l - 2112)\r
+004D LATIN CAPITAL LETTER M\r
+ x (script capital m - 2133)\r
+004E LATIN CAPITAL LETTER N\r
+ x (double-struck capital n - 2115)\r
+004F LATIN CAPITAL LETTER O\r
+0050 LATIN CAPITAL LETTER P\r
+ x (double-struck capital p - 2119)\r
+0051 LATIN CAPITAL LETTER Q\r
+ x (double-struck capital q - 211A)\r
+0052 LATIN CAPITAL LETTER R\r
+ x (script capital r - 211B)\r
+ x (black-letter capital r - 211C)\r
+ x (double-struck capital r - 211D)\r
+0053 LATIN CAPITAL LETTER S\r
+0054 LATIN CAPITAL LETTER T\r
+0055 LATIN CAPITAL LETTER U\r
+0056 LATIN CAPITAL LETTER V\r
+0057 LATIN CAPITAL LETTER W\r
+0058 LATIN CAPITAL LETTER X\r
+0059 LATIN CAPITAL LETTER Y\r
+005A LATIN CAPITAL LETTER Z\r
+ x (double-struck capital z - 2124)\r
+ x (black-letter capital z - 2128)\r
+005B LEFT SQUARE BRACKET\r
+ = OPENING SQUARE BRACKET\r
+ * other bracket characters: 3008-301B\r
+005C REVERSE SOLIDUS\r
+ = BACKSLASH\r
+ x (set minus - 2216)\r
+005D RIGHT SQUARE BRACKET\r
+ = CLOSING SQUARE BRACKET\r
+005E CIRCUMFLEX ACCENT\r
+ * this is a spacing character\r
+ x (modifier letter up arrowhead - 02C4)\r
+ x (modifier letter circumflex accent - 02C6)\r
+ x (combining circumflex accent - 0302)\r
+ x (up arrowhead - 2303)\r
+005F LOW LINE\r
+ = SPACING UNDERSCORE\r
+ * this is a spacing character\r
+ x (modifier letter low macron - 02CD)\r
+ x (combining macron below - 0331)\r
+ x (combining low line - 0332)\r
+ x (double low line - 2017)\r
+0060 GRAVE ACCENT\r
+ * this is a spacing character\r
+ x (modifier letter grave accent - 02CB)\r
+ x (combining grave accent - 0300)\r
+ x (reversed prime - 2035)\r
+0061 LATIN SMALL LETTER A\r
+0062 LATIN SMALL LETTER B\r
+0063 LATIN SMALL LETTER C\r
+0064 LATIN SMALL LETTER D\r
+0065 LATIN SMALL LETTER E\r
+ x (estimated symbol - 212E)\r
+ x (script small e - 212F)\r
+0066 LATIN SMALL LETTER F\r
+0067 LATIN SMALL LETTER G\r
+ x (latin small letter script g - 0261)\r
+ x (script small g - 210A)\r
+0068 LATIN SMALL LETTER H\r
+ x (cyrillic small letter shha - 04BB)\r
+ x (planck constant - 210E)\r
+0069 LATIN SMALL LETTER I\r
+ * Turkish and Azerbaijani use 0130 for uppercase\r
+ x (latin small letter dotless i - 0131)\r
+006A LATIN SMALL LETTER J\r
+006B LATIN SMALL LETTER K\r
+006C LATIN SMALL LETTER L\r
+ x (script small l - 2113)\r
+006D LATIN SMALL LETTER M\r
+006E LATIN SMALL LETTER N\r
+ x (superscript latin small letter n - 207F)\r
+006F LATIN SMALL LETTER O\r
+ x (script small o - 2134)\r
+0070 LATIN SMALL LETTER P\r
+0071 LATIN SMALL LETTER Q\r
+0072 LATIN SMALL LETTER R\r
+0073 LATIN SMALL LETTER S\r
+0074 LATIN SMALL LETTER T\r
+0075 LATIN SMALL LETTER U\r
+0076 LATIN SMALL LETTER V\r
+0077 LATIN SMALL LETTER W\r
+0078 LATIN SMALL LETTER X\r
+0079 LATIN SMALL LETTER Y\r
+007A LATIN SMALL LETTER Z\r
+ x (latin small letter z with stroke - 01B6)\r
+007B LEFT CURLY BRACKET\r
+ = OPENING CURLY BRACKET\r
+ = opening brace\r
+007C VERTICAL LINE\r
+ = VERTICAL BAR\r
+ * used in pairs to indicate absolute value\r
+ x (latin letter dental click - 01C0)\r
+ x (hebrew punctuation paseq - 05C0)\r
+ x (divides - 2223)\r
+ x (light vertical bar - 2758)\r
+007D RIGHT CURLY BRACKET\r
+ = CLOSING CURLY BRACKET\r
+ = closing brace\r
+007E TILDE\r
+ * this is a spacing character\r
+ x (small tilde - 02DC)\r
+ x (combining tilde - 0303)\r
+ x (tilde operator - 223C)\r
+ x (fullwidth tilde - FF5E)\r
+007F <control>\r
+ = DELETE\r
+@@ 0080 C1 Controls and Latin-1 Supplement (Latin-1 Supplement) 00FF\r
+@ C1 controls\r
+@+ Alias names are those for ISO 6429.\r
+0080 <control>\r
+0081 <control>\r
+0082 <control>\r
+ = BREAK PERMITTED HERE\r
+0083 <control>\r
+ = NO BREAK HERE\r
+0084 <control>\r
+0085 <control>\r
+ = NEXT LINE\r
+0086 <control>\r
+ = START OF SELECTED AREA\r
+0087 <control>\r
+ = END OF SELECTED AREA\r
+0088 <control>\r
+ = CHARACTER TABULATION SET\r
+0089 <control>\r
+ = CHARACTER TABULATION WITH JUSTIFICATION\r
+008A <control>\r
+ = LINE TABULATION SET\r
+008B <control>\r
+ = PARTIAL LINE DOWN\r
+008C <control>\r
+ = PARTIAL LINE UP\r
+008D <control>\r
+ = REVERSE LINE FEED\r
+008E <control>\r
+ = SINGLE SHIFT TWO\r
+008F <control>\r
+ = SINGLE SHIFT THREE\r
+0090 <control>\r
+ = DEVICE CONTROL STRING\r
+0091 <control>\r
+ = PRIVATE USE ONE\r
+0092 <control>\r
+ = PRIVATE USE TWO\r
+0093 <control>\r
+ = SET TRANSMIT STATE\r
+0094 <control>\r
+ = CANCEL CHARACTER\r
+0095 <control>\r
+ = MESSAGE WAITING\r
+0096 <control>\r
+ = START OF GUARDED AREA\r
+0097 <control>\r
+ = END OF GUARDED AREA\r
+0098 <control>\r
+ = START OF STRING\r
+0099 <control>\r
+009A <control>\r
+ = SINGLE CHARACTER INTRODUCER\r
+009B <control>\r
+ = CONTROL SEQUENCE INTRODUCER\r
+009C <control>\r
+ = STRING TERMINATOR\r
+009D <control>\r
+ = OPERATING SYSTEM COMMAND\r
+009E <control>\r
+ = PRIVACY MESSAGE\r
+009F <control>\r
+ = APPLICATION PROGRAM COMMAND\r
+@ ISO 8859-1 (aka Latin-1)\r
+00A0 NO-BREAK SPACE\r
+ x (space - 0020)\r
+ x (figure space - 2007)\r
+ x (narrow no-break space - 202F)\r
+ x (zero width no-break space - FEFF)\r
+ # <noBreak> 0020\r
+00A1 INVERTED EXCLAMATION MARK\r
+ * Spanish, Asturian, Galician\r
+ x (exclamation mark - 0021)\r
+00A2 CENT SIGN\r
+00A3 POUND SIGN\r
+ = pound sterling, Irish punt\r
+ x (lira sign - 20A4)\r
+00A4 CURRENCY SIGN\r
+ = Filzlaus, Ricardi-Sonne (German names)\r
+ * other currency symbol characters: 20A0-20AF\r
+ x (dollar sign - 0024)\r
+00A5 YEN SIGN\r
+ = yuan sign\r
+ * glyph may have one or two crossbars\r
+00A6 BROKEN BAR\r
+ = BROKEN VERTICAL BAR\r
+ = parted rule (in typography)\r
+00A7 SECTION SIGN\r
+ * paragraph sign in some European usage\r
+00A8 DIAERESIS\r
+ * this is a spacing character\r
+ x (combining diaeresis - 0308)\r
+ # 0020 0308\r
+00A9 COPYRIGHT SIGN\r
+ x (sound recording copyright - 2117)\r
+00AA FEMININE ORDINAL INDICATOR\r
+ * Spanish\r
+ # <super> 0061\r
+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK *\r
+ = LEFT POINTING GUILLEMET\r
+ = chevrons (in typography)\r
+ * usually opening, sometimes closing\r
+ x (much less-than - 226A)\r
+ x (left double angle bracket - 300A)\r
+00AC NOT SIGN\r
+ = angled dash (in typography)\r
+ x (reversed not sign - 2310)\r
+00AD SOFT HYPHEN\r
+ = discretionary hyphen\r
+ x (mongolian todo soft hyphen - 1806)\r
+00AE REGISTERED SIGN\r
+ = REGISTERED TRADE MARK SIGN\r
+00AF MACRON\r
+ = overline, APL overbar\r
+ * this is a spacing character\r
+ x (modifier letter macron - 02C9)\r
+ x (combining macron - 0304)\r
+ x (combining overline - 0305)\r
+ # 0020 0304\r
+00B0 DEGREE SIGN\r
+ * this is a spacing character\r
+ x (ring above - 02DA)\r
+ x (combining ring above - 030A)\r
+ x (superscript zero - 2070)\r
+ x (ring operator - 2218)\r
+00B1 PLUS-MINUS SIGN\r
+ x (minus-or-plus sign - 2213)\r
+00B2 SUPERSCRIPT TWO\r
+ = squared\r
+ * other superscript digit characters: 2070-2079\r
+ x (superscript one - 00B9)\r
+ # <super> 0032\r
+00B3 SUPERSCRIPT THREE\r
+ = cubed\r
+ x (superscript one - 00B9)\r
+ # <super> 0033\r
+00B4 ACUTE ACCENT\r
+ * this is a spacing character\r
+ x (modifier letter prime - 02B9)\r
+ x (modifier letter acute accent - 02CA)\r
+ x (combining acute accent - 0301)\r
+ x (prime - 2032)\r
+ # 0020 0301\r
+00B5 MICRO SIGN\r
+ # 03BC greek small letter mu\r
+00B6 PILCROW SIGN\r
+ = PARAGRAPH SIGN\r
+ * section sign in some European usage\r
+ x (reversed pilcrow sign - 204B)\r
+ x (curved stem paragraph sign ornament - 2761)\r
+00B7 MIDDLE DOT\r
+ = midpoint (in typography)\r
+ = Georgian comma\r
+ = Greek middle dot\r
+ x (bullet - 2022)\r
+ x (one dot leader - 2024)\r
+ x (hyphenation point - 2027)\r
+ x (bullet operator - 2219)\r
+ x (dot operator - 22C5)\r
+ x (katakana middle dot - 30FB)\r
+00B8 CEDILLA\r
+ * this is a spacing character\r
+ * other spacing accent characters: 02D8-02DB\r
+ x (combining cedilla - 0327)\r
+ # 0020 0327\r
+00B9 SUPERSCRIPT ONE\r
+ x (superscript two - 00B2)\r
+ x (superscript three - 00B3)\r
+ # <super> 0031\r
+00BA MASCULINE ORDINAL INDICATOR\r
+ * Spanish\r
+ # <super> 006F\r
+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK *\r
+ = RIGHT POINTING GUILLEMET\r
+ * usually closing, sometimes opening\r
+ x (much greater-than - 226B)\r
+ x (right double angle bracket - 300B)\r
+00BC VULGAR FRACTION ONE QUARTER\r
+ * bar may be horizontal or slanted\r
+ * other fraction characters: 2153-215E\r
+ # 0031 2044 0034\r
+00BD VULGAR FRACTION ONE HALF\r
+ * bar may be horizontal or slanted\r
+ # 0031 2044 0032\r
+00BE VULGAR FRACTION THREE QUARTERS\r
+ * bar may be horizontal or slanted\r
+ # 0033 2044 0034\r
+00BF INVERTED QUESTION MARK\r
+ = turned question mark\r
+ * Spanish\r
+ x (question mark - 003F)\r
+00C0 LATIN CAPITAL LETTER A WITH GRAVE\r
+ : 0041 0300\r
+00C1 LATIN CAPITAL LETTER A WITH ACUTE\r
+ : 0041 0301\r
+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX\r
+ : 0041 0302\r
+00C3 LATIN CAPITAL LETTER A WITH TILDE\r
+ : 0041 0303\r
+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS\r
+ : 0041 0308\r
+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE\r
+ x (angstrom sign - 212B)\r
+ : 0041 030A\r
+00C6 LATIN CAPITAL LETTER AE (ash) *\r
+ = LATIN CAPITAL LIGATURE AE\r
+00C7 LATIN CAPITAL LETTER C WITH CEDILLA\r
+ : 0043 0327\r
+00C8 LATIN CAPITAL LETTER E WITH GRAVE\r
+ : 0045 0300\r
+00C9 LATIN CAPITAL LETTER E WITH ACUTE\r
+ : 0045 0301\r
+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX\r
+ : 0045 0302\r
+00CB LATIN CAPITAL LETTER E WITH DIAERESIS\r
+ : 0045 0308\r
+00CC LATIN CAPITAL LETTER I WITH GRAVE\r
+ : 0049 0300\r
+00CD LATIN CAPITAL LETTER I WITH ACUTE\r
+ : 0049 0301\r
+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX\r
+ : 0049 0302\r
+00CF LATIN CAPITAL LETTER I WITH DIAERESIS\r
+ : 0049 0308\r
+00D0 LATIN CAPITAL LETTER ETH (Icelandic)\r
+ x (latin small letter eth - 00F0)\r
+ x (latin capital letter d with stroke - 0110)\r
+ x (latin capital letter african d - 0189)\r
+00D1 LATIN CAPITAL LETTER N WITH TILDE\r
+ : 004E 0303\r
+00D2 LATIN CAPITAL LETTER O WITH GRAVE\r
+ : 004F 0300\r
+00D3 LATIN CAPITAL LETTER O WITH ACUTE\r
+ : 004F 0301\r
+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX\r
+ : 004F 0302\r
+00D5 LATIN CAPITAL LETTER O WITH TILDE\r
+ : 004F 0303\r
+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS\r
+ : 004F 0308\r
+00D7 MULTIPLICATION SIGN\r
+ = z notation Cartesian product\r
+00D8 LATIN CAPITAL LETTER O WITH STROKE\r
+ = LATIN CAPITAL LETTER O SLASH\r
+ x (empty set - 2205)\r
+00D9 LATIN CAPITAL LETTER U WITH GRAVE\r
+ : 0055 0300\r
+00DA LATIN CAPITAL LETTER U WITH ACUTE\r
+ : 0055 0301\r
+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX\r
+ : 0055 0302\r
+00DC LATIN CAPITAL LETTER U WITH DIAERESIS\r
+ : 0055 0308\r
+00DD LATIN CAPITAL LETTER Y WITH ACUTE\r
+ : 0059 0301\r
+00DE LATIN CAPITAL LETTER THORN (Icelandic)\r
+00DF LATIN SMALL LETTER SHARP S (German)\r
+ = Eszett\r
+ * German\r
+ * uppercase is "SS"\r
+ * in origin a ligature of 017F and 0073\r
+ x (greek small letter beta - 03B2)\r
+00E0 LATIN SMALL LETTER A WITH GRAVE\r
+ : 0061 0300\r
+00E1 LATIN SMALL LETTER A WITH ACUTE\r
+ : 0061 0301\r
+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX\r
+ : 0061 0302\r
+00E3 LATIN SMALL LETTER A WITH TILDE\r
+ * Portuguese\r
+ : 0061 0303\r
+00E4 LATIN SMALL LETTER A WITH DIAERESIS\r
+ : 0061 0308\r
+00E5 LATIN SMALL LETTER A WITH RING ABOVE\r
+ * Danish, Norwegian, Swedish, Walloon\r
+ : 0061 030A\r
+00E6 LATIN SMALL LETTER AE (ash) *\r
+ = LATIN SMALL LIGATURE AE\r
+ = ash (from Old English æsc)\r
+ * Danish, Norwegian, Icelandic, Faroese, Old English, French, IPA\r
+ x (latin small ligature oe - 0153)\r
+ x (cyrillic small ligature a ie - 04D5)\r
+00E7 LATIN SMALL LETTER C WITH CEDILLA\r
+ : 0063 0327\r
+00E8 LATIN SMALL LETTER E WITH GRAVE\r
+ : 0065 0300\r
+00E9 LATIN SMALL LETTER E WITH ACUTE\r
+ : 0065 0301\r
+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX\r
+ : 0065 0302\r
+00EB LATIN SMALL LETTER E WITH DIAERESIS\r
+ : 0065 0308\r
+00EC LATIN SMALL LETTER I WITH GRAVE\r
+ * Italian, Malagasy\r
+ : 0069 0300\r
+00ED LATIN SMALL LETTER I WITH ACUTE\r
+ : 0069 0301\r
+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX\r
+ : 0069 0302\r
+00EF LATIN SMALL LETTER I WITH DIAERESIS\r
+ : 0069 0308\r
+00F0 LATIN SMALL LETTER ETH (Icelandic)\r
+ * Icelandic, Faroese, Old English, IPA\r
+ x (latin capital letter eth - 00D0)\r
+ x (greek small letter delta - 03B4)\r
+ x (partial differential - 2202)\r
+00F1 LATIN SMALL LETTER N WITH TILDE\r
+ : 006E 0303\r
+00F2 LATIN SMALL LETTER O WITH GRAVE\r
+ : 006F 0300\r
+00F3 LATIN SMALL LETTER O WITH ACUTE\r
+ : 006F 0301\r
+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX\r
+ : 006F 0302\r
+00F5 LATIN SMALL LETTER O WITH TILDE\r
+ * Portuguese, Estonian\r
+ : 006F 0303\r
+00F6 LATIN SMALL LETTER O WITH DIAERESIS\r
+ : 006F 0308\r
+00F7 DIVISION SIGN\r
+00F8 LATIN SMALL LETTER O WITH STROKE\r
+ = LATIN SMALL LETTER O SLASH\r
+ * Danish, Norwegian, Faroese, IPA\r
+00F9 LATIN SMALL LETTER U WITH GRAVE\r
+ * French, Italian\r
+ : 0075 0300\r
+00FA LATIN SMALL LETTER U WITH ACUTE\r
+ : 0075 0301\r
+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX\r
+ : 0075 0302\r
+00FC LATIN SMALL LETTER U WITH DIAERESIS\r
+ : 0075 0308\r
+00FD LATIN SMALL LETTER Y WITH ACUTE\r
+ * Czech, Slovak, Icelandic, Faroese, Welsh, Malagasy\r
+ : 0079 0301\r
+00FE LATIN SMALL LETTER THORN (Icelandic)\r
+ * Icelandic, Old English, phonetics\r
+ * Runic letter borrowed into Latin script\r
+ x (runic letter thurisaz thurs thorn - 16A6)\r
+00FF LATIN SMALL LETTER Y WITH DIAERESIS\r
+ * French\r
+ x (latin capital letter y with diaeresis - 0178)\r
+ : 0079 0308\r
+@@ 0100 Latin Extended-A 017F\r
+@ European Latin\r
+0100 LATIN CAPITAL LETTER A WITH MACRON\r
+ : 0041 0304\r
+0101 LATIN SMALL LETTER A WITH MACRON\r
+ * Latvian, Latin, ...\r
+ : 0061 0304\r
+0102 LATIN CAPITAL LETTER A WITH BREVE\r
+ : 0041 0306\r
+0103 LATIN SMALL LETTER A WITH BREVE\r
+ * Romanian, Vietnamese, Latin, ...\r
+ : 0061 0306\r
+0104 LATIN CAPITAL LETTER A WITH OGONEK\r
+ : 0041 0328\r
+0105 LATIN SMALL LETTER A WITH OGONEK\r
+ * Polish, Lithuanian, ...\r
+ : 0061 0328\r
+0106 LATIN CAPITAL LETTER C WITH ACUTE\r
+ : 0043 0301\r
+0107 LATIN SMALL LETTER C WITH ACUTE\r
+ * Polish, Croatian, ...\r
+ x (cyrillic small letter tshe - 045B)\r
+ : 0063 0301\r
+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX\r
+ : 0043 0302\r
+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX\r
+ * Esperanto\r
+ : 0063 0302\r
+010A LATIN CAPITAL LETTER C WITH DOT ABOVE\r
+ : 0043 0307\r
+010B LATIN SMALL LETTER C WITH DOT ABOVE\r
+ * Maltese, Irish Gaelic (old orthography)\r
+ : 0063 0307\r
+010C LATIN CAPITAL LETTER C WITH CARON\r
+ : 0043 030C\r
+010D LATIN SMALL LETTER C WITH CARON\r
+ * Czech, Slovak, Slovenian, and many other languages\r
+ : 0063 030C\r
+010E LATIN CAPITAL LETTER D WITH CARON\r
+ * the form using caron/hacek is preferred in all contexts\r
+ : 0044 030C\r
+010F LATIN SMALL LETTER D WITH CARON\r
+ * Czech, Slovak\r
+ * the form using apostrophe is preferred in typesetting\r
+ : 0064 030C\r
+0110 LATIN CAPITAL LETTER D WITH STROKE\r
+ x (latin capital letter eth - 00D0)\r
+ x (latin small letter d with stroke - 0111)\r
+ x (latin capital letter african d - 0189)\r
+0111 LATIN SMALL LETTER D WITH STROKE\r
+ * Croatian, Vietnamese, Sámi\r
+ x (latin capital letter d with stroke - 0110)\r
+ x (cyrillic small letter dje - 0452)\r
+0112 LATIN CAPITAL LETTER E WITH MACRON\r
+ : 0045 0304\r
+0113 LATIN SMALL LETTER E WITH MACRON\r
+ * Latvian, Latin, ...\r
+ : 0065 0304\r
+0114 LATIN CAPITAL LETTER E WITH BREVE\r
+ : 0045 0306\r
+0115 LATIN SMALL LETTER E WITH BREVE\r
+ * Malay, Latin, ...\r
+ : 0065 0306\r
+0116 LATIN CAPITAL LETTER E WITH DOT ABOVE\r
+ : 0045 0307\r
+0117 LATIN SMALL LETTER E WITH DOT ABOVE\r
+ * Lithuanian\r
+ : 0065 0307\r
+0118 LATIN CAPITAL LETTER E WITH OGONEK\r
+ : 0045 0328\r
+0119 LATIN SMALL LETTER E WITH OGONEK\r
+ * Polish, Lithuanian, ...\r
+ : 0065 0328\r
+011A LATIN CAPITAL LETTER E WITH CARON\r
+ : 0045 030C\r
+011B LATIN SMALL LETTER E WITH CARON\r
+ * Czech, ...\r
+ : 0065 030C\r
+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX\r
+ : 0047 0302\r
+011D LATIN SMALL LETTER G WITH CIRCUMFLEX\r
+ * Esperanto\r
+ : 0067 0302\r
+011E LATIN CAPITAL LETTER G WITH BREVE\r
+ : 0047 0306\r
+011F LATIN SMALL LETTER G WITH BREVE\r
+ * Turkish, Azerbaijani\r
+ x (latin small letter g with caron - 01E7)\r
+ : 0067 0306\r
+0120 LATIN CAPITAL LETTER G WITH DOT ABOVE\r
+ : 0047 0307\r
+0121 LATIN SMALL LETTER G WITH DOT ABOVE\r
+ * Maltese, Irish Gaelic (old orthography)\r
+ : 0067 0307\r
+0122 LATIN CAPITAL LETTER G WITH CEDILLA\r
+ : 0047 0327\r
+0123 LATIN SMALL LETTER G WITH CEDILLA\r
+ * Latvian\r
+ * there are three major glyph variants\r
+ : 0067 0327\r
+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX\r
+ : 0048 0302\r
+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX\r
+ * Esperanto\r
+ : 0068 0302\r
+0126 LATIN CAPITAL LETTER H WITH STROKE\r
+0127 LATIN SMALL LETTER H WITH STROKE\r
+ * Maltese, IPA, ...\r
+ x (cyrillic small letter tshe - 045B)\r
+ x (planck constant over two pi - 210F)\r
+0128 LATIN CAPITAL LETTER I WITH TILDE\r
+ : 0049 0303\r
+0129 LATIN SMALL LETTER I WITH TILDE\r
+ * Greenlandic (old orthography)\r
+ : 0069 0303\r
+012A LATIN CAPITAL LETTER I WITH MACRON\r
+ : 0049 0304\r
+012B LATIN SMALL LETTER I WITH MACRON\r
+ * Latvian, Latin, ...\r
+ : 0069 0304\r
+012C LATIN CAPITAL LETTER I WITH BREVE\r
+ : 0049 0306\r
+012D LATIN SMALL LETTER I WITH BREVE\r
+ * Latin, ...\r
+ : 0069 0306\r
+012E LATIN CAPITAL LETTER I WITH OGONEK\r
+ : 0049 0328\r
+012F LATIN SMALL LETTER I WITH OGONEK\r
+ * Lithuanian, ...\r
+ : 0069 0328\r
+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE\r
+ = LATIN CAPITAL LETTER I DOT\r
+ * Turkish, Azerbaijani\r
+ * lowercase is 0069\r
+ x (latin capital letter i - 0049)\r
+ : 0049 0307\r
+0131 LATIN SMALL LETTER DOTLESS I\r
+ * Turkish, Azerbaijani\r
+ * uppercase is 0049\r
+ x (latin small letter i - 0069)\r
+0132 LATIN CAPITAL LIGATURE IJ\r
+ # 0049 004A\r
+0133 LATIN SMALL LIGATURE IJ\r
+ * Dutch\r
+ # 0069 006A\r
+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX\r
+ : 004A 0302\r
+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX\r
+ * Esperanto\r
+ : 006A 0302\r
+0136 LATIN CAPITAL LETTER K WITH CEDILLA\r
+ : 004B 0327\r
+0137 LATIN SMALL LETTER K WITH CEDILLA\r
+ * Latvian\r
+ : 006B 0327\r
+0138 LATIN SMALL LETTER KRA (Greenlandic)\r
+ * Greenlandic (old orthography)\r
+0139 LATIN CAPITAL LETTER L WITH ACUTE\r
+ : 004C 0301\r
+013A LATIN SMALL LETTER L WITH ACUTE\r
+ * Slovak\r
+ : 006C 0301\r
+013B LATIN CAPITAL LETTER L WITH CEDILLA\r
+ : 004C 0327\r
+013C LATIN SMALL LETTER L WITH CEDILLA\r
+ * Latvian\r
+ : 006C 0327\r
+013D LATIN CAPITAL LETTER L WITH CARON\r
+ : 004C 030C\r
+013E LATIN SMALL LETTER L WITH CARON\r
+ * Slovak\r
+ * the form using apostrophe is preferred in typesetting\r
+ : 006C 030C\r
+013F LATIN CAPITAL LETTER L WITH MIDDLE DOT\r
+ * some fonts show the middle dot inside the L, but the preferred form has the dot following the L\r
+ # 004C 00B7\r
+0140 LATIN SMALL LETTER L WITH MIDDLE DOT\r
+ * Catalan\r
+ # 006C 00B7\r
+0141 LATIN CAPITAL LETTER L WITH STROKE\r
+0142 LATIN SMALL LETTER L WITH STROKE\r
+ * Polish, ...\r
+ x (latin small letter l with bar - 019A)\r
+0143 LATIN CAPITAL LETTER N WITH ACUTE\r
+ : 004E 0301\r
+0144 LATIN SMALL LETTER N WITH ACUTE\r
+ * Polish, ...\r
+ : 006E 0301\r
+0145 LATIN CAPITAL LETTER N WITH CEDILLA\r
+ : 004E 0327\r
+0146 LATIN SMALL LETTER N WITH CEDILLA\r
+ * Latvian\r
+ : 006E 0327\r
+0147 LATIN CAPITAL LETTER N WITH CARON\r
+ : 004E 030C\r
+0148 LATIN SMALL LETTER N WITH CARON\r
+ * Czech, Slovak\r
+ : 006E 030C\r
+0149 LATIN SMALL LETTER N PRECEDED BY APOSTROPHE\r
+ = LATIN SMALL LETTER APOSTROPHE N\r
+ * Afrikaans\r
+ * this is not actually a single letter\r
+ # 02BC 006E\r
+014A LATIN CAPITAL LETTER ENG (Sami)\r
+ * glyph may also have appearance of large form of the small letter\r
+014B LATIN SMALL LETTER ENG (Sami)\r
+ * Sámi, Mende, IPA, ...\r
+014C LATIN CAPITAL LETTER O WITH MACRON\r
+ : 004F 0304\r
+014D LATIN SMALL LETTER O WITH MACRON\r
+ * Latvian, Latin, ...\r
+ : 006F 0304\r
+014E LATIN CAPITAL LETTER O WITH BREVE\r
+ : 004F 0306\r
+014F LATIN SMALL LETTER O WITH BREVE\r
+ * Latin\r
+ : 006F 0306\r
+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE\r
+ : 004F 030B\r
+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE\r
+ * Hungarian\r
+ : 006F 030B\r
+0152 LATIN CAPITAL LIGATURE OE\r
+0153 LATIN SMALL LIGATURE OE\r
+ = LATIN SMALL LETTER O E\r
+ = ethel (from Old English eðel)\r
+ * French, IPA, Old Icelandic, Old English, ...\r
+ x (latin small letter ae - 00E6)\r
+ x (latin letter small capital oe - 0276)\r
+0154 LATIN CAPITAL LETTER R WITH ACUTE\r
+ : 0052 0301\r
+0155 LATIN SMALL LETTER R WITH ACUTE\r
+ * Slovak, ...\r
+ : 0072 0301\r
+0156 LATIN CAPITAL LETTER R WITH CEDILLA\r
+ : 0052 0327\r
+0157 LATIN SMALL LETTER R WITH CEDILLA\r
+ * Latvian\r
+ : 0072 0327\r
+0158 LATIN CAPITAL LETTER R WITH CARON\r
+ : 0052 030C\r
+0159 LATIN SMALL LETTER R WITH CARON\r
+ * Czech, ...\r
+ : 0072 030C\r
+015A LATIN CAPITAL LETTER S WITH ACUTE\r
+ : 0053 0301\r
+015B LATIN SMALL LETTER S WITH ACUTE\r
+ * Polish, Indic transliteration, ...\r
+ : 0073 0301\r
+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX\r
+ : 0053 0302\r
+015D LATIN SMALL LETTER S WITH CIRCUMFLEX\r
+ * Esperanto\r
+ : 0073 0302\r
+015E LATIN CAPITAL LETTER S WITH CEDILLA *\r
+ : 0053 0327\r
+015F LATIN SMALL LETTER S WITH CEDILLA *\r
+ * Turkish, Azerbaijani, Romanian, ...\r
+ * this character is used in both Turkish and Romanian data\r
+ * a glyph variant with comma below is preferred for Romanian\r
+ x (latin small letter s with comma below - 0219)\r
+ : 0073 0327\r
+0160 LATIN CAPITAL LETTER S WITH CARON\r
+ : 0053 030C\r
+0161 LATIN SMALL LETTER S WITH CARON\r
+ * Czech, Estonian, Finnish, Slovak, and many other languages\r
+ : 0073 030C\r
+0162 LATIN CAPITAL LETTER T WITH CEDILLA *\r
+ : 0054 0327\r
+0163 LATIN SMALL LETTER T WITH CEDILLA *\r
+ * Romanian, Semitic transliteration, ...\r
+ * this character is used in Romanian data\r
+ * a glyph variant with comma below is preferred for Romanian\r
+ x (latin small letter t with comma below - 021B)\r
+ : 0074 0327\r
+0164 LATIN CAPITAL LETTER T WITH CARON\r
+ * the form using caron/hacek is preferred in all contexts\r
+ : 0054 030C\r
+0165 LATIN SMALL LETTER T WITH CARON\r
+ * Czech, Slovak\r
+ * the form using apostrophe is preferred in typesetting\r
+ : 0074 030C\r
+0166 LATIN CAPITAL LETTER T WITH STROKE\r
+0167 LATIN SMALL LETTER T WITH STROKE\r
+ * Sámi\r
+0168 LATIN CAPITAL LETTER U WITH TILDE\r
+ : 0055 0303\r
+0169 LATIN SMALL LETTER U WITH TILDE\r
+ * Greenlandic (old orthography)\r
+ : 0075 0303\r
+016A LATIN CAPITAL LETTER U WITH MACRON\r
+ : 0055 0304\r
+016B LATIN SMALL LETTER U WITH MACRON\r
+ * Latvian, Lithuanian, Latin, ...\r
+ : 0075 0304\r
+016C LATIN CAPITAL LETTER U WITH BREVE\r
+ : 0055 0306\r
+016D LATIN SMALL LETTER U WITH BREVE\r
+ * Latin, Esperanto, ...\r
+ : 0075 0306\r
+016E LATIN CAPITAL LETTER U WITH RING ABOVE\r
+ : 0055 030A\r
+016F LATIN SMALL LETTER U WITH RING ABOVE\r
+ * Czech, ...\r
+ : 0075 030A\r
+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE\r
+ : 0055 030B\r
+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE\r
+ * Hungarian\r
+ : 0075 030B\r
+0172 LATIN CAPITAL LETTER U WITH OGONEK\r
+ : 0055 0328\r
+0173 LATIN SMALL LETTER U WITH OGONEK\r
+ * Lithuanian\r
+ : 0075 0328\r
+0174 LATIN CAPITAL LETTER W WITH CIRCUMFLEX\r
+ : 0057 0302\r
+0175 LATIN SMALL LETTER W WITH CIRCUMFLEX\r
+ * Welsh\r
+ : 0077 0302\r
+0176 LATIN CAPITAL LETTER Y WITH CIRCUMFLEX\r
+ : 0059 0302\r
+0177 LATIN SMALL LETTER Y WITH CIRCUMFLEX\r
+ * Welsh\r
+ : 0079 0302\r
+0178 LATIN CAPITAL LETTER Y WITH DIAERESIS\r
+ * French, Igbo\r
+ x (latin small letter y with diaeresis - 00FF)\r
+ : 0059 0308\r
+0179 LATIN CAPITAL LETTER Z WITH ACUTE\r
+ : 005A 0301\r
+017A LATIN SMALL LETTER Z WITH ACUTE\r
+ * Polish, ...\r
+ : 007A 0301\r
+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE\r
+ : 005A 0307\r
+017C LATIN SMALL LETTER Z WITH DOT ABOVE\r
+ * Polish, ...\r
+ : 007A 0307\r
+017D LATIN CAPITAL LETTER Z WITH CARON\r
+ : 005A 030C\r
+017E LATIN SMALL LETTER Z WITH CARON\r
+ * Czech, Estonian, Finnish, Slovak, Slovenian, and many other languages\r
+ : 007A 030C\r
+017F LATIN SMALL LETTER LONG S\r
+ * in common use in Roman types until the 18th century\r
+ * in current use in Fraktur and Gaelic types\r
+ # 0073 latin small letter s\r
+@@ 0180 Latin Extended-B 024F\r
+@ Latin extended-B\r
+0180 LATIN SMALL LETTER B WITH STROKE\r
+ * Americanist and Indo-Europeanist usage for phonetic beta\r
+ * Old Saxon\r
+ x (greek small letter beta - 03B2)\r
+ x (blank symbol - 2422)\r
+0181 LATIN CAPITAL LETTER B WITH HOOK\r
+ * Zulu, Pan-Nigerian alphabet\r
+ x (latin small letter b with hook - 0253)\r
+0182 LATIN CAPITAL LETTER B WITH TOPBAR\r
+0183 LATIN SMALL LETTER B WITH TOPBAR\r
+ * Zhuang\r
+ * former Soviet minority language scripts\r
+ x (cyrillic capital letter be - 0411)\r
+0184 LATIN CAPITAL LETTER TONE SIX\r
+0185 LATIN SMALL LETTER TONE SIX\r
+ * Zhuang\r
+ * Zhuang tone three is Cyrillic ze\r
+ * Zhuang tone four is Cyrillic che\r
+ x (latin small letter tone two - 01A8)\r
+ x (latin small letter tone five - 01BD)\r
+ x (cyrillic small letter ze - 0437)\r
+ x (cyrillic small letter che - 0447)\r
+ x (cyrillic small letter soft sign - 044C)\r
+0186 LATIN CAPITAL LETTER OPEN O\r
+ * typographically a turned C\r
+ x (latin small letter open o - 0254)\r
+0187 LATIN CAPITAL LETTER C WITH HOOK\r
+0188 LATIN SMALL LETTER C WITH HOOK\r
+ * African\r
+0189 LATIN CAPITAL LETTER AFRICAN D *\r
+ * Ewe\r
+ x (latin capital letter eth - 00D0)\r
+ x (latin capital letter d with stroke - 0110)\r
+ x (latin small letter d with tail - 0256)\r
+018A LATIN CAPITAL LETTER D WITH HOOK\r
+ * Pan-Nigerian alphabet\r
+ x (latin small letter d with hook - 0257)\r
+018B LATIN CAPITAL LETTER D WITH TOPBAR\r
+018C LATIN SMALL LETTER D WITH TOPBAR\r
+ * former-Soviet minority language scripts\r
+018D LATIN SMALL LETTER TURNED DELTA\r
+ * archaic phonetic for labialized dental fricative\r
+ * recommended spellings 007A 02B7 or 007A 032B\r
+018E LATIN CAPITAL LETTER REVERSED E\r
+ = LATIN CAPITAL LETTER TURNED E\r
+ * Pan-Nigerian alphabet\r
+ * lowercase is 01DD\r
+018F LATIN CAPITAL LETTER SCHWA\r
+ * Azerbaijani, ...\r
+ x (latin small letter schwa - 0259)\r
+ x (cyrillic capital letter schwa - 04D8)\r
+0190 LATIN CAPITAL LETTER OPEN E\r
+ = LATIN CAPITAL LETTER EPSILON\r
+ * African\r
+ x (latin small letter open e - 025B)\r
+ x (euler constant - 2107)\r
+0191 LATIN CAPITAL LETTER F WITH HOOK\r
+ * African\r
+0192 LATIN SMALL LETTER F WITH HOOK\r
+ = LATIN SMALL LETTER SCRIPT F\r
+ = Florin currency symbol (Netherlands)\r
+ = function symbol\r
+ = abbreviation convention for folder\r
+0193 LATIN CAPITAL LETTER G WITH HOOK\r
+ * African\r
+ x (latin small letter g with hook - 0260)\r
+0194 LATIN CAPITAL LETTER GAMMA\r
+ * African\r
+ x (latin small letter gamma - 0263)\r
+0195 LATIN SMALL LETTER HV (hwair)\r
+ * Gothic transliteration\r
+ * uppercase is 01F6\r
+0196 LATIN CAPITAL LETTER IOTA\r
+ * African\r
+ x (latin small letter iota - 0269)\r
+0197 LATIN CAPITAL LETTER I WITH STROKE\r
+ = barred i, i bar\r
+ * African\r
+ * ISO 6438 gives lowercase as 026A, not 0268\r
+ x (latin letter small capital i - 026A)\r
+0198 LATIN CAPITAL LETTER K WITH HOOK\r
+0199 LATIN SMALL LETTER K WITH HOOK\r
+ * Hausa, Pan-Nigerian alphabet\r
+019A LATIN SMALL LETTER L WITH BAR\r
+ = barred l\r
+ * Americanist phonetic usage for 026C\r
+ x (latin small letter l with stroke - 0142)\r
+019B LATIN SMALL LETTER LAMBDA WITH STROKE\r
+ = barred lambda, lambda bar\r
+ * Americanist phonetic usage\r
+019C LATIN CAPITAL LETTER TURNED M\r
+ * Zhuang\r
+ x (latin small letter turned m - 026F)\r
+019D LATIN CAPITAL LETTER N WITH LEFT HOOK\r
+ * African\r
+ x (latin small letter n with left hook - 0272)\r
+019E LATIN SMALL LETTER N WITH LONG RIGHT LEG\r
+ * archaic phonetic for Japanese syllabic "n"\r
+ * recommended spelling 006E 0329\r
+019F LATIN CAPITAL LETTER O WITH MIDDLE TILDE *\r
+ = barred o, o bar\r
+ * lowercase is 0275\r
+ * African\r
+ x (cyrillic capital letter barred o - 04E8)\r
+01A0 LATIN CAPITAL LETTER O WITH HORN\r
+ : 004F 031B\r
+01A1 LATIN SMALL LETTER O WITH HORN\r
+ * Vietnamese\r
+ : 006F 031B\r
+01A2 LATIN CAPITAL LETTER OI (gha)\r
+01A3 LATIN SMALL LETTER OI (gha)\r
+ = gha\r
+ * Pan-Turkic Latin alphabets\r
+01A4 LATIN CAPITAL LETTER P WITH HOOK\r
+01A5 LATIN SMALL LETTER P WITH HOOK\r
+ * African\r
+01A6 LATIN LETTER YR *\r
+ * old Norse\r
+ * from German Standard DIN 31624 and ISO 5246-2\r
+ * lowercase is 0280\r
+01A7 LATIN CAPITAL LETTER TONE TWO\r
+01A8 LATIN SMALL LETTER TONE TWO\r
+ * Zhuang\r
+ * typographically a reversed S\r
+ x (latin small letter tone six - 0185)\r
+01A9 LATIN CAPITAL LETTER ESH\r
+ * African\r
+ x (latin small letter esh - 0283)\r
+ x (greek capital letter sigma - 03A3)\r
+01AA LATIN LETTER REVERSED ESH LOOP\r
+ * archaic phonetic for labialized palatoalveolar or palatal fricative\r
+ * Twi\r
+ * recommended spellings 0283 02B7, 00E7 02B7, 0068 0265, etc.\r
+01AB LATIN SMALL LETTER T WITH PALATAL HOOK\r
+ * archaic phonetic for palatalized alveolar or dental stop\r
+ * recommended spelling 0074 02B2\r
+01AC LATIN CAPITAL LETTER T WITH HOOK\r
+01AD LATIN SMALL LETTER T WITH HOOK\r
+ * African\r
+01AE LATIN CAPITAL LETTER T WITH RETROFLEX HOOK\r
+ * African\r
+ x (latin small letter t with retroflex hook - 0288)\r
+01AF LATIN CAPITAL LETTER U WITH HORN\r
+ : 0055 031B\r
+01B0 LATIN SMALL LETTER U WITH HORN\r
+ * Vietnamese\r
+ : 0075 031B\r
+01B1 LATIN CAPITAL LETTER UPSILON\r
+ * African\r
+ * typographically based on turned capital Greek omega\r
+ x (latin small letter upsilon - 028A)\r
+ x (inverted ohm sign - 2127)\r
+01B2 LATIN CAPITAL LETTER V WITH HOOK\r
+ = LATIN CAPITAL LETTER SCRIPT V\r
+ * African\r
+ x (latin small letter v with hook - 028B)\r
+01B3 LATIN CAPITAL LETTER Y WITH HOOK\r
+01B4 LATIN SMALL LETTER Y WITH HOOK\r
+ * Bini, Esoko, and other Edo languages in West Africa\r
+01B5 LATIN CAPITAL LETTER Z WITH STROKE\r
+01B6 LATIN SMALL LETTER Z WITH STROKE\r
+ = barred z, z bar\r
+ * Pan-Turkic Latin orthography\r
+ * handwritten variant of Latin "z"\r
+ x (latin small letter z - 007A)\r
+01B7 LATIN CAPITAL LETTER EZH\r
+ * African, Skolt Sámi\r
+ * lowercase is 0292\r
+ x (latin capital letter yogh - 021C)\r
+ x (cyrillic capital letter abkhasian dze - 04E0)\r
+01B8 LATIN CAPITAL LETTER EZH REVERSED\r
+01B9 LATIN SMALL LETTER EZH REVERSED\r
+ * archaic phonetic for voiced pharyngeal fricative\r
+ * sometimes typographically rendered with a turned digit 3\r
+ * recommended spelling 0295\r
+ x (latin letter pharyngeal voiced fricative - 0295)\r
+ x (arabic letter ain - 0639)\r
+01BA LATIN SMALL LETTER EZH WITH TAIL\r
+ * archaic phonetic for labialized voiced palatoalveolar or palatal fricative\r
+ * Twi\r
+ * recommended spellings 0292 02B7 or 006A 02B7\r
+01BB LATIN LETTER TWO WITH STROKE\r
+ * archaic phonetic for [dz] affricate\r
+ * recommended spellings 0292 or 0064 007A\r
+01BC LATIN CAPITAL LETTER TONE FIVE\r
+01BD LATIN SMALL LETTER TONE FIVE\r
+ * Zhuang\r
+ x (latin small letter tone six - 0185)\r
+01BE LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE\r
+ * archaic phonetic for [ts] affricate\r
+ * recommended spelling 0074 0073\r
+ * letter form is actually derived from ligation of ts, rather than inverted glottal stop\r
+01BF LATIN LETTER WYNN\r
+ = wen\r
+ * Runic letter borrowed into Latin script\r
+ * replaced by "w" in modern transcriptions of Old English\r
+ * uppercase is 01F7\r
+ x (runic letter wunjo wynn w - 16B9)\r
+01C0 LATIN LETTER DENTAL CLICK\r
+ = pipe\r
+ * Khoisan tradition\r
+ * "c" in Zulu orthography\r
+ x (solidus - 002F)\r
+ x (vertical line - 007C)\r
+ x (latin small letter turned t - 0287)\r
+ x (divides - 2223)\r
+01C1 LATIN LETTER LATERAL CLICK\r
+ = double pipe\r
+ * Khoisan tradition\r
+ * "x" in Zulu orthography\r
+ x (latin letter inverted glottal stop - 0296)\r
+ x (parallel to - 2225)\r
+01C2 LATIN LETTER ALVEOLAR CLICK\r
+ = double-barred pipe\r
+ * Khoisan tradition\r
+ x (not equal to - 2260)\r
+01C3 LATIN LETTER RETROFLEX CLICK\r
+ = LATIN LETTER EXCLAMATION MARK\r
+ * Khoisan tradition\r
+ * "q" in Zulu orthography\r
+ x (exclamation mark - 0021)\r
+ x (latin letter stretched c - 0297)\r
+@ Croatian digraphs matching Serbian Cyrillic letters\r
+01C4 LATIN CAPITAL LETTER DZ WITH CARON\r
+ # 0044 017D\r
+01C5 LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON\r
+ # 0044 017E\r
+01C6 LATIN SMALL LETTER DZ WITH CARON\r
+ x (cyrillic small letter dzhe - 045F)\r
+ # 0064 017E\r
+01C7 LATIN CAPITAL LETTER LJ\r
+ # 004C 004A\r
+01C8 LATIN CAPITAL LETTER L WITH SMALL LETTER J\r
+ # 004C 006A\r
+01C9 LATIN SMALL LETTER LJ\r
+ x (cyrillic small letter lje - 0459)\r
+ # 006C 006A\r
+01CA LATIN CAPITAL LETTER NJ\r
+ # 004E 004A\r
+01CB LATIN CAPITAL LETTER N WITH SMALL LETTER J\r
+ # 004E 006A\r
+01CC LATIN SMALL LETTER NJ\r
+ x (cyrillic small letter nje - 045A)\r
+ # 006E 006A\r
+@ Pinyin diacritic-vowel combinations\r
+01CD LATIN CAPITAL LETTER A WITH CARON\r
+ : 0041 030C\r
+01CE LATIN SMALL LETTER A WITH CARON\r
+ * Pinyin third tone\r
+ : 0061 030C\r
+01CF LATIN CAPITAL LETTER I WITH CARON\r
+ : 0049 030C\r
+01D0 LATIN SMALL LETTER I WITH CARON\r
+ * Pinyin third tone\r
+ : 0069 030C\r
+01D1 LATIN CAPITAL LETTER O WITH CARON\r
+ : 004F 030C\r
+01D2 LATIN SMALL LETTER O WITH CARON\r
+ * Pinyin third tone\r
+ : 006F 030C\r
+01D3 LATIN CAPITAL LETTER U WITH CARON\r
+ : 0055 030C\r
+01D4 LATIN SMALL LETTER U WITH CARON\r
+ * Pinyin third tone\r
+ : 0075 030C\r
+01D5 LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON\r
+ : 00DC 0304\r
+01D6 LATIN SMALL LETTER U WITH DIAERESIS AND MACRON\r
+ * Pinyin first tone\r
+ : 00FC 0304\r
+01D7 LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE\r
+ : 00DC 0301\r
+01D8 LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE\r
+ * Pinyin second tone\r
+ : 00FC 0301\r
+01D9 LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON\r
+ : 00DC 030C\r
+01DA LATIN SMALL LETTER U WITH DIAERESIS AND CARON\r
+ * Pinyin third tone\r
+ : 00FC 030C\r
+01DB LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE\r
+ : 00DC 0300\r
+01DC LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE\r
+ * Pinyin fourth tone\r
+ : 00FC 0300\r
+@ Additions\r
+01DD LATIN SMALL LETTER TURNED E\r
+ * Pan-Nigerian alphabet\r
+ * all other usages of schwa are 0259\r
+ * uppercase is 018E\r
+ x (latin small letter schwa - 0259)\r
+01DE LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON\r
+ : 00C4 0304\r
+01DF LATIN SMALL LETTER A WITH DIAERESIS AND MACRON\r
+ * Livonian, Uralicist usage\r
+ : 00E4 0304\r
+01E0 LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON\r
+ : 0226 0304\r
+01E1 LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON\r
+ * Uralicist usage\r
+ : 0227 0304\r
+01E2 LATIN CAPITAL LETTER AE WITH MACRON (ash) *\r
+ : 00C6 0304\r
+01E3 LATIN SMALL LETTER AE WITH MACRON (ash) *\r
+ * Old Norse, Old English\r
+ : 00E6 0304\r
+01E4 LATIN CAPITAL LETTER G WITH STROKE\r
+01E5 LATIN SMALL LETTER G WITH STROKE\r
+ * Skolt Sámi\r
+01E6 LATIN CAPITAL LETTER G WITH CARON\r
+ : 0047 030C\r
+01E7 LATIN SMALL LETTER G WITH CARON\r
+ * Skolt Sámi\r
+ x (latin small letter g with breve - 011F)\r
+ : 0067 030C\r
+01E8 LATIN CAPITAL LETTER K WITH CARON\r
+ : 004B 030C\r
+01E9 LATIN SMALL LETTER K WITH CARON\r
+ * Skolt Sámi\r
+ : 006B 030C\r
+01EA LATIN CAPITAL LETTER O WITH OGONEK\r
+ : 004F 0328\r
+01EB LATIN SMALL LETTER O WITH OGONEK\r
+ * Sámi, Iroquoian, Old Icelandic\r
+ : 006F 0328\r
+01EC LATIN CAPITAL LETTER O WITH OGONEK AND MACRON\r
+ : 01EA 0304\r
+01ED LATIN SMALL LETTER O WITH OGONEK AND MACRON\r
+ * Old Icelandic\r
+ : 01EB 0304\r
+01EE LATIN CAPITAL LETTER EZH WITH CARON\r
+ : 01B7 030C\r
+01EF LATIN SMALL LETTER EZH WITH CARON\r
+ * Skolt Sámi\r
+ : 0292 030C\r
+01F0 LATIN SMALL LETTER J WITH CARON\r
+ * IPA and many languages\r
+ : 006A 030C\r
+01F1 LATIN CAPITAL LETTER DZ\r
+ # 0044 005A\r
+01F2 LATIN CAPITAL LETTER D WITH SMALL LETTER Z\r
+ # 0044 007A\r
+01F3 LATIN SMALL LETTER DZ\r
+ # 0064 007A\r
+01F4 LATIN CAPITAL LETTER G WITH ACUTE\r
+ : 0047 0301\r
+01F5 LATIN SMALL LETTER G WITH ACUTE\r
+ * Macedonian and Serbian transliteration\r
+ : 0067 0301\r
+01F6 LATIN CAPITAL LETTER HWAIR\r
+ * lowercase is 0195\r
+01F7 LATIN CAPITAL LETTER WYNN\r
+ = wen\r
+ * lowercase is 01BF\r
+01F8 LATIN CAPITAL LETTER N WITH GRAVE\r
+ : 004E 0300\r
+01F9 LATIN SMALL LETTER N WITH GRAVE\r
+ * Pinyin\r
+ : 006E 0300\r
+01FA LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE\r
+ : 00C5 0301\r
+01FB LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE\r
+ : 00E5 0301\r
+01FC LATIN CAPITAL LETTER AE WITH ACUTE (ash) *\r
+ : 00C6 0301\r
+01FD LATIN SMALL LETTER AE WITH ACUTE (ash) *\r
+ : 00E6 0301\r
+01FE LATIN CAPITAL LETTER O WITH STROKE AND ACUTE\r
+ : 00D8 0301\r
+01FF LATIN SMALL LETTER O WITH STROKE AND ACUTE\r
+ : 00F8 0301\r
+@ Additions for Slovenian and Croatian\r
+0200 LATIN CAPITAL LETTER A WITH DOUBLE GRAVE\r
+ : 0041 030F\r
+0201 LATIN SMALL LETTER A WITH DOUBLE GRAVE\r
+ : 0061 030F\r
+0202 LATIN CAPITAL LETTER A WITH INVERTED BREVE\r
+ : 0041 0311\r
+0203 LATIN SMALL LETTER A WITH INVERTED BREVE\r
+ : 0061 0311\r
+0204 LATIN CAPITAL LETTER E WITH DOUBLE GRAVE\r
+ : 0045 030F\r
+0205 LATIN SMALL LETTER E WITH DOUBLE GRAVE\r
+ : 0065 030F\r
+0206 LATIN CAPITAL LETTER E WITH INVERTED BREVE\r
+ : 0045 0311\r
+0207 LATIN SMALL LETTER E WITH INVERTED BREVE\r
+ : 0065 0311\r
+0208 LATIN CAPITAL LETTER I WITH DOUBLE GRAVE\r
+ : 0049 030F\r
+0209 LATIN SMALL LETTER I WITH DOUBLE GRAVE\r
+ : 0069 030F\r
+020A LATIN CAPITAL LETTER I WITH INVERTED BREVE\r
+ : 0049 0311\r
+020B LATIN SMALL LETTER I WITH INVERTED BREVE\r
+ : 0069 0311\r
+020C LATIN CAPITAL LETTER O WITH DOUBLE GRAVE\r
+ : 004F 030F\r
+020D LATIN SMALL LETTER O WITH DOUBLE GRAVE\r
+ : 006F 030F\r
+020E LATIN CAPITAL LETTER O WITH INVERTED BREVE\r
+ : 004F 0311\r
+020F LATIN SMALL LETTER O WITH INVERTED BREVE\r
+ : 006F 0311\r
+0210 LATIN CAPITAL LETTER R WITH DOUBLE GRAVE\r
+ : 0052 030F\r
+0211 LATIN SMALL LETTER R WITH DOUBLE GRAVE\r
+ : 0072 030F\r
+0212 LATIN CAPITAL LETTER R WITH INVERTED BREVE\r
+ : 0052 0311\r
+0213 LATIN SMALL LETTER R WITH INVERTED BREVE\r
+ : 0072 0311\r
+0214 LATIN CAPITAL LETTER U WITH DOUBLE GRAVE\r
+ : 0055 030F\r
+0215 LATIN SMALL LETTER U WITH DOUBLE GRAVE\r
+ : 0075 030F\r
+0216 LATIN CAPITAL LETTER U WITH INVERTED BREVE\r
+ : 0055 0311\r
+0217 LATIN SMALL LETTER U WITH INVERTED BREVE\r
+ : 0075 0311\r
+@ Additions for Romanian\r
+0218 LATIN CAPITAL LETTER S WITH COMMA BELOW *\r
+ : 0053 0326\r
+0219 LATIN SMALL LETTER S WITH COMMA BELOW *\r
+ * Romanian, when distinct comma below form is required\r
+ x (latin small letter s with cedilla - 015F)\r
+ : 0073 0326\r
+021A LATIN CAPITAL LETTER T WITH COMMA BELOW *\r
+ : 0054 0326\r
+021B LATIN SMALL LETTER T WITH COMMA BELOW *\r
+ * Romanian, when distinct comma below form is required\r
+ x (latin small letter t with cedilla - 0163)\r
+ : 0074 0326\r
+@ Miscellaneous additions\r
+021C LATIN CAPITAL LETTER YOGH\r
+ x (latin capital letter ezh - 01B7)\r
+021D LATIN SMALL LETTER YOGH\r
+ * Middle English, Scots\r
+ x (latin small letter ezh - 0292)\r
+ x (ounce sign - 2125)\r
+021E LATIN CAPITAL LETTER H WITH CARON\r
+ : 0048 030C\r
+021F LATIN SMALL LETTER H WITH CARON\r
+ * Finnish Romany\r
+ : 0068 030C\r
+0222 LATIN CAPITAL LETTER OU\r
+0223 LATIN SMALL LETTER OU\r
+ * Algonquin, Huron\r
+ x (digit eight - 0038)\r
+0224 LATIN CAPITAL LETTER Z WITH HOOK\r
+0225 LATIN SMALL LETTER Z WITH HOOK\r
+ * Middle High German\r
+0226 LATIN CAPITAL LETTER A WITH DOT ABOVE\r
+ : 0041 0307\r
+0227 LATIN SMALL LETTER A WITH DOT ABOVE\r
+ * Uralicist usage\r
+ : 0061 0307\r
+0228 LATIN CAPITAL LETTER E WITH CEDILLA\r
+ : 0045 0327\r
+0229 LATIN SMALL LETTER E WITH CEDILLA\r
+ : 0065 0327\r
+@ Additions for Livonian\r
+022A LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON\r
+ : 00D6 0304\r
+022B LATIN SMALL LETTER O WITH DIAERESIS AND MACRON\r
+ * Livonian\r
+ : 00F6 0304\r
+022C LATIN CAPITAL LETTER O WITH TILDE AND MACRON\r
+ : 00D5 0304\r
+022D LATIN SMALL LETTER O WITH TILDE AND MACRON\r
+ * Livonian\r
+ : 00F5 0304\r
+022E LATIN CAPITAL LETTER O WITH DOT ABOVE\r
+ : 004F 0307\r
+022F LATIN SMALL LETTER O WITH DOT ABOVE\r
+ * Livonian\r
+ : 006F 0307\r
+0230 LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON\r
+ : 022E 0304\r
+0231 LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON\r
+ * Livonian\r
+ : 022F 0304\r
+0232 LATIN CAPITAL LETTER Y WITH MACRON\r
+ : 0059 0304\r
+0233 LATIN SMALL LETTER Y WITH MACRON\r
+ * Livonian, Cornish\r
+ : 0079 0304\r
+@@ 0250 IPA Extensions 02AF\r
+@ IPA extensions\r
+@+ IPA includes basic Latin letters and a number of Latin letters from other blocks.\r
+ x (latin small letter ae - 00E6)\r
+ x (latin small letter c with cedilla - 00E7)\r
+ x (latin small letter eth - 00F0)\r
+ x (latin small letter o with stroke - 00F8)\r
+ x (latin small letter h with stroke - 0127)\r
+ x (latin small letter eng - 014B)\r
+ x (latin small ligature oe - 0153)\r
+ x (greek small letter beta - 03B2)\r
+ x (greek small letter theta - 03B8)\r
+ x (greek small letter lamda - 03BB)\r
+ x (greek small letter chi - 03C7)\r
+0250 LATIN SMALL LETTER TURNED A\r
+ * low central unrounded vowel\r
+0251 LATIN SMALL LETTER ALPHA\r
+ = LATIN SMALL LETTER SCRIPT A\r
+ * low back unrounded vowel\r
+ x (greek small letter alpha - 03B1)\r
+0252 LATIN SMALL LETTER TURNED ALPHA\r
+ * low back rounded vowel\r
+0253 LATIN SMALL LETTER B WITH HOOK\r
+ * implosive bilabial stop\r
+ * Pan-Nigerian alphabet\r
+ x (latin capital letter b with hook - 0181)\r
+0254 LATIN SMALL LETTER OPEN O\r
+ * typographically a turned c\r
+ * lower-mid back rounded vowel\r
+ x (latin capital letter open o - 0186)\r
+0255 LATIN SMALL LETTER C WITH CURL\r
+ * voiceless alveolo-palatal laminal fricative\r
+ * used in transcription of Mandarin Chinese\r
+ * sound spelled with 015B in Polish\r
+0256 LATIN SMALL LETTER D WITH TAIL\r
+ = LATIN SMALL LETTER D RETROFLEX HOOK\r
+ * voiced retroflex stop\r
+ x (latin capital letter african d - 0189)\r
+0257 LATIN SMALL LETTER D WITH HOOK\r
+ * implosive dental or alveolar stop\r
+ * Ewe, Pan-Nigerian alphabet\r
+ x (latin capital letter d with hook - 018A)\r
+0258 LATIN SMALL LETTER REVERSED E\r
+ * upper-mid central unrounded vowel\r
+0259 LATIN SMALL LETTER SCHWA\r
+ * mid-central unrounded vowel\r
+ * variant uppercase form 018E is associated with 01DD\r
+ x (latin capital letter schwa - 018F)\r
+ x (latin small letter turned e - 01DD)\r
+ x (cyrillic small letter schwa - 04D9)\r
+025A LATIN SMALL LETTER SCHWA WITH HOOK\r
+ * rhotacized schwa\r
+025B LATIN SMALL LETTER OPEN E\r
+ = LATIN SMALL LETTER EPSILON\r
+ * lower-mid front unrounded vowel\r
+ x (latin capital letter open e - 0190)\r
+ x (greek small letter epsilon - 03B5)\r
+025C LATIN SMALL LETTER REVERSED OPEN E\r
+ * lower-mid central unrounded vowel\r
+025D LATIN SMALL LETTER REVERSED OPEN E WITH HOOK\r
+ * rhotacized lower-mid central vowel\r
+025E LATIN SMALL LETTER CLOSED REVERSED OPEN E\r
+ = LATIN SMALL LETTER CLOSED REVERSED EPSILON\r
+ * lower-mid central rounded vowel\r
+025F LATIN SMALL LETTER DOTLESS J WITH STROKE\r
+ * voiced palatal stop\r
+ * typographically a turned f, but better thought of as a form of j\r
+ * "gy" in Hungarian orthography\r
+ * also archaic phonetic for palatoalveolar affricate 02A4\r
+0260 LATIN SMALL LETTER G WITH HOOK\r
+ * implosive velar stop\r
+ x (latin capital letter g with hook - 0193)\r
+0261 LATIN SMALL LETTER SCRIPT G\r
+ * voiced velar stop\r
+ x (latin small letter g - 0067)\r
+0262 LATIN LETTER SMALL CAPITAL G\r
+ * voiced uvular stop\r
+0263 LATIN SMALL LETTER GAMMA\r
+ * voiced velar fricative\r
+ x (latin capital letter gamma - 0194)\r
+ x (greek small letter gamma - 03B3)\r
+0264 LATIN SMALL LETTER RAMS HORN\r
+ = LATIN SMALL LETTER BABY GAMMA\r
+ * upper-mid back unrounded vowel\r
+0265 LATIN SMALL LETTER TURNED H\r
+ * voiced rounded palatal approximant\r
+0266 LATIN SMALL LETTER H WITH HOOK\r
+ * breathy-voiced glottal fricative\r
+ x (modifier letter small h with hook - 02B1)\r
+0267 LATIN SMALL LETTER HENG WITH HOOK\r
+ * voiceless coarticulated velar and palatoalveolar fricative\r
+ * "tj" or "kj" or "sj" in some Swedish dialects\r
+0268 LATIN SMALL LETTER I WITH STROKE\r
+ = barred i, i bar\r
+ * high central unrounded vowel\r
+ * ISO 6438 gives lowercase of 0197 as 026A, not 0268\r
+0269 LATIN SMALL LETTER IOTA\r
+ * semi-high front unrounded vowel\r
+@+ * obsoleted by IPA in 1989\r
+ * preferred use is 026A LATIN LETTER SMALL CAPITAL I\r
+ x (latin capital letter iota - 0196)\r
+ x (greek small letter iota - 03B9)\r
+026A LATIN LETTER SMALL CAPITAL I\r
+ * semi-high front unrounded vowel\r
+ * preferred IPA alternate for 0269\r
+ x (latin capital letter i with stroke - 0197)\r
+026B LATIN SMALL LETTER L WITH MIDDLE TILDE\r
+ * velarized voiced alveolar lateral approximant\r
+026C LATIN SMALL LETTER L WITH BELT\r
+ * voiceless alveolar lateral fricative\r
+026D LATIN SMALL LETTER L WITH RETROFLEX HOOK\r
+ * voiced retroflex lateral\r
+026E LATIN SMALL LETTER LEZH\r
+ * voiced lateral fricative\r
+ * "dhl" in Zulu orthography\r
+026F LATIN SMALL LETTER TURNED M\r
+ * high back unrounded vowel\r
+ x (latin capital letter turned m - 019C)\r
+0270 LATIN SMALL LETTER TURNED M WITH LONG LEG\r
+ * voiced velar approximant\r
+0271 LATIN SMALL LETTER M WITH HOOK\r
+ * voiced labiodental nasal\r
+0272 LATIN SMALL LETTER N WITH LEFT HOOK\r
+ * voiced palatal nasal\r
+ x (latin capital letter n with left hook - 019D)\r
+0273 LATIN SMALL LETTER N WITH RETROFLEX HOOK\r
+ * voiced retroflex nasal\r
+0274 LATIN LETTER SMALL CAPITAL N\r
+ * voiced uvular nasal\r
+0275 LATIN SMALL LETTER BARRED O\r
+ = o bar\r
+ * rounded mid-central vowel, i.e. rounded schwa\r
+ * uppercase is 019F\r
+ x (greek small letter theta - 03B8)\r
+ x (cyrillic small letter fita - 0473)\r
+ x (cyrillic small letter barred o - 04E9)\r
+0276 LATIN LETTER SMALL CAPITAL OE\r
+ * low front rounded vowel\r
+ x (latin small ligature oe - 0153)\r
+0277 LATIN SMALL LETTER CLOSED OMEGA\r
+ * semi-high back rounded vowel\r
+@+ * obsoleted by IPA in 1989\r
+ * preferred use is 028A latin small letter upsilon\r
+0278 LATIN SMALL LETTER PHI\r
+ * voiceless bilabial fricative\r
+ x (greek small letter phi - 03C6)\r
+0279 LATIN SMALL LETTER TURNED R\r
+ * voiced alveolar approximant\r
+ x (modifier letter small turned r - 02B4)\r
+027A LATIN SMALL LETTER TURNED R WITH LONG LEG\r
+ * voiced lateral flap\r
+027B LATIN SMALL LETTER TURNED R WITH HOOK\r
+ * voiced retroflex approximant\r
+ x (modifier letter small turned r with hook - 02B5)\r
+027C LATIN SMALL LETTER R WITH LONG LEG\r
+ * voiced strident apico-alveolar trill\r
+@+ * obsoleted by IPA in 1989\r
+ * sound spelled with 0159 in Czech\r
+ * preferred phonetic representation for Czech is 0072 031D\r
+ * in current use in Gaelic types (as glyph variant of 0072)\r
+027D LATIN SMALL LETTER R WITH TAIL\r
+ * voiced retroflex flap\r
+027E LATIN SMALL LETTER R WITH FISHHOOK\r
+ * voiced alveolar flap or tap\r
+027F LATIN SMALL LETTER REVERSED R WITH FISHHOOK\r
+ * apical dental vowel\r
+ * used in Sinological tradition\r
+ * IPA spelling - 007A 0329\r
+0280 LATIN LETTER SMALL CAPITAL R *\r
+ * voiced uvular trill\r
+ * Germanic, Old Norse\r
+ * uppercase is 01A6\r
+0281 LATIN LETTER SMALL CAPITAL INVERTED R\r
+ * voiced uvular fricative or approximant\r
+ x (modifier letter small capital inverted r - 02B6)\r
+0282 LATIN SMALL LETTER S WITH HOOK\r
+ * voiceless retroflex fricative\r
+0283 LATIN SMALL LETTER ESH\r
+ * voiceless postalveolar fricative\r
+ x (latin capital letter esh - 01A9)\r
+ x (integral - 222B)\r
+0284 LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK\r
+ * implosive palatal stop\r
+ * typographically based on 025F, not on 0283\r
+0285 LATIN SMALL LETTER SQUAT REVERSED ESH\r
+ * apical retroflex vowel\r
+ * used in Sinological tradition\r
+ * IPA spelling - 0290 0329\r
+0286 LATIN SMALL LETTER ESH WITH CURL\r
+ * palatalized voiceless postalveolar fricative\r
+ * suggested spelling - 0283 02B2\r
+0287 LATIN SMALL LETTER TURNED T\r
+ * dental click (sound of "tsk tsk")\r
+ x (latin letter dental click - 01C0)\r
+0288 LATIN SMALL LETTER T WITH RETROFLEX HOOK\r
+ * voiceless retroflex stop\r
+ x (latin capital letter t with retroflex hook - 01AE)\r
+0289 LATIN SMALL LETTER U BAR\r
+ * high central rounded vowel\r
+028A LATIN SMALL LETTER UPSILON\r
+ * semi-high back rounded vowel\r
+ * preferred IPA alternate to 0277\r
+ x (latin capital letter upsilon - 01B1)\r
+ x (greek small letter upsilon - 03C5)\r
+028B LATIN SMALL LETTER V WITH HOOK\r
+ = LATIN SMALL LETTER SCRIPT V\r
+ * voiced labiodental approximant\r
+ x (latin capital letter v with hook - 01B2)\r
+ x (greek small letter upsilon - 03C5)\r
+028C LATIN SMALL LETTER TURNED V\r
+ = caret, wedge\r
+ * lower-mid back unrounded vowel\r
+ x (greek capital letter lamda - 039B)\r
+ x (caret - 2038)\r
+ x (logical and - 2227)\r
+028D LATIN SMALL LETTER TURNED W\r
+ * voiceless rounded labiovelar approximant\r
+028E LATIN SMALL LETTER TURNED Y\r
+ * voiced lateral approximant\r
+028F LATIN LETTER SMALL CAPITAL Y\r
+ * semi-high front rounded vowel\r
+0290 LATIN SMALL LETTER Z WITH RETROFLEX HOOK\r
+ * voiced retroflex fricative\r
+0291 LATIN SMALL LETTER Z WITH CURL\r
+ * voiced alveolo-palatal laminal fricative\r
+ * sound spelled with 017A in Polish\r
+0292 LATIN SMALL LETTER EZH\r
+ = LATIN SMALL LETTER YOGH\r
+ = dram\r
+ * voiced postalveolar fricative\r
+ * uppercase is 01B7\r
+ * Skolt Sámi\r
+ x (latin small letter yogh - 021D)\r
+ x (cyrillic small letter abkhasian dze - 04E1)\r
+ x (ounce sign - 2125)\r
+0293 LATIN SMALL LETTER EZH WITH CURL\r
+ * palatalized voiced postalveolar fricative\r
+0294 LATIN LETTER GLOTTAL STOP\r
+ x (modifier letter glottal stop - 02C0)\r
+0295 LATIN LETTER PHARYNGEAL VOICED FRICATIVE\r
+ = LATIN LETTER REVERSED GLOTTAL STOP\r
+ * voiced pharyngeal fricative\r
+ * ain\r
+ x (latin small letter ezh reversed - 01B9)\r
+ x (modifier letter reversed glottal stop - 02C1)\r
+0296 LATIN LETTER INVERTED GLOTTAL STOP\r
+ * lateral click\r
+ x (latin letter lateral click - 01C1)\r
+0297 LATIN LETTER STRETCHED C\r
+ * palatal (or alveolar) click\r
+ x (latin letter retroflex click - 01C3)\r
+ x (complement - 2201)\r
+0298 LATIN LETTER BILABIAL CLICK\r
+ = LATIN LETTER BULLSEYE\r
+ x (circled dot operator - 2299)\r
+0299 LATIN LETTER SMALL CAPITAL B\r
+ * bilabial trill\r
+029A LATIN SMALL LETTER CLOSED OPEN E\r
+ = LATIN SMALL LETTER CLOSED EPSILON\r
+ * lower-mid front rounded vowel\r
+ * non-IPA alternate for the preferred 0153\r
+029B LATIN LETTER SMALL CAPITAL G WITH HOOK\r
+ * voiced uvular implosive\r
+029C LATIN LETTER SMALL CAPITAL H\r
+ * voiceless epiglottal fricative\r
+029D LATIN SMALL LETTER J WITH CROSSED-TAIL\r
+ * voiced palatal fricative\r
+029E LATIN SMALL LETTER TURNED K\r
+ * proposed for velar click\r
+@+ * withdrawn by IPA in 1970\r
+029F LATIN LETTER SMALL CAPITAL L\r
+ * velar lateral approximant\r
+02A0 LATIN SMALL LETTER Q WITH HOOK\r
+ * voiceless uvular implosive\r
+02A1 LATIN LETTER GLOTTAL STOP WITH STROKE\r
+ * voiced epiglottal stop\r
+02A2 LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE\r
+ * voiced epiglottal fricative\r
+02A3 LATIN SMALL LETTER DZ DIGRAPH\r
+ * voiced dental affricate\r
+02A4 LATIN SMALL LETTER DEZH DIGRAPH\r
+ * voiced postalveolar affricate\r
+02A5 LATIN SMALL LETTER DZ DIGRAPH WITH CURL\r
+ * voiced alveolo-palatal affricate\r
+02A6 LATIN SMALL LETTER TS DIGRAPH\r
+ * voiceless dental affricate\r
+02A7 LATIN SMALL LETTER TESH DIGRAPH\r
+ * voiceless postalveolar affricate\r
+02A8 LATIN SMALL LETTER TC DIGRAPH WITH CURL\r
+ * voiceless alveolo-palatal affricate\r
+@ IPA characters for disordered speech\r
+02A9 LATIN SMALL LETTER FENG DIGRAPH\r
+ * velopharyngeal fricative\r
+02AA LATIN SMALL LETTER LS DIGRAPH\r
+ * lateral alveolar fricative (lisp)\r
+02AB LATIN SMALL LETTER LZ DIGRAPH\r
+ * voiced lateral alveolar fricative\r
+02AC LATIN LETTER BILABIAL PERCUSSIVE\r
+ * audible lip smack\r
+02AD LATIN LETTER BIDENTAL PERCUSSIVE\r
+ * audible teeth gnashing\r
+@@ 02B0 Spacing Modifier Letters 02FF\r
+@ Phonetic modifiers derived from Latin letters\r
+02B0 MODIFIER LETTER SMALL H\r
+ * aspiration\r
+ # <super> 0068\r
+02B1 MODIFIER LETTER SMALL H WITH HOOK\r
+ * breathy voiced, murmured\r
+ x (latin small letter h with hook - 0266)\r
+ x (combining diaeresis below - 0324)\r
+ # <super> 0266\r
+02B2 MODIFIER LETTER SMALL J\r
+ * palatalization\r
+ x (combining palatalized hook below - 0321)\r
+ # <super> 006A\r
+02B3 MODIFIER LETTER SMALL R\r
+ # <super> 0072\r
+02B4 MODIFIER LETTER SMALL TURNED R\r
+ x (latin small letter turned r - 0279)\r
+ # <super> 0279\r
+02B5 MODIFIER LETTER SMALL TURNED R WITH HOOK\r
+ x (latin small letter turned r with hook - 027B)\r
+ # <super> 027B\r
+02B6 MODIFIER LETTER SMALL CAPITAL INVERTED R\r
+ * preceding four used for r-coloring or r-offglides\r
+ x (latin letter small capital inverted r - 0281)\r
+ # <super> 0281\r
+02B7 MODIFIER LETTER SMALL W\r
+ * labialization\r
+ x (combining inverted double arch below - 032B)\r
+ # <super> 0077\r
+02B8 MODIFIER LETTER SMALL Y\r
+ * palatalization\r
+ * common Americanist substitution for 02B2\r
+ # <super> 0079\r
+@ Miscellaneous phonetic modifiers\r
+02B9 MODIFIER LETTER PRIME\r
+ * primary stress, emphasis\r
+ * transliteration of mjagkij znak (Cyrillic soft sign: palatalization)\r
+ x (apostrophe - 0027)\r
+ x (acute accent - 00B4)\r
+ x (modifier letter acute accent - 02CA)\r
+ x (combining acute accent - 0301)\r
+ x (greek numeral sign - 0374)\r
+ x (prime - 2032)\r
+02BA MODIFIER LETTER DOUBLE PRIME\r
+ * exaggerated stress, contrastive stress\r
+ * transliteration of tverdyj znak (Cyrillic hard sign: no palatalization)\r
+ x (quotation mark - 0022)\r
+ x (combining double acute accent - 030B)\r
+ x (double prime - 2033)\r
+02BB MODIFIER LETTER TURNED COMMA\r
+ * typographical alternate for 02BD or 02BF\r
+ x (combining turned comma above - 0312)\r
+ x (left single quotation mark - 2018)\r
+02BC MODIFIER LETTER APOSTROPHE\r
+ = apostrophe\r
+ * glottal stop, glottalization, ejective\r
+ * spacing clone of Greek smooth breathing mark\r
+ * many languages use this as a letter of their alphabets\r
+ x (apostrophe - 0027)\r
+ x (combining comma above - 0313)\r
+ x (combining comma above right - 0315)\r
+ x (armenian apostrophe - 055A)\r
+ x (right single quotation mark - 2019)\r
+02BD MODIFIER LETTER REVERSED COMMA\r
+ * weak aspiration\r
+ * spacing clone of Greek rough breathing mark\r
+ x (combining reversed comma above - 0314)\r
+ x (armenian modifier letter left half ring - 0559)\r
+ x (single high-reversed-9 quotation mark - 201B)\r
+02BE MODIFIER LETTER RIGHT HALF RING\r
+ * transliteration of Arabic hamza (glottal stop)\r
+ x (armenian apostrophe - 055A)\r
+ x (arabic letter hamza - 0621)\r
+02BF MODIFIER LETTER LEFT HALF RING\r
+ * transliteration of Arabic ain (voiced pharyngeal fricative)\r
+ x (armenian modifier letter left half ring - 0559)\r
+ x (arabic letter ain - 0639)\r
+02C0 MODIFIER LETTER GLOTTAL STOP\r
+ * ejective or glottalized\r
+ * typographical alternate for 02BC or 02BE\r
+ x (latin letter glottal stop - 0294)\r
+ x (combining hook above - 0309)\r
+02C1 MODIFIER LETTER REVERSED GLOTTAL STOP\r
+ * typographical alternate for 02BF\r
+ x (latin letter pharyngeal voiced fricative - 0295)\r
+02C2 MODIFIER LETTER LEFT ARROWHEAD\r
+ * fronted articulation\r
+02C3 MODIFIER LETTER RIGHT ARROWHEAD\r
+ * backed articulation\r
+02C4 MODIFIER LETTER UP ARROWHEAD\r
+ * raised articulation\r
+ x (circumflex accent - 005E)\r
+ x (up arrowhead - 2303)\r
+02C5 MODIFIER LETTER DOWN ARROWHEAD\r
+ * lowered articulation\r
+02C6 MODIFIER LETTER CIRCUMFLEX ACCENT\r
+ * rising-falling tone, falling tone, secondary stress, etc.\r
+ x (circumflex accent - 005E)\r
+ x (combining circumflex accent - 0302)\r
+02C7 CARON (Mandarin Chinese third tone)\r
+ = hacek\r
+ * falling-rising tone\r
+ * Mandarin Chinese third tone\r
+ x (combining caron - 030C)\r
+02C8 MODIFIER LETTER VERTICAL LINE\r
+ * primary stress, downstep\r
+ * precedes letter or syllable modified\r
+ x (apostrophe - 0027)\r
+ x (combining vertical line above - 030D)\r
+02C9 MODIFIER LETTER MACRON (Mandarin Chinese first tone)\r
+ * high level tone\r
+ * precedes or follows letter or syllable modified\r
+ * Mandarin Chinese first tone\r
+ x (macron - 00AF)\r
+ x (combining macron - 0304)\r
+02CA MODIFIER LETTER ACUTE ACCENT (Mandarin Chinese second tone)\r
+ * high-rising tone (IPA), high tone, primary stress\r
+ * Mandarin Chinese second tone\r
+ x (acute accent - 00B4)\r
+ x (modifier letter prime - 02B9)\r
+ x (combining acute accent - 0301)\r
+ x (greek numeral sign - 0374)\r
+ x (armenian emphasis mark - 055B)\r
+02CB MODIFIER LETTER GRAVE ACCENT (Mandarin Chinese fourth tone)\r
+ * high-falling tone (IPA), low tone, secondary or tertiary stress\r
+ * Mandarin Chinese fourth tone\r
+ x (grave accent - 0060)\r
+ x (combining grave accent - 0300)\r
+ x (armenian comma - 055D)\r
+02CC MODIFIER LETTER LOW VERTICAL LINE\r
+ * secondary stress\r
+ * precedes letter or syllable modified\r
+ x (combining vertical line below - 0329)\r
+02CD MODIFIER LETTER LOW MACRON\r
+ * low level tone\r
+ x (low line - 005F)\r
+ x (combining macron below - 0331)\r
+02CE MODIFIER LETTER LOW GRAVE ACCENT\r
+ * low-falling tone\r
+02CF MODIFIER LETTER LOW ACUTE ACCENT\r
+ * low-rising tone\r
+ x (greek lower numeral sign - 0375)\r
+02D0 MODIFIER LETTER TRIANGULAR COLON\r
+ * length mark\r
+ x (colon - 003A)\r
+02D1 MODIFIER LETTER HALF TRIANGULAR COLON\r
+ * half-length mark\r
+ x (middle dot - 00B7)\r
+02D2 MODIFIER LETTER CENTRED RIGHT HALF RING\r
+ * more rounded articulation\r
+02D3 MODIFIER LETTER CENTRED LEFT HALF RING\r
+ * less rounded articulation\r
+02D4 MODIFIER LETTER UP TACK\r
+ * vowel raising or closing\r
+ x (combining up tack below - 031D)\r
+ x (combining dot below - 0323)\r
+02D5 MODIFIER LETTER DOWN TACK\r
+ * vowel lowering or opening\r
+ x (combining left half ring below - 031C)\r
+ x (combining down tack below - 031E)\r
+02D6 MODIFIER LETTER PLUS SIGN\r
+ * advanced or fronted articulation\r
+ x (combining plus sign below - 031F)\r
+02D7 MODIFIER LETTER MINUS SIGN\r
+ * retracted or backed articulation\r
+ * glyph may have small end-serifs\r
+ x (combining minus sign below - 0320)\r
+@ Spacing clones of diacritics\r
+02D8 BREVE\r
+ x (combining breve - 0306)\r
+ # 0020 0306\r
+02D9 DOT ABOVE (Mandarin Chinese light tone)\r
+ * Mandarin Chinese fifth tone (light or neutral)\r
+ x (combining dot above - 0307)\r
+ # 0020 0307\r
+02DA RING ABOVE\r
+ x (degree sign - 00B0)\r
+ x (combining ring above - 030A)\r
+ # 0020 030A\r
+02DB OGONEK\r
+ x (combining ogonek - 0328)\r
+ # 0020 0328\r
+02DC SMALL TILDE\r
+ x (tilde - 007E)\r
+ x (combining tilde - 0303)\r
+ x (tilde operator - 223C)\r
+ # 0020 0303\r
+02DD DOUBLE ACUTE ACCENT\r
+ x (combining double acute accent - 030B)\r
+ # 0020 030B\r
+@ Additions based on 1989 IPA\r
+02DE MODIFIER LETTER RHOTIC HOOK\r
+ * rhotacization in vowel\r
+ * often ligated: 025A = 0259 + 02DE; 025D = 025C + 02DE\r
+02DF MODIFIER LETTER CROSS ACCENT\r
+ * Swedish grave accent\r
+02E0 MODIFIER LETTER SMALL GAMMA\r
+ * these modifier letters are occasionally used in transcription of affricates\r
+ # <super> 0263\r
+02E1 MODIFIER LETTER SMALL L\r
+ # <super> 006C\r
+02E2 MODIFIER LETTER SMALL S\r
+ # <super> 0073\r
+02E3 MODIFIER LETTER SMALL X\r
+ # <super> 0078\r
+02E4 MODIFIER LETTER SMALL REVERSED GLOTTAL STOP\r
+ # <super> 0295\r
+@ Tone letters\r
+02E5 MODIFIER LETTER EXTRA-HIGH TONE BAR\r
+02E6 MODIFIER LETTER HIGH TONE BAR\r
+02E7 MODIFIER LETTER MID TONE BAR\r
+02E8 MODIFIER LETTER LOW TONE BAR\r
+02E9 MODIFIER LETTER EXTRA-LOW TONE BAR\r
+02EA MODIFIER LETTER YIN DEPARTING TONE MARK\r
+02EB MODIFIER LETTER YANG DEPARTING TONE MARK\r
+@ IPA modifiers\r
+02EC MODIFIER LETTER VOICING\r
+02ED MODIFIER LETTER UNASPIRATED\r
+@ Other modifier letters\r
+02EE MODIFIER LETTER DOUBLE APOSTROPHE\r
+\r
+2000 EN QUAD\r
+ : 2002 en space\r
+2001 EM QUAD\r
+ = mutton quad\r
+ : 2003 em space\r
+2002 EN SPACE\r
+ = nut\r
+ * half an em\r
+ # 0020 space\r
+2003 EM SPACE\r
+ = mutton\r
+ * nominally, a space equal to the type size in points\r
+ * may scale by the condensation factor of a font\r
+ # 0020 space\r
+2004 THREE-PER-EM SPACE\r
+ = thick space\r
+ # 0020 space\r
+2005 FOUR-PER-EM SPACE\r
+ = mid space\r
+ # 0020 space\r
+2006 SIX-PER-EM SPACE\r
+ * in computer typography sometimes equated to thin space\r
+ # 0020 space\r
+2007 FIGURE SPACE\r
+ * space equal to tabular width of a font\r
+ * this is equivalent to the digit width of fonts with fixed-width digits\r
+ # <noBreak> 0020\r
+2008 PUNCTUATION SPACE\r
+ * space equal to narrow punctuation of a font\r
+ # 0020 space\r
+2009 THIN SPACE\r
+ * a fifth of an em (or sometimes a sixth)\r
+ # 0020 space\r
+200A HAIR SPACE\r
+ * thinner than a thin space\r
+ * in traditional typography, the thinnest space available\r
+ # 0020 space\r
+200B ZERO WIDTH SPACE\r
+ * nominally zero width, but may expand in justification\r
+@ Formatting characters\r
+200C ZERO WIDTH NON-JOINER\r
+ = ZWNJ\r
+200D ZERO WIDTH JOINER\r
+ = ZWJ\r
+200E LEFT-TO-RIGHT MARK\r
+ = LRM\r
+200F RIGHT-TO-LEFT MARK\r
+ = RLM\r
+@ Dashes\r
+2010 HYPHEN\r
+ x (hyphen-minus - 002D)\r
+2011 NON-BREAKING HYPHEN\r
+ x (hyphen-minus - 002D)\r
+ # <noBreak> 2010\r
+2012 FIGURE DASH\r
+2013 EN DASH\r
+2014 EM DASH\r
+ * may be used in pairs to offset parenthetical text\r
+ x (katakana-hiragana prolonged sound mark - 30FC)\r
+2015 HORIZONTAL BAR\r
+ = QUOTATION DASH\r
+ * long dash introducing quoted text\r
+@ General punctuation\r
+2016 DOUBLE VERTICAL LINE\r
+ * used in pairs to indicate norm of a matrix\r
+ x (parallel to - 2225)\r
+2017 DOUBLE LOW LINE\r
+ * this is a spacing character\r
+ x (low line - 005F)\r
+ x (combining double low line - 0333)\r
+ # 0020 0333\r
+2018 LEFT SINGLE QUOTATION MARK\r
+ = SINGLE TURNED COMMA QUOTATION MARK\r
+ * this is the preferred glyph (as opposed to 201B)\r
+ x (apostrophe - 0027)\r
+ x (modifier letter turned comma - 02BB)\r
+ x (heavy single turned comma quotation mark ornament - 275B)\r
+2019 RIGHT SINGLE QUOTATION MARK\r
+ = SINGLE COMMA QUOTATION MARK\r
+ * this is the preferred character to use for apostrophe\r
+ x (apostrophe - 0027)\r
+ x (modifier letter apostrophe - 02BC)\r
+ x (heavy single comma quotation mark ornament - 275C)\r
+201A SINGLE LOW-9 QUOTATION MARK\r
+ = LOW SINGLE COMMA QUOTATION MARK\r
+ * used as opening single quotation mark in some languages\r
+201B SINGLE HIGH-REVERSED-9 QUOTATION MARK\r
+ = SINGLE REVERSED COMMA QUOTATION MARK\r
+ * glyph variant of 2018\r
+ x (modifier letter reversed comma - 02BD)\r
+201C LEFT DOUBLE QUOTATION MARK\r
+ = DOUBLE TURNED COMMA QUOTATION MARK\r
+ * this is the preferred glyph (as opposed to 201F)\r
+ x (quotation mark - 0022)\r
+ x (heavy double turned comma quotation mark ornament - 275D)\r
+ x (reversed double prime quotation mark - 301D)\r
+201D RIGHT DOUBLE QUOTATION MARK\r
+ = DOUBLE COMMA QUOTATION MARK\r
+ x (quotation mark - 0022)\r
+ x (double prime - 2033)\r
+ x (heavy double comma quotation mark ornament - 275E)\r
+ x (double prime quotation mark - 301E)\r
+201E DOUBLE LOW-9 QUOTATION MARK\r
+ = LOW DOUBLE COMMA QUOTATION MARK\r
+ * used as opening double quotation mark in some languages\r
+ x (low double prime quotation mark - 301F)\r
+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK\r
+ = DOUBLE REVERSED COMMA QUOTATION MARK\r
+ * glyph variant of 201C\r
+2020 DAGGER\r
+ = obelisk, obelus, long cross\r
+2021 DOUBLE DAGGER\r
+ = diesis, double obelisk\r
+2022 BULLET\r
+ = black small circle\r
+ x (middle dot - 00B7)\r
+ x (one dot leader - 2024)\r
+ x (bullet operator - 2219)\r
+ x (inverse bullet - 25D8)\r
+ x (white bullet - 25E6)\r
+2023 TRIANGULAR BULLET\r
+ x (end of proof - 220E)\r
+ x (black right-pointing small triangle - 25B8)\r
+2024 ONE DOT LEADER\r
+ x (middle dot - 00B7)\r
+ x (bullet - 2022)\r
+ x (bullet operator - 2219)\r
+ # 002E full stop\r
+2025 TWO DOT LEADER\r
+ # 002E 002E\r
+2026 HORIZONTAL ELLIPSIS\r
+ = three dot leader\r
+ x (vertical ellipsis - 22EE)\r
+ # 002E 002E 002E\r
+2027 HYPHENATION POINT\r
+@ Formatting characters\r
+2028 LINE SEPARATOR\r
+ * may be used to represent this semantic unambiguously\r
+2029 PARAGRAPH SEPARATOR\r
+ * may be used to represent this semantic unambiguously\r
+202A LEFT-TO-RIGHT EMBEDDING\r
+ = LRE\r
+202B RIGHT-TO-LEFT EMBEDDING\r
+ = RLE\r
+202C POP DIRECTIONAL FORMATTING\r
+ = PDF\r
+202D LEFT-TO-RIGHT OVERRIDE\r
+ = LRO\r
+202E RIGHT-TO-LEFT OVERRIDE\r
+ = RLO\r
+202F NARROW NO-BREAK SPACE\r
+ x (no-break space - 00A0)\r
+ # <noBreak> 0020\r
+@ General punctuation\r
+2030 PER MILLE SIGN\r
+ x (percent sign - 0025)\r
+2031 PER TEN THOUSAND SIGN\r
+ x (percent sign - 0025)\r
+2032 PRIME\r
+ = minutes, feet\r
+ x (apostrophe - 0027)\r
+ x (acute accent - 00B4)\r
+ x (modifier letter prime - 02B9)\r
+2033 DOUBLE PRIME\r
+ = seconds, inches\r
+ x (quotation mark - 0022)\r
+ x (modifier letter double prime - 02BA)\r
+ x (right double quotation mark - 201D)\r
+ x (ditto mark - 3003)\r
+ x (double prime quotation mark - 301E)\r
+ # 2032 2032\r
+2034 TRIPLE PRIME\r
+ # 2032 2032 2032\r
+2035 REVERSED PRIME\r
+ x (grave accent - 0060)\r
+2036 REVERSED DOUBLE PRIME\r
+ x (reversed double prime quotation mark - 301D)\r
+ # 2035 2035\r
+2037 REVERSED TRIPLE PRIME\r
+ # 2035 2035 2035\r
+2038 CARET\r
+ x (up arrowhead - 2303)\r
+2039 SINGLE LEFT-POINTING ANGLE QUOTATION MARK\r
+ = LEFT POINTING SINGLE GUILLEMET\r
+ * usually opening, sometimes closing\r
+ x (less-than sign - 003C)\r
+ x (left-pointing angle bracket - 2329)\r
+ x (left angle bracket - 3008)\r
+203A SINGLE RIGHT-POINTING ANGLE QUOTATION MARK\r
+ = RIGHT POINTING SINGLE GUILLEMET\r
+ * usually closing, sometimes opening\r
+ x (greater-than sign - 003E)\r
+ x (right-pointing angle bracket - 232A)\r
+ x (right angle bracket - 3009)\r
+203B REFERENCE MARK\r
+ = Japanese kome\r
+ = Urdu paragraph separator\r
+ x (tibetan ku ru kha bzhi mig can - 0FBF)\r
+203C DOUBLE EXCLAMATION MARK\r
+ x (exclamation mark - 0021)\r
+ # 0021 0021\r
+203D INTERROBANG\r
+ x (exclamation mark - 0021)\r
+ x (question mark - 003F)\r
+203E OVERLINE\r
+ = SPACING OVERSCORE\r
+ # 0020 0305\r
+203F UNDERTIE (Enotikon)\r
+ = Greek enotikon\r
+ x (smile - 2323)\r
+2040 CHARACTER TIE\r
+ x (frown - 2322)\r
+2041 CARET INSERTION POINT\r
+ * proofreader's mark: insert here\r
+ x (right semidirect product - 22CC)\r
+2042 ASTERISM\r
+2043 HYPHEN BULLET\r
+2044 FRACTION SLASH\r
+ = solidus (in typography)\r
+ * for composing arbitrary fractions\r
+ x (solidus - 002F)\r
+ x (division slash - 2215)\r
+2045 LEFT SQUARE BRACKET WITH QUILL\r
+2046 RIGHT SQUARE BRACKET WITH QUILL\r
+2048 QUESTION EXCLAMATION MARK\r
+ * designed for use in vertical text\r
+ # 003F 0021\r
+2049 EXCLAMATION QUESTION MARK\r
+ * designed for use in vertical text\r
+ # 0021 003F\r
+204A TIRONIAN SIGN ET\r
+ * Irish Gaelic, ...\r
+204B REVERSED PILCROW SIGN\r
+ x (pilcrow sign - 00B6)\r
+204C BLACK LEFTWARDS BULLET\r
+204D BLACK RIGHTWARDS BULLET\r
+@ Deprecated\r
+206A INHIBIT SYMMETRIC SWAPPING\r
+206B ACTIVATE SYMMETRIC SWAPPING\r
+206C INHIBIT ARABIC FORM SHAPING\r
+206D ACTIVATE ARABIC FORM SHAPING\r
+206E NATIONAL DIGIT SHAPES\r
+206F NOMINAL DIGIT SHAPES\r
+@@ 2070 Superscripts and Subscripts 209F\r
+@ Superscripts\r
+2070 SUPERSCRIPT ZERO\r
+ # <super> 0030\r
+2071 <reserved>\r
+ x (superscript one - 00B9)\r
+2072 <reserved>\r
+ x (superscript two - 00B2)\r
+2073 <reserved>\r
+ x (superscript three - 00B3)\r
+2074 SUPERSCRIPT FOUR\r
+ # <super> 0034\r
+2075 SUPERSCRIPT FIVE\r
+ # <super> 0035\r
+2076 SUPERSCRIPT SIX\r
+ # <super> 0036\r
+2077 SUPERSCRIPT SEVEN\r
+ # <super> 0037\r
+2078 SUPERSCRIPT EIGHT\r
+ # <super> 0038\r
+2079 SUPERSCRIPT NINE\r
+ # <super> 0039\r
+207A SUPERSCRIPT PLUS SIGN\r
+ # <super> 002B\r
+207B SUPERSCRIPT MINUS\r
+ # <super> 2212\r
+207C SUPERSCRIPT EQUALS SIGN\r
+ # <super> 003D\r
+207D SUPERSCRIPT LEFT PARENTHESIS\r
+ # <super> 0028\r
+207E SUPERSCRIPT RIGHT PARENTHESIS\r
+ # <super> 0029\r
+207F SUPERSCRIPT LATIN SMALL LETTER N\r
+ # <super> 006E\r
+@ Subscripts\r
+2080 SUBSCRIPT ZERO\r
+ # <sub> 0030\r
+2081 SUBSCRIPT ONE\r
+ # <sub> 0031\r
+2082 SUBSCRIPT TWO\r
+ # <sub> 0032\r
+2083 SUBSCRIPT THREE\r
+ # <sub> 0033\r
+2084 SUBSCRIPT FOUR\r
+ # <sub> 0034\r
+2085 SUBSCRIPT FIVE\r
+ # <sub> 0035\r
+2086 SUBSCRIPT SIX\r
+ # <sub> 0036\r
+2087 SUBSCRIPT SEVEN\r
+ # <sub> 0037\r
+2088 SUBSCRIPT EIGHT\r
+ # <sub> 0038\r
+2089 SUBSCRIPT NINE\r
+ # <sub> 0039\r
+208A SUBSCRIPT PLUS SIGN\r
+ # <sub> 002B\r
+208B SUBSCRIPT MINUS\r
+ # <sub> 2212\r
+208C SUBSCRIPT EQUALS SIGN\r
+ # <sub> 003D\r
+208D SUBSCRIPT LEFT PARENTHESIS\r
+ # <sub> 0028\r
+208E SUBSCRIPT RIGHT PARENTHESIS\r
+ # <sub> 0029\r
+@@ 20A0 Currency Symbols 20CF\r
+@ Currency symbols\r
+@+ A number of currency symbols are found in other blocks.\r
+ x (dollar sign - 0024)\r
+ x (cent sign - 00A2)\r
+ x (pound sign - 00A3)\r
+ x (currency sign - 00A4)\r
+ x (yen sign - 00A5)\r
+ x (bengali rupee mark - 09F2)\r
+ x (bengali rupee sign - 09F3)\r
+ x (thai currency symbol baht - 0E3F)\r
+ x (khmer currency symbol riel - 17DB)\r
+20A0 EURO-CURRENCY SIGN\r
+ * intended for ECU, but not widely used\r
+ * historical character, this is NOT the euro!\r
+ x (euro sign - 20AC)\r
+20A1 COLON SIGN\r
+ * Costa Rica, El Salvador\r
+20A2 CRUZEIRO SIGN\r
+ * Brazil\r
+20A3 FRENCH FRANC SIGN\r
+ * France\r
+20A4 LIRA SIGN\r
+ * Italy, Turkey\r
+ x (pound sign - 00A3)\r
+20A5 MILL SIGN\r
+ * USA (1/10 cent)\r
+20A6 NAIRA SIGN\r
+ * Nigeria\r
+20A7 PESETA SIGN\r
+ * Spain\r
+20A8 RUPEE SIGN\r
+ * India\r
+ # 0052 0073\r
+20A9 WON SIGN\r
+ * Korea\r
+20AA NEW SHEQEL SIGN\r
+ * Israel\r
+20AB DONG SIGN\r
+ * Vietnam\r
+20AC EURO SIGN\r
+ * currency sign for the European Monetary Union\r
+ * euro, not ECU\r
+ x (euro-currency sign - 20A0)\r
+20AD KIP SIGN\r
+ * Laos\r
+20AE TUGRIK SIGN\r
+ * Mongolia\r
+ * also transliterated as tugrug, tugric, tugrog, togrog\r
+20AF DRACHMA SIGN\r
+ * Greece\r
+@@ 20D0 Combining Diacritical Marks for Symbols 20FF\r
+@ Combining diacritical marks for symbols\r
+20D0 COMBINING LEFT HARPOON ABOVE\r
+20D1 COMBINING RIGHT HARPOON ABOVE\r
+ * vector\r
+20D2 COMBINING LONG VERTICAL LINE OVERLAY\r
+20D3 COMBINING SHORT VERTICAL LINE OVERLAY\r
+ * negation\r
+20D4 COMBINING ANTICLOCKWISE ARROW ABOVE\r
+20D5 COMBINING CLOCKWISE ARROW ABOVE\r
+ * rotation\r
+20D6 COMBINING LEFT ARROW ABOVE\r
+20D7 COMBINING RIGHT ARROW ABOVE\r
+ * vector\r
+20D8 COMBINING RING OVERLAY\r
+20D9 COMBINING CLOCKWISE RING OVERLAY\r
+20DA COMBINING ANTICLOCKWISE RING OVERLAY\r
+20DB COMBINING THREE DOTS ABOVE\r
+ = third derivative\r
+20DC COMBINING FOUR DOTS ABOVE\r
+ = fourth derivative\r
+@ Enclosing diacritics\r
+20DD COMBINING ENCLOSING CIRCLE\r
+ = JIS composition circle\r
+ x (white circle - 25CB)\r
+ x (large circle - 25EF)\r
+ x (ideographic number zero - 3007)\r
+20DE COMBINING ENCLOSING SQUARE\r
+ x (white square - 25A1)\r
+20DF COMBINING ENCLOSING DIAMOND\r
+ x (white diamond - 25C7)\r
+20E0 COMBINING ENCLOSING CIRCLE BACKSLASH\r
+ * prohibition\r
+@ Additional diacritical mark for symbols\r
+20E1 COMBINING LEFT RIGHT ARROW ABOVE\r
+ * tensor\r
+@ Additional enclosing diacritics\r
+20E2 COMBINING ENCLOSING SCREEN\r
+ x (clear screen symbol - 239A)\r
+20E3 COMBINING ENCLOSING KEYCAP\r
+\r
+*/\r
+\r
--- /dev/null
+//\r
+// charnames.h\r
+//\r
+// A header file that links Unicode character names to character numbers.\r
+// Also, throws in the Macintosh standard glyph names to boot.\r
+//\r
+// by James L. Hammons\r
+//\r
+\r
+extern unsigned char macStdNames[];\r
+extern unsigned char unicodeChars[];\r
+\r
+/*struct unicodeChar\r
+{\r
+ int cNum;\r
+\r
+};*/\r
+\r
--- /dev/null
+//\r
+// DEBUG.CPP: Debugging support\r
+// by James L. Hammons\r
+// (C) 2002 Underground Software\r
+//\r
+// JLH = James Hammons <jlhamm@acm.org>\r
+//\r
+// Who When What\r
+// --- ---------- ------------------------------------------------------------\r
+// JLH 07/31/2002 Created this file\r
+// JLH 07/31/2002 Added debug log functions & system error logging functions\r
+// JLH 08/16/2002 Added debug log function for SQL error reporting, made\r
+// WriteLogMsg thread safe\r
+// JLH 12/10/2002 Added code to have a background message window\r
+// JLH 05/14/2004 Converted code to C++ (sans ODBC logging)\r
+// JLH 05/15/2005 Converted code to generic C++\r
+//\r
+\r
+//#include <windows.h>\r
+//#include <odbc.h>\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+#include "debug.h"\r
+\r
+// EQUATES\r
+\r
+//#define USDB_WRITEMESSAGE WM_USER + 1 // Display a message on the debug window\r
+\r
+// Function prototypes\r
+\r
+//void CreateDebugWin(void);\r
+//LRESULT CALLBACK DebugWinProc(HWND, UINT, WPARAM, LPARAM);\r
+\r
+// CONSTANTS\r
+\r
+const char logFilename[] = "debug.log";\r
+\r
+// DATA\r
+\r
+FILE * logFile = NULL;\r
+\r
+// UNINITIALIZED DATA\r
+\r
+//CRITICAL_SECTION csLock; // Critical section lock\r
+\r
+//\r
+// Open the debugging log file\r
+//\r
+void OpenDebugLog(void)\r
+{\r
+// hLogFile = CreateFile(logFilename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+// NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH | FILE_ATTRIBUTE_NORMAL, NULL);\r
+// InitializeCriticalSection(&csLock);\r
+ logFile = fopen(logFilename, "wb");\r
+#ifdef DEBUGWIN\r
+ CreateDebugWin();\r
+#endif\r
+}\r
+\r
+//\r
+// Close the debugging log file\r
+//\r
+void CloseDebugLog(void)\r
+{\r
+// CloseHandle(hLogFile);\r
+ fclose(logFile);\r
+// DeleteCriticalSection(&csLock);\r
+\r
+// if (hDebugWnd)\r
+// DestroyWindow(hDebugWnd);\r
+}\r
+\r
+//\r
+// Write a message to the log file\r
+//\r
+/*void WriteLogMsg(char * msg)\r
+{\r
+ if (!msg) // Check for valid pointer\r
+ return;\r
+\r
+ EnterCriticalSection(&csLock);\r
+\r
+ if (hLogFile)\r
+ WriteFile(hLogFile, msg, lstrlen(msg), &wfBytesWritten, NULL);\r
+\r
+ if (hDebugWnd)\r
+ SendMessage(hDebugWnd, USDB_WRITEMESSAGE, FALSE, (LPARAM)msg);\r
+\r
+ LeaveCriticalSection(&csLock);\r
+}//*/\r
+\r
+//\r
+// This logger is used mainly to ensure that text gets written to the log file\r
+// even if the program crashes. The performance hit is acceptable in this case!\r
+//\r
+void WriteLogMsg(const char * msg, ...)\r
+{\r
+ if (!msg) // Check for valid pointer\r
+ return;\r
+\r
+// EnterCriticalSection(&csLock);\r
+\r
+ va_list arg;\r
+\r
+ va_start(arg, msg);\r
+// wvsprintf(str, msg, arg);\r
+ if (logFile)\r
+ {\r
+ vfprintf(logFile, msg, arg);\r
+ fflush(logFile);\r
+ }\r
+\r
+ va_end(arg);\r
+\r
+// if (hLogFile)\r
+// WriteFile(hLogFile, str, lstrlen(msg), &wfBytesWritten, NULL);\r
+\r
+// if (hDebugWnd)\r
+// SendMessage(hDebugWnd, USDB_WRITEMESSAGE, FALSE, (LPARAM)str);\r
+\r
+// LeaveCriticalSection(&csLock);\r
+}\r
+\r
+\r
+//\r
+// Display a system error message on the screen\r
+//\r
+/*void DisplaySysError(HWND hWnd)\r
+{\r
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL,\r
+ GetLastError(), 1024, pBuf, 0, NULL);\r
+ MessageBox(hWnd, pBuf, errTitle, MB_ICONERROR);\r
+ LocalFree(pBuf);\r
+}\r
+\r
+//\r
+// Create "live log" debug window\r
+//\r
+void CreateDebugWin(void)\r
+{\r
+ WNDCLASS wc;\r
+\r
+ RtlZeroMemory(&wc, sizeof(wc));\r
+ wc.lpfnWndProc = DebugWinProc;\r
+ wc.hInstance = GetModuleHandle(NULL);\r
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);\r
+ wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);\r
+ wc.lpszClassName = CNDebug;\r
+\r
+ if (!RegisterClass(&wc))\r
+ return;\r
+\r
+ hDebugWnd = CreateWindowEx(NULL, CNDebug, debugWin,\r
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_SYSMENU,\r
+ 0, 0, 400, 400, NULL, NULL, NULL, NULL);\r
+}\r
+\r
+//\r
+// Debug "live log" window procedure\r
+//\r
+LRESULT CALLBACK DebugWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ switch (uMsg)\r
+ {\r
+ // *****************\r
+ // *** WM_CREATE ***\r
+ // *****************\r
+\r
+ case WM_CREATE:\r
+ hEdit1 = CreateWindowEx(NULL, CNEdit, NULL,\r
+ WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_READONLY | ES_MULTILINE | ES_AUTOVSCROLL,\r
+ 0, 0, 1, 1, hWnd, NULL, NULL, NULL);\r
+ break;\r
+\r
+ // ******************\r
+ // *** WM_DESTROY ***\r
+ // ******************\r
+\r
+ case WM_DESTROY:\r
+ hDebugWnd = NULL; // Just in case user closes it himself...\r
+ break;\r
+\r
+ // ***************\r
+ // *** WM_SIZE ***\r
+ // ***************\r
+\r
+ case WM_SIZE:\r
+ SetWindowPos(hEdit1, NULL, 0, 0, lParam & 0xFFFF, lParam >> 16, SWP_NOMOVE | SWP_NOZORDER);\r
+ break;\r
+\r
+ // *************************\r
+ // *** USDB_WRITEMESSAGE ***\r
+ // *************************\r
+\r
+ case USDB_WRITEMESSAGE:\r
+ SendMessage(hEdit1, EM_SETSEL, -2, -2);\r
+ SendMessage(hEdit1, EM_REPLACESEL, wParam, lParam);\r
+ break;\r
+\r
+ default:\r
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);\r
+ }\r
+\r
+ return 0;\r
+}\r
+//*/\r
--- /dev/null
+//\r
+// DEBUG.H: Debugging support header\r
+// by James L. Hammons\r
+// (C) 2002 Underground Software\r
+//\r
+\r
+// Function prototypes\r
+\r
+void OpenDebugLog(void);\r
+void CloseDebugLog(void);\r
+void WriteLogMsg(const char *, ...);\r
+//void WriteSysMsg(void);\r
+//void WriteSQLMsg(DWORD, DWORD);\r
+//void DisplaySysError(HWND);\r
+\r
--- /dev/null
+//\r
+// GLYPHPOINTS.CPP\r
+//\r
+// Class implementation. Nothing too inexplicable going on here. Fairly\r
+// straightforward stuff.\r
+//\r
+// by James L. Hammons\r
+// (C) 2004 Underground Software\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who When What\r
+// --- ---------- ------------------------------------------------------------\r
+// JLH ??/??/200? Created this file\r
+// JLH 05/18/2004 Added pure point adding, inserting, better polygon handling\r
+//\r
+\r
+// Uncomment this for debugging...\r
+#define DEBUG\r
+\r
+#include "glyphpoints.h"\r
+#ifdef DEBUG\r
+#include "debug.h"\r
+#endif\r
+\r
+/*GlyphPoints::GlyphPoints(void)\r
+{\r
+ GlyphPoints(0, 0, NULL, NULL, NULL, NULL);\r
+}*/\r
+\r
+GlyphPoints::GlyphPoints(int nPts/*=0*/, int nPlys/*=0*/, int * xa/*=null*/, int * ya/*=null*/,\r
+ bool * oca/*=null*/, uint16 * pa/*=null*/): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)\r
+//GlyphPoints::GlyphPoints(int nPts, int nPlys/*=0*/, int * xa/*=null*/, int * ya/*=null*/,\r
+// bool * oca/*=null*/, uint16 * pa/*=null*/): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)\r
+{\r
+ AllocateAndCopy(nPts, nPlys, xa, ya, oca, pa);\r
+\r
+ if (nPlys == 0)\r
+ {\r
+ numPolys = 1;\r
+ polyEnd = new uint16[numPolys];\r
+ polyEnd[0] = numPoints - 1;\r
+ }\r
+#ifdef DEBUG\r
+WriteLogMsg("GlyphPoints: Default constructor. %u points, %u polys.\n", numPoints, numPolys);\r
+#endif\r
+}\r
+\r
+GlyphPoints::GlyphPoints(int xx, int yy, bool oc)\r
+{\r
+//Hmm. What to do with this...?\r
+ AllocateAndCopy(1, 0, &xx, &yy, &oc, NULL);\r
+#ifdef DEBUG\r
+WriteLogMsg("GlyphPoints: Single point constructor. %u points, %u polys.\n", numPoints, numPolys);\r
+#endif\r
+}\r
+\r
+// Copy constructor (needed for deep copying)\r
+\r
+//GlyphPoints::GlyphPoints(GlyphPoints &c): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)\r
+GlyphPoints::GlyphPoints(const GlyphPoints &c): x(NULL), y(NULL), onCurve(NULL), polyEnd(NULL)\r
+{\r
+ *this = c; // Use overloaded operator=\r
+#ifdef DEBUG\r
+WriteLogMsg("GlyphPoints: Copy constructor. %u points, %u polys.\n", numPoints, numPolys);\r
+#endif\r
+}\r
+\r
+GlyphPoints::~GlyphPoints()\r
+{\r
+ if (x)\r
+ delete[] x;\r
+\r
+ if (y)\r
+ delete[] y;\r
+\r
+ if (onCurve)\r
+ delete[] onCurve;\r
+\r
+ if (polyEnd)\r
+ delete[] polyEnd;\r
+}\r
+\r
+void GlyphPoints::AllocateAndCopy(int nPts, int nPlys, int * xa, int * ya, bool * oca, uint16 * pa)\r
+{\r
+ numPoints = nPts, numPolys = nPlys;\r
+\r
+ if (nPts)\r
+ {\r
+ x = new int[numPoints];\r
+ y = new int[numPoints];\r
+ onCurve = new bool[numPoints];\r
+\r
+ if (xa) // Copy points in if they're passed in...\r
+ for(int i=0; i<nPts; i++)\r
+ x[i] = xa[i];\r
+\r
+ if (ya)\r
+ for(int i=0; i<nPts; i++)\r
+ y[i] = ya[i];\r
+\r
+ if (oca)\r
+ for(int i=0; i<nPts; i++)\r
+ onCurve[i] = oca[i];\r
+ }\r
+\r
+ if (numPolys)\r
+ {\r
+ polyEnd = new uint16[numPolys];\r
+\r
+ if (pa) // Copy poly ends in if they're passed in...\r
+ for(int i=0; i<nPlys; i++)\r
+ polyEnd[i] = pa[i];\r
+ }\r
+}\r
+\r
+GlyphPoints& GlyphPoints::operator=(const GlyphPoints &c)\r
+{\r
+ if (this == &c)\r
+ return *this; // Take care of self-assignment\r
+\r
+ if (x)\r
+ delete[] x;\r
+\r
+ if (y)\r
+ delete[] y;\r
+\r
+ if (onCurve)\r
+ delete[] onCurve;\r
+\r
+ if (polyEnd)\r
+ delete[] polyEnd;\r
+\r
+ AllocateAndCopy(c.numPoints, c.numPolys, c.x, c.y, c.onCurve, c.polyEnd);\r
+\r
+ return *this;\r
+}\r
+\r
+// Add another GlyphPoints' points to this one...\r
+\r
+GlyphPoints GlyphPoints::operator+(const GlyphPoints &c)\r
+{\r
+ int totPoints = numPoints + c.numPoints, totPolys = numPolys + c.numPolys;\r
+\r
+ int * totX = new int[totPoints];\r
+ int * totY = new int[totPoints];\r
+ bool * totOnCurve = new bool[totPoints];\r
+ uint16 * totPolyEnd = new uint16[totPolys];\r
+\r
+ for(int i=0; i<numPoints; i++)\r
+ {\r
+ totX[i] = x[i];\r
+ totY[i] = y[i];\r
+ totOnCurve[i] = onCurve[i];\r
+ }\r
+\r
+ for(int i=0; i<numPolys; i++)\r
+ totPolyEnd[i] = polyEnd[i];\r
+\r
+ for(int i=0; i<c.numPoints; i++)\r
+ {\r
+ totX[numPoints+i] = c.x[i];\r
+ totY[numPoints+i] = c.y[i];\r
+ totOnCurve[numPoints+i] = c.onCurve[i];\r
+ }\r
+\r
+ for(int i=0; i<c.numPolys; i++)\r
+ totPolyEnd[numPolys+i] = numPoints + c.polyEnd[i]; // Need to adjust the "added in"\r
+ // poly's end points...\r
+\r
+ GlyphPoints retVal(totPoints, totPolys, totX, totY, totOnCurve, totPolyEnd);\r
+ delete[] totX;\r
+ delete[] totY;\r
+ delete[] totOnCurve;\r
+ delete[] totPolyEnd;\r
+\r
+ return retVal;\r
+}\r
+\r
+// Add a point to this GlyphPoints...\r
+\r
+GlyphPoints GlyphPoints::operator+(const IPoint &c)\r
+{\r
+//This is kinda silly. We can do better than this! !!! FIX !!!\r
+ int * totX = new int[numPoints + 1];\r
+ int * totY = new int[numPoints + 1];\r
+ bool * totOnCurve = new bool[numPoints + 1];\r
+ uint16 * totPolyEnd = new uint16[numPolys];\r
+\r
+ for(int i=0; i<numPoints; i++)\r
+ totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];\r
+\r
+ totX[numPoints] = c.x, totY[numPoints] = c.y, totOnCurve[numPoints] = c.onCurve;\r
+\r
+ for(int i=0; i<numPolys; i++)\r
+ totPolyEnd[i] = polyEnd[i];\r
+\r
+ totPolyEnd[numPolys - 1]++; // Bump polygon's end point\r
+ GlyphPoints retVal(numPoints + 1, numPolys, totX, totY, totOnCurve, totPolyEnd);\r
+\r
+ delete[] totX;\r
+ delete[] totY;\r
+ delete[] totOnCurve;\r
+\r
+ return retVal;\r
+}\r
+\r
+GlyphPoints& GlyphPoints::operator+=(const IPoint &p)\r
+{\r
+ InsertPoint(numPoints, p.x, p.y, p.onCurve);\r
+\r
+ return *this;\r
+}\r
+\r
+void GlyphPoints::InsertPoint(uint16 pt, int xx, int yy, bool oc)\r
+{\r
+ if (pt > numPoints) // > because we can insert at end...!\r
+ throw GP_OUT_OF_RANGE;\r
+\r
+//This is kinda silly. We can do better than this! !!! FIX !!!\r
+ int * totX = new int[numPoints + 1];\r
+ int * totY = new int[numPoints + 1];\r
+ bool * totOnCurve = new bool[numPoints + 1];\r
+\r
+ for(int i=0; i<pt; i++)\r
+ totX[i] = x[i], totY[i] = y[i], totOnCurve[i] = onCurve[i];\r
+\r
+ for(int i=pt; i<numPoints; i++)\r
+ totX[i + 1] = x[i], totY[i + 1] = y[i], totOnCurve[i + 1] = onCurve[i];\r
+\r
+ totX[pt] = xx, totY[pt] = yy, totOnCurve[pt] = oc;\r
+\r
+//A way to fix the kludge in GetPoly() would be to put a check here to see if \r
+//we're adding to the end of the structure: [DONE, below]\r
+ int polyInsert = (pt == numPoints ? numPolys - 1 : GetPoly(pt));\r
+ for(int i=polyInsert; i<numPolys; i++)\r
+// for(int i=GetPoly(pt); i<numPolys; i++)\r
+ polyEnd[i]++; // Bump polygons' end point\r
+\r
+ numPoints++;\r
+\r
+ delete[] x;\r
+ delete[] y;\r
+ delete[] onCurve;\r
+\r
+ x = totX, y = totY, onCurve = totOnCurve;\r
+}\r
+\r
+void GlyphPoints::InsertPoint(uint16 pt, const IPoint &p)\r
+{\r
+ InsertPoint(pt, p.x, p.y, p.onCurve);\r
+}\r
+\r
+//\r
+// Delete a point from the glyph\r
+// Note that we don't bother to reallocate anything here, just bump the\r
+// size counters down as needed. In the future, we'll keep track so we\r
+// don't have to reallocate *every* damn time a point is added...\r
+//\r
+void GlyphPoints::DeletePoint(uint16 pt)\r
+{\r
+ // Adjust polygon ends appropriately\r
+ uint16 poly = GetPoly(pt);\r
+\r
+ for(int i=poly; i<numPolys; i++)\r
+ polyEnd[i]--;\r
+\r
+//Need to check here if we're deleting the last point in the glyph or not.\r
+//!!! FIX !!! [DONE]\r
+ if (GetNumPoints(poly) == 0 && numPoints > 0)\r
+ {\r
+ numPolys--;\r
+\r
+ for(int i=poly; i<numPolys; i++)\r
+ polyEnd[i] = polyEnd[i + 1];\r
+ }\r
+\r
+//This causes a crash becuz GetPoly() uses numPoints... !!! FIX !!! [DONE by switching poly delete & point delete]\r
+ // Close up the gap left by the current point\r
+ numPoints--;\r
+\r
+ for(int i=pt; i<numPoints; i++)\r
+ x[i] = x[i + 1], y[i] = y[i + 1], onCurve[i] = onCurve[i + 1];\r
+}\r
+\r
+uint16 GlyphPoints::GetNumPoints(void)\r
+{\r
+ return numPoints;\r
+}\r
+\r
+uint16 GlyphPoints::GetNumPoints(uint16 poly)\r
+{\r
+ if (poly >= numPolys)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetNumPoints(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);\r
+#endif\r
+ throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+ return polyEnd[poly] - (poly == 0 ? -1 : polyEnd[poly - 1]);\r
+}\r
+\r
+uint16 GlyphPoints::GetNumPolys(void)\r
+{\r
+ return numPolys;\r
+}\r
+\r
+int GlyphPoints::GetX(uint16 pt)\r
+{\r
+ if (pt >= numPoints)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetX(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);\r
+#endif\r
+ throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+ return x[pt];\r
+}\r
+\r
+int GlyphPoints::GetY(uint16 pt)\r
+{\r
+ if (pt >= numPoints)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetY(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);\r
+#endif\r
+ throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+ return y[pt];\r
+}\r
+\r
+bool GlyphPoints::GetOnCurve(uint16 pt)\r
+{\r
+ if (pt >= numPoints)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetOnCurve(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);\r
+#endif\r
+ throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+ return onCurve[pt];\r
+}\r
+\r
+int GlyphPoints::GetX(uint16 poly, uint16 pt)\r
+{\r
+ if (pt >= GetNumPoints(poly))\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetX(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);\r
+#endif\r
+ throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+ return x[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];\r
+}\r
+\r
+int GlyphPoints::GetY(uint16 poly, uint16 pt)\r
+{\r
+ if (pt >= GetNumPoints(poly))\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetY(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);\r
+#endif\r
+ throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+ return y[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];\r
+}\r
+\r
+bool GlyphPoints::GetOnCurve(uint16 poly, uint16 pt)\r
+{\r
+ if (pt >= GetNumPoints(poly))\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetOnCurve(uint16, uint16). poly= %u, pt=%u, numPoints=%u\xD\xA", poly, pt, numPoints);\r
+#endif\r
+ throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+ return onCurve[pt + (poly == 0 ? 0 : polyEnd[poly - 1] + 1)];\r
+}\r
+\r
+uint16 GlyphPoints::GetPolyEnd(uint16 poly)\r
+{\r
+ if (poly >= numPolys)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);\r
+#endif\r
+ throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+ return polyEnd[poly];\r
+}\r
+\r
+void GlyphPoints::OffsetPoints(int xOff, int yOff)\r
+{\r
+ for(int i=0; i<numPoints; i++)\r
+ x[i] += xOff, y[i] += yOff;\r
+}\r
+\r
+//\r
+// Offset only a specific polygon in the glyph\r
+//\r
+void GlyphPoints::OffsetPoly(uint16 poly, int32 xOff, int32 yOff)\r
+{\r
+ if (poly >= numPolys)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetPolyEnd(uint16). poly=%u, numPolys=%u\xD\xA", poly, numPolys);\r
+#endif\r
+ throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+ uint16 polyStart = (poly == 0 ? 0 : polyEnd[poly - 1] + 1);\r
+\r
+ for(int i=0; i<GetNumPoints(poly); i++)\r
+ x[polyStart + i] += xOff, y[polyStart + i] += yOff;\r
+}\r
+\r
+void GlyphPoints::ScalePoints(float sc)\r
+{\r
+ for(int i=0; i<numPoints; i++)\r
+ x[i] = (int)(((float)x[i] * sc) + 0.5f),\r
+ y[i] = (int)(((float)y[i] * sc) + 0.5f);\r
+}\r
+\r
+void GlyphPoints::SetXY(uint16 pt, int xx, int yy)\r
+{\r
+ if (pt >= numPoints)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: SetXY(uint16, int, int). pt=%u, numPoints=%u\xD\xA", pt, numPoints);\r
+#endif\r
+ throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+ x[pt] = xx, y[pt] = yy;\r
+}\r
+\r
+void GlyphPoints::SetOnCurve(uint16 pt, bool oc)\r
+{\r
+ if (pt >= numPoints)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: SetOnCurve(uint16, bool). pt=%u, numPoints=%u\xD\xA", pt, numPoints);\r
+#endif\r
+ throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+ onCurve[pt] = oc;\r
+}\r
+\r
+uint16 GlyphPoints::GetPrev(uint16 pt)\r
+{\r
+// pt = 7, polyEnd = 4, 9, 15\r
+ uint16 min = 0, max = numPoints - 1;\r
+\r
+ for(int i=0; i<numPolys; i++)\r
+ {\r
+ if (pt <= polyEnd[i])\r
+ {\r
+ if (i > 0)\r
+ min = polyEnd[i - 1] + 1;\r
+\r
+ max = polyEnd[i];\r
+ break;\r
+ }\r
+ }\r
+\r
+ uint16 retVal = pt - 1;\r
+\r
+ if (pt == min)\r
+ retVal = max;\r
+\r
+ return retVal;\r
+}\r
+\r
+uint16 GlyphPoints::GetNext(uint16 pt)\r
+{\r
+ uint16 min = 0, max = numPoints - 1;\r
+\r
+ for(int i=0; i<numPolys; i++)\r
+ {\r
+ if (pt <= polyEnd[i])\r
+ {\r
+ if (i > 0)\r
+ min = polyEnd[i - 1] + 1;\r
+\r
+ max = polyEnd[i];\r
+ break;\r
+ }\r
+ }\r
+\r
+ uint16 retVal = pt + 1;\r
+\r
+ if (pt == max)\r
+ retVal = min;\r
+\r
+ return retVal;\r
+}\r
+\r
+//\r
+// Get previous point for this polygon using wraparound.\r
+// Note that pt is a zero-based index!\r
+//\r
+uint16 GlyphPoints::GetPrev(uint16 poly, uint16 pt)\r
+{\r
+ return (pt == 0 ? GetNumPoints(poly) - 1 : pt - 1);\r
+}\r
+\r
+//\r
+// Get next point for this polygon using wraparound.\r
+// Note that pt is a zero-based index!\r
+//\r
+uint16 GlyphPoints::GetNext(uint16 poly, uint16 pt)\r
+{\r
+ return (pt == GetNumPoints(poly) - 1 ? 0 : pt + 1);\r
+}\r
+\r
+uint16 GlyphPoints::GetPoly(uint16 pt)\r
+{\r
+ if (pt >= numPoints)\r
+#ifdef DEBUG\r
+{\r
+WriteLogMsg("Exception: GetPoly(uint16). pt=%u, numPoints=%u\xD\xA", pt, numPoints);\r
+#endif\r
+ throw GP_OUT_OF_RANGE;\r
+#ifdef DEBUG\r
+}\r
+#endif\r
+\r
+ for(int i=0; i<numPolys; i++)\r
+ if (pt <= polyEnd[i])\r
+ return i;\r
+\r
+ return (uint16)-1;\r
+}\r
+\r
+void GlyphPoints::AddNewPolyAtEnd(void)\r
+{\r
+ if (numPoints == 0) // By default, we already *have* a poly\r
+ return;\r
+\r
+ uint16 * newPolyEnd = new uint16[numPolys + 1];\r
+\r
+ for(uint16 i=0; i<numPolys; i++)\r
+ newPolyEnd[i] = polyEnd[i];\r
+\r
+ newPolyEnd[numPolys] = newPolyEnd[numPolys - 1];\r
+ numPolys++;\r
+ delete[] polyEnd;\r
+ polyEnd = newPolyEnd;\r
+}\r
+\r
--- /dev/null
+//\r
+// glyphpoints.h\r
+//\r
+// by James L. Hammons\r
+//\r
+// This class encapsulates the data associated with a TrueType glyph.\r
+// Data is dynamically allocated.\r
+//\r
+\r
+#ifndef __GLYPHPOINTS_H__\r
+#define __GLYPHPOINTS_H__\r
+\r
+#include "types.h"\r
+\r
+\r
+struct IPoint\r
+{\r
+ int32 x, y;\r
+ bool onCurve;\r
+\r
+ IPoint(int32 xx=0, int32 yy=0, bool oc=true): x(xx), y(yy), onCurve(oc) {}\r
+};\r
+\r
+// Throws the following exceptions:\r
+#define GP_OUT_OF_RANGE 1\r
+\r
+class GlyphPoints\r
+{\r
+ public:\r
+//For some reason, gcc barfs here when something tries to use the copy\r
+//constructor because it gets confused between the optional arguments (which\r
+//start with an INT for cryin' out loud) and the GlyphPoints & argument. So,\r
+//Let's try making it a non-optional first param, and go from there...\r
+//Turns out the compiler barfs regardless...\r
+//Turns out the problem was that the copy ctor wasn't declared as CONST...\r
+ GlyphPoints(int nPts = 0, int nPlys = 0, int * xa = NULL, int * ya = NULL,\r
+ bool * oca = NULL, uint16 * pa = NULL);\r
+// GlyphPoints(void);// And now *this* is needed... Bleah!\r
+// GlyphPoints(int nPts, int nPlys = 0, int * xa = NULL, int * ya = NULL,\r
+// bool * oca = NULL, uint16 * pa = NULL);\r
+ GlyphPoints(int xx, int yy, bool oc);\r
+// GlyphPoints(GlyphPoints &); // Copy constructor\r
+ GlyphPoints(const GlyphPoints &); // Copy constructor\r
+ ~GlyphPoints();\r
+ GlyphPoints& operator=(const GlyphPoints &);\r
+ GlyphPoints operator+(const GlyphPoints &);\r
+ GlyphPoints operator+(const IPoint &);\r
+ GlyphPoints& operator+=(const IPoint &);\r
+ void InsertPoint(uint16, int, int, bool);\r
+ void InsertPoint(uint16, const IPoint &);\r
+ void DeletePoint(uint16);\r
+ uint16 GetNumPoints(void);\r
+ uint16 GetNumPoints(uint16);\r
+ uint16 GetNumPolys(void);\r
+ int GetX(uint16);\r
+ int GetY(uint16);\r
+ bool GetOnCurve(uint16);\r
+ int GetX(uint16, uint16);\r
+ int GetY(uint16, uint16);\r
+ bool GetOnCurve(uint16, uint16);\r
+ uint16 GetPolyEnd(uint16);\r
+ void OffsetPoints(int, int);\r
+ void OffsetPoly(uint16, int32, int32);\r
+ void ScalePoints(float);\r
+ void SetXY(uint16, int, int);\r
+ void SetOnCurve(uint16, bool);\r
+ uint16 GetPrev(uint16);\r
+ uint16 GetNext(uint16);\r
+ uint16 GetPrev(uint16, uint16);\r
+ uint16 GetNext(uint16, uint16);\r
+ uint16 GetPoly(uint16);\r
+ void AddNewPolyAtEnd(void);\r
+\r
+ private:\r
+ void AllocateAndCopy(int, int, int *, int *, bool *, uint16 *);\r
+\r
+ private:\r
+ int numPoints, numPolys;\r
+ int * x, * y;\r
+ bool * onCurve;\r
+ uint16 * polyEnd;\r
+ uint16 pointsAllocated, polysAllocated;\r
+};\r
+\r
+#endif // __GLYPHPOINTS_H__\r
--- /dev/null
+//\r
+// A generic list class using a circular singly linked list\r
+// by James L. Hammons\r
+// (C) 2004 Underground Software\r
+//\r
+// Based upon work I did for CS240 Project 5 at Cal Poly Pomona for Dr. Bruce Hillam.\r
+// Hello Dr. Hillam! :-)\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who When What\r
+// --- ---------- -------------------------------------------------------------\r
+// JLH 08/30/1999 Created this file\r
+// JLH 05/11/2004 Cleaned up a few things in the implementation\r
+//\r
+\r
+\r
+// Some exception constants\r
+\r
+#define LIST_EMPTY 1\r
+#define OUT_OF_RANGE 2\r
+\r
+template <class T> class List; // Forward declaration...\r
+template <class T> class Node\r
+{\r
+ friend class List<T>;\r
+\r
+ public:\r
+// Node(void) { next = NULL; }\r
+ Node(void): next(NULL) {}\r
+// Node(const T d, Node * ptr = NULL) { data = d; next = ptr; }\r
+ Node(const T d, Node * ptr = NULL): data(d), next(ptr) {}\r
+\r
+ private:\r
+ T data;\r
+ Node * next;\r
+};\r
+\r
+template <class T> class List \r
+{\r
+ // This class implements the following exceptions:\r
+ // LIST_EMPTY is thrown if you attempt to remove an object from an empty list.\r
+ // OUT_OF_RANGE is thrown if you attempt to Add or Get from a position that\r
+ // does not exist for the list.\r
+\r
+ private:\r
+ Node<T> * last;\r
+ int length;\r
+\r
+ public:\r
+ List(void);\r
+ ~List();\r
+ bool operator==(List &l);\r
+ void AddAtFront(T data);\r
+ void AddAtRear(T data);\r
+ void AddAtPosition(int pos, T data);\r
+ T GetFront(void);\r
+ T GetRear(void);\r
+ T GetPosition(int pos);\r
+ T PeekFront(void);\r
+ T PeekRear(void);\r
+ T PeekPosition(int pos);\r
+ bool IsEmpty(void);\r
+ int Length(void);\r
+};\r
+\r
+//\r
+// List class implementation\r
+//\r
+template <class T> List<T>::List(void)\r
+{\r
+ last = NULL;\r
+ length = 0;\r
+}\r
+\r
+template <class T> List<T>::~List()\r
+{\r
+ while (length) // Destroy all nodes that were created...\r
+ {\r
+ Node<T> * tmp = last;\r
+ last = last->next;\r
+ delete tmp;\r
+ length--;\r
+ }\r
+}\r
+\r
+template <class T> bool List<T>::operator==(List &l)\r
+{\r
+ if (Length() != l.Length())\r
+ return false;\r
+\r
+ Node<T> * ptr1 = last->next, * ptr2 = l.last->next;\r
+\r
+ do\r
+ {\r
+ if (ptr1->data != ptr2->data)\r
+ return false;\r
+\r
+ ptr1 = ptr1->next, ptr2 = ptr2->next;\r
+ }\r
+ while (ptr1 != last);\r
+\r
+ return true;\r
+}\r
+\r
+template <class T> void List<T>::AddAtFront(T data)\r
+{\r
+ Node<T> * newNode = new Node<T>(data);\r
+\r
+ if (last == NULL) // i.e., the list is empty...\r
+ last = newNode->next = newNode;\r
+ else\r
+ {\r
+ newNode->next = last->next;\r
+ last->next = newNode;\r
+ }\r
+\r
+ length++;\r
+}\r
+\r
+template <class T> void List<T>::AddAtRear(T data)\r
+{\r
+ Node<T> * newNode = new Node<T>(data);\r
+\r
+ if (last == NULL) // i.e., the list is empty...\r
+ last = newNode->next = newNode;\r
+ else\r
+ {\r
+ newNode->next = last->next;\r
+ last->next = newNode;\r
+ last = newNode;\r
+ }\r
+\r
+ length++;\r
+}\r
+\r
+template <class T> void List<T>::AddAtPosition(int pos, T data)\r
+{\r
+ if ((pos < 1) || (pos > length))\r
+ throw OUT_OF_RANGE;\r
+\r
+ if (pos == 1)\r
+ AddAtFront(data); // Why reinvent the wheel?\r
+\r
+ if (pos == length)\r
+ AddAtRear(data);\r
+\r
+ Node<T> * newNode = new Node<T>(data), * tmp = last;\r
+\r
+ for(int i=1; i!=pos; i++) // Make tmp point to node ahead of add position\r
+ tmp = tmp->next;\r
+\r
+ newNode->next = tmp->next;\r
+ tmp->next = newNode;\r
+\r
+ length++;\r
+}\r
+\r
+template <class T> T List<T>::GetFront(void)\r
+{\r
+ if (IsEmpty())\r
+ throw LIST_EMPTY;\r
+\r
+ T retVal = last->next->data;\r
+ Node<T> * ptr = last->next;\r
+\r
+ if (length == 1)\r
+ last = NULL;\r
+ else\r
+ last->next = last->next->next;\r
+\r
+ delete ptr;\r
+ length--;\r
+\r
+ return retVal;\r
+}\r
+\r
+template <class T> T List<T>::GetRear(void)\r
+{\r
+ if (IsEmpty())\r
+ throw LIST_EMPTY;\r
+\r
+ T retVal = last->data;\r
+ Node<T> * ptr = last;\r
+\r
+ if (length == 1)\r
+ {\r
+ delete last;\r
+ last = NULL;\r
+ }\r
+ else\r
+ {\r
+ while (ptr->next != last)\r
+ ptr = ptr->next;\r
+\r
+ ptr->next = ptr->next->next;\r
+ delete last;\r
+ last = ptr; \r
+ }\r
+\r
+ length--;\r
+\r
+ return retVal;\r
+}\r
+\r
+template <class T> T List<T>::GetPosition(int pos)\r
+{\r
+ if (IsEmpty())\r
+ throw LIST_EMPTY;\r
+\r
+ if ((pos < 1) || (pos > length))\r
+ throw OUT_OF_RANGE;\r
+\r
+ if (pos == 1)\r
+ return GetFront(); // Why reinvent the wheel?\r
+\r
+ if (pos == length)\r
+ return GetRear();\r
+\r
+ Node<T> * tmp = last;\r
+\r
+ for(int i=1; i!=pos; i++) // Make tmp point to node ahead of del position\r
+ tmp = tmp->next;\r
+\r
+ Node<T> * nodeToDelete = tmp->next;\r
+ T retVal = nodeToDelete->data;\r
+\r
+ tmp->next = tmp->next->next;\r
+ delete nodeToDelete;\r
+\r
+ length--;\r
+ return retVal;\r
+}\r
+\r
+template <class T> T List<T>::PeekFront(void)\r
+{\r
+ if (IsEmpty())\r
+ throw LIST_EMPTY;\r
+\r
+ return last->next->data;\r
+}\r
+\r
+template <class T> T List<T>::PeekRear(void)\r
+{\r
+ if (IsEmpty())\r
+ throw LIST_EMPTY;\r
+\r
+ return last->data;\r
+}\r
+\r
+template <class T> T List<T>::PeekPosition(int pos)\r
+{\r
+ if (IsEmpty())\r
+ throw LIST_EMPTY;\r
+\r
+ if ((pos < 1) || (pos > length))\r
+ throw OUT_OF_RANGE;\r
+\r
+ if (pos == 1)\r
+ return PeekFront(); // Why reinvent the wheel?\r
+\r
+ if (pos == length)\r
+ return PeekRear();\r
+\r
+ Node<T> * tmp = last;\r
+\r
+ for(int i=1; i!=pos; i++)\r
+ tmp = tmp->next;\r
+\r
+ return tmp->next->data;\r
+}\r
+\r
+template <class T> inline bool List<T>::IsEmpty(void)\r
+{\r
+ return (bool)(length == 0);\r
+}\r
+\r
+template <class T> inline int List<T>::Length(void)\r
+{\r
+ return length;\r
+}\r
--- /dev/null
+//\r
+// REGISTRY.CPP - Win32 support file\r
+// by James L. Hammons\r
+// (C) 2002 Underground Software\r
+//\r
+// JLH = James Hammons <jlhamm@acm.org>\r
+//\r
+// Who When What\r
+// --- ---------- ------------------------------------------------------------\r
+// JLH 05/16/2002 Created this file\r
+// JLH 12/10/2002 Updated InitINIFile to take a parameter so that you can open\r
+// an .INI file that doesn't belong to the current module\r
+//\r
+// STILL TO BE DONE:\r
+//\r
+// - Convert to wxWidgets...\r
+//\r
+\r
+#warning This file not yet converted to wxWidgets!!!\r
+\r
+#if 0\r
+#include <windows.h>\r
+#include "registry.h"\r
+\r
+// Local data\r
+\r
+static char INIPath[MAX_PATH];\r
+static char str[4096];\r
+\r
+//\r
+// Initialize the application .INI file\r
+// Returns TRUE if succesful, FALSE otherwise...\r
+//\r
+void InitINIFile(char * path/*= NULL*/)\r
+{\r
+ if (!GetModuleFileName(NULL, INIPath, MAX_PATH))\r
+ return;\r
+\r
+ if (path == NULL)\r
+ {\r
+ int len = lstrlen(INIPath);\r
+ lstrcpy(INIPath + len - 4, ".ini");\r
+ }\r
+ else\r
+ {\r
+ for(int i=lstrlen(INIPath); i>=0; i--)\r
+ {\r
+ if (INIPath[i] == '\\')\r
+ {\r
+ lstrcpy(INIPath + i + 1, path);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+//\r
+// Write an int value to our .INI file\r
+//\r
+void SetINIInt(char * section, char * entry, int32 value)\r
+{\r
+ const char fmtStr[] = "%d";\r
+ char strVal[20];\r
+\r
+ wsprintf(strVal, fmtStr, value);\r
+ WritePrivateProfileString(section, entry, strVal, INIPath);\r
+}\r
+\r
+//\r
+// Write a string value to our .INI file\r
+//\r
+void SetINIString(char * section, char * entry, char * value)\r
+{\r
+ WritePrivateProfileString(section, entry, value, INIPath);\r
+}\r
+\r
+//\r
+// Get an int value from our .INI file\r
+//\r
+int32 GetINIInt(char * section, char * entry, int32 _default)\r
+{\r
+ return GetPrivateProfileInt(section, entry, _default, INIPath);\r
+}\r
+\r
+//\r
+// Get a string value from our .INI file\r
+//\r
+const char * GetINIString(char * section, char * entry, char * _default)\r
+{\r
+ GetPrivateProfileString(section, entry, _default, str, 4096, INIPath);\r
+\r
+ return str;\r
+}\r
+#endif\r
--- /dev/null
+//\r
+// REGISTRY.H - Win32 support file header\r
+// by James L. Hammons\r
+// (C) 2002 Underground Software\r
+//\r
+// JLH = James Hammons <jlhamm@acm.org>\r
+//\r
+\r
+#ifndef __REGISTRY_H__\r
+#define __REGISTRY_H__\r
+\r
+#include "types.h"\r
+\r
+// Function prototypes\r
+\r
+void InitINIFile(char * path = NULL);\r
+void SetINIInt(char *, char *, int32);\r
+void SetINIString(char *, char *, char *);\r
+int32 GetINIInt(char *, char *, int32);\r
+const char * GetINIString(char *, char *, char *);\r
+\r
+#endif // __REGISTRY_H__\r
--- /dev/null
+//\r
+// Resource includes\r
+//\r
+// by James L. Hammons\r
+//\r
+\r
+// Uncomment this to debug logging...\r
+//Actually, this is done on a file by file basis and NOT here...\r
+//#define DEBUG\r
+\r
+//\r
+// Common equates also used in the resource file\r
+//\r
+\r
+#define IDI_ICON 0x01L // IDs same as in ttedit.asm\r
+#define IDM_MENU 0x02L\r
+#define IDA_ACCEL 0x03L\r
+#define IDD_ABOUT 0x04L\r
+#define IDR_TOOLBAR1 0x05L\r
+#define IDB_TOOLBAR1 0x06L\r
+#define IDB_TOOLPAL1 0x07L\r
+#define IDC_CURSOR1 0x08L\r
+#define IDC_CURSOR2 0x09L\r
+#define IDC_CURSOR3 0x0AL\r
+#define IDC_CURSOR4 0x0BL\r
+#define IDC_CURSOR5 0x0CL\r
+#define IDC_CURSOR6 0x0DL\r
+#define IDC_CURSOR7 0x0EL\r
+#define IDC_CURSOR8 0x0FL\r
+\r
+#define IDS_SYSMENU 0x010L\r
+#define IDM_FILEMENU 0x011L\r
+#define IDM_HELPMENU 0x012L\r
+\r
+#define IDM_NEW 0x020L\r
+#define IDM_OPEN 0x021L\r
+#define IDM_SAVE 0x022L\r
+#define IDM_SAVEAS 0x023L\r
+#define IDM_EXIT 0x024L\r
+#define IDM_HELPTOPICS 0x025L\r
+#define IDM_ABOUT 0x026L\r
+\r
+#define ID_TBLEFT 0x030L\r
+#define ID_TBRIGHT 0x031L\r
+#define ID_TBCHARWIN 0x032L\r
+\r
--- /dev/null
+//\r
+// TTEDIT.CPP - The TrueType Editor\r
+// by James L. Hammons\r
+// (C) 2004 Underground Software\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who When What\r
+// --- ---------- -------------------------------------------------------------\r
+// JLH 04/10/2002 Created this file\r
+// JLH 05/10/2004 Translated file from ASM to CPP\r
+// JLH 05/14/2004 Added rudimentary editing capability to tool palette tools\r
+// JLH 11/18/2006 Initial port to Linux\r
+//\r
+\r
+// STILL TO BE DONE:\r
+//\r
+// - Fix bug in Glyphpoints when dragging on an empty canvas or loading a font\r
+// - Fix scrolling, zooming, settings (ini)\r
+// - Finish conversion to wxWidgets for cross-platform portability\r
+// - Fix problem with owned window causing main window refresh problems\r
+// (ironically enough, it doesn't seem to be a problem anymore...)\r
+//\r
+\r
+// Uncomment this for debugging...\r
+#define DEBUG\r
+#define DEBUGFOO // Various tool debugging...\r
+\r
+#include <math.h>\r
+#include "types.h"\r
+#include "tte_res.h"\r
+#include "ttf.h"\r
+#include "registry.h"\r
+#include "bezier.h"\r
+#include "glyphpoints.h"\r
+#include "vector.h"\r
+#ifdef DEBUG\r
+#include "debug.h"\r
+#endif\r
+#include "ttedit.h" // Usually not necessary, but here we are...\r
+#include <wx/confbase.h>\r
+#include <wx/fileconf.h>\r
+#include <wx/image.h>\r
+\r
+#include "res/ttedit.xpm" // *nix only, but small enough to not matter\r
+#include "res/toolpal1.xpm" // Docs say this is portable... Let's see!\r
+#include "res/cur1.xpm"\r
+#include "res/cur2.xpm"\r
+#include "res/cur3.xpm"\r
+#include "res/cur4.xpm"\r
+#include "res/cur5.xpm"\r
+#include "res/cur6.xpm"\r
+#include "res/cur7.xpm"\r
+#include "res/cur8.xpm"\r
+#include "res/tool1.xpm"\r
+#include "res/tool2.xpm"\r
+#include "res/tool3.xpm"\r
+\r
+//\r
+// E Q U A T E S\r
+//\r
+#define TOOLSelect 0x00 // The "selection" tool\r
+#define TOOLPolySelect 0x01 // Polygon selection tool\r
+#define TOOLScroll 0x02 // Scroll window tool\r
+#define TOOLZoom 0x03 // Zoom window tool\r
+#define TOOLAddPt 0x04 // Add point tool\r
+#define TOOLAddPoly 0x05 // Polygon creation tool\r
+#define TOOLDelPt 0x06 // Delete point tool\r
+#define TOOLDelPoly 0x07 // Delete polygon tool\r
+\r
+//\r
+// Function and Procedure Prototypes\r
+//\r
+//BOOL CALLBACK AboutProc(HWND, UINT, WPARAM, LPARAM);\r
+//void MiscCenterWnd(HWND, HWND);\r
+//bool OnlyOneInstance(void);\r
+void CreateResources(void);\r
+bool Initialization(void);\r
+void DeallocateResources(void);\r
+void SaveAppState(void);\r
+void DrawRoundDot(wxDC &, int32, int32);\r
+void DrawSquareDot(wxDC &, int32, int32);\r
+void DrawRoundDotN(wxDC &, int32, int32, uint32);\r
+void DrawSquareDotN(wxDC &, int32, int32, uint32);\r
+void CreateNewDoc(void);\r
+bool SaveChanges(void);\r
+\r
+// Global constant data\r
+\r
+//const char className[] = "TTEDIT";\r
+//const char CNCharWin[] = "US_CHARWIN";\r
+//const char CNToolPal[] = "US_TOOLPALETTE";\r
+//const char CNStatus[] = "msctls_statusbar32";\r
+const char filter[] = "Font Files (*.TTF)\0*.TTF\0All Files (*.*)\0*.*\0";\r
+const char defExt[] = "ttf";\r
+//const char mtitle[] = "Character Window!";\r
+const char zoom[] = "Zoom: %u%%";\r
+\r
+/*const TBBUTTON tbButtons[4] = {\r
+ { 0, ID_TBLEFT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0 },\r
+ { 1, ID_TBRIGHT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0 },\r
+ { 0, 0, 0, TBSTYLE_SEP, 0, 0 },\r
+ { 2, ID_TBCHARWIN, TBSTATE_ENABLED | TBSTATE_CHECKED, TBSTYLE_CHECK, 0, 0 }\r
+};*/\r
+\r
+\r
+//\r
+// U N I N I T I A L I Z E D D A T A\r
+//\r
+/*\r
+szSaveChanges SBYTE "Save changes to the following file?", 0Ah, 0Ah\r
+szFile SBYTE MAX_PATH DUP (0)\r
+szWindowName SBYTE (MAX_PATH + 10h) DUP (0)\r
+fScaleFactor REAL4 1.0 // Window scaling factor\r
+\r
+*/\r
+\r
+//HINSTANCE hInst;\r
+int nCmdShow;\r
+//HWND hMainWnd, hStatusBar, hToolBar, hCharWnd, hToolPalWnd;\r
+char statusBarTxt[64];\r
+char toolTipTxt[16];\r
+char strBuf[1024];\r
+\r
+//HCURSOR hCur[8];\r
+wxCursor * cur[8];\r
+\r
+//HBITMAP hBMToolPal1;\r
+//HPEN hRedPen1, hBluePen1, hGreenPen1, hBlackPen1;\r
+//HBRUSH hNullBrush;\r
+\r
+//POINT sizeStamp, sizeTPBM, ptPrevious;\r
+//PTSTRUCT aPts[16];\r
+//uint32 numPts = 0;\r
+GlyphPoints pts;\r
+int32 ptHighlight = -1, oldPtHighlight = -1, ptNextHighlight = -1, oldPtNextHighlight = -1;\r
+int32 currentTool = TOOLSelect; // Current tool is "selection" tool\r
+bool mouseDown = false; // Mouse down flag\r
+bool NCMouseDown;\r
+//POINT ptWinOffset;\r
+uint32 zoomWndWidth;\r
+bool polyFirstPoint = true;\r
+\r
+char curCharName[] = "Own3d W1nd0w"; // Need to make this a buffer w/default\r
+\r
+//WINDOWPLACEMENT wpM, wpC;\r
+//POINT ptVPM;\r
+\r
+\r
+\r
+IMPLEMENT_APP(TTEditApp) // Run the main application loop\r
+\r
+bool TTEditApp::OnInit()\r
+{\r
+ wxLog * logTarget = new wxLogStderr();//fopen("!ttedit_log.txt", "wb"));\r
+ wxLog::SetActiveTarget(logTarget);\r
+#ifdef DEBUG\r
+ OpenDebugLog();\r
+#endif\r
+\r
+ // Initialize all the top-level window members to NULL.\r
+ mainFrame = NULL;\r
+ charWin = NULL;\r
+ toolPalette = NULL;\r
+\r
+ CreateResources();\r
+\r
+ mainFrame = new TTEditFrame(NULL, _("TTEdit"), wxPoint(155, 165), wxSize(300, 300),\r
+ wxDEFAULT_FRAME_STYLE | wxFULL_REPAINT_ON_RESIZE);\r
+// wxMINIMIZE_BOX | wxRESIZE_BOX | wxMAXIMIZE_BOX | | wxSYSTEM_MENU | wxCAPTION);\r
+\r
+ charWin = new CharWindow(NULL);//, _T("Own3d W1nd0w"), wxDefaultPosition, wxDefaultSize);\r
+ toolPalette = new ToolWindow(mainFrame, _(""), wxDefaultPosition, wxDefaultSize,\r
+ wxNO_BORDER | wxFRAME_NO_TASKBAR);\r
+\r
+ return true;\r
+}\r
+\r
+int TTEditApp::OnExit()\r
+{\r
+#ifdef DEBUG\r
+ CloseDebugLog();\r
+#endif\r
+\r
+ return 0;\r
+}\r
+\r
+BEGIN_EVENT_TABLE(TTEditFrame, wxFrame)\r
+ EVT_MENU(IDM_OPEN, TTEditFrame::OnOpen)\r
+ EVT_MENU(IDM_EXIT, TTEditFrame::OnExit)\r
+ EVT_MENU(IDM_ABOUT, TTEditFrame::OnAbout)\r
+ EVT_CLOSE(TTEditFrame::OnCloseWindow)\r
+END_EVENT_TABLE()\r
+\r
+TTEditFrame::TTEditFrame(wxFrame * parent, const wxString &title, const wxPoint &pos,\r
+ const wxSize &size, long style): wxFrame(parent, -1, title, pos, size, style), app(wxGetApp())\r
+{\r
+ // Initialize child subwindow members (and hopefully avoid subtle bugs)\r
+ mainWindow = NULL;\r
+\r
+ SetIcon(wxICON(ttedit));\r
+// CreateStatusBar(2); // Create 2 panes\r
+ int widths[2] = { -1, 100 };\r
+ wxStatusBar * sb = CreateStatusBar(2, 0); // Create 2 panes\r
+ sb->SetStatusWidths(2, widths);\r
+ wxToolBar * tb = CreateToolBar();\r
+\r
+ if (tb != NULL)\r
+ {\r
+ // Create buttons\r
+\r
+ wxBitmap tool1(tool1_xpm);\r
+ wxBitmap tool2(tool2_xpm);\r
+ wxBitmap tool3(tool3_xpm);\r
+\r
+ tb->AddTool(ID_TBLEFT, _("Prev char"), tool1, _("Go to prev char"), wxITEM_NORMAL);\r
+ tb->AddTool(ID_TBRIGHT, _("Next char"), tool2, _("Go to next char"), wxITEM_NORMAL);\r
+ tb->AddTool(ID_TBCHARWIN, _("Char Wnd"), tool3, _("Toggle char window"), wxITEM_NORMAL);\r
+ tb->Realize();\r
+ }\r
+\r
+ // Create a menu bar for the frame\r
+ menuBar = new wxMenuBar;\r
+ wxMenu * menu1 = new wxMenu;\r
+ menu1->Append(IDM_NEW, _("&New\tCtrl+N"), _("Create a new font."));\r
+ menu1->Append(IDM_OPEN, _("&Open...\tCtrl+O"), _("Opens an existing font."));\r
+ menu1->Append(IDM_SAVE, _("&Save\tCtrl+S"), _("Save the current font."));\r
+ menu1->Append(IDM_SAVEAS, _("Save &As..."), _("Save the current font under a different name."));\r
+ menu1->AppendSeparator();\r
+ menu1->Append(IDM_EXIT, _("E&xit\tAlt+X"), _("Quits the TTEdit program."));\r
+ menuBar->Append(menu1, _("&File"));\r
+ wxMenu * menu2 = new wxMenu;\r
+ menu2->Append(IDM_HELPTOPICS, _("&Help Topics"), _("Displays the Help contents and index."));\r
+ menu2->AppendSeparator();\r
+ menu2->Append(IDM_ABOUT, _("&About TTEdit"), _("Displays information about TTEdit."));\r
+ menuBar->Append(menu2, _("&Help"));\r
+ SetMenuBar(menuBar);\r
+\r
+ // Create child subwindows\r
+ mainWindow = new TTEditWindow(this);\r
+\r
+ Centre(wxBOTH); // Centre frame on the screen\r
+ Show(true); // Show the frame\r
+}\r
+\r
+TTEditFrame::~TTEditFrame()\r
+{\r
+}\r
+\r
+void TTEditFrame::OnOpen(wxCommandEvent &e)\r
+{\r
+ wxFileDialog fd(this, _("Choose a font to load"), _(""), _(""), _("TTF files (*.ttf)|*.ttf|All files (*.*)|*.*"), wxOPEN);\r
+\r
+ if (fd.ShowModal() != wxID_OK)\r
+ return;\r
+\r
+// Hmm. The font object is causing a massive crash... (gdb says it's in "Load")\r
+ if (app.font.Load((char *)fd.GetPath().c_str()) != true)\r
+ {\r
+ wxMessageDialog dlg(NULL, _("Load font failed!"), _("Houston, we have a problem..."), wxOK | wxICON_ERROR);\r
+ dlg.ShowModal();\r
+ }\r
+\r
+//Huzzah! It works! Now just need scaling, scrolling, etc...\r
+// pts = app.font.GetGlyphPoints(45);\r
+}\r
+\r
+void TTEditFrame::OnAbout(wxCommandEvent &e)\r
+{\r
+ wxMessageDialog dlg(NULL, _("TrueType Edit v1.0.0\n\nA handy tool for editing TrueType fonts!\nby James \"Shamus\" Hammons\n(C) 2006 Underground Software"), _("About TrueType Edit"), wxOK | wxICON_INFORMATION);\r
+ dlg.ShowModal();\r
+}\r
+\r
+void TTEditFrame::OnExit(wxCommandEvent &e)\r
+{\r
+ wxGetApp().toolPalette->Destroy();\r
+ this->Destroy();\r
+}\r
+\r
+void TTEditFrame::OnCloseWindow(wxCloseEvent &e)\r
+{\r
+ wxGetApp().toolPalette->Destroy();\r
+ this->Destroy();\r
+}\r
+\r
+BEGIN_EVENT_TABLE(TTEditWindow, wxWindow)\r
+ EVT_PAINT(TTEditWindow::OnPaint)\r
+ EVT_MOUSE_EVENTS(TTEditWindow::OnMouseEvent)\r
+END_EVENT_TABLE()\r
+\r
+TTEditWindow::TTEditWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):\r
+ wxWindow(parent, -1, pos, size, style), app(wxGetApp())\r
+{ \r
+ bmp = NULL;\r
+ scale = 1.0;\r
+ offsetX = offsetY = -10;\r
+\r
+ SetCursor(*cur[currentTool]);\r
+ SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));\r
+\r
+ wxString s;\r
+ s.Printf(_("Zoom: %.2f%%"), scale * 100.0);\r
+ parent->SetStatusText(s, 1);\r
+}\r
+\r
+TTEditWindow::~TTEditWindow(void)\r
+{\r
+ if (bmp)\r
+ delete bmp;\r
+}\r
+\r
+void TTEditWindow::OnPaint(wxPaintEvent &e)\r
+{\r
+/* wxPaintDC dc(this);\r
+\r
+ // Insert your drawing code here.\r
+ if (!bmp)\r
+ {\r
+ bmp = new wxBitmap(field_width * x_cell * X_UNIT + 1, field_height * y_cell * Y_UNIT + 1);\r
+\r
+ if (bmp)\r
+ {\r
+ wxMemoryDC memDC;\r
+ memDC.SelectObject(*bmp);\r
+ DrawField(&memDC, 0, 0, field_width - 1, field_height - 1);\r
+ memDC.SelectObject(wxNullBitmap);\r
+ }\r
+ }\r
+\r
+ if (bmp)\r
+ {\r
+ wxMemoryDC memDC;\r
+ memDC.SelectObject(* bmp);\r
+ dc.Blit(0, 0, field_width * x_cell * X_UNIT + 1, field_height * y_cell * Y_UNIT + 1,\r
+ &memDC, 0, 0, wxCOPY);\r
+ memDC.SelectObject(wxNullBitmap);\r
+ }\r
+ else\r
+ DrawField(&dc, 0, 0, field_width - 1, field_height - 1);*/\r
+\r
+ wxPaintDC dc(this);\r
+//Doesn't do crap!\r
+//dc.SetBackground(*wxWHITE_BRUSH);\r
+\r
+// Due to the screwiness of wxWidgets coord system, the origin is ALWAYS\r
+// the upper left corner--regardless of axis orientation, etc...\r
+ wxCoord width, height;\r
+ dc.GetSize(&width, &height);\r
+\r
+ dc.SetDeviceOrigin(-offsetX, height - (-offsetY));\r
+ dc.SetAxisOrientation(true, true);\r
+\r
+// Scrolling can be done by using OffsetViewportOrgEx\r
+// Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)\r
+// you'd use: % = ViewportExt / WindowExt\r
+// But it makes the window look like crap: fuggetuboutit.\r
+// Instead, we have to scale EVERYTHING by hand. Crap!\r
+// It's not *that* bad, but not as convenient either...\r
+\r
+ dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));\r
+// dc.DrawLine(0, 0, 10, 10);\r
+\r
+ // Draw coordinate axes\r
+\r
+ dc.CrossHair(0, 0);\r
+\r
+ // Draw points\r
+\r
+ for(int i=0; i<pts.GetNumPoints(); i++)\r
+ {\r
+ if (i == ptHighlight)\r
+ {\r
+ dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));\r
+// SelectObject(hdc, hRedPen1);\r
+\r
+ if (pts.GetOnCurve(i))\r
+ {\r
+ DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
+ DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
+ }\r
+ else\r
+ {\r
+ DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
+ DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
+ }\r
+ }\r
+ else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)\r
+ {\r
+ dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));\r
+// SelectObject(hdc, hGreenPen1);\r
+\r
+ if (pts.GetOnCurve(i))\r
+ {\r
+ DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
+ DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
+ }\r
+ else\r
+ {\r
+ DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
+ DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));\r
+// SelectObject(hdc, hBlackPen1);\r
+\r
+ if (pts.GetOnCurve(i))\r
+ DrawSquareDot(dc, pts.GetX(i), pts.GetY(i));\r
+ else\r
+ DrawRoundDot(dc, pts.GetX(i), pts.GetY(i));\r
+ }\r
+\r
+ if (currentTool == TOOLDelPt && i == ptHighlight)\r
+ {\r
+ dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));\r
+// SelectObject(hdc, hRedPen1);\r
+// MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);\r
+// LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);\r
+// LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!\r
+// MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);\r
+// LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);\r
+// LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!\r
+ dc.DrawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);\r
+ dc.DrawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);\r
+ }\r
+ }\r
+\r
+// SelectObject(hdc, hBlackPen1);\r
+ dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));\r
+\r
+ // Draw curve formed by points\r
+\r
+ for(int poly=0; poly<pts.GetNumPolys(); poly++)\r
+ {\r
+ if (pts.GetNumPoints(poly) > 2)\r
+ {\r
+ // Initial move...\r
+ // If it's not on curve, then move to it, otherwise move to last point...\r
+\r
+ wxCoord x, y;\r
+ \r
+ if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))\r
+ x = (wxCoord)pts.GetX(poly, pts.GetNumPoints(poly) - 1), y = (wxCoord)pts.GetY(poly, pts.GetNumPoints(poly) - 1);\r
+ else\r
+ x = (wxCoord)pts.GetX(poly, 0), y = (wxCoord)pts.GetY(poly, 0);\r
+ \r
+ for(int i=0; i<pts.GetNumPoints(poly); i++)\r
+ {\r
+ if (pts.GetOnCurve(poly, i))\r
+// LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));\r
+ {\r
+ dc.DrawLine(x, y, pts.GetX(poly, i), pts.GetY(poly, i));\r
+ x = (wxCoord)pts.GetX(poly, i), y = (wxCoord)pts.GetY(poly, i);\r
+ }\r
+ else\r
+ {\r
+ uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);\r
+ float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),\r
+ nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);\r
+ \r
+ if (!pts.GetOnCurve(poly, prev))\r
+ px = (px + pts.GetX(poly, i)) / 2.0f,\r
+ py = (py + pts.GetY(poly, i)) / 2.0f;\r
+ \r
+ if (!pts.GetOnCurve(poly, next))\r
+ nx = (nx + pts.GetX(poly, i)) / 2.0f,\r
+ ny = (ny + pts.GetY(poly, i)) / 2.0f;\r
+ \r
+ Bezier(dc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));\r
+ x = (wxCoord)nx, y = (wxCoord)ny;\r
+ \r
+ if (pts.GetOnCurve(poly, next))\r
+ i++; // Following point is on curve, so move past it\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+// SelectObject(hdc, oldPen); // Restore the stuff we disrupted...\r
+ dc.SetPen(wxNullPen);\r
+// SelectObject(hdc, oldBrush);\r
+// EndPaint(hWnd, &ps);\r
+}\r
+\r
+void TTEditWindow::OnMouseEvent(wxMouseEvent &e)\r
+{\r
+ if (e.RightDown())\r
+ {\r
+ wxPoint pt = ClientToScreen(e.GetPosition());\r
+ wxGetApp().toolPalette->Move(pt);\r
+ wxGetApp().toolPalette->Show(true);\r
+ wxGetApp().toolPalette->SetFocus();\r
+ wxGetApp().toolPalette->CaptureMouse();\r
+ SetCursor(*wxSTANDARD_CURSOR);\r
+ }\r
+ else if (e.LeftDown())\r
+ {\r
+ if (currentTool == TOOLScroll || currentTool == TOOLZoom)\r
+ CaptureMouse(); // Make sure we capture the mouse when in scroll/zoom mode\r
+ else if (currentTool == TOOLAddPt) // "Add Point" tool\r
+ {\r
+ if (pts.GetNumPoints() > 0)\r
+ {\r
+ wxPoint pt = GetAdjustedMousePosition(e);\r
+ pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));\r
+ ptHighlight = ptNextHighlight;\r
+ Refresh();\r
+ }\r
+ }\r
+ else if (currentTool == TOOLAddPoly) // "Add Poly" tool\r
+ {\r
+#ifdef DEBUGFOO\r
+WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());\r
+#endif\r
+ if (polyFirstPoint)\r
+ {\r
+ polyFirstPoint = false;\r
+ pts.AddNewPolyAtEnd();\r
+ }\r
+\r
+ wxPoint pt = GetAdjustedMousePosition(e);\r
+ // Append a point to the end of the structure\r
+ pts += IPoint(pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));\r
+ ptHighlight = pts.GetNumPoints() - 1;\r
+ Refresh();\r
+#ifdef DEBUGFOO\r
+WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());\r
+#endif\r
+ }\r
+ else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)\r
+ {\r
+ if (pts.GetNumPoints() > 0)\r
+ {\r
+ pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));\r
+ WarpPointer(pt.x, pt.y);\r
+\r
+ if (e.ShiftDown() | e.ControlDown())\r
+ pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));\r
+ }\r
+ }\r
+ else if (currentTool == TOOLDelPt)\r
+ {\r
+ if (pts.GetNumPoints() > 0)\r
+//Or could use:\r
+// if (ptHighlight != -1)\r
+ {\r
+//This assumes that WM_MOUSEMOVE happens before this!\r
+//The above commented out line should take care of this contingency... !!! FIX !!!\r
+ pts.DeletePoint(ptHighlight);\r
+ Refresh();\r
+ }\r
+ }\r
+ }\r
+ else if (e.LeftUp())\r
+ {\r
+// mouseDown = false;\r
+\r
+ if (currentTool == TOOLScroll || currentTool == TOOLZoom)\r
+// ReleaseCapture();\r
+ ReleaseMouse();\r
+ }\r
+ else if (e.Dragging())\r
+ {\r
+//Do this here? Needed? SetCursor(hCur[currentTool]);\r
+\r
+ // Extract current point from lParam/calc offset from previous point\r
+\r
+ pt = e.GetPosition();\r
+ ptOffset.x = pt.x - ptPrevious.x,\r
+ ptOffset.y = pt.y - ptPrevious.y;\r
+\r
+// if (e.LeftIsDown())\r
+// {\r
+ if (currentTool == TOOLScroll)\r
+ {\r
+ // NOTE: OffsetViewportOrg operates in DEVICE UNITS...\r
+\r
+//Seems there's no equivalent for this in wxWidgets...!\r
+//!!! FIX !!!\r
+// hdc = GetDC(hWnd);\r
+// OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);\r
+// ReleaseDC(hWnd, hdc);\r
+\r
+// this shows that it works, so the logic above must be faulty...\r
+// And it is. It should convert the coords first, then do the subtraction to figure the offset...\r
+// Above: DONE\r
+// Then multiply it by the scaling factor. Whee!\r
+ // This looks wacky because we're using screen coords for the offset...\r
+ // Otherwise, we would subtract both offsets!\r
+ offsetX -= ptOffset.x, offsetY += ptOffset.y;\r
+ Refresh();\r
+ }\r
+ else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)\r
+ {\r
+ if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.\r
+ {\r
+ wxPoint pt2 = GetAdjustedMousePosition(e);\r
+ pts.SetXY(ptHighlight, pt2.x, pt2.y);\r
+ Refresh();\r
+ }\r
+ }\r
+ else if (currentTool == TOOLPolySelect)\r
+ {\r
+ if (pts.GetNumPoints() > 0)\r
+ {\r
+ wxPoint pt2 = GetAdjustedMousePosition(e);\r
+ // Should also set onCurve here as well, depending on keystate\r
+//Or should we?\r
+ pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));\r
+ Refresh();\r
+ }\r
+ }\r
+// }\r
+\r
+ ptPrevious = pt;\r
+ }\r
+ else if (e.Moving())\r
+ {\r
+// else // Moving, not dragging...\r
+// {\r
+ if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt\r
+ || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)\r
+ {\r
+ wxPoint pt2 = GetAdjustedMousePosition(e);\r
+ double closest = 1.0e+99;\r
+\r
+ for(int i=0; i<pts.GetNumPoints(); i++)\r
+ {\r
+ double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))\r
+ + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));\r
+\r
+ if (dist < closest)\r
+ closest = dist, ptHighlight = i;\r
+ }\r
+\r
+ if (ptHighlight != oldPtHighlight)\r
+ {\r
+ oldPtHighlight = ptHighlight;\r
+ Refresh();\r
+ }\r
+\r
+ // What follows here looks like voodoo, but is really simple. What we do is\r
+ // check to see if the mouse point has a perpendicular intersection with any of\r
+ // the line segments. If it does, calculate the length of the perpendicular\r
+ // and choose the smallest length. If there is no perpendicular, then choose the\r
+ // length of line connecting the closer of either the first endpoint or the\r
+ // second and choose the smallest of those.\r
+\r
+ // There is one bit of math that looks like voodoo to me ATM--will explain once\r
+ // I understand it better (the calculation of the length of the perpendicular).\r
+\r
+ if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)\r
+ {\r
+ double smallest = 1.0e+99;\r
+\r
+ for(int i=0; i<pts.GetNumPoints(); i++)\r
+ {\r
+ int32 p1x = pts.GetX(i), p1y = pts.GetY(i),\r
+ p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));\r
+\r
+ vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),\r
+ v2(pt2.x, pt2.y, 0, p2x, p2y, 0);\r
+ double pp = ls.dot(v1) / ls.length(), dist;\r
+// Geometric interpretation:\r
+// pp is the paremeterized point on the vector ls where the perpendicular intersects ls.\r
+// If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,\r
+// then the perpendicular lies beyond the 2nd endpoint.\r
+\r
+ if (pp < 0.0)\r
+ dist = v1.length();\r
+ else if (pp > ls.length())\r
+ dist = v2.length();\r
+ else // distance = ?Det?(ls, v1) / |ls|\r
+ dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length());\r
+\r
+//The answer to the above looks like it might be found here:\r
+//\r
+//If the segment endpoints are s and e, and the point is p, then the test for the perpendicular\r
+//intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and\r
+//{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is\r
+//computed by first computing the area of the triangle the three points form, then dividing by the\r
+//length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the\r
+//triangle formed by three points is the determinant of the following matrix:\r
+//\r
+//sx sy 1\r
+//ex ey 1\r
+//px py 1\r
+//\r
+//(???) By translating the start point to the origin, this can be rewritten as:\r
+//By subtracting row 1 from all rows, you get the following:\r
+//\r
+//0 0 0\r
+//(ex - sx) (ey - sy) 0\r
+//(px - sx) (py - sy) 0\r
+//\r
+//which greatly simplifies the calculation of the determinant.\r
+\r
+ if (dist < smallest)\r
+ smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;\r
+ }\r
+\r
+ if (ptNextHighlight != oldPtNextHighlight)\r
+ {\r
+ oldPtNextHighlight = ptNextHighlight;\r
+ Refresh();\r
+ }\r
+ }\r
+ }\r
+// }\r
+\r
+ ptPrevious = e.GetPosition();\r
+ }\r
+}\r
+\r
+\r
+wxPoint TTEditWindow::GetAdjustedMousePosition(wxMouseEvent &e)\r
+{\r
+ wxCoord width, height;\r
+ wxClientDC dc(this);\r
+\r
+ dc.GetSize(&width, &height);\r
+ dc.SetDeviceOrigin(-offsetX, height - (-offsetY));\r
+ dc.SetAxisOrientation(true, true);\r
+\r
+/*wxStatusBar * sb = ((wxFrame *)GetParent())->GetStatusBar();\r
+wxString s;\r
+s.Printf("Logical mouse pos: %d, %d (%d, %d)", pt.x, pt.y, width, height);\r
+sb->SetStatusText(s);//*/\r
+\r
+ return e.GetLogicalPosition(dc);\r
+}\r
+\r
+wxPoint TTEditWindow::GetAdjustedClientPosition(wxCoord x, wxCoord y)\r
+{\r
+ wxCoord width, height;\r
+ wxClientDC dc(this);\r
+\r
+ dc.GetSize(&width, &height);\r
+ dc.SetDeviceOrigin(-offsetX, height - (-offsetY));\r
+ dc.SetAxisOrientation(true, true);\r
+\r
+ return wxPoint(dc.LogicalToDeviceX(x), dc.LogicalToDeviceY(y));\r
+}\r
+\r
+//\r
+\r
+void CreateResources(void)\r
+{\r
+ // This is a sucky way to create cursors, but at least it's cross-platform...\r
+ // NOTE: Need to fix hotspots on a few... !!! FIX !!!\r
+\r
+ wxBitmap cursorBM1(cur1_xpm);\r
+ wxImage cursorImage1 = cursorBM1.ConvertToImage();\r
+ cursorImage1.SetMaskFromImage(cursorImage1, 0xFF, 0xFF, 0xFF);\r
+ cur[0] = new wxCursor(cursorImage1);\r
+\r
+ wxBitmap cursorBM2(cur2_xpm);\r
+ wxImage cursorImage2 = cursorBM2.ConvertToImage();\r
+ cursorImage2.SetMaskFromImage(cursorImage2, 0xFF, 0xFF, 0xFF);\r
+ cur[1] = new wxCursor(cursorImage2);\r
+\r
+ wxBitmap cursorBM3(cur3_xpm);\r
+ wxImage cursorImage3 = cursorBM3.ConvertToImage();\r
+ cursorImage3.SetMaskFromImage(cursorImage3, 0xFF, 0xFF, 0xFF);\r
+ cur[2] = new wxCursor(cursorImage3);\r
+\r
+ wxBitmap cursorBM4(cur4_xpm);\r
+ wxImage cursorImage4 = cursorBM4.ConvertToImage();\r
+ cursorImage4.SetMaskFromImage(cursorImage4, 0xFF, 0xFF, 0xFF);\r
+ cur[3] = new wxCursor(cursorImage4);\r
+\r
+ wxBitmap cursorBM5(cur5_xpm);\r
+ wxImage cursorImage5 = cursorBM5.ConvertToImage();\r
+ cursorImage5.SetMaskFromImage(cursorImage5, 0xFF, 0xFF, 0xFF);\r
+ cur[4] = new wxCursor(cursorImage5);\r
+\r
+ wxBitmap cursorBM6(cur6_xpm);\r
+ wxImage cursorImage6 = cursorBM6.ConvertToImage();\r
+ cursorImage6.SetMaskFromImage(cursorImage6, 0xFF, 0xFF, 0xFF);\r
+ cur[5] = new wxCursor(cursorImage6);\r
+\r
+ wxBitmap cursorBM7(cur7_xpm);\r
+ wxImage cursorImage7 = cursorBM7.ConvertToImage();\r
+ cursorImage7.SetMaskFromImage(cursorImage7, 0xFF, 0xFF, 0xFF);\r
+ cur[6] = new wxCursor(cursorImage7);\r
+\r
+ wxBitmap cursorBM8(cur8_xpm);\r
+ wxImage cursorImage8 = cursorBM8.ConvertToImage();\r
+ cursorImage8.SetMaskFromImage(cursorImage8, 0xFF, 0xFF, 0xFF);\r
+ cur[7] = new wxCursor(cursorImage8);\r
+}\r
+\r
+//\r
+// Draw a round dot (5x5, centered on [x, y])\r
+//\r
+void DrawRoundDot(wxDC &dc, int32 x, int32 y)\r
+{\r
+ wxPoint pt[8];\r
+\r
+ pt[0].x = x - 1, pt[0].y = y - 2;\r
+ pt[1].x = x + 1, pt[1].y = y - 2;\r
+ pt[2].x = x + 2, pt[2].y = y - 1;\r
+ pt[3].x = x + 2, pt[3].y = y + 1;\r
+ pt[4].x = x + 1, pt[4].y = y + 2;\r
+ pt[5].x = x - 1, pt[5].y = y + 2;\r
+ pt[6].x = x - 2, pt[6].y = y + 1;\r
+ pt[7].x = x - 2, pt[7].y = y - 1;\r
+\r
+ dc.DrawPolygon(8, pt);\r
+}\r
+\r
+//\r
+// Draw a sqaure dot (5x5, centered on [x, y])\r
+//\r
+void DrawSquareDot(wxDC &dc, int32 x, int32 y)\r
+{\r
+ wxPoint pt[4];\r
+\r
+ pt[0].x = x - 2, pt[0].y = y - 2;\r
+ pt[1].x = x + 2, pt[1].y = y - 2;\r
+ pt[2].x = x + 2, pt[2].y = y + 2;\r
+ pt[3].x = x - 2, pt[3].y = y + 2;\r
+\r
+ dc.DrawPolygon(4, pt);\r
+}\r
+\r
+//\r
+// Draw a sqaure dot (nxn, centered on [x, y])\r
+//\r
+void DrawSquareDotN(wxDC &dc, int32 x, int32 y, uint32 n)\r
+{\r
+ wxPoint pt[4];\r
+ uint32 offset = (n - 1) / 2;\r
+\r
+ pt[0].x = x - offset, pt[0].y = y - offset;\r
+ pt[1].x = x + offset, pt[1].y = y - offset;\r
+ pt[2].x = x + offset, pt[2].y = y + offset;\r
+ pt[3].x = x - offset, pt[3].y = y + offset;\r
+\r
+ dc.DrawPolygon(4, pt);\r
+}\r
+\r
+//\r
+// Draw a round dot (nxn, centered on [x, y])\r
+//\r
+void DrawRoundDotN(wxDC &dc, int32 x, int32 y, uint32 n)\r
+{\r
+ dc.DrawCircle(x, y, (n / 2) + 1);\r
+}\r
+\r
+\r
+BEGIN_EVENT_TABLE(CharWindow, wxWindow)\r
+// EVT_PAINT(CharWindow::OnPaint)\r
+// EVT_MOUSE_EVENTS(CharWindow::OnMouseEvent)\r
+END_EVENT_TABLE()\r
+\r
+CharWindow::CharWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):\r
+ wxWindow(parent, -1, pos, size, style)\r
+{\r
+} \r
+\r
+CharWindow::~CharWindow()\r
+{\r
+}\r
+\r
+\r
+BEGIN_EVENT_TABLE(ToolWindow, wxWindow)\r
+ EVT_PAINT(ToolWindow::OnPaint)\r
+ EVT_MOUSE_EVENTS(ToolWindow::OnMouseEvent)\r
+END_EVENT_TABLE()\r
+\r
+ToolWindow::ToolWindow(wxFrame * parent, const wxString &title, const wxPoint &pos,\r
+ const wxSize &size, long style): wxFrame(parent, -1, title, pos, size, style)\r
+//ToolWindow::ToolWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):\r
+// wxWindow(parent, -1, pos, size, style)\r
+{\r
+ bmp = new wxBitmap(toolpal1_xpm);\r
+ prevTool = -1;\r
+\r
+ // Set up sizes\r
+\r
+ sizeTPBM.x = bmp->GetWidth(), sizeTPBM.y = bmp->GetHeight();\r
+ sizeStamp.x = sizeTPBM.x / 4, sizeStamp.y = sizeTPBM.y / 2;\r
+\r
+ SetSize(10, 10, sizeTPBM.x, sizeTPBM.y);\r
+ Show(false);\r
+}\r
+\r
+ToolWindow::~ToolWindow()\r
+{\r
+}\r
+\r
+void ToolWindow::OnPaint(wxPaintEvent &e)\r
+{\r
+ wxPaintDC dc(this);\r
+\r
+ wxMemoryDC memDC;\r
+ memDC.SelectObject(*bmp);\r
+ dc.Blit(0, 0, sizeTPBM.x, sizeTPBM.y, &memDC, 0, 0, wxCOPY);\r
+\r
+ int32 tool = FindSelectedTool();\r
+\r
+ if (tool != -1)\r
+ {\r
+ //need ul corner of bitmap, ul corner of dest, width/height\r
+ wxPoint pt(sizeStamp.x * (tool & 0x03), sizeStamp.y * (tool >> 2));\r
+ dc.Blit(pt.x, pt.y, sizeStamp.x, sizeStamp.y, &memDC, pt.x, pt.y, wxSRC_INVERT);\r
+ }\r
+\r
+ memDC.SelectObject(wxNullBitmap);\r
+}\r
+\r
+void ToolWindow::OnMouseEvent(wxMouseEvent &e)\r
+{\r
+// if (e.Moving())\r
+ if (e.Dragging())\r
+ {\r
+ int32 tool = FindSelectedTool();\r
+\r
+ if (tool != prevTool)\r
+ {\r
+ prevTool = tool;\r
+ Refresh(false);\r
+ }\r
+ }\r
+\r
+ if (e.RightUp())\r
+ {\r
+ int32 tool = FindSelectedTool(), oldTool = currentTool;\r
+\r
+ if (tool != -1)\r
+ currentTool = tool;\r
+\r
+ if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt\r
+ && currentTool != TOOLPolySelect)\r
+ ptHighlight = -1;\r
+\r
+ if (currentTool != oldTool)\r
+ Refresh(false);\r
+\r
+ if (currentTool == TOOLAddPoly)\r
+#ifdef DEBUGFOO\r
+{\r
+#endif\r
+ polyFirstPoint = true;\r
+#ifdef DEBUGFOO\r
+sprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");\r
+WriteLogMsg(strBuf);\r
+}\r
+#endif\r
+\r
+ ReleaseMouse();\r
+ Show(false);\r
+ wxGetApp().mainFrame->mainWindow->SetCursor(*cur[currentTool]);\r
+ wxGetApp().mainFrame->mainWindow->SetFocus(); // Make sure the main wnd keeps focus!\r
+ }\r
+}\r
+\r
+//\r
+// Find which tool we're pointing at\r
+// Use: xcoord = mouse.x / (bmsize.x/4), ycoord = mouse.y / (bmsize.y/2)\r
+//\r
+int32 ToolWindow::FindSelectedTool(void)\r
+{\r
+ wxPoint pt = ScreenToClient(wxGetMousePosition());\r
+ uint32 x = (uint32)pt.x / sizeStamp.x, y = (uint32)pt.y / sizeStamp.y, tool = (uint32)-1;\r
+\r
+ if (x < 4 && y < 2)\r
+ tool = (y * 4) + x;\r
+\r
+ return tool;\r
+}\r
+\r
+\r
+/*\r
+LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)\r
+{\r
+ RECT rc1, rc2;\r
+ HDC hdc;\r
+ POINT pt, ptOffset;\r
+ SIZE sz;\r
+ PAINTSTRUCT ps;\r
+\r
+ switch (msgID)\r
+ {\r
+ case WM_CREATE:\r
+\r
+ MiscCenterWnd(hWnd, GetDesktopWindow());\r
+ InitCommonControls();\r
+ hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE, statusBarTxt, hWnd, ID_STATUSBAR);\r
+\r
+ if (!hStatusBar)\r
+ return -1;\r
+\r
+// clean this crap up!\r
+// well, the only crappy thing here is using a POINT as an int array, but otherwise, this is OK\r
+ wsprintf(strBuf, zoom, 1000);\r
+ hdc = GetDC(hWnd);\r
+ GetTextExtentPoint32(hdc, strBuf, lstrlen(strBuf), &sz);\r
+ ReleaseDC(hWnd, hdc);\r
+ zoomWndWidth = sz.cx;\r
+ wsprintf(strBuf, zoom, 100);\r
+\r
+ GetClientRect(hWnd, &rc1);\r
+ pt.x = rc1.right - zoomWndWidth, pt.y = -1;\r
+ SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);\r
+ SendMessage(hStatusBar, SB_SETTEXT, (0 | SBT_NOBORDERS), (LPARAM)statusBarTxt);\r
+ SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM)strBuf);\r
+\r
+ hToolBar = CreateToolbarEx(hWnd, WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS,\r
+ IDR_TOOLBAR1, 3, hInst, IDB_TOOLBAR1, tbButtons, 4, 16, 16, 16, 16, sizeof(TBBUTTON));\r
+\r
+ if (!hToolBar)\r
+ return -1;\r
+\r
+ CreateNewDoc();\r
+\r
+// The following can only be done because we use a private DC (using "CS_OWNDC")\r
+// (Is that true???)\r
+// Set the mapping to draw the character so it fits in the viewport...\r
+ hdc = GetDC(hWnd);\r
+ GetClientRect(hWnd, &rc1);\r
+ GetClientRect(hStatusBar, &rc2);\r
+ rc1.bottom -= rc2.bottom;\r
+ SetMapMode(hdc, MM_ISOTROPIC);\r
+ SetWindowExtEx(hdc, rc1.right, rc1.bottom, NULL);\r
+ SetViewportExtEx(hdc, rc1.right, -rc1.bottom, NULL);\r
+ SetViewportOrgEx(hdc, 0, rc1.bottom, NULL);\r
+ ReleaseDC(hWnd, hdc);\r
+ break;\r
+\r
+ case WM_CLOSE:\r
+\r
+ if (SaveChanges())\r
+ {\r
+ wpM.length = wpC.length = sizeof(WINDOWPLACEMENT);\r
+ GetWindowPlacement(hMainWnd, &wpM);\r
+ GetWindowPlacement(hCharWnd, &wpC);\r
+\r
+ if (!IsWindowVisible(hCharWnd)) // Needed because Windows lies about visibility\r
+ wpC.showCmd = SW_HIDE;\r
+\r
+ hdc = GetDC(hWnd);\r
+ GetViewportOrgEx(hdc, &ptVPM);\r
+ ReleaseDC(hWnd, hdc);\r
+\r
+ DestroyWindow(hWnd);\r
+ }\r
+\r
+ break;\r
+\r
+ case WM_DESTROY:\r
+\r
+ PostQuitMessage(0);\r
+ break;\r
+\r
+ case WM_NCLBUTTONDOWN:\r
+\r
+ if (wParam == HTCAPTION)\r
+ {\r
+ NCMouseDown = true;\r
+ GetWindowRect(hMainWnd, &rc1);\r
+ GetWindowRect(hCharWnd, &rc2);\r
+ ptWinOffset.x = rc2.left - rc1.left;\r
+ ptWinOffset.y = rc2.top - rc1.top;\r
+ }\r
+ \r
+ // Let Windows do its thing with this msg, or weird things will happen...\r
+\r
+ DefWindowProc(hWnd, msgID, wParam, lParam);\r
+ NCMouseDown = false;\r
+ break;\r
+\r
+ case WM_WINDOWPOSCHANGING:\r
+\r
+ if (NCMouseDown)\r
+ {\r
+ WINDOWPOS * wp = (WINDOWPOS *)lParam;\r
+\r
+ if (wp->hwnd == hMainWnd && !(wp->flags & SWP_NOMOVE))\r
+ SetWindowPos(hCharWnd, 0, wp->x + ptWinOffset.x, wp->y + ptWinOffset.y,\r
+ 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);\r
+ }\r
+\r
+ return DefWindowProc(hWnd, msgID, wParam, lParam); // Seems this is needed... Bleah!\r
+\r
+ case WM_PAINT:\r
+ {\r
+ hdc = BeginPaint(hWnd, &ps);\r
+\r
+// Scrolling can be done by using OffsetViewportOrgEx\r
+// Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)\r
+// you'd use: % = ViewportExt / WindowExt\r
+// But it makes the window look like crap: fuggetuboutit.\r
+// Instead, we have to scale EVERYTHING by hand. Crap!\r
+\r
+ // Apparently, you *must* save the individual object types (pen, brush, etc.)\r
+\r
+ HGDIOBJ oldPen = SelectObject(hdc, hBluePen1),\r
+ oldBrush = SelectObject(hdc, hNullBrush);\r
+\r
+ // Draw coordinate axes\r
+\r
+ MoveToEx(hdc, 0, -32000, NULL);\r
+ LineTo(hdc, 0, 32000);\r
+ MoveToEx(hdc, -32000, 0, NULL);\r
+ LineTo(hdc, 32000, 0);\r
+\r
+ // Draw points\r
+\r
+ for(int i=0; i<pts.GetNumPoints(); i++)\r
+ {\r
+ if (i == ptHighlight)\r
+ {\r
+ SelectObject(hdc, hRedPen1);\r
+\r
+ if (pts.GetOnCurve(i))\r
+ {\r
+ DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
+ DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
+ }\r
+ else\r
+ {\r
+ DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
+ DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
+ }\r
+ }\r
+ else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)\r
+ {\r
+ SelectObject(hdc, hGreenPen1);\r
+\r
+ if (pts.GetOnCurve(i))\r
+ {\r
+ DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
+ DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
+ }\r
+ else\r
+ {\r
+ DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
+ DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ SelectObject(hdc, hBlackPen1);\r
+\r
+ if (pts.GetOnCurve(i))\r
+ DrawSquareDot(hdc, pts.GetX(i), pts.GetY(i));\r
+ else\r
+ DrawRoundDot(hdc, pts.GetX(i), pts.GetY(i));\r
+ }\r
+\r
+ if (currentTool == TOOLDelPt && i == ptHighlight)\r
+ {\r
+ SelectObject(hdc, hRedPen1);\r
+ MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);\r
+ LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);\r
+ LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!\r
+ MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);\r
+ LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);\r
+ LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!\r
+ }\r
+ }\r
+\r
+ SelectObject(hdc, hBlackPen1);\r
+\r
+ // Draw curve formed by points\r
+\r
+ for(int poly=0; poly<pts.GetNumPolys(); poly++)\r
+ {\r
+ if (pts.GetNumPoints(poly) > 2)\r
+ {\r
+ // Initial move...\r
+ // If it's not on curve, then move to it, otherwise move to last point...\r
+ \r
+ if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))\r
+ MoveToEx(hdc, pts.GetX(poly, pts.GetNumPoints(poly) - 1), pts.GetY(poly, pts.GetNumPoints(poly) - 1), NULL);\r
+ else\r
+ MoveToEx(hdc, pts.GetX(poly, 0), pts.GetY(poly, 0), NULL);\r
+ \r
+ for(int i=0; i<pts.GetNumPoints(poly); i++)\r
+ {\r
+ if (pts.GetOnCurve(poly, i))\r
+ LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));\r
+ else\r
+ {\r
+ uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);\r
+ float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),\r
+ nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);\r
+ \r
+ if (!pts.GetOnCurve(poly, prev))\r
+ px = (px + pts.GetX(poly, i)) / 2.0f,\r
+ py = (py + pts.GetY(poly, i)) / 2.0f;\r
+ \r
+ if (!pts.GetOnCurve(poly, next))\r
+ nx = (nx + pts.GetX(poly, i)) / 2.0f,\r
+ ny = (ny + pts.GetY(poly, i)) / 2.0f;\r
+ \r
+ Bezier(hdc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));\r
+ \r
+ if (pts.GetOnCurve(poly, next))\r
+ i++; // Following point is on curve, so move past it\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ SelectObject(hdc, oldPen); // Restore the stuff we disrupted...\r
+ SelectObject(hdc, oldBrush);\r
+ EndPaint(hWnd, &ps);\r
+ break;\r
+ }\r
+ case WM_SIZE:\r
+\r
+ // Apparently this is needed since these windows don't update themselves.\r
+ SendMessage(hStatusBar, msgID, wParam, lParam);\r
+ SendMessage(hToolBar, msgID, wParam, lParam);\r
+\r
+ // This is needed to make the 2nd status pane visible\r
+ GetClientRect(hWnd, &rc1);\r
+ pt.x = rc1.right - zoomWndWidth, pt.y = -1;\r
+ SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);\r
+ break;\r
+\r
+ case WM_RBUTTONDOWN:\r
+\r
+ GetCursorPos(&pt);\r
+ SetWindowPos(hToolPalWnd, 0, pt.x, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);\r
+ SetFocus(hToolPalWnd);\r
+ SetCapture(hToolPalWnd); // Ensure tool palette gets RButtonUp\r
+ SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW))); // Tool pallete has "regular" cursor\r
+ break;\r
+\r
+ case WM_LBUTTONDOWN:\r
+\r
+ mouseDown = true;\r
+\r
+ if (currentTool == TOOLScroll || currentTool == TOOLZoom)\r
+ SetCapture(hWnd); // Make sure we capture the mouse when in scroll/zoom mode\r
+ else if (currentTool == TOOLAddPt) // "Add Point" tool\r
+ {\r
+ if (pts.GetNumPoints() > 0)\r
+ {\r
+//Do we really need to put a cap on this???\r
+//Maybe...\r
+// if (pts.GetNumPoints() < 16)\r
+// {\r
+ pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;\r
+ hdc = GetDC(hWnd);\r
+ DPtoLP(hdc, &pt, 1);\r
+ pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));\r
+ ptHighlight = ptNextHighlight;\r
+ ReleaseDC(hWnd, hdc);\r
+ InvalidateRect(hWnd, NULL, TRUE);\r
+// }\r
+ }\r
+ }\r
+ else if (currentTool == TOOLAddPoly) // "Add Poly" tool\r
+ {\r
+#ifdef DEBUGFOO\r
+wsprintf(strBuf, "Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());\r
+WriteLogMsg(strBuf);\r
+#endif\r
+ if (polyFirstPoint)\r
+ {\r
+ polyFirstPoint = false;\r
+ pts.AddNewPolyAtEnd();\r
+ }\r
+\r
+//Do we really need to put a cap on this???\r
+//Maybe...\r
+// if (pts.GetNumPoints() < 16)\r
+// {\r
+ pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;\r
+ hdc = GetDC(hWnd);\r
+ DPtoLP(hdc, &pt, 1);\r
+ ReleaseDC(hWnd, hdc);\r
+ // Append a point to the end of the structure\r
+ pts += IPoint(pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));\r
+ptHighlight = pts.GetNumPoints() - 1;\r
+ InvalidateRect(hWnd, NULL, TRUE);\r
+// }\r
+#ifdef DEBUGFOO\r
+wsprintf(strBuf, " --> [# polys: %u, # points: %u]\xD\xA", pts.GetNumPolys(), pts.GetNumPoints());\r
+WriteLogMsg(strBuf);\r
+#endif\r
+ }\r
+ else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)\r
+ {\r
+ if (pts.GetNumPoints() > 0)\r
+ {\r
+ pt.x = pts.GetX(ptHighlight), pt.y = pts.GetY(ptHighlight);\r
+ hdc = GetDC(hWnd);\r
+ LPtoDP(hdc, &pt, 1);\r
+ ClientToScreen(hWnd, &pt);\r
+ SetCursorPos(pt.x, pt.y);\r
+ ReleaseDC(hWnd, hdc);\r
+\r
+ if (wParam & (MK_SHIFT | MK_CONTROL))\r
+ pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));\r
+ }\r
+ }\r
+ else if (currentTool == TOOLDelPt)\r
+ {\r
+ if (pts.GetNumPoints() > 0)\r
+//Or could use:\r
+// if (ptHighlight != -1)\r
+ {\r
+//This assumes that WM_MOUSEMOVE happens before this!\r
+//The above commented out line should take care of this contingency... !!! FIX !!!\r
+ pts.DeletePoint(ptHighlight);\r
+ InvalidateRect(hWnd, NULL, TRUE);\r
+ }\r
+ }\r
+\r
+ break;\r
+\r
+ case WM_LBUTTONUP:\r
+\r
+ mouseDown = false;\r
+\r
+ if (currentTool == TOOLScroll || currentTool == TOOLZoom)\r
+ ReleaseCapture();\r
+\r
+ break;\r
+\r
+ case WM_MOUSEMOVE:\r
+\r
+ SetCursor(hCur[currentTool]);\r
+\r
+ // Extract current point from lParam/calc offset from previous point\r
+\r
+ pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;\r
+ ptOffset.x = pt.x - ptPrevious.x,\r
+ ptOffset.y = pt.y - ptPrevious.y;\r
+\r
+ if (mouseDown)\r
+ {\r
+ if (currentTool == TOOLScroll)\r
+ {\r
+ // NOTE: OffsetViewportOrg operates in DEVICE UNITS...\r
+\r
+ hdc = GetDC(hWnd);\r
+ OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);\r
+ ReleaseDC(hWnd, hdc);\r
+\r
+// this shows that it works, so the logic above must be faulty...\r
+// And it is. It should convert the coords first, then do the subtraction to figure the offset...\r
+// Above: DONE\r
+// Then multiply it by the scaling factor. Whee!\r
+\r
+ InvalidateRect(hWnd, NULL, TRUE);\r
+// SendMessage(hWnd, WM_PAINT, NULL, NULL);\r
+ }\r
+ else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)\r
+ {\r
+ if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.\r
+ {\r
+ POINT pt2;\r
+ pt2.x = pt.x, pt2.y = pt.y;\r
+ // Should also set onCurve here as well, depending on keystate\r
+//Or should we?\r
+ hdc = GetDC(hWnd);\r
+ DPtoLP(hdc, &pt2, 1);\r
+ pts.SetXY(ptHighlight, pt2.x, pt2.y);\r
+ ReleaseDC(hWnd, hdc);\r
+ InvalidateRect(hWnd, NULL, TRUE);\r
+ }\r
+ }\r
+ else if (currentTool == TOOLPolySelect)\r
+ {\r
+ if (pts.GetNumPoints() > 0)\r
+ {\r
+ POINT pt2;\r
+ pt2.x = pt.x, pt2.y = pt.y;\r
+ // Should also set onCurve here as well, depending on keystate\r
+//Or should we?\r
+ hdc = GetDC(hWnd);\r
+ DPtoLP(hdc, &pt2, 1);\r
+ pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));\r
+ ReleaseDC(hWnd, hdc);\r
+ InvalidateRect(hWnd, NULL, TRUE);\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt\r
+ || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)\r
+ {\r
+ POINT pt2;\r
+ pt2.x = pt.x, pt2.y = pt.y;\r
+ hdc = GetDC(hWnd);\r
+ DPtoLP(hdc, &pt2, 1);\r
+ ReleaseDC(hWnd, hdc);\r
+\r
+ double closest = 1.0e+99;\r
+\r
+ for(int i=0; i<pts.GetNumPoints(); i++)\r
+ {\r
+ double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))\r
+ + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));\r
+\r
+ if (dist < closest)\r
+ closest = dist, ptHighlight = i;\r
+ }\r
+\r
+ if (ptHighlight != oldPtHighlight)\r
+ {\r
+ oldPtHighlight = ptHighlight;\r
+ InvalidateRect(hWnd, NULL, TRUE);\r
+ }\r
+\r
+ // What follows here looks like voodoo, but is really simple. What we do is\r
+ // check to see if the mouse point has a perpendicular intersection with any of\r
+ // the line segments. If it does, calculate the length of the perpendicular\r
+ // and choose the smallest length. If there is no perpendicular, then choose the\r
+ // length of line connecting the closer of either the first endpoint or the\r
+ // second and choose the smallest of those.\r
+\r
+ // There is one bit of math that looks like voodoo to me ATM--will explain once\r
+ // I understand it better (the calculation of the length of the perpendicular).\r
+\r
+ if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)\r
+ {\r
+ double smallest = 1.0e+99;\r
+\r
+ for(int i=0; i<pts.GetNumPoints(); i++)\r
+ {\r
+ int32 p1x = pts.GetX(i), p1y = pts.GetY(i),\r
+ p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));\r
+\r
+ vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),\r
+ v2(pt2.x, pt2.y, 0, p2x, p2y, 0);\r
+ double pp = ls.dot(v1) / ls.length(), dist;\r
+// Geometric interpretation:\r
+// pp is the paremeterized point on the vector ls where the perpendicular intersects ls.\r
+// If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,\r
+// then the perpendicular lies beyond the 2nd endpoint.\r
+\r
+ if (pp < 0.0)\r
+ dist = v1.length();\r
+ else if (pp > ls.length())\r
+ dist = v2.length();\r
+ else // distance = ?Det?(ls, v1) / |ls|\r
+ dist = abs((ls.x * v1.y - v1.x * ls.y) / ls.length());\r
+\r
+//The answer to the above looks like it might be found here:\r
+//\r
+//If the segment endpoints are s and e, and the point is p, then the test for the perpendicular\r
+//intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and\r
+//{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is\r
+//computed by first computing the area of the triangle the three points form, then dividing by the\r
+//length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the\r
+//triangle formed by three points is the determinant of the following matrix:\r
+//\r
+//sx sy 1\r
+//ex ey 1\r
+//px py 1\r
+//\r
+//(???) By translating the start point to the origin, this can be rewritten as:\r
+//By subtracting row 1 from all rows, you get the following:\r
+//\r
+//0 0 0\r
+//(ex - sx) (ey - sy) 0\r
+//(px - sx) (py - sy) 0\r
+//\r
+//which greatly simplifies the calculation of the determinant.\r
+\r
+ if (dist < smallest)\r
+ smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;\r
+ }\r
+\r
+ if (ptNextHighlight != oldPtNextHighlight)\r
+ {\r
+ oldPtNextHighlight = ptNextHighlight;\r
+ InvalidateRect(hWnd, NULL, TRUE);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ ptPrevious.x = pt.x, ptPrevious.y = pt.y;\r
+\r
+ break;\r
+\r
+ case WM_NOTIFY:\r
+\r
+ if (((NMHDR *)lParam)->code == TTN_NEEDTEXT)\r
+ {\r
+ LoadString(hInst, ((TOOLTIPTEXT *)lParam)->hdr.idFrom + 0x80, toolTipTxt, 16);\r
+ ((TOOLTIPTEXT *)lParam)->lpszText = toolTipTxt;\r
+ }\r
+\r
+ break;\r
+\r
+ case WM_MENUSELECT:\r
+ {\r
+ statusBarTxt[0] = 0; // Clear status bar text\r
+ uint16 flags = wParam >> 16; // Extract flags\r
+\r
+ if (!(flags & MFT_SEPARATOR))\r
+ {\r
+ uint16 id = wParam & 0xFFFF;\r
+\r
+ if (flags & MF_POPUP)\r
+ {\r
+ if (flags & MF_SYSMENU)\r
+ id = IDS_SYSMENU;\r
+ else\r
+ id = IDM_FILEMENU + wParam;\r
+ }\r
+\r
+ LoadString(hInst, id, statusBarTxt, 64);\r
+ }\r
+\r
+ SendMessage(hStatusBar, SB_SETTEXT, 0 + SBT_NOBORDERS, (LPARAM)statusBarTxt);\r
+ break;\r
+ }\r
+ case WM_COMMAND:\r
+ {\r
+ uint16 cmd = wParam & 0xFFFF;\r
+\r
+ if (cmd == IDM_NEW)\r
+ {\r
+// call CmdIDM_NEW\r
+ }\r
+ else if (cmd == IDM_OPEN)\r
+ {\r
+// call SaveChanges\r
+// .IF (eax)\r
+// movmov ofn.hwndOwner, eax, hMainWnd\r
+// mov ofn.Flags, OFN_PATHMUSTEXIST + OFN_FILEMUSTEXIST\r
+// invoke GetOpenFileName, ADDR ofn\r
+// .IF (eax)\r
+////////\r
+//jmp @F\r
+//szDMsg1a BYTE "Could not open the file (GetOpenFileName)...", 0\r
+//szDMsg1b BYTE "Open error!", 0\r
+//szDMsg1c BYTE "About to attempt to open file...", 0\r
+//@@:\r
+////invoke MessageBox, hWnd, ADDR szDMsg1a, ADDR szDMsg1b, MB_ICONERROR or MB_OK\r
+//invoke MessageBox, hMainWnd, ADDR szDMsg1c, ADDR szFile, MB_ICONERROR or MB_OK\r
+// invoke LoadTTF, ADDR szFile\r
+//\r
+//////\r
+// // <<< FILE OPEN CODE HERE >>>\r
+// or fFileStatus, NAMEDbit\r
+// and fFileStatus, NOT CHANGEDbit\r
+// call NewWindowName\r
+// mov eax, TRUE // return TRUE\r
+// jmp Return\r
+// //ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\r
+//OpenError: invoke GetLastError\r
+// // <<< FILE OPEN ERROR CODE HERE >>>\r
+// .ENDIF\r
+// zero eax // return FALSE\r
+// .ENDIF\r
+ }\r
+ else if (cmd == IDM_SAVEAS)\r
+ {\r
+// and fFileStatus, NOT NAMEDbit\r
+// call CmdIDM_SAVE\r
+ }\r
+ else if (cmd == IDM_SAVE)\r
+ {\r
+// call CmdIDM_SAVE\r
+ }\r
+ else if (cmd == IDM_ABOUT)\r
+ DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ABOUT), hMainWnd, AboutProc, NULL);\r
+ else if (cmd == IDM_EXIT)\r
+ SendMessage(hWnd, WM_CLOSE, 0, 0);\r
+ else if (cmd == ID_TBCHARWIN)\r
+ {\r
+ ShowWindow(hCharWnd, (IsWindowVisible(hCharWnd) ? SW_HIDE : SW_SHOWNOACTIVATE));\r
+\r
+#ifdef DEBUGFOO\r
+wpC.length = sizeof(WINDOWPLACEMENT);\r
+GetWindowPlacement(hCharWnd, &wpC);\r
+wsprintf(strBuf, "Char window showCmd = %08X...\n", wpC.showCmd);\r
+WriteLogMsg(strBuf);\r
+#endif\r
+ }\r
+ else\r
+ return DefWindowProc(hWnd, msgID, wParam, lParam);\r
+\r
+ break;\r
+ }\r
+ default:\r
+ return DefWindowProc(hWnd, msgID, wParam, lParam);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+//\r
+// Initialize TTF data\r
+//\r
+void CreateNewDoc(void)\r
+{\r
+}\r
+\r
+//\r
+// Save changes to document before quitting\r
+//\r
+bool SaveChanges(void)\r
+{\r
+ return true;\r
+}\r
+\r
+\r
+\r
+//\r
+// ABOUT Dialog WndProc\r
+//\r
+BOOL CALLBACK AboutProc(HWND hDlg, UINT msgID, WPARAM wParam, LPARAM lParam)\r
+{\r
+ switch (msgID)\r
+ {\r
+ case WM_INITDIALOG:\r
+\r
+ MiscCenterWnd(hDlg, hMainWnd);\r
+ break;\r
+\r
+ case WM_COMMAND:\r
+\r
+ if (wParam == IDOK || wParam == IDCANCEL)\r
+ EndDialog(hDlg, TRUE);\r
+\r
+ break;\r
+\r
+ default:\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+//\r
+// Character Window WndProc\r
+//\r
+WndProcCW PROC STDCALL, hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM\r
+\r
+ mov eax, uMsg // pickup our message\r
+ .IF (eax == WM_PAINT)\r
+ mov eax, 0 // Non-sense... (placeholder!)\r
+// Scan conversion etc. goes here...\r
+ .ELSEIF (eax == WM_LBUTTONDOWN)\r
+ invoke SetCapture, hCharWnd\r
+ .ELSEIF (eax == WM_LBUTTONUP)\r
+ invoke ReleaseCapture\r
+ invoke SetFocus, hMainWnd // Make sure the main wnd keeps focus!\r
+ .ELSEIF (eax == WM_NCLBUTTONDOWN)\r
+ invoke DefWindowProc, hWnd, uMsg, wParam, lParam // Let it do its thing\r
+ invoke SetFocus, hMainWnd // Make sure the main wnd keeps focus!\r
+ .ELSE\r
+DefProc: invoke DefWindowProc, hWnd, uMsg, wParam, lParam\r
+ .ENDIF\r
+ ret\r
+\r
+WndProcCW ENDP\r
+\r
+//\r
+// Character Window WndProc\r
+//\r
+LRESULT CALLBACK WndProcCW(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)\r
+{\r
+ switch (msgID)\r
+ {\r
+ default:\r
+ return DefWindowProc(hWnd, msgID, wParam, lParam);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+// Function prototypes\r
+\r
+int32 FindSelectedTool(void);\r
+\r
+//\r
+// Tool Palette WndProc\r
+//\r
+LRESULT CALLBACK WndProcTP(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)\r
+{\r
+ PAINTSTRUCT ps;\r
+ HDC hdc;\r
+ POINT pt;\r
+ static uint32 prevTool = -1;\r
+\r
+ switch (msgID)\r
+ {\r
+ case WM_PAINT:\r
+ {\r
+ hdc = BeginPaint(hWnd, &ps);\r
+ HDC newDC = CreateCompatibleDC(NULL);\r
+ SelectObject(newDC, hBMToolPal1);\r
+ BitBlt(hdc, 0, 0, sizeTPBM.x, sizeTPBM.y, newDC, 0, 0, SRCCOPY);\r
+ DeleteDC(newDC);\r
+\r
+// This is crappy. Find some way to tighten this up!\r
+ int32 tool = FindSelectedTool();\r
+\r
+ if (tool != -1)\r
+ {\r
+ newDC = CreateCompatibleDC(NULL);\r
+ SelectObject(newDC, hBMToolPal1);\r
+ //need ul corner of bitmap, ul corner of dest, width/height\r
+ pt.x = sizeStamp.x * (tool & 0x03), pt.y = sizeStamp.y * (tool >> 2);\r
+ BitBlt(hdc, pt.x, pt.y, sizeStamp.x, sizeStamp.y, newDC, pt.x, pt.y, NOTSRCCOPY);\r
+ DeleteDC(newDC);\r
+ }\r
+\r
+ EndPaint(hWnd, &ps);\r
+ break;\r
+ }\r
+ case WM_MOUSEMOVE:\r
+ {\r
+ int32 tool = FindSelectedTool();\r
+\r
+ if (tool != prevTool)\r
+ {\r
+ prevTool = tool;\r
+ InvalidateRect(hWnd, NULL, FALSE);\r
+ }\r
+\r
+ break;\r
+ }\r
+ case WM_RBUTTONUP:\r
+ {\r
+ int32 tool = FindSelectedTool(), oldTool = currentTool;\r
+\r
+ if (tool != -1)\r
+ currentTool = tool;\r
+\r
+ if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt\r
+ && currentTool != TOOLPolySelect)\r
+ ptHighlight = -1;\r
+\r
+ if (currentTool != oldTool)\r
+ InvalidateRect(hMainWnd, NULL, TRUE);\r
+\r
+ if (currentTool == TOOLAddPoly)\r
+#ifdef DEBUGFOO\r
+{\r
+#endif\r
+ polyFirstPoint = true;\r
+#ifdef DEBUGFOO\r
+wsprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");\r
+WriteLogMsg(strBuf);\r
+}\r
+#endif\r
+\r
+ ReleaseCapture();\r
+ ShowWindow(hToolPalWnd, SW_HIDE);\r
+ SetFocus(hMainWnd); // Make sure the main wnd keeps focus!\r
+\r
+ break;\r
+ }\r
+ default:\r
+ return DefWindowProc(hWnd, msgID, wParam, lParam);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+//\r
+// Find which tool we're pointing at\r
+// Use: xcoord = mouse.x / (bmsize.x/4), ycoord = mouse.y / (bmsize.y/2)\r
+//\r
+int32 FindSelectedTool(void)\r
+{\r
+ POINT pt;\r
+ \r
+ GetCursorPos(&pt);\r
+ ScreenToClient(hToolPalWnd, &pt);\r
+\r
+ uint32 x = (uint32)pt.x / sizeStamp.x, y = (uint32)pt.y / sizeStamp.y, tool = -1;\r
+\r
+ if (x < 4 && y < 2)\r
+// {\r
+ tool = (y * 4) + x;\r
+\r
+// if (tool == 7)\r
+// tool = -1; // 7 has no tool...\r
+// }\r
+\r
+ return tool;\r
+}\r
+\r
+\r
+//\r
+// Misc center window\r
+//\r
+void MiscCenterWnd(HWND hChild, HWND hParent)\r
+{\r
+ RECT parent, child;\r
+\r
+ if (!GetWindowRect(hParent, &parent) || !GetWindowRect(hChild, &child))\r
+ return;\r
+\r
+ int32 x = parent.left + (((parent.right - parent.left) - (child.right - child.left)) / 2),\r
+ y = parent.top + (((parent.bottom - parent.top) - (child.bottom - child.top)) / 2);\r
+\r
+ if (x < 0)\r
+ x = 0;\r
+ else if (x > GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left))\r
+ x = GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left);\r
+\r
+ if (y < 0)\r
+ y = 0;\r
+ else if (y > GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top))\r
+ y = GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top);\r
+\r
+ SetWindowPos(hChild, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);\r
+}\r
+\r
+//\r
+// Allow only one instance\r
+//\r
+bool OnlyOneInstance(void)\r
+{\r
+ HWND window = FindWindow(className, NULL);\r
+\r
+ if (window == NULL)\r
+ return true;\r
+\r
+ ShowWindow(window, SW_SHOWNORMAL);\r
+ SetWindowPos(window, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);\r
+\r
+ return false;\r
+}\r
+\r
+//\r
+// Load/Allocate all resources\r
+//\r
+bool LoadResources(void)\r
+{\r
+ hCur[0] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR1));\r
+ hCur[1] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR2));\r
+ hCur[2] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR3));\r
+ hCur[3] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR4));\r
+ hCur[4] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR5));\r
+ hCur[5] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR6));\r
+ hCur[6] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR7));\r
+ hCur[7] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR8));\r
+\r
+ BITMAP bm;\r
+\r
+ hBMToolPal1 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TOOLPAL1));\r
+ GetObject(hBMToolPal1, sizeof(bm), &bm);\r
+\r
+ // Set up sizes\r
+\r
+ sizeTPBM.x = bm.bmWidth, sizeTPBM.y = bm.bmHeight;\r
+ sizeStamp.x = bm.bmWidth / 4, sizeStamp.y = bm.bmHeight / 2;\r
+\r
+ hBluePen1 = CreatePen(PS_DOT, 1, 0x00FF0000);\r
+ hRedPen1 = CreatePen(PS_SOLID, 1, 0x000000FF);\r
+ hGreenPen1 = CreatePen(PS_SOLID, 1, 0x0000AF00);\r
+ hBlackPen1 = CreatePen(PS_SOLID, 1, 0x00000000);\r
+\r
+ LOGBRUSH lb = { BS_NULL, 0, 0 };\r
+\r
+ hNullBrush = CreateBrushIndirect(&lb);\r
+\r
+ return true;\r
+}\r
+\r
+//\r
+// Deallocate all resources\r
+//\r
+void DeallocateResources(void)\r
+{\r
+ DeleteObject(hBMToolPal1);\r
+ DeleteObject(hBluePen1);\r
+ DeleteObject(hRedPen1);\r
+ DeleteObject(hGreenPen1);\r
+ DeleteObject(hBlackPen1);\r
+ DeleteObject(hNullBrush);\r
+}\r
+\r
+//\r
+// Save all application specific data, so we can pick up where we last left off...\r
+//\r
+void SaveAppState(void)\r
+{\r
+ SetINIInt("Main", "flags", wpM.flags);\r
+ SetINIInt("Main", "showCmd", wpM.showCmd);\r
+ SetINIInt("Main", "x1", wpM.rcNormalPosition.left);\r
+ SetINIInt("Main", "y1", wpM.rcNormalPosition.top);\r
+ SetINIInt("Main", "x2", wpM.rcNormalPosition.right);\r
+ SetINIInt("Main", "y2", wpM.rcNormalPosition.bottom);\r
+\r
+ SetINIInt("Main", "vpx", ptVPM.x);\r
+ SetINIInt("Main", "vpy", ptVPM.y);\r
+\r
+ SetINIInt("Char", "flags", wpC.flags);\r
+ SetINIInt("Char", "showCmd", wpC.showCmd);\r
+ SetINIInt("Char", "x1", wpC.rcNormalPosition.left);\r
+ SetINIInt("Char", "y1", wpC.rcNormalPosition.top);\r
+ SetINIInt("Char", "x2", wpC.rcNormalPosition.right);\r
+ SetINIInt("Char", "y2", wpC.rcNormalPosition.bottom);\r
+\r
+ // Need to write out currently opened font, character looking at, other misc. crap\r
+// SetINIString("Main", "currentFile", pDoc->GetPathName());\r
+// SetINIInt("Main", "currentChar", pDoc->character_num);\r
+}\r
+\r
+//\r
+// Restore all application specific data previously saved\r
+//\r
+bool RestoreAppState(void)\r
+{\r
+ InitINIFile();\r
+\r
+ WINDOWPLACEMENT wp;\r
+ wp.length = sizeof(WINDOWPLACEMENT);\r
+ GetWindowPlacement(hMainWnd, &wp);\r
+\r
+ wp.flags = GetINIInt("Main", "flags", wp.flags);\r
+ wp.showCmd = GetINIInt("Main", "showCmd", wp.showCmd);\r
+ wp.rcNormalPosition.left = GetINIInt("Main", "x1", wp.rcNormalPosition.left);\r
+ wp.rcNormalPosition.top = GetINIInt("Main", "y1", wp.rcNormalPosition.top);\r
+ wp.rcNormalPosition.right = GetINIInt("Main", "x2", wp.rcNormalPosition.right);\r
+ wp.rcNormalPosition.bottom = GetINIInt("Main", "y2", wp.rcNormalPosition.bottom);\r
+\r
+ SetWindowPlacement(hMainWnd, &wp);\r
+\r
+ HDC hdc;\r
+ POINT pt;\r
+ hdc = GetDC(hMainWnd);\r
+ GetViewportOrgEx(hdc, &pt);\r
+\r
+ pt.x = GetINIInt("Main", "vpx", pt.x);\r
+ pt.y = GetINIInt("Main", "vpy", pt.y);\r
+\r
+ SetViewportOrgEx(hdc, pt.x, pt.y, NULL);\r
+ ReleaseDC(hMainWnd, hdc);\r
+\r
+ GetWindowPlacement(hCharWnd, &wp);\r
+\r
+ wp.flags = GetINIInt("Char", "flags", wp.flags);\r
+ wp.showCmd = GetINIInt("Char", "showCmd", wp.showCmd);\r
+ wp.rcNormalPosition.left = GetINIInt("Char", "x1", wp.rcNormalPosition.left);\r
+ wp.rcNormalPosition.top = GetINIInt("Char", "y1", wp.rcNormalPosition.top);\r
+ wp.rcNormalPosition.right = GetINIInt("Char", "x2", wp.rcNormalPosition.right);\r
+ wp.rcNormalPosition.bottom = GetINIInt("Char", "y2", wp.rcNormalPosition.bottom);\r
+\r
+ SetWindowPlacement(hCharWnd, &wp);\r
+\r
+ if (wp.showCmd == SW_HIDE)\r
+ SendMessage(hToolBar, TB_SETSTATE, ID_TBCHARWIN, MAKELONG(TBSTATE_ENABLED, 0));\r
+\r
+// CString lastFile = theApplicationObject.GetProfileString(version, "currentFile", "");\r
+// int lastChar = theApplicationObject.GetProfileInt(version, "currentChar", 0);\r
+// if (lastFile.GetLength())\r
+// {\r
+// // Attempt to restore the last session by open the last file used, etc...\r
+// if (!pDoc->m_myFont.Load(lastFile))\r
+// {\r
+// // Err, make sure you can support any allegations you make below, buddy!\r
+// AfxMessageBox("The last file opened with TTF Edit\n\rseems to have been moved or deleted.");\r
+// }\r
+// else\r
+// {\r
+// pDoc->m_myFont.SetGlyph(lastChar); // Set TTF object to last used char\r
+// pDoc->character_num = lastChar;\r
+// pDoc->SetPathName(lastFile);\r
+//\r
+// BYTE name[512];\r
+// pDoc->m_myFont.GetCharName(lastChar, name);\r
+// m_wndOwned.SetWindowText((char *)name);\r
+// }\r
+// }\r
+\r
+ return true;\r
+}\r
+\r
+//\r
+// Initialization\r
+//\r
+bool Initialization(void)\r
+{\r
+ WNDCLASSEX wcex;\r
+\r
+ if (!LoadResources())\r
+ return false;\r
+\r
+ RtlFillMemory(&wcex, sizeof(WNDCLASSEX), 0);\r
+ wcex.cbSize = sizeof(WNDCLASSEX);\r
+ wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;\r
+ wcex.lpfnWndProc = WndProc;\r
+ wcex.hInstance = hInst;\r
+ wcex.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON));\r
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);\r
+ wcex.lpszMenuName = MAKEINTRESOURCE(IDM_MENU);\r
+ wcex.lpszClassName = className;\r
+ wcex.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, NULL);\r
+\r
+ if (!RegisterClassEx(&wcex))\r
+ return false;\r
+\r
+ hMainWnd = CreateWindowEx(NULL, className, className, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,\r
+ 0, 0, 0x1A0, 0x180, NULL, NULL, hInst, NULL);\r
+\r
+ if (!hMainWnd)\r
+ return false;\r
+\r
+ ShowWindow(hMainWnd, nCmdShow);\r
+ UpdateWindow(hMainWnd);\r
+\r
+ // Character window creation\r
+\r
+ wcex.lpfnWndProc = WndProcCW;\r
+ wcex.lpszMenuName = NULL;\r
+ wcex.lpszClassName = CNCharWin;\r
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW); // Owned windows have "regular" cursors\r
+\r
+ if (!RegisterClassEx(&wcex))\r
+ return false;\r
+\r
+ hCharWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW, CNCharWin,\r
+ curCharName, WS_POPUP | WS_CAPTION | WS_VISIBLE | WS_THICKFRAME,\r
+ 100, 100, 120, 120, hMainWnd, NULL, hInst, NULL);\r
+\r
+ if (!hCharWnd)\r
+ return false;\r
+\r
+ ShowWindow(hCharWnd, SW_SHOWNORMAL);\r
+ UpdateWindow(hCharWnd);\r
+ SetFocus(hMainWnd); // Make sure main wnd has focus!\r
+\r
+ // Tool palette window creation\r
+\r
+ wcex.lpfnWndProc = WndProcTP;\r
+ wcex.lpszClassName = CNToolPal;\r
+\r
+ if (!RegisterClassEx(&wcex))\r
+ return false;\r
+\r
+ hToolPalWnd = CreateWindowEx(WS_EX_WINDOWEDGE, CNToolPal, NULL, WS_POPUP,\r
+ 0, 0, sizeTPBM.x, sizeTPBM.y, hMainWnd, NULL, hInst, NULL);\r
+\r
+ if (!hToolPalWnd)\r
+ return false;\r
+\r
+// Note: A better way to handle this would be to have a sub that registers ALL\r
+// classes beforehand and passes a TRUE/FALSE back depending on whether or not\r
+// all the classes were able to be registered or not, THEN create the windows\r
+// and controls...\r
+\r
+ RestoreAppState(); // Restore app related stuff\r
+\r
+ return true;\r
+}\r
+\r
+*/\r
+\r
--- /dev/null
+//\r
+// TTEDIT.H: Header file\r
+//\r
+// by James L. Hammons\r
+// (C) 2005 Underground Software\r
+//\r
+\r
+#ifndef __TTEDIT_H__\r
+#define __TTEDIT_H__\r
+\r
+#include <wx/wx.h> // So that whoever uses this can without having\r
+ // to pull in a bunch of references manually\r
+#include "ttf.h"\r
+\r
+// Forward declarations\r
+\r
+class TTEditFrame;\r
+class TTEditWindow;\r
+class CharWindow;\r
+class ToolWindow;\r
+\r
+//\r
+// Class representing the entire Application\r
+//\r
+class TTEditApp: public wxApp\r
+{\r
+ public:\r
+ TTEditFrame * mainFrame;\r
+ CharWindow * charWin;\r
+ ToolWindow * toolPalette;\r
+ TTF font;\r
+\r
+ bool OnInit();\r
+ int OnExit();\r
+};\r
+\r
+DECLARE_APP(TTEditApp)\r
+\r
+class TTEditFrame: public wxFrame\r
+{\r
+ private:\r
+ protected:\r
+ public:\r
+ TTEditApp & app; // Reference to the application object\r
+ // Subwindows for reference within the program.\r
+ TTEditWindow * mainWindow;\r
+ wxMenuBar * menuBar;\r
+\r
+ // Constructor and destructor\r
+ TTEditFrame(wxFrame * parent, const wxString &title, const wxPoint &pos, const wxSize &size, long style);\r
+ ~TTEditFrame(void);\r
+\r
+ void OnCloseWindow(wxCloseEvent &e);\r
+\r
+ void OnOpen(wxCommandEvent &e);\r
+ void OnExit(wxCommandEvent &e);\r
+ void OnAbout(wxCommandEvent &e);\r
+// void OnEasy(wxCommandEvent &event);\r
+/// void OnMedium(wxCommandEvent &event);\r
+// void OnDifficult(wxCommandEvent &event);\r
+\r
+ DECLARE_EVENT_TABLE()\r
+};\r
+\r
+class TTEditWindow: public wxWindow\r
+{\r
+ private:\r
+ TTEditApp & app; // Reference to the application object\r
+ double scale; // Window scaling factor\r
+ int32 offsetX, offsetY; // Window offsets\r
+\r
+ protected:\r
+ public:\r
+// int field_width, field_height;\r
+// int x_cell, y_cell;\r
+ wxBitmap * bmp;\r
+ wxPoint pt, ptOffset, ptPrevious;\r
+\r
+ // Constructor and destructor\r
+ TTEditWindow(wxFrame * parent, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = 0);\r
+ ~TTEditWindow(void);\r
+\r
+ void OnPaint(wxPaintEvent &e);\r
+ void OnMouseEvent(wxMouseEvent &e);\r
+// void DrawField(wxDC *, int xc1, int yc1, int xc2, int yc2);\r
+// void Refresh(int xc1, int yc1, int xc2, int yc2);\r
+// void Uncover(int x, int y);\r
+// void UpdateFieldSize();\r
+\r
+ protected:\r
+ wxPoint GetAdjustedMousePosition(wxMouseEvent &e);\r
+ wxPoint GetAdjustedClientPosition(wxCoord x, wxCoord y);\r
+\r
+ DECLARE_EVENT_TABLE()\r
+};\r
+\r
+class CharWindow: public wxWindow\r
+{\r
+ private:\r
+ protected:\r
+ public:\r
+// int field_width, field_height;\r
+// int x_cell, y_cell;\r
+ wxBitmap * bmp;\r
+\r
+ // Constructor and destructor\r
+ CharWindow(wxFrame * parent, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = 0);\r
+ ~CharWindow(void);\r
+\r
+ void OnPaint(wxPaintEvent &e);\r
+ void OnMouseEvent(wxMouseEvent &e);\r
+// void DrawField(wxDC *, int xc1, int yc1, int xc2, int yc2);\r
+// void Refresh(int xc1, int yc1, int xc2, int yc2);\r
+// void Uncover(int x, int y);\r
+// void UpdateFieldSize();\r
+\r
+ DECLARE_EVENT_TABLE()\r
+};\r
+\r
+class ToolWindow: public wxFrame\r
+//class ToolWindow: public wxWindow\r
+{\r
+ private:\r
+ protected:\r
+ public:\r
+ wxBitmap * bmp;\r
+ wxPoint sizeStamp, sizeTPBM;\r
+ int prevTool;\r
+\r
+ // Constructor and destructor\r
+ ToolWindow(wxFrame * parent, const wxString &title, const wxPoint &pos, const wxSize &size, long style);\r
+// ToolFrame(wxFrame * parent, const wxString &title, const wxPoint &pos, const wxSize &size, long style);\r
+// ToolWindow(wxFrame * parent, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = 0);\r
+ ~ToolWindow(void);\r
+\r
+ void OnPaint(wxPaintEvent &e);\r
+ void OnMouseEvent(wxMouseEvent &e);\r
+// void DrawField(wxDC *, int xc1, int yc1, int xc2, int yc2);\r
+// void Refresh(int xc1, int yc1, int xc2, int yc2);\r
+// void Uncover(int x, int y);\r
+// void UpdateFieldSize();\r
+ int32 FindSelectedTool(void);\r
+\r
+ DECLARE_EVENT_TABLE()\r
+};\r
+\r
+// Resource/control IDs\r
+/*\r
+#define IDI_ICON 0x01L // IDs same as in ttedit.asm\r
+#define IDM_MENU 0x02L\r
+#define IDA_ACCEL 0x03L\r
+#define IDD_ABOUT 0x04L\r
+#define IDR_TOOLBAR1 0x05L\r
+#define IDB_TOOLBAR1 0x06L\r
+#define IDB_TOOLPAL1 0x07L\r
+#define IDC_CURSOR1 0x08L\r
+#define IDC_CURSOR2 0x09L\r
+#define IDC_CURSOR3 0x0AL\r
+#define IDC_CURSOR4 0x0BL\r
+#define IDC_CURSOR5 0x0CL\r
+#define IDC_CURSOR6 0x0DL\r
+#define IDC_CURSOR7 0x0EL\r
+#define IDC_CURSOR8 0x0FL\r
+\r
+#define IDS_SYSMENU 0x010L\r
+#define IDM_FILEMENU 0x011L\r
+#define IDM_HELPMENU 0x012L\r
+\r
+#define IDM_NEW 0x020L\r
+#define IDM_OPEN 0x021L\r
+#define IDM_SAVE 0x022L\r
+#define IDM_SAVEAS 0x023L\r
+#define IDM_EXIT 0x024L\r
+#define IDM_HELPTOPICS 0x025L\r
+#define IDM_ABOUT 0x026L\r
+\r
+#define ID_TBLEFT 0x030L\r
+#define ID_TBRIGHT 0x031L\r
+#define ID_TBCHARWIN 0x032L */\r
+\r
+#endif // __TTEDIT_H__\r
--- /dev/null
+//\r
+// TTF.CPP - The TrueType class\r
+// by James L. Hammons\r
+// (C) 2005 Underground Software\r
+//\r
+// This class encapsulates all the complexity of a TrueType Font File\r
+// database. Included are functions to load, save, & initialize the\r
+// TTF database, move, add, & delete points & glyphs, i.e. manipulate\r
+// a TTF file in just about any way imaginable!\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who When What\r
+// --- ---------- -------------------------------------------------------------\r
+// JLH ??/??/199? Created this file\r
+//\r
+//\r
+// STILL TO BE DONE:\r
+//\r
+// - Eliminate ALL references to BYTE, WORD, SBYTE, SWORD, etc.\r
+//\r
+\r
+#include <stdio.h> // For file handling, etc. //\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include "charnames.h"\r
+#include "ttf.h"\r
+\r
+#define TTFDEBUG\r
+\r
+#ifdef TTFDEBUG\r
+#include "debug.h"\r
+#endif\r
+\r
+#define NUMTABS 24 // Number of distinct tables\r
+\r
+\r
+/*void fskip(HANDLE file, uint32 bytesToSkip)\r
+{\r
+ SetFilePointer(file, (LONG)bytesToSkip, NULL, FILE_CURRENT);\r
+}*/\r
+\r
+//\r
+// Get a BYTE from the current file...\r
+//\r
+uint8 ReadByte(FILE * file)\r
+{\r
+ return (uint8)fgetc(file);\r
+}\r
+\r
+// The following routines get and put WORDs and DWORDs in little endian\r
+// format, so they should work no matter what endianess the platform that\r
+// holds the TTF object.\r
+\r
+//\r
+// Get a WORD from the current file...\r
+//\r
+uint16 ReadWord(FILE * file)\r
+{\r
+ uint16 word = (uint16)fgetc(file) << 8;\r
+ word |= (uint16)fgetc(file);\r
+\r
+ return word;\r
+}\r
+\r
+//\r
+// Get a double WORD from the current file...\r
+//\r
+uint32 ReadDWord(FILE * file)\r
+{\r
+ uint32 dword = 0;\r
+\r
+ for(int i=0; i<4; i++)\r
+ {\r
+ dword <<= 8;\r
+ dword |= (uint8)fgetc(file);\r
+ }\r
+\r
+ return dword;\r
+}\r
+\r
+//\r
+// Write a WORD to the current file...\r
+//\r
+void WriteWord(FILE * file, uint16 word)\r
+{\r
+ fputc(word >> 8, file); // Hi byte\r
+ fputc(word & 0xFF, file); // Lo byte\r
+}\r
+\r
+//\r
+// Write a double WORD to the current file...\r
+//\r
+void WriteDWord(FILE * file, uint32 dword)\r
+{\r
+ for(int i=0; i<4; i++)\r
+ {\r
+ fputc((char)(dword >> 24), file);\r
+ dword <<= 8;\r
+ }\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Table extraction helper routines (inline 'em?)\r
+////////////////////////////////////////////////////////////////////////////\r
+\r
+//\r
+// Return a BYTE from a BYTE based table\r
+//\r
+uint8 GetByte(uint8 * table, uint32 &ptr)\r
+{\r
+ return table[ptr++];\r
+}\r
+\r
+//\r
+// Return a WORD from a BYTE based table\r
+//\r
+uint16 GetWord(uint8 * table, uint32 &ptr)\r
+{\r
+ uint16 hi = table[ptr++];\r
+ uint16 lo = table[ptr++];\r
+\r
+ return (uint16)((hi<<8) | lo);\r
+}\r
+\r
+//\r
+// Return a double WORD from a BYTE based table\r
+//\r
+uint32 GetDWord(uint8 * table, uint32 &ptr)\r
+{\r
+ uint32 hi1 = table[ptr++];\r
+ uint32 lo1 = table[ptr++];\r
+ uint32 hi2 = table[ptr++];\r
+ uint32 lo2 = table[ptr++];\r
+\r
+ return (uint32)((hi1 << 24) | (lo1 << 16) | (hi2 << 8) | lo2);\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Table storage helper routines (inline 'em?)\r
+////////////////////////////////////////////////////////////////////////////\r
+\r
+//\r
+// Store a BYTE in a BYTE based table\r
+//\r
+void SetByte(uint8 * table, uint32 &ptr, uint8 data)\r
+{\r
+ table[ptr++] = data;\r
+}\r
+\r
+//\r
+// Store a WORD in a BYTE based table\r
+//\r
+void SetWord(uint8 * table, uint32 &ptr, uint16 data)\r
+{\r
+ table[ptr++] = data>>8; table[ptr++] = data&0xFF;\r
+}\r
+\r
+//\r
+// Store a DWORD in a BYTE based table\r
+//\r
+void SetDWord(uint8 * table, uint32 &ptr, uint32 data)\r
+{\r
+ table[ptr++] = (uint8)(data >> 24); table[ptr++] = (uint8)(data >> 16);\r
+ table[ptr++] = (uint8)(data >> 8); table[ptr++] = (uint8)(data & 0xFF);\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Fixed point to float (& vice versa) conversions\r
+/////////////////////////////////////////////////////////////////////////////\r
+float FixedToFloat(int16 fixed)\r
+{\r
+ return (float)fixed / 16384.0f;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// TTF Constructor\r
+/////////////////////////////////////////////////////////////////////////////\r
+TTF::TTF(void)\r
+{\r
+ loaded = false; // Set font initializer\r
+ isDirty = false; // Glyphs are clean\r
+ numberOfPolys = 0; // Set reasonable values\r
+ isCompositeGlyph = false; // No composite glyph (yet)\r
+\r
+ parray[0] = &EBDT; parray[1] = &EBLC; parray[2] = &EBSC; // Init pointer\r
+ parray[3] = <SH; parray[4] = &OS_2; parray[5] = &PCLT; // array...\r
+ parray[6] = &VDMX; parray[7] = &cmap; parray[8] = &cvt; \r
+ parray[9] = &fpgm; parray[10] = &gasp; parray[11] = &glyf;\r
+ parray[12] = &hdmx; parray[13] = &head; parray[14] = &hhea;\r
+ parray[15] = &hmtx; parray[16] = &kern; parray[17] = &loca;\r
+ parray[18] = &maxp; parray[19] = &name; parray[20] = &post;\r
+ parray[21] = &prep; parray[22] = &vhea; parray[23] = &vmtx;\r
+\r
+ larray[0] = &EBDT_len; larray[1] = &EBLC_len; larray[2] = &EBSC_len;\r
+ larray[3] = <SH_len; larray[4] = &OS_2_len; larray[5] = &PCLT_len;\r
+ larray[6] = &VDMX_len; larray[7] = &cmap_len; larray[8] = &cvt_len;\r
+ larray[9] = &fpgm_len; larray[10] = &gasp_len; larray[11] = &glyf_len;\r
+ larray[12] = &hdmx_len; larray[13] = &head_len; larray[14] = &hhea_len;\r
+ larray[15] = &hmtx_len; larray[16] = &kern_len; larray[17] = &loca_len;\r
+ larray[18] = &maxp_len; larray[19] = &name_len; larray[20] = &post_len;\r
+ larray[21] = &prep_len; larray[22] = &vhea_len; larray[23] = &vmtx_len;\r
+\r
+ for(uint32 i=0; i<NUMTABS; i++)\r
+ *parray[i] = NULL; // Init pointers...\r
+\r
+ for(uint32 i=0; i<MAXGLYPHS; i++)\r
+ glyph[i] = NULL;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// TTF Destructor\r
+/////////////////////////////////////////////////////////////////////////////\r
+TTF::~TTF()\r
+{\r
+ ClearTables(); // This should handle deallocation correctly...\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: void Init(void)\r
+//\r
+// This function initializes the TTF object, setting reasonable values for\r
+// the various internal variables used by the object.\r
+// [distinct from New?]\r
+/////////////////////////////////////////////////////////////////////////////\r
+void TTF::Init(void)\r
+{\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Clear the tables so that file can be reloaded\r
+/////////////////////////////////////////////////////////////////////////////\r
+void TTF::ClearTables(void)\r
+{\r
+ for(uint32 i=0; i<NUMTABS; i++)\r
+ {\r
+ if ((*parray[i]) != NULL)\r
+ {\r
+ free(*parray[i]);\r
+ *parray[i] = NULL;\r
+ *larray[i] = 0;\r
+ }\r
+ } \r
+\r
+ for(uint32 i=0; i<MAXGLYPHS; i++)\r
+ {\r
+ if (glyph[i] != NULL)\r
+ {\r
+ free(glyph[i]);\r
+ glyph[i] = NULL;\r
+ }\r
+ }\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL Load(const char * filename)\r
+//\r
+// This loads the TTF database from an external file. Returns 'true' if\r
+// successful.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::Load(const char * filename)\r
+{\r
+// unsigned char ch; // Temp variable\r
+// UINT num_tabs; // Number of tables\r
+ uint32 offset[NUMTABS], length[NUMTABS]; // Temporary storage...\r
+ char names[NUMTABS][5];\r
+ char narray[NUMTABS][5] = { "EBDT", "EBLC", "EBSC", "LTSH", "OS/2", "PCLT",\r
+ "VDMX", "cmap", "cvt ", "fpgm", "gasp", "glyf", "hdmx", "head", "hhea",\r
+ "hmtx", "kern", "loca", "maxp", "name", "post", "prep", "vhea", "vmtx" };\r
+\r
+ //loaded = false;\r
+// file.open(filename, ios::binary|ios::in); // Open the file\r
+ FILE * file = fopen(filename, "rb");\r
+\r
+ if (file == NULL)\r
+#ifdef TTFDEBUG\r
+{\r
+WriteLogMsg("Failed to open file!\n");\r
+#endif\r
+ return false;\r
+#ifdef TTFDEBUG\r
+}\r
+#endif\r
+\r
+ if (ReadDWord(file) != 0x00010000)\r
+#ifdef TTFDEBUG\r
+{\r
+WriteLogMsg("File was NOT a TTF file!\n");\r
+#endif\r
+ return false; // Not a TTF file...\r
+#ifdef TTFDEBUG\r
+}\r
+#endif\r
+\r
+ uint32 num_tabs = ReadWord(file); // Get # of tables\r
+#ifdef TTFDEBUG\r
+WriteLogMsg("Number of tables is %u...\n", num_tabs);\r
+#endif\r
+// fskip(file, 6); // Skip this shiat...\r
+ fseek(file, 6, SEEK_CUR);\r
+\r
+#ifdef TTFDEBUG\r
+WriteLogMsg("Reading names of tables...\n");\r
+#endif\r
+ for(uint32 i=0; i<num_tabs; i++)\r
+ {\r
+// ReadFile(file, names[i], 4, &bytesRead, NULL);\r
+ fread(names[i], 1, 4, file);\r
+ names[i][4] = 0;\r
+// fskip(file, 4); // Checksum\r
+ fseek(file, 4, SEEK_CUR); // Checksum\r
+ offset[i] = ReadDWord(file); // Offset from start of file\r
+ length[i] = ReadDWord(file); // Length of table\r
+ }\r
+\r
+#ifdef TTFDEBUG\r
+WriteLogMsg("Reading tables...\n");\r
+#endif\r
+ for(uint32 i=0; i<num_tabs; i++)\r
+ {\r
+ for(uint32 j=0; j<NUMTABS; j++)\r
+ {\r
+ if ((strcmp(names[i], narray[j])) == 0) // Found a match...\r
+ {\r
+// *parray[j] = (uint8 *)GlobalAlloc(GMEM_FIXED, length[i]); // Allocate space\r
+ *parray[j] = (uint8 *)malloc(length[i]); // Alloc space\r
+\r
+ if (*parray[j] == NULL)\r
+ return false; // Bail out if nothing allocated\r
+\r
+ *larray[j] = length[i]; // Set its length...\r
+// SetFilePointer(file, (LONG)offset[i], NULL, FILE_BEGIN);\r
+// ReadFile(file, *parray[j], length[i], &bytesRead, NULL);\r
+ fseek(file, offset[i], SEEK_SET);\r
+ fread(*parray[j], 1, length[i], file);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ fclose(file);\r
+\r
+// This shouldn't be necessary, since it's irrelevant (loaded flag)\r
+// loaded = true; // Set 'loaded' flag...\r
+ isDirty = false; // Glyphs are clean\r
+ ExtractTables(); // Move table data to my structs\r
+ // & ignore return val\r
+ // (should handle errors here)\r
+ return true;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL Save(const char * filename)\r
+//\r
+// Save the TT font currently in the object\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::Save(const char * filename)\r
+{\r
+// fstream file;\r
+// ULONG offset = 12;\r
+ uint32 numtabs = 0;\r
+ char padding[3] = { 0, 0, 0 };\r
+ // Convert this to a table of ULONGs to decrease complexity...\r
+//wouldn't be endian safe then...\r
+ char narray[NUMTABS][5] = { "EBDT", "EBLC", "EBSC", "LTSH", "OS/2", "PCLT",\r
+ "VDMX", "cmap", "cvt ", "fpgm", "gasp", "glyf", "hdmx", "head", "hhea",\r
+ "hmtx", "kern", "loca", "maxp", "name", "post", "prep", "vhea", "vmtx" };\r
+\r
+ if (isDirty)\r
+ EncodeGlyph(currentGlyph);\r
+\r
+ BuildTables(); // Ignore return value... \r
+\r
+ for(uint32 i=0; i<NUMTABS; i++) // Figure out how many tables there are\r
+ if ((*parray[i]) != NULL)\r
+ numtabs++;\r
+\r
+ uint32 offset = 12 + (numtabs * 16); // Calc correct offset to start of data\r
+\r
+// HANDLE file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+// NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\r
+ FILE * file = fopen(filename, "wb");\r
+\r
+ WriteDWord(file, 0x00010000); // Write header...\r
+ WriteWord(file, numtabs);\r
+ WriteWord(file, 0); // SearchRange (Max power of 2 <= numTables) x 16.\r
+ WriteWord(file, 0); // entrySelector Log2(max power of 2 <= numTables).\r
+ WriteWord(file, 0); // NumTables x 16 - searchRange.\r
+\r
+ for(uint32 i=0; i<NUMTABS; i++) // Write out table directory...\r
+ {\r
+ if ((*parray[i]) != NULL)\r
+ {\r
+// for(int j=0; j<4; j++)\r
+// file.put(narray[i][j]); // Name\r
+// WriteFile(file, narray[i], 4, &bytesWritten, NULL);\r
+ fwrite(narray[i], 1, 4, file); // Name\r
+\r
+ WriteDWord(file, 0); // Checksum\r
+ WriteDWord(file, offset); // Offset\r
+ WriteDWord(file, (*larray[i])); // Length\r
+\r
+ offset += (((*larray[i]) + 3) & ~3); // Pad out to 4-uint8 boundary...\r
+ }\r
+ }\r
+\r
+ for(uint32 i=0; i<NUMTABS; i++) // Write out the tables...\r
+ {\r
+ if ((*parray[i]) != NULL)\r
+ {\r
+// for(uint32 j=0; j<(*larray[i]); j++)\r
+// file.put((*parray[i])[j]);\r
+// WriteFile(file, *parray[i], *larray[i], &bytesWritten, NULL);\r
+ fwrite(*parray[i], 1, *larray[i], file);\r
+\r
+ uint32 remainder = ((*larray[i]) & 0x3);\r
+ if (remainder) // i.e., it's not evenly div by 4\r
+// for(j=remainder; j<4; j++)\r
+// file.put((char)0); // pad it!\r
+// WriteFile(file, padding, 4 - remainder, &bytesWritten, NULL);\r
+ fwrite(padding, 1, 4 - remainder, file);\r
+ }\r
+ }\r
+\r
+ fclose(file);\r
+\r
+ return true; // Whether or not it was successful...\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL EncodeGlyph(int glyphnum)\r
+//\r
+// This function encodes the glyph data and stores it to the 'glyf' table.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::EncodeGlyph(uint16 glyphnum)\r
+{\r
+ bool retval = false; // Assume failure\r
+ uint8 flag, xbuf[4000], ybuf[4000], fbuf[2000];\r
+ uint32 xp = 0, yp = 0, fp = 0; // Table pointers\r
+\r
+ if (glyphnum < myMaxp.numGlyphs) // numofgls is 1 based ind, glyph# 0 based\r
+ {\r
+ // need to add composite encoding...\r
+ int lastx = 0, lasty = 0;\r
+\r
+ for(uint32 i=0; i<numberOfPoints; i++)\r
+ {\r
+ flag = 0;\r
+ int curx = gx[i] - lastx, cury = gy[i] - lasty;\r
+\r
+ if (onCurve[i])\r
+ flag |= 0x01; // Set on curve info\r
+\r
+ if (curx)\r
+ {\r
+ if ((curx > 255) || (curx < -255)) // I.e., it's 2 uint8 value\r
+ SetWord(xbuf, xp, curx);\r
+ else\r
+ {\r
+ if (curx & 0x100)\r
+ {\r
+ flag |= 0x02; // I.e., it's negative\r
+ curx *= -1; // Flip it so correct value is stored\r
+ }\r
+ else\r
+ flag |= 0x12;\r
+\r
+ SetByte(xbuf, xp, curx); // Automagically strips neg bit\r
+ }\r
+ }\r
+ else\r
+ flag |= 0x10; // X-coord is same...\r
+ \r
+ if (cury)\r
+ {\r
+ if ((cury > 255) || (cury < -255)) // I.e., it's 2 uint8 value\r
+ SetWord(ybuf, yp, cury);\r
+ else\r
+ {\r
+ if (cury & 0x100)\r
+ {\r
+ flag |= 0x04; // I.e., it's negative\r
+ cury *= -1;\r
+ }\r
+ else\r
+ flag |= 0x24;\r
+ \r
+ SetByte(ybuf, yp, cury);\r
+ }\r
+ }\r
+ else\r
+ flag |= 0x20; // Y-coord is same...\r
+ \r
+ fbuf[i] = flag;\r
+ lastx = gx[i]; lasty = gy[i];\r
+ }\r
+\r
+ // Now crunch flags... ugly, ugly, ugly.\r
+/*\r
+ fbuf[numberOfPoints] = 0; // Set sentinel value (ugly way to do this)\r
+ for(i=0; i<numberOfPoints; i++);\r
+ {\r
+ if (fbuf[i] == fbuf[i+1]) // \r
+ {\r
+ uint8 count = 0; // Sentinel takes care of check for end of flags...\r
+ while (fbuf[i] == fbuf[++i]) count++; // Count number of repeats\r
+ i--;\r
+ fbuf[fp++] = fbuf[i] | 0x08; // Set repeat flag\r
+ fbuf[fp++] = count; // & number of repeats\r
+ }\r
+ else fbuf[fp++] = fbuf[i]; // Otherwise, just copy...\r
+ }\r
+*/\r
+ fp = numberOfPoints;\r
+ // Find length of glyph and reallocate space if necessary\r
+\r
+ uint32 newLength = 12 + numberOfPolys*2 + numberOfHints + fp + xp + yp;\r
+\r
+ if (newLength & 0x03)\r
+ newLength += (4 - newLength & 0x03);\r
+\r
+ if (glyphLen[glyphnum] != newLength)\r
+ {\r
+ glyph[glyphnum] = (uint8 *)realloc(glyph[glyphnum], newLength);\r
+ glyphLen[glyphnum] = newLength;\r
+ }\r
+\r
+ // And finally, store it!\r
+\r
+ uint32 gp = 0; // Glyph pointer...\r
+ SetWord(glyph[glyphnum], gp, numberOfPolys);\r
+ SetWord(glyph[glyphnum], gp, llx);\r
+ SetWord(glyph[glyphnum], gp, lly);\r
+ SetWord(glyph[glyphnum], gp, urx);\r
+ SetWord(glyph[glyphnum], gp, ury);\r
+ for(uint32 i=0; i<numberOfPolys; i++)\r
+ SetWord(glyph[glyphnum], gp, poly[i]);\r
+ SetWord(glyph[glyphnum], gp, numberOfHints);\r
+ for(uint32 i=0; i<numberOfHints; i++)\r
+ SetByte(glyph[glyphnum], gp, hint[i]);\r
+ for(uint32 i=0; i<fp; i++)\r
+ SetByte(glyph[glyphnum], gp, fbuf[i]);\r
+ for(uint32 i=0; i<xp; i++)\r
+ SetByte(glyph[glyphnum], gp, xbuf[i]);\r
+ for(uint32 i=0; i<yp; i++)\r
+ SetByte(glyph[glyphnum], gp, ybuf[i]);\r
+\r
+ retval = true; // Successfully encoded!\r
+ }\r
+\r
+ return retval;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL DecodeGlyph(int glyphnum)\r
+//\r
+// This function decodes the glyph data and stores it to the object's\r
+// internal array.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::DecodeGlyph(uint16 glyphnum)\r
+{\r
+ bool retval = false;\r
+ uint32 i, dp;\r
+\r
+ // glyphnum is 0 based index, while numGlyphs is 1 based\r
+ if (glyphnum >= myMaxp.numGlyphs)\r
+ return false; // Invalid char #\r
+\r
+ if (!glyphLen[glyphnum])\r
+ {\r
+ numberOfPoints = numberOfPolys = 0;\r
+ return true; // Zero length IS valid...\r
+ }\r
+// else // Get character data...\r
+// {\r
+ // Now get the character data...\r
+ dp = 0; // Reset data pointer\r
+ isCompositeGlyph = false; // Default is no\r
+ numberOfPolys = GetWord(glyph[glyphnum], dp); // # of polygons\r
+\r
+ llx = (int16)GetWord(glyph[glyphnum], dp); // Lower left X\r
+ lly = (int16)GetWord(glyph[glyphnum], dp); // Lower left Y\r
+ urx = (int16)GetWord(glyph[glyphnum], dp); // Upper right X\r
+ ury = (int16)GetWord(glyph[glyphnum], dp); // Upper right Y\r
+\r
+ // Need to handle composite glyphs better here. The ways things\r
+ // are set now is a recipe for disaster...\r
+\r
+ if (numberOfPolys == 0xFFFF)\r
+ {\r
+ isCompositeGlyph = true;\r
+ numberOfPolys = 0; // Set for no points\r
+\r
+ Composite cmpst;\r
+\r
+ while (!compositeList.IsEmpty()) // Empty composite list...\r
+ compositeList.GetFront();\r
+\r
+ do\r
+ {\r
+ cmpst.flags = GetWord(glyph[glyphnum], dp);\r
+ cmpst.glyphIndex = GetWord(glyph[glyphnum], dp);\r
+ cmpst.arg1 = (cmpst.flags & 0x01 ? (int16)GetWord(glyph[glyphnum], dp) : (int8)GetByte(glyph[glyphnum], dp));\r
+ cmpst.arg2 = (cmpst.flags & 0x01 ? (int16)GetWord(glyph[glyphnum], dp) : (int8)GetByte(glyph[glyphnum], dp));\r
+\r
+ if (cmpst.flags & 0x08)\r
+ cmpst.xScale = cmpst.yScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp));\r
+ else if (cmpst.flags & 0x40)\r
+ cmpst.xScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),\r
+ cmpst.yScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp));\r
+ else if (cmpst.flags & 0x80)\r
+ cmpst.xScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),\r
+ cmpst.scale01 = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),\r
+ cmpst.scale10 = FixedToFloat((int16)GetWord(glyph[glyphnum], dp)),\r
+ cmpst.yScale = FixedToFloat((int16)GetWord(glyph[glyphnum], dp));\r
+\r
+ compositeList.AddAtRear(cmpst);\r
+ }\r
+ while (cmpst.flags & 0x20); //*/\r
+\r
+ return true;\r
+ }\r
+\r
+//do {\r
+// USHORT flags;\r
+// USHORT glyphIndex;\r
+// if ( flags & ARG_1_AND_2_ARE_uint16S) {\r
+// (SHORT or Fuint16) argument1;\r
+// (SHORT or Fuint16) argument2;\r
+// } else {\r
+// USHORT arg1and2; /* (arg1 << 8) | arg2 */\r
+// }\r
+// if ( flags & WE_HAVE_A_SCALE ) {\r
+// F2Dot14 scale; /* Format 2.14 */\r
+// } else if ( flags & WE_HAVE_AN_X_AND_Y_SCALE ) {\r
+// F2Dot14 xscale; /* Format 2.14 */\r
+// F2Dot14 yscale; /* Format 2.14 */\r
+// } else if ( flags & WE_HAVE_A_TWO_BY_TWO ) {\r
+// F2Dot14 xscale; /* Format 2.14 */\r
+// F2Dot14 scale01; /* Format 2.14 */\r
+// F2Dot14 scale10; /* Format 2.14 */\r
+// F2Dot14 yscale; /* Format 2.14 */\r
+// }\r
+//} while ( flags & MORE_COMPONENTS ) \r
+//if (flags & WE_HAVE_INSTR){\r
+// USHORT numInstr\r
+// uint8 instr[numInstr]\r
+//\r
+//Flags Bit Description \r
+//ARG_1_AND_2_ARE_uint16S 0 If this is set, the arguments are uint16s;\r
+// otherwise, they are uint8s.\r
+//ARGS_ARE_XY_VALUES 1 If this is set, the arguments are xy values;\r
+// otherwise, they are points.\r
+//ROUND_XY_TO_GRID 2 For the xy values if the preceding is true.\r
+//WE_HAVE_A_SCALE 3 This indicates that there is a simple scale\r
+// for the component. Otherwise, scale = 1.0.\r
+//RESERVED 4 This bit is reserved. Set it to 0. \r
+//MORE_COMPONENTS 5 Indicates at least one more glyph after this\r
+// one.\r
+//WE_HAVE_AN_X_AND_Y_SCALE 6 The x direction will use a different scale\r
+// from the y direction.\r
+//WE_HAVE_A_TWO_BY_TWO 7 There is a 2 by 2 transformation that will\r
+// be used to scale the component.\r
+//WE_HAVE_INSTRUCTIONS 8 Following the last component are\r
+// instructions for the composite character.\r
+//USE_MY_METRICS 9 If set, this forces the aw and lsb (and rsb)\r
+// for the composite to be equal to those from\r
+// this original glyph. This works for hinted\r
+// and unhinted characters.\r
+\r
+ for(i=0; i<numberOfPolys; i++)\r
+ poly[i] = GetWord(glyph[glyphnum], dp);\r
+\r
+ numberOfHints = GetWord(glyph[glyphnum], dp);\r
+\r
+ for(i=0; i<numberOfHints; i++)\r
+ hint[i] = GetByte(glyph[glyphnum], dp);\r
+\r
+ // Decode the dots...\r
+\r
+ uint32 num_pts = poly[numberOfPolys-1] + 1;\r
+ numberOfPoints = num_pts; // necessary??\r
+ uint32 xptr, yptr; // pointers to beginning of coord data\r
+ uint32 numXs = 0;\r
+ int xx = 0, yy = 0, repeat;\r
+ uint32 numTokens = num_pts, k, numRep;\r
+\r
+ // We make an educated guess that num_pts = num_tokens; but if there\r
+ // is repeated data in the tokens, then we need to adjust the # of\r
+ // tokens down appropriately.\r
+\r
+ for(uint32 i=0; i<numTokens; i++)\r
+ {\r
+ uint8 token = glyph[glyphnum][dp+i]; uint32 rpts = 1;\r
+\r
+ if (token & 0x08) // Repeated token?\r
+ {\r
+ i++; // Yes, bump pointer to # of times to repeat\r
+ numRep = glyph[glyphnum][dp+i];\r
+ rpts += numRep;\r
+\r
+ if (numRep > 1) // Do we need to adjust numTokens?\r
+ // this is bad, modifying numTokens while it's used as a compare value\r
+ // in the above loop...\r
+ // Is it necessary to do so in order to keep from going too far?\r
+ numTokens -= (numRep - 1); // Yes, adjust.\r
+ }\r
+\r
+ // 10 = same x(0uint8s), 00 = 2uint8s, 02&12 = 1uint8\r
+ if ((token & 0x02) == 0x02)\r
+ numXs += rpts;\r
+\r
+ if ((token & 0x12) == 0x00)\r
+ numXs += (rpts*2);\r
+ }\r
+\r
+ xptr = dp + numTokens;\r
+ yptr = dp + numTokens + numXs;\r
+\r
+ // & continue decoding X/Y-coords...\r
+\r
+ k = 0; // Index to the point array\r
+\r
+ for(uint32 i=0; i<numTokens; i++)\r
+ {\r
+ uint8 token = glyph[glyphnum][dp+i];\r
+ repeat = 1;\r
+\r
+ if (token & 0x08)\r
+ {\r
+ i++;\r
+ repeat += glyph[glyphnum][dp+i]; // Set repeat data...\r
+ }\r
+\r
+ while (repeat--)\r
+ {\r
+ if ((token & 0x12) == 0x12)\r
+ xx += GetByte(glyph[glyphnum], xptr);\r
+\r
+ if ((token & 0x12) == 0x02)\r
+ xx -= GetByte(glyph[glyphnum], xptr);\r
+\r
+ if ((token & 0x12) == 0x00)\r
+ xx += (int16)GetWord(glyph[glyphnum], xptr);\r
+\r
+ gx[k] = xx; // Store x-coordinate\r
+\r
+ if ((token & 0x24) == 0x24)\r
+ yy += GetByte(glyph[glyphnum], yptr);\r
+\r
+ if ((token & 0x24) == 0x04)\r
+ yy -= GetByte(glyph[glyphnum], yptr);\r
+\r
+ if ((token & 0x24) == 0x00)\r
+ yy += (int16)GetWord(glyph[glyphnum], yptr);\r
+\r
+ gy[k] = yy; // Store y-coordinate\r
+\r
+ onCurve[k++] = (token & 0x01 ? true : false); // If bit 0 set, then it's on curve\r
+ }\r
+ }\r
+\r
+ retval = true; // Hmm. Successfully decoded a glyph...\r
+// }\r
+\r
+ isDirty = false; // do it here?\r
+\r
+ return retval;\r
+}\r
+\r
+/*****************************************************************************\r
+ Member function:\r
+\r
+ This function decodes the 'glyf' data for a non-composite (atomic) glyph and\r
+ returns it as a GlyphPoints object. Helper function.\r
+ *****************************************************************************/\r
+GlyphPoints TTF::GetGlyphPoints(uint16 glyphNum)\r
+{\r
+ if (DecodeGlyph(glyphNum))\r
+ return GlyphPoints(numberOfPoints, numberOfPolys, gx, gy, onCurve, poly);\r
+\r
+ return GlyphPoints();\r
+}\r
+\r
+/*****************************************************************************\r
+ Member function:\r
+\r
+ This function decodes the 'glyf' data for a composite glyph and returns\r
+ it as a GlyphPoints object.\r
+ *****************************************************************************/\r
+GlyphPoints TTF::GetAllCompositePoints(uint16 glyphNum)\r
+{\r
+// int tmpGlyph = currentGlyph;\r
+ \r
+ DecodeGlyph(glyphNum); // Check for composite-ness\r
+\r
+ if (!isCompositeGlyph)\r
+ return GlyphPoints();\r
+\r
+/*\r
+ for(int i=1; i<=pDoc->m_myFont.compositeList.Length(); i++)\r
+ {\r
+ TComposite cmpst = fnt->compositeList.PeekPosition(i);\r
+ fnt->SetGlyph(cmpst.glyphIndex);\r
+ if (cmpst.flags & 0x0002)\r
+ m_nXOffset = cmpst.arg1, m_nYOffset = cmpst.arg2;\r
+ ScanConvertSingleGlyph(pDC, nScanlines, nHorzLines, nXOffset, nYOffset);\r
+ }\r
+ fnt->SetGlyph(pDoc->character_num);\r
+*/\r
+\r
+ GlyphPoints retVal;\r
+\r
+ for(int i=1; i<=compositeList.Length(); i++)\r
+ {\r
+ Composite cmpst = compositeList.PeekPosition(i);\r
+ \r
+// SetGlyph(cmpst.glyphIndex);\r
+// if (cmpst.flags & 0x0002)\r
+// m_nXOffset = cmpst.arg1, m_nYOffset = cmpst.arg2;\r
+// ScanConvertSingleGlyph(pDC, nScanlines, nHorzLines, nXOffset, nYOffset);\r
+ GlyphPoints gp = GetGlyphPoints(cmpst.glyphIndex);\r
+\r
+ if (cmpst.flags & 0x0002)\r
+ gp.OffsetPoints(cmpst.arg1, cmpst.arg2);\r
+\r
+ retVal = retVal + gp;\r
+ // NOTE: May have to adjust scanlines as per 0x0002 above...\r
+ }\r
+\r
+// SetGlyph(tmpGlyph);\r
+ DecodeGlyph(currentGlyph); // Reset needed here...\r
+\r
+ return retVal;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: void GetCharName(int cNum, uint8 * buf)\r
+//\r
+// This function returns the character name of the glyph number passed in.\r
+/////////////////////////////////////////////////////////////////////////////\r
+void TTF::GetCharName(int cNum, uint8 * buf)\r
+{\r
+ buf[0] = 0; // Set failure as default condition\r
+ \r
+ if (!post) // PS names are here...\r
+ return;\r
+\r
+ if (post[1] != 0x02 || post[2] != 0x00) // i.e., it's NOT a V2.0 table\r
+ return;\r
+\r
+ uint8 * pTab = NULL;\r
+ uint32 tabOff = 34, numGlyphs = (uint32)((post[32] << 8) | post[33]);\r
+ uint32 index = (uint32)((post[tabOff + cNum * 2] << 8) | post[tabOff + cNum * 2 + 1]);\r
+ uint32 nInd2;\r
+\r
+ if (index > 257)\r
+ {\r
+ index -= 258;\r
+ nInd2 = tabOff + (2 * numGlyphs);\r
+ pTab = post;\r
+ }\r
+ else\r
+ {\r
+ nInd2 = 0;\r
+ pTab = macStdNames;\r
+ }\r
+\r
+ for(uint32 i=0; i<index; i++)\r
+ nInd2 = nInd2 + pTab[nInd2] + 1; // 1st uint8 is length of string + that uint8\r
+\r
+ uint8 len = pTab[nInd2];\r
+ nInd2++;\r
+\r
+ for(uint8 i=0; i<len; i++)\r
+ buf[i] = pTab[nInd2 + i];\r
+\r
+ buf[len] = 0;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL ExtractTables(void)\r
+//\r
+// This function extracts the data from the various tables and puts them in\r
+// various structs for easier handling of the font data.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::ExtractTables(void)\r
+{\r
+ if (head_len != 54)\r
+ {\r
+#ifdef TTFDEBUG\r
+WriteLogMsg("Bad HEAD header: Expected 54, found %u...\n", head_len);\r
+#endif\r
+ return false; // Corrupt data?\r
+ }\r
+\r
+ uint32 tp = 0;\r
+ myHead.version = GetDWord(head, tp);\r
+ myHead.fontRevision = GetDWord(head, tp);\r
+ myHead.checkSumAdjustment = GetDWord(head, tp);\r
+ myHead.magicNumber = GetDWord(head, tp);\r
+ myHead.flags = GetWord(head, tp);\r
+ myHead.unitsPerEm = GetWord(head, tp);\r
+ myHead.createdh = GetDWord(head, tp);\r
+ myHead.createdl = GetDWord(head, tp);\r
+ myHead.modifiedh = GetDWord(head, tp);\r
+ myHead.modifiedl = GetDWord(head, tp);\r
+ myHead.xMin = GetWord(head, tp);\r
+ myHead.yMin = GetWord(head, tp);\r
+ myHead.xMax = GetWord(head, tp);\r
+ myHead.yMax = GetWord(head, tp);\r
+ myHead.macStyle = GetWord(head, tp);\r
+ myHead.lowestRecPPEM = GetWord(head, tp);\r
+ myHead.fontDirectionHint = (int16)GetWord(head, tp);\r
+ myHead.indexToLocFormat = (int16)GetWord(head, tp);\r
+ myHead.glyphDataFormat = (int16)GetWord(head, tp);\r
+\r
+ if (maxp_len != 32)\r
+ {\r
+#ifdef TDEBUG\r
+WriteLogMsg("Bad MAXP header: Expected 32, found %u...\n", maxp_len);\r
+#endif\r
+ return false; // Corrupt data?\r
+ }\r
+\r
+ tp = 0; // Reset table pointer\r
+ myMaxp.version = GetDWord(maxp, tp);\r
+ myMaxp.numGlyphs = GetWord(maxp, tp);\r
+ myMaxp.maxPoints = GetWord(maxp, tp);\r
+ myMaxp.maxContours = GetWord(maxp, tp);\r
+ myMaxp.maxCompositePoints = GetWord(maxp, tp);\r
+ myMaxp.maxCompositeContours = GetWord(maxp, tp);\r
+ myMaxp.maxZones = GetWord(maxp, tp);\r
+ myMaxp.maxTwilightPoints = GetWord(maxp, tp);\r
+ myMaxp.maxStorage = GetWord(maxp, tp);\r
+ myMaxp.maxFunctionDefs = GetWord(maxp, tp);\r
+ myMaxp.maxInstructionDefs = GetWord(maxp, tp);\r
+ myMaxp.maxStackElements = GetWord(maxp, tp);\r
+ myMaxp.maxSizeOfInstructions = GetWord(maxp, tp);\r
+ myMaxp.maxComponentElements = GetWord(maxp, tp);\r
+ myMaxp.maxComponentDepth = GetWord(maxp, tp);\r
+\r
+ tp = 0; // Reset table pointer\r
+ uint32 start = (myHead.indexToLocFormat ? GetDWord(loca, tp) : GetWord(loca, tp) << 1);\r
+\r
+ for(uint32 i=0; i<myMaxp.numGlyphs; i++)\r
+ {\r
+ uint32 end = (myHead.indexToLocFormat ? GetDWord(loca, tp) : GetWord(loca, tp) << 1);\r
+ uint32 length = end - start;\r
+ glyphLen[i] = length; // Lengths are saved 'cause malloc is sloppy\r
+\r
+ if (length) // loca+start? pointer arithmetic?\r
+ {\r
+ glyph[i] = (uint8 *)malloc(length); // Allocate space,\r
+ memcpy(glyph[i], glyf+start, length); // and move it!\r
+ }\r
+ else\r
+ glyph[i] = NULL;\r
+\r
+ start = end; // Reset start value\r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL BuildTables(void)\r
+//\r
+// This function builds the various TTF tables using info in the various\r
+// structs so that a TTF file can be written out to disk.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::BuildTables(void)\r
+{\r
+ uint32 i, tp, start;\r
+\r
+ myHead.indexToLocFormat = 1; // We don't bother with [uint16s*2] format...\r
+\r
+ // Build HEAD table\r
+\r
+ tp = 0; // Reset table pointer\r
+ SetDWord(head, tp, myHead.version);// = GetDWord(head, tp);\r
+ SetDWord(head, tp, myHead.fontRevision);// = GetDWord(head, tp);\r
+ SetDWord(head, tp, myHead.checkSumAdjustment);// = GetDWord(head, tp);\r
+ SetDWord(head, tp, myHead.magicNumber);// = GetDWord(head, tp);\r
+ SetWord(head, tp, myHead.flags);// = GetWord(head, tp);\r
+ SetWord(head, tp, myHead.unitsPerEm);// = GetWord(head, tp);\r
+ SetDWord(head, tp, myHead.createdh);// = GetDWord(head, tp);\r
+ SetDWord(head, tp, myHead.createdl);// = GetDWord(head, tp);\r
+ SetDWord(head, tp, myHead.modifiedh);// = GetDWord(head, tp);\r
+ SetDWord(head, tp, myHead.modifiedl);// = GetDWord(head, tp);\r
+ SetWord(head, tp, myHead.xMin);// = GetWord(head, tp);\r
+ SetWord(head, tp, myHead.yMin);// = GetWord(head, tp);\r
+ SetWord(head, tp, myHead.xMax);// = GetWord(head, tp);\r
+ SetWord(head, tp, myHead.yMax);// = GetWord(head, tp);\r
+ SetWord(head, tp, myHead.macStyle);// = GetWord(head, tp);\r
+ SetWord(head, tp, myHead.lowestRecPPEM);// = GetWord(head, tp);\r
+ SetWord(head, tp, myHead.fontDirectionHint);// = (int16)GetWord(head, tp);\r
+ SetWord(head, tp, myHead.indexToLocFormat);// = (int16)GetWord(head, tp);\r
+ SetWord(head, tp, myHead.glyphDataFormat);// = (int16)GetWord(head, tp);\r
+\r
+ // Build MAXP table\r
+\r
+ tp = 0; // Reset table pointer\r
+ SetDWord(maxp, tp, myMaxp.version);// = GetDWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.numGlyphs);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxPoints);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxContours);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxCompositePoints);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxCompositeContours);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxZones);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxTwilightPoints);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxStorage);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxFunctionDefs);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxInstructionDefs);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxStackElements);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxSizeOfInstructions);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxComponentElements);// = GetWord(maxp, tp);\r
+ SetWord(maxp, tp, myMaxp.maxComponentDepth);// = GetWord(maxp, tp);\r
+\r
+ // Build LOCA & GLYF tables\r
+\r
+ loca_len = (myMaxp.numGlyphs+1) * 4; // Set size of table\r
+\r
+ if (loca)\r
+ free(loca); // And create/reallocate it...\r
+\r
+ loca = (uint8 *) malloc(loca_len);\r
+\r
+ glyf_len = 0; // Refigure glyf table length\r
+\r
+ for(i=0; i<myMaxp.numGlyphs; i++)\r
+ glyf_len += glyphLen[i];\r
+\r
+ if (glyf)\r
+ free(glyf);\r
+\r
+ glyf = (uint8 *) malloc(glyf_len);\r
+\r
+ start = tp = 0; // Reset table pointer\r
+\r
+ for(i=0; i<myMaxp.numGlyphs; i++)\r
+ {\r
+ SetDWord(loca, tp, start); // Store glyph start address\r
+\r
+ if (glyphLen[i])\r
+ memcpy(glyf+start, glyph[i], glyphLen[i]);\r
+\r
+ start += glyphLen[i];\r
+ }\r
+\r
+ SetDWord(loca, tp, start); // Finally, store end of glyphs+1\r
+\r
+ return true;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL SetGlyph(int glyphnum)\r
+//\r
+// This function decodes the glyph data and stores the points in its own\r
+// internal array. If the flag isDirty is set, it also encodes the internal\r
+// array and stores it to the 'glyf' table.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::SetGlyph(uint16 glyphnum)\r
+{\r
+ bool retval = false; // Set failure as default\r
+\r
+ if (isDirty)\r
+ EncodeGlyph(currentGlyph);\r
+\r
+ isDirty = false;\r
+\r
+ if (glyphnum < myMaxp.numGlyphs) // numofgls is 1 based ind, glyph# 0 based\r
+ {\r
+ currentGlyph = glyphnum;\r
+ DecodeGlyph(currentGlyph);\r
+ retval = true;\r
+ }\r
+\r
+ return retval;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL AddGlyph(int glyphnum)\r
+//\r
+// This function adds a glyph of zero size at position glyphnum. If glyphnum\r
+// is greater than the number of glyphs, glyph is added at end of list. This\r
+// glyph then becomes the current glyph.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::AddGlyph(uint16 glyphnum)\r
+{\r
+ // incomplete: JLH\r
+ bool retval = false;\r
+\r
+ if (isDirty)\r
+ EncodeGlyph(currentGlyph);\r
+\r
+ isDirty = false;\r
+\r
+ return retval;\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Member function: BOOL DeleteGlyph(int glyphnum)\r
+//\r
+// This function deletes the glyph at position glyphnum. All glyphs after\r
+// this glyph are moved down in position.\r
+/////////////////////////////////////////////////////////////////////////////\r
+bool TTF::DeleteGlyph(uint16 glyphnum)\r
+{\r
+ // incomplete: JLH\r
+ bool retval = false;\r
+\r
+ return retval;\r
+}\r
+\r
+//\r
+// Various & sundry member functions implementation\r
+//\r
+// NOTE: For error handling, should throw exceptions--not return values...! !!! FIX !!!\r
+//\r
+\r
+Box TTF::GetBoundingBox(void)\r
+{\r
+ return Box(llx, lly, urx, ury);\r
+}\r
+\r
+GlyphPt TTF::GetPoint(uint16 pointno)\r
+{\r
+ GlyphPt p;\r
+\r
+ if (pointno >= MAXPOINTS)\r
+ return p; // Fix to make invalid\r
+\r
+ p.x = gx[pointno], p.y = gy[pointno], p.onCurve = onCurve[pointno];\r
+ return p;\r
+}\r
+\r
+uint16 TTF::GetNumberOfPolys(void)\r
+{\r
+ return numberOfPolys;\r
+}\r
+\r
+uint16 TTF::GetPolyEnd(uint16 polynum)\r
+{\r
+ if (polynum >= numberOfPolys)\r
+ return 0;\r
+\r
+ return poly[polynum];\r
+}\r
+\r
+int TTF::GetPointX(uint16 pointno)\r
+{\r
+ if (pointno >= MAXPOINTS)\r
+ return 0;\r
+\r
+ return gx[pointno];\r
+}\r
+\r
+int TTF::GetPointY(uint16 pointno)\r
+{\r
+ if (pointno >= MAXPOINTS)\r
+ return 0;\r
+\r
+ return gy[pointno];\r
+}\r
+\r
+bool TTF::GetOnCurve(uint16 pointno)\r
+{\r
+ if (pointno >= MAXPOINTS)\r
+ return true;\r
+\r
+ return onCurve[pointno];\r
+}\r
+\r
+bool TTF::SetOnCurve(uint16 pointno, bool state)\r
+{\r
+ if (pointno >= numberOfPoints)\r
+ return false;\r
+\r
+ onCurve[pointno] = state;\r
+ isDirty = true;\r
+\r
+ return true;\r
+}\r
+\r
+bool TTF::MovePoint(uint16 pointno, int x, int y)\r
+{\r
+ if (pointno >= numberOfPoints)\r
+ return false;\r
+\r
+ gx[pointno] = x; gy[pointno] = y;\r
+ isDirty = true;\r
+\r
+ return true;\r
+}\r
+\r
+bool TTF::MovePoint(uint16 pointno, GlyphPt p)\r
+{\r
+ if (pointno >= numberOfPoints)\r
+ return false;\r
+\r
+ gx[pointno] = p.x; gy[pointno] = p.y; onCurve[pointno] = p.onCurve;\r
+ isDirty = true;\r
+\r
+ return true;\r
+}\r
+\r
+bool TTF::IsCompositeGlyph(void)\r
+{\r
+ return isCompositeGlyph;\r
+}\r
+\r
--- /dev/null
+//\r
+// TTF.H: TTF Class\r
+// by James L. Hammons\r
+// (C) 1999 Underground Software\r
+//\r
+// This class encapsulates all the complexity of a TrueType Font File\r
+// database. Included are functions to load, save, & initialize the\r
+// TTF database.\r
+//\r
+\r
+// These really shouldn't be included here, but are for now...\r
+//#include <string.h>\r
+////#include <afxwin.h> // This is needed only for things like BOOL, etc.\r
+//#include <fstream.h>\r
+//#include <stdlib.h>\r
+//#include <malloc.h> // Both for malloc, free, _msize, realloc\r
+\r
+#ifndef __TTF_H__\r
+#define __TTF_H__\r
+\r
+#include "list.h"\r
+#include "types.h"\r
+#include "glyphpoints.h"\r
+\r
+#define MAXGLYPHS 4096 // Number of glyphs in object\r
+#define MAXPOINTS 2000 // Number of points in a glyph\r
+#define MAXHINTS 2000 // Number of hint uint8s in glyph\r
+\r
+//\r
+// "head" struct\r
+//\r
+struct Head\r
+{\r
+ uint32 version; // Fixed - Table version number (0x00010000 for version 1.0.)\r
+ uint32 fontRevision; // Fixed - fontRevision (Set by font manufacturer.)\r
+ uint32 checkSumAdjustment; // To compute: Set it to 0, sum the entire font\r
+ // as ULONG, then store 0xB1B0AFBA - sum.\r
+ uint32 magicNumber; // Set to 0x5F0F3CF5.\r
+ uint16 flags; /* Bit 0 - baseline for font at y=0;\r
+ Bit 1 - left sidebearing at x=0;\r
+ Bit 2 - instructions may depend on point size;\r
+ Bit 3 - force ppem to integer values for all\r
+ internal scaler math; may use\r
+ fractional ppem sizes if this bit is clear;\r
+ Bit 4 - instructions may alter advance width\r
+ (the advance widths might not scale linearly);\r
+ Note: All other bits must be zero.*/\r
+ uint16 unitsPerEm; // Valid range is from 16 to 16384\r
+ uint32 /*longDateTime*/ createdh, createdl; // International date (8-uint8 field).\r
+ uint32 /*longDateTime*/ modifiedh, modifiedl; // International date (8-uint8 field).\r
+ uint16 xMin; // For all glyph bounding boxes.\r
+ uint16 yMin; // For all glyph bounding boxes.\r
+ uint16 xMax; // For all glyph bounding boxes.\r
+ uint16 yMax; // For all glyph bounding boxes.\r
+ uint16 macStyle; /* Bit 0 bold (if set to 1); Bit 1 italic (if set to 1)\r
+ Bits 2-15 reserved (set to 0).*/\r
+ uint16 lowestRecPPEM; // Smallest readable size in pixels.\r
+ int16 fontDirectionHint; /* 0 Fully mixed directional glyphs;\r
+ 1 Only strongly left to right;\r
+ 2 Like 1 but also contains neutrals;\r
+ -1 Only strongly right to left;\r
+ -2 Like -1 but also contains neutrals.*/\r
+ int16 indexToLocFormat; // 0 for short offsets, 1 for long.\r
+ int16 glyphDataFormat; // 0 for current format.\r
+};\r
+\r
+//\r
+// "maxp" struct\r
+//\r
+struct Maxp\r
+{\r
+ uint32 version; // Table version number 0x00010000 for version 1.0. \r
+ uint16 numGlyphs; // The number of glyphs in the font. \r
+ uint16 maxPoints; // Maximum points in a non-composite glyph. \r
+ uint16 maxContours; // Maximum contours in a non-composite glyph. \r
+ uint16 maxCompositePoints; // Maximum points in a composite glyph. \r
+ uint16 maxCompositeContours; // Maximum contours in a composite glyph. \r
+ uint16 maxZones; // 1 if instructions do not use the twilight\r
+ // zone (Z0), or 2 if instructions do use Z0;\r
+ // should be set to 2 in most cases. \r
+ uint16 maxTwilightPoints; // Maximum points used in Z0. \r
+ uint16 maxStorage; // Number of Storage Area locations. \r
+ uint16 maxFunctionDefs; // Number of FDEFs. \r
+ uint16 maxInstructionDefs; // Number of IDEFs. \r
+ uint16 maxStackElements; // Maximum stack depth. \r
+ uint16 maxSizeOfInstructions; // Maximum uint8 count for glyph instructions. \r
+ uint16 maxComponentElements; // Maximum number of components referenced at\r
+ // "top level" for any composite glyph. \r
+ uint16 maxComponentDepth; // Maximum levels of recursion; 1 for simple components.\r
+};\r
+\r
+//\r
+// "cmap" struct\r
+//\r
+/*\r
+USHORT Table version number (0).\r
+USHORT Number of encoding tables, n. \r
+\r
+This is followed by an entry for each of the n encoding table specifying the\r
+particular encoding, and the offset to the actual subtable:\r
+\r
+Type Description \r
+USHORT Platform ID. \r
+USHORT Platform-specific encoding ID. \r
+ULONG uint8 offset from beginning of table to the subtable for this encoding. \r
+\r
+USHORT format Format number is set to 4. \r
+USHORT length Length in uint8s. \r
+USHORT version Version number (starts at 0). \r
+USHORT segCountX2 2 x segCount. \r
+USHORT searchRange 2 x (2**floor(log2(segCount))) \r
+USHORT entrySelector log2(searchRange/2) \r
+USHORT rangeShift 2 x segCount - searchRange \r
+USHORT endCount[segCount] End characterCode for each segment,\r
+ last =0xFFFF. \r
+USHORT reservedPad Set to 0. \r
+USHORT startCount[segCount] Start character code for each segment. \r
+USHORT idDelta[segCount] Delta for all character codes in segment. \r
+USHORT idRangeOffset[segCount] Offsets into glyphIdArray or 0 \r
+USHORT glyphIdArray[ ] Glyph index array (arbitrary length) \r
+\r
+The number of segments is specified by segCount, which is not explicitly in\r
+the header; however, all of the header parameters are derived from it. The\r
+searchRange value is twice the largest power of 2 that is less than or equal\r
+to segCount. For example, if segCount=39, we have the following:\r
+\r
+segCountX2 78\r
+searchRange 64 (2 * largest power of 2 <= 39)\r
+entrySelector 5 log2(32)\r
+rangeShift 14 2 x 39 - 64\r
+*/\r
+\r
+struct GlyphPt\r
+{\r
+ int x, y;\r
+ bool onCurve;\r
+\r
+ // Default constructor\r
+ GlyphPt(int xx = 0, int yy = 0, bool oc = true): x(xx), y(yy), onCurve(oc) {}\r
+};\r
+\r
+struct Box\r
+{\r
+ int16 llx, lly, urx, ury;\r
+\r
+ // Default constructor\r
+ Box(int16 lx = 0, int16 ly = 0, int16 rx = 0, int16 ry = 0):\r
+ llx(lx), lly(ly), urx(rx), ury(ry) {}\r
+};\r
+\r
+struct NameRec\r
+{\r
+ uint16 platformID, platformSpecID, languageID, nameID, length;\r
+ uint8 * str;\r
+\r
+ NameRec(): str(NULL) {}\r
+\r
+ NameRec(NameRec &c): str(NULL)\r
+ {\r
+ *this = c;\r
+ }\r
+\r
+ ~NameRec()\r
+ {\r
+ if (str)\r
+ delete[] str;\r
+ }\r
+\r
+ void operator=(const NameRec &c)\r
+ {\r
+ if (this == &c)\r
+ return; // Take care of self-assignment\r
+\r
+ if (str)\r
+ delete[] str;\r
+\r
+ platformID = c.platformID;\r
+ platformSpecID = c.platformSpecID;\r
+ languageID = c.languageID;\r
+ nameID = c.nameID;\r
+ length = c.length;\r
+//Fix this str = (uint8 *)strdup((char *)c.str);\r
+ }\r
+};\r
+\r
+struct Composite\r
+{\r
+ uint16 flags, glyphIndex;\r
+ int16 arg1, arg2;\r
+ float xScale, yScale, scale01, scale10;\r
+\r
+ Composite(uint16 fl = 0, uint16 gl = 0, int16 a1 = 0, int16 a2 = 0,\r
+ float xs = 1.0f, float ys = 1.0f, float s01 = 1.0f, float s10 = 1.0f):\r
+ flags(fl), glyphIndex(gl), arg1(a1), arg2(a2), xScale(xs), yScale(ys),\r
+ scale01(s01), scale10(s10) {}\r
+};\r
+\r
+//\r
+// The TTF class\r
+//\r
+// The following is a set of member functions that needs to be implemented\r
+// to fully encapsulate a TTF database.\r
+//\r
+// SetGlyph(glyphno)\r
+// DeleteGlyph(glyphno)\r
+// AddGlyph()\r
+// GetNumberOfPolys()\r
+// GetPolyStart(polyno)\r
+// SetPolyStart(polyno)\r
+// AddPoly(polyno)\r
+// DeletePoly(polyno)\r
+// IsCompositeGlyph()\r
+// MovePoint(pointno, x, y)\r
+// AddPoint(pointno, x, y)\r
+// DeletePoint(pointno)\r
+// maybe: TGlyphPt GetPointInfo(pointno) instead of three following...\r
+// GetPointX(pointno)\r
+// GetPointY(pointno)\r
+// GetOnCurve(pointno)\r
+// SetOnCurve(pointno)\r
+// ConnectGlyphToChar(glyphno, charno)\r
+// EncodeGlyph(glyphno)\r
+// DecodeGlyph(glyphno)\r
+// GetNumberOfPoints()\r
+// SwapPoints(pointno1, pointno2)\r
+//\r
+// More to be added, as necessary...\r
+//\r
+class TTF\r
+{\r
+ private:\r
+ bool EncodeGlyph(uint16);\r
+ bool DecodeGlyph(uint16);\r
+ bool ExtractTables(void);\r
+ bool BuildTables(void);\r
+\r
+ public:\r
+ TTF(void); // Constructor\r
+ ~TTF(); // Destructor\r
+ void Init(void); // Initalize font database\r
+ bool Load(const char *); // Load font database\r
+ bool Save(const char *); // Save font database\r
+ void ClearTables(void); // Deallocate memory...\r
+ bool SetGlyph(uint16 glyphnum); // Set internal pointer/encode/decode\r
+ bool AddGlyph(uint16 glyphnum);\r
+ bool DeleteGlyph(uint16 glyphnum);\r
+ Box GetBoundingBox(void);\r
+ GlyphPt GetPoint(uint16 pointno);\r
+ uint16 GetNumberOfPolys(void);\r
+ uint16 GetPolyEnd(uint16 polynum);\r
+ int GetPointX(uint16 pointno);\r
+ int GetPointY(uint16 pointno);\r
+ bool GetOnCurve(uint16 pointno);\r
+ bool SetOnCurve(uint16 pointno, bool state);\r
+ bool MovePoint(uint16 pointno, int x, int y);\r
+ bool MovePoint(uint16 pointno, GlyphPt p);\r
+ bool AddPoint(uint16 pointno, int x, int y, bool state);\r
+ bool DeletePoint(uint16 pointno);\r
+ bool IsCompositeGlyph(void);\r
+ GlyphPoints GetGlyphPoints(uint16);\r
+ GlyphPoints GetAllCompositePoints(uint16);\r
+ void GetCharName(int, uint8 *);\r
+\r
+ private:\r
+ bool isDirty; // Has glyph been modified?\r
+ bool isCompositeGlyph; // Is it a composite? (need structs to store composite info...)\r
+ uint16 currentGlyph; // The glyph currently decoded\r
+ uint16 numberOfPoints;\r
+ int gx[MAXPOINTS]; // Internal point arrays...\r
+ int gy[MAXPOINTS]; // These could be dynamically allocated in the\r
+ bool onCurve[MAXPOINTS]; // constructor, with default values being set\r
+ uint16 numberOfHints;\r
+ uint8 hint[MAXHINTS]; // Hints storage\r
+ uint16 numberOfPolys; // Number of polygons in glyph\r
+ uint16 poly[200]; // End points of polygons\r
+ int16 llx, lly, urx, ury; // Lower left/Upper right X/Y\r
+// public://remove after debugging...\r
+ uint8 * glyph[MAXGLYPHS]; // Placeholders for glyphs\r
+ uint32 glyphLen[MAXGLYPHS]; // Glyph lengths are stored since malloc() is sloppy\r
+ Maxp myMaxp; // Internal placeholders for this shiat\r
+ Head myHead;\r
+// public: //private: later...\r
+ List<Composite> compositeList; // Composite glyph list\r
+ uint8 * EBDT, * EBLC, * EBSC, * LTSH, * OS_2, * PCLT, * VDMX, * cmap, * cvt, * fpgm,\r
+ * gasp, * glyf, * hdmx, * head, * hhea, * hmtx, * kern, * loca, * maxp, * name,\r
+ * post, * prep, * vhea, * vmtx;\r
+ uint32 EBDT_len, EBLC_len, EBSC_len, LTSH_len, OS_2_len, PCLT_len, VDMX_len, cmap_len,\r
+ cvt_len, fpgm_len, gasp_len, glyf_len, hdmx_len, head_len, hhea_len, hmtx_len,\r
+ kern_len, loca_len, maxp_len, name_len, post_len, prep_len, vhea_len, vmtx_len;\r
+ uint8 * * parray[24]; // Pointer array\r
+ uint32 * larray[24]; // Length array\r
+ bool loaded; // Font loaded/init'ed?\r
+};\r
+\r
+#endif // __TTF_H__\r
+\r
--- /dev/null
+//\r
+// Basic types for platform independent code\r
+//\r
+\r
+#ifndef __TYPES_H__\r
+#define __TYPES_H__\r
+\r
+// This is only good on certain intel 32-bit platforms...\r
+// You may need to tweak to suit your specific platform.\r
+\r
+typedef unsigned char uint8;\r
+typedef signed char int8;\r
+typedef unsigned short uint16;\r
+typedef signed short int16;\r
+typedef unsigned uint32;\r
+typedef signed int32;\r
+//typedef unsigned long long uint64;\r
+//typedef signed long long int64;\r
+\r
+//typedef signed char SBYTE;\r
+//typedef signed short int SWORD;\r
+//typedef signed long int SDWORD;\r
+\r
+/*#ifndef _WINDOWS_\r
+#define NULL 0\r
+// This is for non-compliant compilers that don't follow proper scoping rules (and suck). ;-)\r
+#define for if(false);else for\r
+#endif*/\r
+#ifndef NULL\r
+#define NULL 0\r
+#endif\r
+\r
+#endif // __TYPES_H__\r
--- /dev/null
+//\r
+// VECTOR.H - vector class definition\r
+//\r
+// by James L. Hammons\r
+// (C) 2004 Underground Software\r
+//\r
+// JLH = James L. Hammons <jlhamm@acm.org>\r
+//\r
+// Who When What\r
+// --- ---------- -------------------------------------------------------------\r
+// JLH ??/??/2003 Created original implementation\r
+// JLH 05/14/2004 Separated header from implementation, added operator-\r
+// function\r
+// JLH 05/15/2004 Added operator+ function\r
+//\r
+\r
+#include <math.h>\r
+#include "vector.h"\r
+\r
+vector::vector(double a1/*= 0.0*/, double b1/*= 0.0*/, double c1/*= 0.0*/,\r
+ double a2/*= 0.0*/, double b2/*= 0.0*/, double c2/*= 0.0*/):\r
+ x(a1 - a2), y(b1 - b2), z(c1 - c2)\r
+{\r
+}\r
+\r
+vector::vector(const vector &v1, const vector &v2):\r
+ x(v1.x - v2.x), y(v1.y - v2.y), z(v1.z - v2.z)\r
+{\r
+}\r
+\r
+vector& vector::operator=(const vector &v)\r
+{\r
+ x = v.x, y = v.y, z = v.z;\r
+ return *this;\r
+}\r
+\r
+bool vector::operator==(const vector &v)\r
+{\r
+ if ((x == v.x) && (y == v.y) && (z == v.z))\r
+ return true;\r
+\r
+ return false;\r
+}\r
+\r
+void vector::unitize(void)\r
+{\r
+ double dist = sqrt(x*x + y*y + z*z);\r
+\r
+ if (dist != 0.0)\r
+ x /= dist, y /= dist, z /= dist;\r
+\r
+ if (x == -0.0)\r
+ x = +0.0;\r
+\r
+ if (y == -0.0)\r
+ y = +0.0;\r
+\r
+ if (z == -0.0)\r
+ z = +0.0;\r
+}\r
+\r
+vector vector::operator*(const vector &v) // Cross product: "this" x "v"\r
+{\r
+ vector r;\r
+\r
+ r.x = (y * v.z) - (v.y * z);\r
+ r.y = -((x * v.z) - (v.x * z));\r
+ r.z = (x * v.y) - (v.x * y);\r
+\r
+ return r;\r
+}\r
+\r
+vector vector::operator+(const vector &v)\r
+{\r
+ return vector(x + v.x, y + v.y, z + v.z);\r
+}\r
+\r
+vector vector::operator-(const vector &v)\r
+{\r
+ return vector(x, y, z, v.x, v.y, v.z);\r
+}\r
+\r
+double vector::dot(const vector &v1, const vector &v2)\r
+{\r
+ return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;\r
+}\r
+\r
+double vector::dot(const vector &v)\r
+{\r
+ return x * v.x + y * v.y + z * v.z;\r
+}\r
+\r
+double vector::distance(const vector &v) // Pythagoras extended to 3 dimensions\r
+{\r
+ double a = x - v.x, b = y - v.y, c = z - v.z;\r
+\r
+ return sqrt(a * a + b * b + c * c);\r
+}\r
+\r
+double vector::length(void)\r
+{\r
+ return sqrt(x * x + y * y + z * z);\r
+}\r
+\r
+void vector::operator*=(const double &d)\r
+{\r
+ x *= d, y *= d, z *= d;\r
+}\r
+\r
+void vector::operator/=(const double &d)\r
+{\r
+ if (d != 0.0)\r
+ x /= d, y /= d, z /= d;\r
+}\r
+\r
+void vector::operator+=(const vector &v)\r
+{\r
+ x += v.x, y += v.y, z += v.z;\r
+}\r
+\r
+void vector::operator-=(const vector &v)\r
+{\r
+ x -= v.x, y -= v.y, z -= v.z;\r
+}\r
+\r
+vector vector::operator*(const double &d) // Scale vector by amount\r
+{\r
+ return vector(x * d, y * d, z * d);\r
+}\r
+\r
+void vector::zero(const double epsilon)\r
+{\r
+ if (fabs(x) < epsilon)\r
+ x = 0.0;\r
+\r
+ if (fabs(y) < epsilon)\r
+ y = 0.0;\r
+\r
+ if (fabs(z) < epsilon)\r
+ z = 0.0;\r
+}\r
--- /dev/null
+//\r
+// VECTOR.H - vector class definition\r
+//\r
+// by James L. Hammons\r
+// (C) 2003 Underground Software\r
+//\r
+\r
+#ifndef __VECTOR_H__\r
+#define __VECTOR_H__\r
+\r
+struct vector\r
+{\r
+ double x, y, z;\r
+\r
+ vector(double a1=0.0, double b1=0.0, double c1=0.0, double a2=0.0, double b2=0.0, double c2=0.0);\r
+ vector(const vector &v1, const vector &v2);\r
+ vector& operator=(const vector &v);\r
+ bool operator==(const vector &v);\r
+ void unitize(void);\r
+ vector operator*(const vector &v); // Cross product: "this" x "v"\r
+ vector operator+(const vector &v);\r
+ vector operator-(const vector &v);\r
+ double dot(const vector &v1, const vector &v2);\r
+ double dot(const vector &v);\r
+ double distance(const vector &v); // Pythagoras extended to 3 dimensions\r
+ double length(void);\r
+ void operator*=(const double &d);\r
+ void operator/=(const double &d);\r
+ void operator+=(const vector &v);\r
+ void operator-=(const vector &v);\r
+ vector operator*(const double &d); // Scale vector by amount\r
+ void zero(const double epsilon);\r
+};\r
+\r
+#endif // __VECTOR_H__\r