|
@@ -78,7 +78,7 @@ TextNode(const string &name) : NamedNode(name) {
|
|
|
_num_rows = 0;
|
|
_num_rows = 0;
|
|
|
|
|
|
|
|
_freeze_level = 0;
|
|
_freeze_level = 0;
|
|
|
- _needs_rebuild = false;
|
|
|
|
|
|
|
+ _needs_rebuild = false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
@@ -90,6 +90,41 @@ TextNode::
|
|
|
~TextNode() {
|
|
~TextNode() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: TextNode::set_text
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Changes the text that is displayed under the
|
|
|
|
|
+// TextNode.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void TextNode::
|
|
|
|
|
+set_text(const string &text) {
|
|
|
|
|
+ _text = text;
|
|
|
|
|
+ switch (_encoding) {
|
|
|
|
|
+ case E_utf8:
|
|
|
|
|
+ {
|
|
|
|
|
+ StringUtf8Decoder decoder(_text);
|
|
|
|
|
+ decode_wtext(decoder);
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case E_unicode:
|
|
|
|
|
+ {
|
|
|
|
|
+ StringUnicodeDecoder decoder(_text);
|
|
|
|
|
+ decode_wtext(decoder);
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case E_iso8859:
|
|
|
|
|
+ default:
|
|
|
|
|
+ {
|
|
|
|
|
+ StringDecoder decoder(_text);
|
|
|
|
|
+ decode_wtext(decoder);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ rebuild(true);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: TextNode::write
|
|
// Function: TextNode::write
|
|
@@ -242,21 +277,18 @@ generate() {
|
|
|
|
|
|
|
|
root_arc->set_transition(new TransformTransition(mat));
|
|
root_arc->set_transition(new TransformTransition(mat));
|
|
|
|
|
|
|
|
- string text = _text;
|
|
|
|
|
|
|
+ wstring wtext = _wtext;
|
|
|
if (has_wordwrap()) {
|
|
if (has_wordwrap()) {
|
|
|
- text = wordwrap_to(text, _wordwrap_width, false);
|
|
|
|
|
|
|
+ wtext = _font->wordwrap_to(wtext, _wordwrap_width, false);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- StringDecoder *decoder = make_decoder(text);
|
|
|
|
|
-
|
|
|
|
|
// Assemble the text.
|
|
// Assemble the text.
|
|
|
LVector2f ul, lr;
|
|
LVector2f ul, lr;
|
|
|
int num_rows = 0;
|
|
int num_rows = 0;
|
|
|
- PT_Node text_root = assemble_text(decoder, ul, lr, num_rows);
|
|
|
|
|
|
|
+ PT_Node text_root = assemble_text(wtext.begin(), wtext.end(), ul, lr, num_rows);
|
|
|
RenderRelation *text_arc =
|
|
RenderRelation *text_arc =
|
|
|
new RenderRelation(sub_root, text_root, _draw_order + 2);
|
|
new RenderRelation(sub_root, text_root, _draw_order + 2);
|
|
|
|
|
|
|
|
- delete decoder;
|
|
|
|
|
|
|
|
|
|
if (has_text_color()) {
|
|
if (has_text_color()) {
|
|
|
text_arc->set_transition(new ColorTransition(_text_color));
|
|
text_arc->set_transition(new ColorTransition(_text_color));
|
|
@@ -361,6 +393,120 @@ generate() {
|
|
|
return root;
|
|
return root;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: TextNode::decode_wtext
|
|
|
|
|
+// Access: Private
|
|
|
|
|
+// Description: Decodes the eight-bit stream from the indicated
|
|
|
|
|
+// decoder, storing the decoded unicode characters in
|
|
|
|
|
+// _wtext.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void TextNode::
|
|
|
|
|
+decode_wtext(StringDecoder &decoder) {
|
|
|
|
|
+ _wtext.erase(_wtext.begin(), _wtext.end());
|
|
|
|
|
+ bool expand_amp = get_expand_amp();
|
|
|
|
|
+
|
|
|
|
|
+ wchar_t character = decoder.get_next_character();
|
|
|
|
|
+ while (!decoder.is_eof()) {
|
|
|
|
|
+ if (character == '&' && expand_amp) {
|
|
|
|
|
+ // An ampersand in expand_amp mode is treated as an escape
|
|
|
|
|
+ // character.
|
|
|
|
|
+ character = expand_amp_sequence(decoder);
|
|
|
|
|
+ }
|
|
|
|
|
+ _wtext += character;
|
|
|
|
|
+ character = decoder.get_next_character();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// 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 (!decoder.is_eof() && 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::do_rebuild
|
|
// Function: TextNode::do_rebuild
|
|
|
// Access: Private
|
|
// Access: Private
|
|
@@ -411,18 +557,14 @@ do_measure() {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- string text = _text;
|
|
|
|
|
|
|
+ wstring wtext = _wtext;
|
|
|
if (has_wordwrap()) {
|
|
if (has_wordwrap()) {
|
|
|
- text = wordwrap_to(text, _wordwrap_width, false);
|
|
|
|
|
|
|
+ wtext = _font->wordwrap_to(wtext, _wordwrap_width, false);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- StringDecoder *decoder = make_decoder(text);
|
|
|
|
|
-
|
|
|
|
|
LVector2f ul, lr;
|
|
LVector2f ul, lr;
|
|
|
int num_rows = 0;
|
|
int num_rows = 0;
|
|
|
- measure_text(decoder, ul, lr, num_rows);
|
|
|
|
|
-
|
|
|
|
|
- delete decoder;
|
|
|
|
|
|
|
+ measure_text(wtext.begin(), wtext.end(), ul, lr, num_rows);
|
|
|
|
|
|
|
|
_num_rows = num_rows;
|
|
_num_rows = num_rows;
|
|
|
_ul2d = ul;
|
|
_ul2d = ul;
|
|
@@ -434,28 +576,7 @@ do_measure() {
|
|
|
_lr3d = _lr3d * _transform;
|
|
_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);
|
|
|
|
|
- };
|
|
|
|
|
-}
|
|
|
|
|
|
|
+#ifndef CPPPARSER // interrogate has a bit of trouble with wstring.
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: TextNode::assemble_row
|
|
// Function: TextNode::assemble_row
|
|
@@ -467,21 +588,13 @@ make_decoder(const string &text) {
|
|
|
// to the terminating character.
|
|
// to the terminating character.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
float TextNode::
|
|
float TextNode::
|
|
|
-assemble_row(StringDecoder *decoder, Node *dest) {
|
|
|
|
|
|
|
+assemble_row(wstring::iterator &si, const wstring::iterator &send,
|
|
|
|
|
+ Node *dest) {
|
|
|
nassertr(_font != (TextFont *)NULL, 0.0f);
|
|
nassertr(_font != (TextFont *)NULL, 0.0f);
|
|
|
|
|
|
|
|
float xpos = 0.0f;
|
|
float xpos = 0.0f;
|
|
|
- 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);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ while (si != send && (*si) != '\n') {
|
|
|
|
|
+ wchar_t character = *si;
|
|
|
|
|
|
|
|
if (character == ' ') {
|
|
if (character == ' ') {
|
|
|
// A space is a special case.
|
|
// A space is a special case.
|
|
@@ -523,10 +636,7 @@ assemble_row(StringDecoder *decoder, Node *dest) {
|
|
|
xpos += glyph->get_advance() * glyph_scale;
|
|
xpos += glyph->get_advance() * glyph_scale;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- if (decoder->is_eof()) {
|
|
|
|
|
- return xpos;
|
|
|
|
|
- }
|
|
|
|
|
- character = decoder->get_next_character();
|
|
|
|
|
|
|
+ ++si;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return xpos;
|
|
return xpos;
|
|
@@ -540,8 +650,8 @@ assemble_row(StringDecoder *decoder, Node *dest) {
|
|
|
// returns it. Also sets the ul, lr corners.
|
|
// returns it. Also sets the ul, lr corners.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
Node *TextNode::
|
|
Node *TextNode::
|
|
|
-assemble_text(StringDecoder *decoder, LVector2f &ul, LVector2f &lr,
|
|
|
|
|
- int &num_rows) {
|
|
|
|
|
|
|
+assemble_text(wstring::iterator si, const wstring::iterator &send,
|
|
|
|
|
+ LVector2f &ul, LVector2f &lr, int &num_rows) {
|
|
|
nassertr(_font != (TextFont *)NULL, (Node *)NULL);
|
|
nassertr(_font != (TextFont *)NULL, (Node *)NULL);
|
|
|
float line_height = get_line_height();
|
|
float line_height = get_line_height();
|
|
|
|
|
|
|
@@ -553,13 +663,17 @@ assemble_text(StringDecoder *decoder, LVector2f &ul, LVector2f &lr,
|
|
|
|
|
|
|
|
float posy = 0.0f;
|
|
float posy = 0.0f;
|
|
|
int row_index = 0;
|
|
int row_index = 0;
|
|
|
- while (!decoder->is_eof()) {
|
|
|
|
|
|
|
+ while (si != send) {
|
|
|
char numstr[20];
|
|
char numstr[20];
|
|
|
sprintf(numstr, "row%d", row_index);
|
|
sprintf(numstr, "row%d", row_index);
|
|
|
nassertr(strlen(numstr) < 20, root_node);
|
|
nassertr(strlen(numstr) < 20, root_node);
|
|
|
|
|
|
|
|
Node *row = new NamedNode(numstr);
|
|
Node *row = new NamedNode(numstr);
|
|
|
- float row_width = assemble_row(decoder, row);
|
|
|
|
|
|
|
+ float row_width = assemble_row(si, send, row);
|
|
|
|
|
+ if (si != send) {
|
|
|
|
|
+ // Skip past the newline.
|
|
|
|
|
+ ++si;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
LMatrix4f mat = LMatrix4f::ident_mat();
|
|
LMatrix4f mat = LMatrix4f::ident_mat();
|
|
|
if (_align == A_left) {
|
|
if (_align == A_left) {
|
|
@@ -607,21 +721,10 @@ assemble_text(StringDecoder *decoder, LVector2f &ul, LVector2f &lr,
|
|
|
// it.
|
|
// it.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
float TextNode::
|
|
float TextNode::
|
|
|
-measure_row(StringDecoder *decoder) {
|
|
|
|
|
- nassertr(_font != (TextFont *)NULL, 0.0f);
|
|
|
|
|
-
|
|
|
|
|
|
|
+measure_row(wstring::iterator &si, const wstring::iterator &send) {
|
|
|
float xpos = 0.0f;
|
|
float xpos = 0.0f;
|
|
|
- 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);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ while (si != send && *si != '\n') {
|
|
|
|
|
+ wchar_t character = *si;
|
|
|
|
|
|
|
|
if (character == ' ') {
|
|
if (character == ' ') {
|
|
|
// A space is a special case.
|
|
// A space is a special case.
|
|
@@ -636,10 +739,7 @@ measure_row(StringDecoder *decoder) {
|
|
|
xpos += glyph->get_advance() * glyph_scale;
|
|
xpos += glyph->get_advance() * glyph_scale;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- if (decoder->is_eof()) {
|
|
|
|
|
- return xpos;
|
|
|
|
|
- }
|
|
|
|
|
- character = decoder->get_next_character();
|
|
|
|
|
|
|
+ ++si;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return xpos;
|
|
return xpos;
|
|
@@ -652,8 +752,8 @@ measure_row(StringDecoder *decoder) {
|
|
|
// actually assembling it.
|
|
// actually assembling it.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void TextNode::
|
|
void TextNode::
|
|
|
-measure_text(StringDecoder *decoder, LVector2f &ul, LVector2f &lr,
|
|
|
|
|
- int &num_rows) {
|
|
|
|
|
|
|
+measure_text(wstring::iterator si, const wstring::iterator &send,
|
|
|
|
|
+ LVector2f &ul, LVector2f &lr, int &num_rows) {
|
|
|
nassertv(_font != (TextFont *)NULL);
|
|
nassertv(_font != (TextFont *)NULL);
|
|
|
float line_height = get_line_height();
|
|
float line_height = get_line_height();
|
|
|
|
|
|
|
@@ -661,8 +761,12 @@ measure_text(StringDecoder *decoder, LVector2f &ul, LVector2f &lr,
|
|
|
lr.set(0.0f, 0.0f);
|
|
lr.set(0.0f, 0.0f);
|
|
|
|
|
|
|
|
float posy = 0.0f;
|
|
float posy = 0.0f;
|
|
|
- while (!decoder->is_eof()) {
|
|
|
|
|
- float row_width = measure_row(decoder);
|
|
|
|
|
|
|
+ while (si != send) {
|
|
|
|
|
+ float row_width = measure_row(si, send);
|
|
|
|
|
+ if (si != send) {
|
|
|
|
|
+ // Skip past the newline.
|
|
|
|
|
+ ++si;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
if (_align == A_left) {
|
|
if (_align == A_left) {
|
|
|
lr[0] = max(lr[0], row_width);
|
|
lr[0] = max(lr[0], row_width);
|
|
@@ -683,95 +787,7 @@ measure_text(StringDecoder *decoder, LVector2f &ul, LVector2f &lr,
|
|
|
|
|
|
|
|
lr[1] = posy + 0.8f * line_height;
|
|
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;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+#endif // CPPPARSER
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: TextNode::make_frame
|
|
// Function: TextNode::make_frame
|