more control over encoding

This commit is contained in:
David Rose 2003-02-06 01:32:05 +00:00
parent 84cb559f00
commit 9aeeb1ce1a
3 changed files with 177 additions and 32 deletions

View File

@ -154,6 +154,7 @@ get_default_encoding() {
return _default_encoding; return _default_encoding;
} }
/*
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::set_expand_amp // Function: TextNode::set_expand_amp
// Access: Published // Access: Published
@ -185,6 +186,7 @@ INLINE bool TextNode::
get_expand_amp() const { get_expand_amp() const {
return (_flags & F_expand_amp) != 0; return (_flags & F_expand_amp) != 0;
} }
*/
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::get_line_height // Function: TextNode::get_line_height
@ -1129,6 +1131,21 @@ set_text(const string &text) {
} }
} }
////////////////////////////////////////////////////////////////////
// Function: TextNode::set_text
// Access: Published
// Description: The two-parameter version of set_text() accepts an
// explicit encoding; the text is immediately decoded
// and stored as a wide-character string. Subsequent
// calls to get_text() will return the same text
// re-encoded using whichever encoding is specified by
// set_encoding().
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
set_text(const string &text, TextNode::Encoding encoding) {
set_wtext(decode_text(text, encoding));
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::clear_text // Function: TextNode::clear_text
// Access: Published // Access: Published
@ -1159,7 +1176,8 @@ has_text() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::get_text // Function: TextNode::get_text
// Access: Published // Access: Published
// Description: // Description: Returns the current text, as encoded via the current
// encoding system.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE string TextNode:: INLINE string TextNode::
get_text() const { get_text() const {
@ -1170,6 +1188,17 @@ get_text() const {
return _text; return _text;
} }
////////////////////////////////////////////////////////////////////
// Function: TextNode::get_text
// Access: Published
// Description: Returns the current text, as encoded via the indicated
// encoding system.
////////////////////////////////////////////////////////////////////
INLINE string TextNode::
get_text(TextNode::Encoding encoding) const {
return encode_wtext(get_wtext(), encoding);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::append_text // Function: TextNode::append_text
// Access: Published // Access: Published
@ -1184,14 +1213,14 @@ append_text(const string &text) {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::append_char // Function: TextNode::append_unicode_char
// Access: Published // Access: Published
// Description: Appends a single character to the end of the stored // Description: Appends a single character to the end of the stored
// text. This may be a wide character, up to 16 bits in // text. This may be a wide character, up to 16 bits in
// Unicode. // Unicode.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE void TextNode:: INLINE void TextNode::
append_char(int character) { append_unicode_char(int character) {
_wtext = get_wtext() + wstring(1, (wchar_t)character); _wtext = get_wtext() + wstring(1, (wchar_t)character);
_flags = (_flags | F_got_wtext) & ~F_got_text; _flags = (_flags | F_got_wtext) & ~F_got_text;
invalidate_with_measure(); invalidate_with_measure();
@ -1210,7 +1239,7 @@ get_num_chars() const {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::get_char // Function: TextNode::get_unicode_char
// Access: Published // Access: Published
// Description: Returns the Unicode value of the nth character in the // Description: Returns the Unicode value of the nth character in the
// stored text. This may be a wide character (greater // stored text. This may be a wide character (greater
@ -1218,12 +1247,35 @@ get_num_chars() const {
// according to set_encoding(). // according to set_encoding().
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE int TextNode:: INLINE int TextNode::
get_char(int index) const { get_unicode_char(int index) const {
get_wtext(); get_wtext();
nassertr(index >= 0 && index < (int)_wtext.length(), 0); nassertr(index >= 0 && index < (int)_wtext.length(), 0);
return _wtext[index]; return _wtext[index];
} }
////////////////////////////////////////////////////////////////////
// Function: TextNode::get_encoded_char
// Access: Published
// Description: Returns the nth char of the stored text, as a one-,
// two-, or three-byte encoded string.
////////////////////////////////////////////////////////////////////
INLINE string TextNode::
get_encoded_char(int index) const {
return get_encoded_char(index, get_encoding());
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::get_encoded_char
// Access: Published
// Description: Returns the nth char of the stored text, as a one-,
// two-, or three-byte encoded string.
////////////////////////////////////////////////////////////////////
INLINE string TextNode::
get_encoded_char(int index, TextNode::Encoding encoding) const {
wstring wch(1, (wchar_t)get_unicode_char(index));
return encode_wtext(wch, encoding);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::get_text_as_ascii // Function: TextNode::get_text_as_ascii
// Access: Published // Access: Published
@ -1248,6 +1300,21 @@ get_text_as_ascii() const {
return encode_wtext(get_wtext_as_ascii()); return encode_wtext(get_wtext_as_ascii());
} }
////////////////////////////////////////////////////////////////////
// Function: TextNode::reencode_text
// Access: Published, Static
// Description: Given the indicated text string, which is assumed to
// be encoded via the encoding "from", decodes it and
// then reencodes it into the encoding "to", and returns
// the newly encoded string. This does not change or
// affect any properties on the TextNode itself.
////////////////////////////////////////////////////////////////////
INLINE string TextNode::
reencode_text(const string &text, TextNode::Encoding from,
TextNode::Encoding to) {
return encode_wtext(decode_text(text, from), to);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::calc_width // Function: TextNode::calc_width
// Access: Published // Access: Published
@ -1491,6 +1558,28 @@ wordwrap_to(const wstring &wtext, float wordwrap_width,
return _font->wordwrap_to(wtext, wordwrap_width, preserve_trailing_whitespace); return _font->wordwrap_to(wtext, wordwrap_width, preserve_trailing_whitespace);
} }
////////////////////////////////////////////////////////////////////
// Function: TextNode::encode_wtext
// Access: Public
// Description: Encodes a wide-text string into a single-char string,
// according to the current encoding.
////////////////////////////////////////////////////////////////////
INLINE string TextNode::
encode_wtext(const wstring &wtext) const {
return encode_wtext(wtext, _encoding);
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::decode_text
// Access: Public
// Description: Returns the given wstring decoded to a single-byte
// string, via the current encoding system.
////////////////////////////////////////////////////////////////////
INLINE wstring TextNode::
decode_text(const string &text) const {
return decode_text(text, _encoding);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::invalidate_no_measure // Function: TextNode::invalidate_no_measure
// Access: Private // Access: Private

View File

@ -44,6 +44,8 @@
#include "cullTraverserData.h" #include "cullTraverserData.h"
#include "geometricBoundingVolume.h" #include "geometricBoundingVolume.h"
#include "accumulatedAttribs.h" #include "accumulatedAttribs.h"
#include "renderState.h"
#include "cullFaceAttrib.h"
#include "dcast.h" #include "dcast.h"
#include <stdio.h> #include <stdio.h>
@ -466,18 +468,34 @@ get_wtext_as_ascii() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::encode_wchar // Function: TextNode::encode_wchar
// Access: Public // Access: Public, Static
// Description: Encodes a single wide char into a one-, two-, or // Description: Encodes a single wide char into a one-, two-, or
// three-byte string, according to the current encoding // three-byte string, according to the given encoding
// system in effect. // system.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
string TextNode:: string TextNode::
encode_wchar(wchar_t ch) const { encode_wchar(wchar_t ch, TextNode::Encoding encoding) {
switch (_encoding) { switch (encoding) {
case E_iso8859: case E_iso8859:
if (isascii((unsigned int)ch)) { if (ch < 0x100) {
return string(1, (char)ch); return string(1, (char)ch);
} else { } else {
// The character won't fit in the 8-bit ISO 8859. See if we can
// make it fit by reducing it to its ascii equivalent
// (essentially stripping off an unusual accent mark).
const UnicodeLatinMap::Entry *map_entry =
UnicodeLatinMap::look_up(ch);
if (map_entry != NULL && map_entry->_ascii_equiv != 0) {
// Yes, it has an ascii equivalent.
if (map_entry->_ascii_additional != 0) {
// In fact, it has two of them.
return
string(1, map_entry->_ascii_equiv) +
string(1, map_entry->_ascii_additional);
}
return string(1, map_entry->_ascii_equiv);
}
// Nope; return "." for lack of anything better.
return "."; return ".";
} }
@ -506,16 +524,16 @@ encode_wchar(wchar_t ch) const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::encode_wtext // Function: TextNode::encode_wtext
// Access: Public // Access: Public, Static
// Description: Encodes a wide-text string into a single-char string, // Description: Encodes a wide-text string into a single-char string,
// accoding to the current encoding. // according to the given encoding.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
string TextNode:: string TextNode::
encode_wtext(const wstring &wtext) const { encode_wtext(const wstring &wtext, TextNode::Encoding encoding) {
string result; string result;
for (wstring::const_iterator pi = wtext.begin(); pi != wtext.end(); ++pi) { for (wstring::const_iterator pi = wtext.begin(); pi != wtext.end(); ++pi) {
result += encode_wchar(*pi); result += encode_wchar(*pi, encoding);
} }
return result; return result;
@ -523,13 +541,13 @@ encode_wtext(const wstring &wtext) const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::decode_text // Function: TextNode::decode_text
// Access: Public // Access: Public, Static
// Description: Returns the given wstring decoded to a single-byte // Description: Returns the given wstring decoded to a single-byte
// string, via the current encoding system. // string, via the given encoding system.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
wstring TextNode:: wstring TextNode::
decode_text(const string &text) const { decode_text(const string &text, TextNode::Encoding encoding) {
switch (_encoding) { switch (encoding) {
case E_utf8: case E_utf8:
{ {
StringUtf8Decoder decoder(text); StringUtf8Decoder decoder(text);
@ -762,22 +780,24 @@ recompute_internal_bound() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::decode_text_impl // Function: TextNode::decode_text_impl
// Access: Private // Access: Private, Static
// Description: Decodes the eight-bit stream from the indicated // Description: Decodes the eight-bit stream from the indicated
// decoder, returning the decoded wide-char string. // decoder, returning the decoded wide-char string.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
wstring TextNode:: wstring TextNode::
decode_text_impl(StringDecoder &decoder) const { decode_text_impl(StringDecoder &decoder) {
wstring result; wstring result;
bool expand_amp = get_expand_amp(); // bool expand_amp = get_expand_amp();
wchar_t character = decoder.get_next_character(); wchar_t character = decoder.get_next_character();
while (!decoder.is_eof()) { while (!decoder.is_eof()) {
/*
if (character == '&' && expand_amp) { if (character == '&' && expand_amp) {
// An ampersand in expand_amp mode is treated as an escape // An ampersand in expand_amp mode is treated as an escape
// character. // character.
character = expand_amp_sequence(decoder); character = expand_amp_sequence(decoder);
} }
*/
result += character; result += character;
character = decoder.get_next_character(); character = decoder.get_next_character();
} }
@ -785,6 +805,7 @@ decode_text_impl(StringDecoder &decoder) const {
return result; return result;
} }
/*
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::expand_amp_sequence // Function: TextNode::expand_amp_sequence
// Access: Private // Access: Private
@ -832,7 +853,7 @@ expand_amp_sequence(StringDecoder &decoder) const {
int code; int code;
} tokens[] = { } tokens[] = {
{ "amp", '&' }, { "lt", '<' }, { "gt", '>' }, { "quot", '"' }, { "amp", '&' }, { "lt", '<' }, { "gt", '>' }, { "quot", '"' },
{ "nbsp", ' ' /* 160 */ }, { "nbsp", ' ' },
{ "iexcl", 161 }, { "cent", 162 }, { "pound", 163 }, { "curren", 164 }, { "iexcl", 161 }, { "cent", 162 }, { "pound", 163 }, { "curren", 164 },
{ "yen", 165 }, { "brvbar", 166 }, { "brkbar", 166 }, { "sect", 167 }, { "yen", 165 }, { "brvbar", 166 }, { "brkbar", 166 }, { "sect", 167 },
@ -873,6 +894,7 @@ expand_amp_sequence(StringDecoder &decoder) const {
// Some unrecognized sequence. // Some unrecognized sequence.
return 0; return 0;
} }
*/
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1494,6 +1516,10 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement,
float t, u; float t, u;
LMatrix4f accent_mat; LMatrix4f accent_mat;
// This gets set to true if the glyph gets mirrored and needs
// to have backface culling disabled.
bool mirrored = false;
switch (transform) { switch (transform) {
case CT_none: case CT_none:
accent_mat = LMatrix4f::ident_mat(); accent_mat = LMatrix4f::ident_mat();
@ -1504,6 +1530,7 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement,
t = min_accent[0]; t = min_accent[0];
min_accent[0] = -max_accent[0]; min_accent[0] = -max_accent[0];
max_accent[0] = -t; max_accent[0] = -t;
mirrored = true;
break; break;
case CT_mirror_y: case CT_mirror_y:
@ -1511,6 +1538,7 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement,
t = min_accent[2]; t = min_accent[2];
min_accent[2] = -max_accent[2]; min_accent[2] = -max_accent[2];
max_accent[2] = -t; max_accent[2] = -t;
mirrored = true;
break; break;
case CT_rotate_90: case CT_rotate_90:
@ -1563,6 +1591,7 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement,
t = min_accent[2]; t = min_accent[2];
min_accent[2] = -max_accent[2] * squash_accent_scale_y; min_accent[2] = -max_accent[2] * squash_accent_scale_y;
max_accent[2] = -t * squash_accent_scale_y; max_accent[2] = -t * squash_accent_scale_y;
mirrored = true;
break; break;
case CT_squash_mirror_diag: case CT_squash_mirror_diag:
@ -1577,6 +1606,7 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement,
max_accent[0] = max_accent[2] * -squash_accent_scale_x; max_accent[0] = max_accent[2] * -squash_accent_scale_x;
min_accent[2] = -u * squash_accent_scale_y; min_accent[2] = -u * squash_accent_scale_y;
max_accent[2] = -t * squash_accent_scale_y; max_accent[2] = -t * squash_accent_scale_y;
mirrored = true;
break; break;
case CT_small_squash: case CT_small_squash:
@ -1594,6 +1624,7 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement,
t = min_accent[2]; t = min_accent[2];
min_accent[2] = -max_accent[2] * small_squash_accent_scale_y; min_accent[2] = -max_accent[2] * small_squash_accent_scale_y;
max_accent[2] = -t * small_squash_accent_scale_y; max_accent[2] = -t * small_squash_accent_scale_y;
mirrored = true;
break; break;
case CT_small: case CT_small:
@ -1630,6 +1661,7 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement,
max_accent[0] = -t * tiny_accent_scale; max_accent[0] = -t * tiny_accent_scale;
min_accent[2] *= tiny_accent_scale; min_accent[2] *= tiny_accent_scale;
max_accent[2] *= tiny_accent_scale; max_accent[2] *= tiny_accent_scale;
mirrored = true;
break; break;
case CT_tiny_rotate_270: case CT_tiny_rotate_270:
@ -1685,7 +1717,21 @@ tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement,
accent_mat.set_row(3, trans); accent_mat.set_row(3, trans);
accent_geom->transform_vertices(accent_mat); accent_geom->transform_vertices(accent_mat);
dest->add_geom(accent_geom, accent_glyph->get_state()); if (mirrored) {
// Once someone asks for this pointer, we hold its reference
// count and never free it.
static CPT(RenderState) disable_backface;
if (disable_backface == (const RenderState *)NULL) {
disable_backface = RenderState::make
(CullFaceAttrib::make(CullFaceAttrib::M_cull_none));
}
CPT(RenderState) state =
accent_glyph->get_state()->compose(disable_backface);
dest->add_geom(accent_geom, state);
} else {
dest->add_geom(accent_geom, accent_glyph->get_state());
}
geom_array[num_geoms++] = accent_geom; geom_array[num_geoms++] = accent_geom;
return true; return true;

View File

@ -84,8 +84,10 @@ PUBLISHED:
INLINE static void set_default_encoding(Encoding encoding); INLINE static void set_default_encoding(Encoding encoding);
INLINE static Encoding get_default_encoding(); INLINE static Encoding get_default_encoding();
/*
INLINE void set_expand_amp(bool expand_amp); INLINE void set_expand_amp(bool expand_amp);
INLINE bool get_expand_amp() const; INLINE bool get_expand_amp() const;
*/
INLINE float get_line_height() const; INLINE float get_line_height() const;
@ -180,15 +182,21 @@ PUBLISHED:
INLINE CoordinateSystem get_coordinate_system() const; INLINE CoordinateSystem get_coordinate_system() const;
INLINE void set_text(const string &text); INLINE void set_text(const string &text);
INLINE void set_text(const string &text, Encoding encoding);
INLINE void clear_text(); INLINE void clear_text();
INLINE bool has_text() const; INLINE bool has_text() const;
INLINE string get_text() const; INLINE string get_text() const;
INLINE string get_text(Encoding encoding) const;
INLINE void append_text(const string &text); INLINE void append_text(const string &text);
INLINE void append_char(int character); INLINE void append_unicode_char(int character);
INLINE int get_num_chars() const; INLINE int get_num_chars() const;
INLINE int get_char(int index) const; INLINE int get_unicode_char(int index) const;
INLINE string get_encoded_char(int index) const;
INLINE string get_encoded_char(int index, Encoding encoding) const;
INLINE string get_text_as_ascii() const; INLINE string get_text_as_ascii() const;
INLINE static string reencode_text(const string &text, Encoding from, Encoding to);
INLINE float calc_width(int character) const; INLINE float calc_width(int character) const;
INLINE float calc_width(const string &line) const; INLINE float calc_width(const string &line) const;
string wordwrap_to(const string &text, float wordwrap_width, string wordwrap_to(const string &text, float wordwrap_width,
@ -225,9 +233,11 @@ public:
INLINE wstring wordwrap_to(const wstring &wtext, float wordwrap_width, INLINE wstring wordwrap_to(const wstring &wtext, float wordwrap_width,
bool preserve_trailing_whitespace) const; bool preserve_trailing_whitespace) const;
string encode_wchar(wchar_t ch) const; static string encode_wchar(wchar_t ch, Encoding encoding);
string encode_wtext(const wstring &wtext) const; INLINE string encode_wtext(const wstring &wtext) const;
wstring decode_text(const string &text) const; static string encode_wtext(const wstring &wtext, Encoding encoding);
INLINE wstring decode_text(const string &text) const;
static wstring decode_text(const string &text, Encoding encoding);
// From parent class PandaNode // From parent class PandaNode
virtual int get_unsafe_to_apply_attribs() const; virtual int get_unsafe_to_apply_attribs() const;
@ -245,8 +255,8 @@ public:
virtual BoundingVolume *recompute_internal_bound(); virtual BoundingVolume *recompute_internal_bound();
private: private:
wstring decode_text_impl(StringDecoder &decoder) const; static wstring decode_text_impl(StringDecoder &decoder);
int expand_amp_sequence(StringDecoder &decoder) const; // int expand_amp_sequence(StringDecoder &decoder) const;
INLINE void invalidate_no_measure(); INLINE void invalidate_no_measure();
INLINE void invalidate_with_measure(); INLINE void invalidate_with_measure();
@ -344,7 +354,7 @@ private:
F_frame_corners = 0x00000100, F_frame_corners = 0x00000100,
F_card_transp = 0x00000200, F_card_transp = 0x00000200,
F_has_card_border = 0x00000400, F_has_card_border = 0x00000400,
F_expand_amp = 0x00000800, // F_expand_amp = 0x00000800,
F_got_text = 0x00001000, F_got_text = 0x00001000,
F_got_wtext = 0x00002000, F_got_wtext = 0x00002000,
F_needs_rebuild = 0x00004000, F_needs_rebuild = 0x00004000,