From e914c4f508327bba2d2c41c18262eb4d52cafbc7 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 12 Feb 2002 01:49:01 +0000 Subject: [PATCH] add unicode decoding --- panda/src/text/Sources.pp | 3 + panda/src/text/dynamicTextFont.cxx | 18 ++- panda/src/text/stringDecoder.I | 58 ++++++++ panda/src/text/stringDecoder.cxx | 120 +++++++++++++++++ panda/src/text/stringDecoder.h | 71 ++++++++++ panda/src/text/textNode.I | 81 ++++++++--- panda/src/text/textNode.cxx | 210 ++++++++++++++++++++++++----- panda/src/text/textNode.h | 71 ++++++---- panda/src/text/text_composite1.cxx | 1 + 9 files changed, 551 insertions(+), 82 deletions(-) create mode 100644 panda/src/text/stringDecoder.I create mode 100644 panda/src/text/stringDecoder.cxx create mode 100644 panda/src/text/stringDecoder.h diff --git a/panda/src/text/Sources.pp b/panda/src/text/Sources.pp index a0f3a68d5b..0c32d6d21b 100644 --- a/panda/src/text/Sources.pp +++ b/panda/src/text/Sources.pp @@ -18,6 +18,7 @@ dynamicTextPage.I dynamicTextPage.h \ geomTextGlyph.I geomTextGlyph.h \ staticTextFont.I staticTextFont.h \ + stringDecoder.I stringDecoder.h \ textFont.I textFont.h \ textGlyph.I textGlyph.h \ textNode.I textNode.h textNode.cxx @@ -28,6 +29,7 @@ dynamicTextGlyph.cxx \ dynamicTextPage.cxx \ geomTextGlyph.cxx \ + stringDecoder.cxx \ staticTextFont.cxx \ textFont.cxx textGlyph.cxx @@ -38,6 +40,7 @@ dynamicTextPage.I dynamicTextPage.h \ geomTextGlyph.I geomTextGlyph.h \ staticTextFont.I staticTextFont.h \ + stringDecoder.I stringDecoder.h \ textFont.I textFont.h \ textGlyph.I textGlyph.h \ textNode.I textNode.h diff --git a/panda/src/text/dynamicTextFont.cxx b/panda/src/text/dynamicTextFont.cxx index 547cef06db..78591c732c 100644 --- a/panda/src/text/dynamicTextFont.cxx +++ b/panda/src/text/dynamicTextFont.cxx @@ -98,10 +98,20 @@ DynamicTextFont(const Filename &font_filename, int face_index) { } set_name(name); - text_cat.info() - << "Loaded font " << get_name() << "\n"; - _is_valid = true; - reset_scale(); + if (!FT_IS_SCALABLE(_face)) { + text_cat.error() + << "Unable to read font " << get_name() + << ": non-scalable fonts not supported.\n"; + // Although we could support these if we wanted to, just + // haven't bothered to write the few lines of glue code that + // would do it. + + } else { + text_cat.info() + << "Loaded font " << get_name() << "\n"; + _is_valid = true; + reset_scale(); + } } } } diff --git a/panda/src/text/stringDecoder.I b/panda/src/text/stringDecoder.I new file mode 100644 index 0000000000..bf2f6519ec --- /dev/null +++ b/panda/src/text/stringDecoder.I @@ -0,0 +1,58 @@ +// Filename: stringDecoder.I +// Created by: drose (11Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: StringDecoder::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE StringDecoder:: +StringDecoder(const string &input) : _input(input) { + _p = 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: StringDecoder::is_eof +// Access: Public +// Description: Returns true if the decoder has returned the last +// character in the string, false if there are more to +// go. +//////////////////////////////////////////////////////////////////// +INLINE bool StringDecoder:: +is_eof() { + return (_p >= _input.size()); +} + +//////////////////////////////////////////////////////////////////// +// Function: StringUtf8Decoder::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE StringUtf8Decoder:: +StringUtf8Decoder(const string &input) : StringDecoder(input) { +} + +//////////////////////////////////////////////////////////////////// +// Function: StringUnicodeDecoder::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE StringUnicodeDecoder:: +StringUnicodeDecoder(const string &input) : StringDecoder(input) { +} diff --git a/panda/src/text/stringDecoder.cxx b/panda/src/text/stringDecoder.cxx new file mode 100644 index 0000000000..f698fa7282 --- /dev/null +++ b/panda/src/text/stringDecoder.cxx @@ -0,0 +1,120 @@ +// Filename: stringDecoder.cxx +// Created by: drose (11Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "stringDecoder.h" + +//////////////////////////////////////////////////////////////////// +// Function: StringDecoder::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +StringDecoder:: +~StringDecoder() { +} + +//////////////////////////////////////////////////////////////////// +// Function: StringDecoder::get_next_character +// Access: Public, Virtual +// Description: Returns the next character in sequence. +//////////////////////////////////////////////////////////////////// +int StringDecoder:: +get_next_character() { + if (is_eof()) { + return -1; + } + return (unsigned char)_input[_p++]; +} + +/* +In UTF-8, each 16-bit Unicode character is encoded as a sequence of +one, two, or three 8-bit bytes, depending on the value of the +character. The following table shows the format of such UTF-8 byte +sequences (where the "free bits" shown by x's in the table are +combined in the order shown, and interpreted from most significant to +least significant): + + Binary format of bytes in sequence: + Number of Maximum expressible + 1st byte 2nd byte 3rd byte free bits: Unicode value: + + 0xxxxxxx 7 007F hex (127) + 110xxxxx 10xxxxxx (5+6)=11 07FF hex (2047) + 1110xxxx 10xxxxxx 10xxxxxx (4+6+6)=16 FFFF hex (65535) + +The value of each individual byte indicates its UTF-8 function, as follows: + + 00 to 7F hex (0 to 127): first and only byte of a sequence. + 80 to BF hex (128 to 191): continuing byte in a multi-byte sequence. + C2 to DF hex (194 to 223): first byte of a two-byte sequence. + E0 to EF hex (224 to 239): first byte of a three-byte sequence. +*/ + +//////////////////////////////////////////////////////////////////// +// Function: StringUtf8Decoder::get_next_character +// Access: Public, Virtual +// Description: Returns the next character in sequence. +//////////////////////////////////////////////////////////////////// +int StringUtf8Decoder:: +get_next_character() { + if (is_eof()) { + return -1; + } + + unsigned int result = (unsigned char)_input[_p++]; + if ((result & 0xe0) == 0xc0) { + // First byte of two. + unsigned int two = 0; + if (!is_eof()) { + two = (unsigned char)_input[_p++]; + } + result = ((result & 0x1f) << 6) | (two & 0x3f); + + } else if ((result & 0xf0) == 0xe0) { + // First byte of three. + unsigned int two = 0; + unsigned int three = 0; + if (!is_eof()) { + two = (unsigned char)_input[_p++]; + } + if (!is_eof()) { + three = (unsigned char)_input[_p++]; + } + result = ((result & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f); + } + + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: StringUnicodeDecoder::get_next_character +// Access: Public, Virtual +// Description: Returns the next character in sequence. +//////////////////////////////////////////////////////////////////// +int StringUnicodeDecoder:: +get_next_character() { + if (is_eof()) { + return -1; + } + + unsigned int high = (unsigned char)_input[_p++]; + unsigned int low = 0; + if (!is_eof()) { + low = (unsigned char)_input[_p++]; + } + return ((high << 8) | low); +} diff --git a/panda/src/text/stringDecoder.h b/panda/src/text/stringDecoder.h new file mode 100644 index 0000000000..bc797bda9c --- /dev/null +++ b/panda/src/text/stringDecoder.h @@ -0,0 +1,71 @@ +// Filename: stringDecoder.h +// Created by: drose (11Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef STRINGDECODER_H +#define STRINGDECODER_H + +#include "pandabase.h" + + +//////////////////////////////////////////////////////////////////// +// Class : StringDecoder +// Description : The base class to a family of classes that decode +// various kinds of encoded byte streams. Give it a +// string, then ask it to pull the characters out one at +// a time. This also serves as the plain old +// byte-at-a-time decoder. +//////////////////////////////////////////////////////////////////// +class StringDecoder { +public: + INLINE StringDecoder(const string &input); + virtual ~StringDecoder(); + + virtual int get_next_character(); + INLINE bool is_eof(); + +protected: + string _input; + size_t _p; +}; + +//////////////////////////////////////////////////////////////////// +// Class : StringUtf8Decoder +// Description : This decoder extracts utf-8 sequences. +//////////////////////////////////////////////////////////////////// +class StringUtf8Decoder : public StringDecoder { +public: + INLINE StringUtf8Decoder(const string &input); + + virtual int get_next_character(); +}; + +//////////////////////////////////////////////////////////////////// +// Class : StringUnicodeDecoder +// Description : This decoder extracts characters two at a time to get +// a plain wide character sequence. +//////////////////////////////////////////////////////////////////// +class StringUnicodeDecoder : public StringDecoder { +public: + INLINE StringUnicodeDecoder(const string &input); + + virtual int get_next_character(); +}; + +#include "stringDecoder.I" + +#endif diff --git a/panda/src/text/textNode.I b/panda/src/text/textNode.I index cf0309f33f..c61b5928b7 100644 --- a/panda/src/text/textNode.I +++ b/panda/src/text/textNode.I @@ -86,22 +86,6 @@ thaw() { return _freeze_level; } -/* -//////////////////////////////////////////////////////////////////// -// Function: TextNode::set_font -// Access: Published -// Description: Sets the font that will be used when making text. -//////////////////////////////////////////////////////////////////// -INLINE void TextNode:: -set_font(Node *font_node) { - if (font_node == (Node *)NULL) { - set_font((TextFont *)NULL); - } else { - set_font(new TextFont(font_node)); - } -} -*/ - //////////////////////////////////////////////////////////////////// // Function: TextNode::set_font // Access: Published @@ -125,6 +109,67 @@ get_font() const { return _font; } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::set_encoding +// Access: Published +// Description: Specifies how the string set via set_text() is to be +// interpreted. The default, E_iso8859, means a +// standard string with one-byte characters +// (i.e. ASCII). Other encodings are possible to take +// advantage of character sets with more than 256 +// characters. +//////////////////////////////////////////////////////////////////// +INLINE void TextNode:: +set_encoding(TextNode::Encoding encoding) { + if (_encoding != encoding) { + _encoding = encoding; + rebuild(true); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TextNode::get_encoding +// Access: Published +// Description: Returns the encoding by which the string set via +// set_text() is to be interpreted. See set_encoding(). +//////////////////////////////////////////////////////////////////// +INLINE TextNode::Encoding TextNode:: +get_encoding() const { + return _encoding; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextNode::set_expand_amp +// Access: Published +// Description: Sets the state of the expand_amp flag. When this is +// true, embedded ampersands in the text string are +// expanded to special characters according to a subset +// of the HTML conventions. When this is false, +// ampersands are treated as ordinary characters. +//////////////////////////////////////////////////////////////////// +INLINE void TextNode:: +set_expand_amp(bool expand_amp) { + bool current_expand_amp = get_expand_amp(); + if (expand_amp && !current_expand_amp) { + _flags |= F_expand_amp; + rebuild(true); + } else { + _flags &= ~F_expand_amp; + rebuild(true); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TextNode::get_expand_amp +// Access: Published +// Description: Returns the state of the expand_amp flag. See +// set_expand_amp(). +//////////////////////////////////////////////////////////////////// +INLINE bool TextNode:: +get_expand_amp() const { + return (_flags & F_expand_amp) != 0; +} + //////////////////////////////////////////////////////////////////// // Function: TextNode::get_line_height // Access: Published @@ -165,7 +210,7 @@ get_slant() const { // Description: //////////////////////////////////////////////////////////////////// INLINE void TextNode:: -set_align(int align_type) { +set_align(TextNode::Alignment align_type) { if (_align != align_type) { _align = align_type; rebuild(true); @@ -177,7 +222,7 @@ set_align(int align_type) { // Access: Published // Description: //////////////////////////////////////////////////////////////////// -INLINE int TextNode:: +INLINE TextNode::Alignment TextNode:: get_align() const { return _align; } diff --git a/panda/src/text/textNode.cxx b/panda/src/text/textNode.cxx index 05a5024075..c35ac36bc7 100644 --- a/panda/src/text/textNode.cxx +++ b/panda/src/text/textNode.cxx @@ -17,6 +17,7 @@ //////////////////////////////////////////////////////////////////// #include "textNode.h" #include "textGlyph.h" +#include "stringDecoder.h" #include "config_text.h" #include "compose_matrix.h" @@ -45,10 +46,11 @@ TypeHandle TextNode::_type_handle; //////////////////////////////////////////////////////////////////// TextNode:: TextNode(const string &name) : NamedNode(name) { + _encoding = E_iso8859; _slant = 0.0f; _flags = 0; - _align = TM_ALIGN_LEFT; + _align = A_left; _wordwrap_width = 1.0f; _text_color.set(1.0f, 1.0f, 1.0f, 1.0f); @@ -112,16 +114,16 @@ write(ostream &out, int indent_level) const { indent(out, indent_level + 2) << "alignment is "; switch (_align) { - case TM_ALIGN_LEFT: - out << "TM_ALIGN_LEFT\n"; + case A_left: + out << "A_left\n"; break; - case TM_ALIGN_RIGHT: - out << "TM_ALIGN_RIGHT\n"; + case A_right: + out << "A_right\n"; break; - case TM_ALIGN_CENTER: - out << "TM_ALIGN_CENTER\n"; + case A_center: + out << "A_center\n"; break; } @@ -245,13 +247,17 @@ generate() { text = wordwrap_to(text, _wordwrap_width, false); } + StringDecoder *decoder = make_decoder(text); + // Assemble the text. LVector2f ul, lr; int num_rows = 0; - PT_Node text_root = assemble_text(text.c_str(), ul, lr, num_rows); + PT_Node text_root = assemble_text(decoder, ul, lr, num_rows); RenderRelation *text_arc = new RenderRelation(sub_root, text_root, _draw_order + 2); + delete decoder; + if (has_text_color()) { text_arc->set_transition(new ColorTransition(_text_color)); if (_text_color[3] != 1.0) { @@ -410,9 +416,13 @@ do_measure() { text = wordwrap_to(text, _wordwrap_width, false); } + StringDecoder *decoder = make_decoder(text); + LVector2f ul, lr; int num_rows = 0; - measure_text(text.c_str(), ul, lr, num_rows); + measure_text(decoder, ul, lr, num_rows); + + delete decoder; _num_rows = num_rows; _ul2d = ul; @@ -424,6 +434,29 @@ do_measure() { _lr3d = _lr3d * _transform; } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::make_decoder +// Access: Private +// Description: Creates and returns a new StringDecoder suitable for +// decoding the given input text, and corresponding to +// our input encoding type. The decoder must be freed +// via delete later. +//////////////////////////////////////////////////////////////////// +StringDecoder *TextNode:: +make_decoder(const string &text) { + switch (_encoding) { + case E_utf8: + return new StringUtf8Decoder(text); + + case E_unicode: + return new StringUnicodeDecoder(text); + + case E_iso8859: + default: + return new StringDecoder(text); + }; +} + //////////////////////////////////////////////////////////////////// // Function: TextNode::assemble_row // Access: Private @@ -434,12 +467,21 @@ do_measure() { // to the terminating character. //////////////////////////////////////////////////////////////////// float TextNode:: -assemble_row(const char *&source, Node *dest) { +assemble_row(StringDecoder *decoder, Node *dest) { nassertr(_font != (TextFont *)NULL, 0.0f); float xpos = 0.0f; - while (*source != '\0' && *source != '\n') { - int character = (unsigned char)*source; + bool expand_amp = get_expand_amp(); + if (decoder->is_eof()) { + return xpos; + } + int character = decoder->get_next_character(); + while (character != '\n') { + if (character == '&' && expand_amp) { + // An ampersand in expand_amp mode is treated as an escape + // character. + character = expand_amp_sequence(decoder); + } if (character == ' ') { // A space is a special case. @@ -481,7 +523,10 @@ assemble_row(const char *&source, Node *dest) { xpos += glyph->get_advance() * glyph_scale; } } - source++; + if (decoder->is_eof()) { + return xpos; + } + character = decoder->get_next_character(); } return xpos; @@ -495,7 +540,7 @@ assemble_row(const char *&source, Node *dest) { // returns it. Also sets the ul, lr corners. //////////////////////////////////////////////////////////////////// Node *TextNode:: -assemble_text(const char *source, LVector2f &ul, LVector2f &lr, +assemble_text(StringDecoder *decoder, LVector2f &ul, LVector2f &lr, int &num_rows) { nassertr(_font != (TextFont *)NULL, (Node *)NULL); float line_height = get_line_height(); @@ -508,24 +553,20 @@ assemble_text(const char *source, LVector2f &ul, LVector2f &lr, float posy = 0.0f; int row_index = 0; - while (*source != '\0') { + while (!decoder->is_eof()) { char numstr[20]; sprintf(numstr, "row%d", row_index); nassertr(strlen(numstr) < 20, root_node); Node *row = new NamedNode(numstr); - float row_width = assemble_row(source, row); - if (*source != '\0') { - // Skip past the newline. - source++; - } + float row_width = assemble_row(decoder, row); LMatrix4f mat = LMatrix4f::ident_mat(); - if (_align == TM_ALIGN_LEFT) { + if (_align == A_left) { mat.set_row(3, LVector3f(0.0f, 0.0f, posy)); lr[0] = max(lr[0], row_width); - } else if (_align == TM_ALIGN_RIGHT) { + } else if (_align == A_right) { mat.set_row(3, LVector3f(-row_width, 0.0f, posy)); ul[0] = min(ul[0], -row_width); @@ -566,10 +607,21 @@ assemble_text(const char *source, LVector2f &ul, LVector2f &lr, // it. //////////////////////////////////////////////////////////////////// float TextNode:: -measure_row(const char *&source) { +measure_row(StringDecoder *decoder) { + nassertr(_font != (TextFont *)NULL, 0.0f); + float xpos = 0.0f; - while (*source != '\0' && *source != '\n') { - int character = (unsigned char)*source; + bool expand_amp = get_expand_amp(); + if (decoder->is_eof()) { + return xpos; + } + int character = decoder->get_next_character(); + while (character != '\n') { + if (character == '&' && expand_amp) { + // An ampersand in expand_amp mode is treated as an escape + // character. + character = expand_amp_sequence(decoder); + } if (character == ' ') { // A space is a special case. @@ -584,7 +636,10 @@ measure_row(const char *&source) { xpos += glyph->get_advance() * glyph_scale; } } - source++; + if (decoder->is_eof()) { + return xpos; + } + character = decoder->get_next_character(); } return xpos; @@ -597,7 +652,7 @@ measure_row(const char *&source) { // actually assembling it. //////////////////////////////////////////////////////////////////// void TextNode:: -measure_text(const char *source, LVector2f &ul, LVector2f &lr, +measure_text(StringDecoder *decoder, LVector2f &ul, LVector2f &lr, int &num_rows) { nassertv(_font != (TextFont *)NULL); float line_height = get_line_height(); @@ -606,17 +661,13 @@ measure_text(const char *source, LVector2f &ul, LVector2f &lr, lr.set(0.0f, 0.0f); float posy = 0.0f; - while (*source != '\0') { - float row_width = measure_row(source); - if (*source != '\0') { - // Skip past the newline. - source++; - } + while (!decoder->is_eof()) { + float row_width = measure_row(decoder); - if (_align == TM_ALIGN_LEFT) { + if (_align == A_left) { lr[0] = max(lr[0], row_width); - } else if (_align == TM_ALIGN_RIGHT) { + } else if (_align == A_right) { ul[0] = min(ul[0], -row_width); } else { @@ -633,6 +684,95 @@ measure_text(const char *source, LVector2f &ul, LVector2f &lr, lr[1] = posy + 0.8f * line_height; } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::expand_amp_sequence +// Access: Private +// Description: Given that we have just read an ampersand from the +// StringDecoder, and that we have expand_amp in effect +// and are therefore expected to expand the sequence +// that this ampersand begins into a single unicode +// character, do the expansion and return the character. +//////////////////////////////////////////////////////////////////// +int TextNode:: +expand_amp_sequence(StringDecoder *decoder) { + int result = 0; + + int character = decoder->get_next_character(); + if (character == '#') { + // An explicit numeric sequence: &#nnn; + result = 0; + character = decoder->get_next_character(); + while (!decoder->is_eof() && character < 128 && isdigit(character)) { + result = (result * 10) + (character - '0'); + character = decoder->get_next_character(); + } + if (character != ';') { + // Invalid sequence. + return 0; + } + + return result; + } + + string sequence; + + // Some non-numeric sequence. + while (!decoder->is_eof() && character < 128 && isalpha(character)) { + sequence += character; + character = decoder->get_next_character(); + } + if (character != ';') { + // Invalid sequence. + return 0; + } + + static const struct { + const char *name; + int code; + } tokens[] = { + { "amp", '&' }, { "lt", '<' }, { "gt", '>' }, { "quot", '"' }, + { "nbsp", ' ' /* 160 */ }, + + { "iexcl", 161 }, { "cent", 162 }, { "pound", 163 }, { "curren", 164 }, + { "yen", 165 }, { "brvbar", 166 }, { "brkbar", 166 }, { "sect", 167 }, + { "uml", 168 }, { "die", 168 }, { "copy", 169 }, { "ordf", 170 }, + { "laquo", 171 }, { "not", 172 }, { "shy", 173 }, { "reg", 174 }, + { "macr", 175 }, { "hibar", 175 }, { "deg", 176 }, { "plusmn", 177 }, + { "sup2", 178 }, { "sup3", 179 }, { "acute", 180 }, { "micro", 181 }, + { "para", 182 }, { "middot", 183 }, { "cedil", 184 }, { "sup1", 185 }, + { "ordm", 186 }, { "raquo", 187 }, { "frac14", 188 }, { "frac12", 189 }, + { "frac34", 190 }, { "iquest", 191 }, { "Agrave", 192 }, { "Aacute", 193 }, + { "Acirc", 194 }, { "Atilde", 195 }, { "Auml", 196 }, { "Aring", 197 }, + { "AElig", 198 }, { "Ccedil", 199 }, { "Egrave", 200 }, { "Eacute", 201 }, + { "Ecirc", 202 }, { "Euml", 203 }, { "Igrave", 204 }, { "Iacute", 205 }, + { "Icirc", 206 }, { "Iuml", 207 }, { "ETH", 208 }, { "Dstrok", 208 }, + { "Ntilde", 209 }, { "Ograve", 210 }, { "Oacute", 211 }, { "Ocirc", 212 }, + { "Otilde", 213 }, { "Ouml", 214 }, { "times", 215 }, { "Oslash", 216 }, + { "Ugrave", 217 }, { "Uacute", 218 }, { "Ucirc", 219 }, { "Uuml", 220 }, + { "Yacute", 221 }, { "THORN", 222 }, { "szlig", 223 }, { "agrave", 224 }, + { "aacute", 225 }, { "acirc", 226 }, { "atilde", 227 }, { "auml", 228 }, + { "aring", 229 }, { "aelig", 230 }, { "ccedil", 231 }, { "egrave", 232 }, + { "eacute", 233 }, { "ecirc", 234 }, { "euml", 235 }, { "igrave", 236 }, + { "iacute", 237 }, { "icirc", 238 }, { "iuml", 239 }, { "eth", 240 }, + { "ntilde", 241 }, { "ograve", 242 }, { "oacute", 243 }, { "ocirc", 244 }, + { "otilde", 245 }, { "ouml", 246 }, { "divide", 247 }, { "oslash", 248 }, + { "ugrave", 249 }, { "uacute", 250 }, { "ucirc", 251 }, { "uuml", 252 }, + { "yacute", 253 }, { "thorn", 254 }, { "yuml", 255 }, + + { NULL, 0 }, + }; + + for (int i = 0; tokens[i].name != NULL; i++) { + if (sequence == tokens[i].name) { + // Here's a match. + return tokens[i].code; + } + } + + // Some unrecognized sequence. + return 0; +} + //////////////////////////////////////////////////////////////////// // Function: TextNode::make_frame // Access: Private diff --git a/panda/src/text/textNode.h b/panda/src/text/textNode.h index 421a6e8877..d7b3148ba5 100644 --- a/panda/src/text/textNode.h +++ b/panda/src/text/textNode.h @@ -15,36 +15,34 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// + #ifndef TEXTNODE_H #define TEXTNODE_H -// -//////////////////////////////////////////////////////////////////// -// Includes -//////////////////////////////////////////////////////////////////// -#include + +#include "pandabase.h" #include "config_text.h" #include "textFont.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "pt_Node.h" +#include "namedNode.h" +#include "luse.h" +#include "geom.h" +#include "geomNode.h" +#include "renderRelation.h" +#include "textureTransition.h" +#include "transparencyTransition.h" +#include "allTransitionsWrapper.h" -//////////////////////////////////////////////////////////////////// -// Defines -//////////////////////////////////////////////////////////////////// +// These are deprecated. Use TextNode::Alignment instead. BEGIN_PUBLISH #define TM_ALIGN_LEFT 1 #define TM_ALIGN_RIGHT 2 #define TM_ALIGN_CENTER 3 END_PUBLISH +class StringDecoder; + //////////////////////////////////////////////////////////////////// // Class : TextNode // Description : The primary interface to this module. This class @@ -76,21 +74,38 @@ PUBLISHED: TextNode(const string &name = ""); ~TextNode(); + enum Alignment { + A_left = TM_ALIGN_LEFT, + A_right = TM_ALIGN_RIGHT, + A_center = TM_ALIGN_CENTER, + }; + + enum Encoding { + E_iso8859, + E_utf8, + E_unicode + }; + INLINE int freeze(); INLINE int get_freeze_level() const; INLINE int thaw(); - // INLINE void set_font(Node *font_node); INLINE void set_font(TextFont *font); INLINE TextFont *get_font() const; + INLINE void set_encoding(Encoding encoding); + INLINE Encoding get_encoding() const; + + INLINE void set_expand_amp(bool expand_amp); + INLINE bool get_expand_amp() const; + INLINE float get_line_height() const; INLINE void set_slant(float slant); INLINE float get_slant() const; - INLINE void set_align(int align_type); - INLINE int get_align() const; + INLINE void set_align(Alignment align_type); + INLINE Alignment get_align() const; INLINE void set_wordwrap(float width); INLINE void clear_wordwrap(); @@ -206,19 +221,24 @@ private: void do_rebuild(); void do_measure(); - float assemble_row(const char *&source, Node *dest); - Node *assemble_text(const char *source, LVector2f &ul, LVector2f &lr, + StringDecoder *make_decoder(const string &text); + + float assemble_row(StringDecoder *decoder, Node *dest); + Node *assemble_text(StringDecoder *decoder, LVector2f &ul, LVector2f &lr, int &num_rows); - float measure_row(const char *&source); - void measure_text(const char *source, LVector2f &ul, LVector2f &lr, + float measure_row(StringDecoder *decoder); + void measure_text(StringDecoder *decoder, LVector2f &ul, LVector2f &lr, int &num_rows); + int expand_amp_sequence(StringDecoder *decoder); + Node *make_frame(); Node *make_card(); Node *make_card_with_border(); PT(TextFont) _font; + Encoding _encoding; float _slant; PT(Texture) _card_texture; @@ -239,10 +259,11 @@ private: F_frame_corners = 0x0100, F_card_transp = 0x0200, F_has_card_border = 0x0400, + F_expand_amp = 0x0800, }; int _flags; - int _align; + Alignment _align; float _wordwrap_width; float _frame_width; float _card_border_size; diff --git a/panda/src/text/text_composite1.cxx b/panda/src/text/text_composite1.cxx index 0facf45237..0f7b554d49 100644 --- a/panda/src/text/text_composite1.cxx +++ b/panda/src/text/text_composite1.cxx @@ -4,5 +4,6 @@ #include "dynamicTextPage.cxx" #include "geomTextGlyph.cxx" #include "staticTextFont.cxx" +#include "stringDecoder.cxx" #include "textFont.cxx" #include "textGlyph.cxx"