diff --git a/panda/src/text/dynamicTextGlyph.I b/panda/src/text/dynamicTextGlyph.I index aeac8d0191..4048e3b02c 100644 --- a/panda/src/text/dynamicTextGlyph.I +++ b/panda/src/text/dynamicTextGlyph.I @@ -16,7 +16,7 @@ //////////////////////////////////////////////////////////////////// // Function: DynamicTextGlyph::Constructor -// Access: Publiic +// Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE DynamicTextGlyph:: @@ -33,7 +33,7 @@ DynamicTextGlyph(int character, DynamicTextPage *page, int x, int y, //////////////////////////////////////////////////////////////////// // Function: DynamicTextGlyph::Constructor -// Access: Publiic +// Access: Public // Description: This constructor makes an empty glyph, whose only // purpose is to remember its width. It has no bitmap // and no Geom. diff --git a/panda/src/text/dynamicTextGlyph.cxx b/panda/src/text/dynamicTextGlyph.cxx index 9ad1852250..02cd951d10 100644 --- a/panda/src/text/dynamicTextGlyph.cxx +++ b/panda/src/text/dynamicTextGlyph.cxx @@ -191,5 +191,17 @@ set_geom(GeomVertexData *vdata, GeomPrimitive *prim, _state = state; } +//////////////////////////////////////////////////////////////////// +// Function: DynamicTextGlyph::is_whitespace +// Access: Public, Virtual +// Description: Returns true if this glyph represents invisible +// whitespace, or false if it corresponds to some +// visible character. +//////////////////////////////////////////////////////////////////// +bool DynamicTextGlyph:: +is_whitespace() const { + return (_page == (DynamicTextPage *)NULL); +} + #endif // HAVE_FREETYPE diff --git a/panda/src/text/dynamicTextGlyph.h b/panda/src/text/dynamicTextGlyph.h index e00cceb7d6..99f06131a7 100644 --- a/panda/src/text/dynamicTextGlyph.h +++ b/panda/src/text/dynamicTextGlyph.h @@ -51,6 +51,7 @@ public: float font_pixels_per_unit, float tex_pixels_per_unit); void set_geom(GeomVertexData *vdata, GeomPrimitive *prim, const RenderState *state); + virtual bool is_whitespace() const; DynamicTextPage *_page; int _geom_count; diff --git a/panda/src/text/textAssembler.cxx b/panda/src/text/textAssembler.cxx index 5742e5b6cc..65d2ce3289 100644 --- a/panda/src/text/textAssembler.cxx +++ b/panda/src/text/textAssembler.cxx @@ -626,7 +626,7 @@ assemble_text() { //////////////////////////////////////////////////////////////////// // Function: TextAssembler::calc_width -// Access: Private, Static +// Access: Published, Static // Description: Returns the width of a single character, according to // its associated font. This also correctly calculates // the width of cheesy ligatures and accented @@ -668,7 +668,7 @@ calc_width(wchar_t character, const TextProperties &properties) { //////////////////////////////////////////////////////////////////// // Function: TextAssembler::calc_width -// Access: Private, Static +// Access: Published, Static // Description: Returns the width of a single TextGraphic image. //////////////////////////////////////////////////////////////////// float TextAssembler:: @@ -677,6 +677,113 @@ calc_width(const TextGraphic *graphic, const TextProperties &properties) { return (frame[1] - frame[0]) * properties.get_glyph_scale() * properties.get_text_scale(); } +//////////////////////////////////////////////////////////////////// +// Function: TextAssembler::has_exact_character +// Access: Published, Static +// Description: Returns true if the named character exists in the +// font exactly as named, false otherwise. Note that +// because Panda can assemble glyphs together +// automatically using cheesy accent marks, this is not +// a reliable indicator of whether a suitable glyph can +// be rendered for the character. For that, use +// has_character() instead. +// +// This returns true for whitespace and Unicode +// whitespace characters (if they exist in the font), +// but returns false for characters that would render +// with the "invalid glyph". It also returns false for +// characters that would be synthesized within Panda, +// but see has_character(). +//////////////////////////////////////////////////////////////////// +bool TextAssembler:: +has_exact_character(wchar_t character, const TextProperties &properties) { + if (character == ' ' || character == '\n') { + // A space is a special case. Every font implicitly has a space. + // We also treat newlines specially. + return true; + } + + TextFont *font = properties.get_font(); + nassertr(font != (TextFont *)NULL, false); + + const TextGlyph *glyph = NULL; + return font->get_glyph(character, glyph); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextAssembler::has_character +// Access: Published, Static +// Description: Returns true if the named character exists in the +// font or can be synthesized by Panda, false otherwise. +// (Panda can synthesize some accented characters by +// combining similar-looking glyphs from the font.) +// +// This returns true for whitespace and Unicode +// whitespace characters (if they exist in the font), +// but returns false for characters that would render +// with the "invalid glyph". +//////////////////////////////////////////////////////////////////// +bool TextAssembler:: +has_character(wchar_t character, const TextProperties &properties) { + if (character == ' ' || character == '\n') { + // A space is a special case. Every font implicitly has a space. + // We also treat newlines specially. + return true; + } + + bool got_glyph; + const TextGlyph *first_glyph = NULL; + const TextGlyph *second_glyph = NULL; + UnicodeLatinMap::AccentType accent_type; + int additional_flags; + float glyph_scale; + float advance_scale; + get_character_glyphs(character, &properties, + got_glyph, first_glyph, second_glyph, accent_type, + additional_flags, glyph_scale, advance_scale); + return got_glyph; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextAssembler::is_whitespace +// Access: Published, Static +// Description: Returns true if the indicated character represents +// whitespace in the font, or false if anything visible +// will be rendered for it. +// +// This returns true for whitespace and Unicode +// whitespace characters (if they exist in the font), +// and returns false for any other characters, including +// characters that do not exist in the font (these would +// be rendered with the "invalid glyph", which is +// visible). +// +// Note that this function can be reliably used to +// identify Unicode whitespace characters only if the +// font has all of the whitespace characters defined. +// It will return false for any character not in the +// font, even if it is an official Unicode whitespace +// character. +//////////////////////////////////////////////////////////////////// +bool TextAssembler:: +is_whitespace(wchar_t character, const TextProperties &properties) { + if (character == ' ' || character == '\n') { + // A space or a newline is a special case. + return true; + } + + + TextFont *font = properties.get_font(); + nassertr(font != (TextFont *)NULL, false); + + const TextGlyph *glyph = NULL; + if (!font->get_glyph(character, glyph)) { + return false; + } + + return glyph->is_whitespace(); +} + #ifndef CPPPARSER // interrogate has a bit of trouble with wstring. //////////////////////////////////////////////////////////////////// // Function: TextAssembler::scan_wtext diff --git a/panda/src/text/textAssembler.h b/panda/src/text/textAssembler.h index b2f83ab3f9..7dc6f996dd 100644 --- a/panda/src/text/textAssembler.h +++ b/panda/src/text/textAssembler.h @@ -93,6 +93,10 @@ PUBLISHED: static float calc_width(wchar_t character, const TextProperties &properties); static float calc_width(const TextGraphic *graphic, const TextProperties &properties); + static bool has_exact_character(wchar_t character, const TextProperties &properties); + static bool has_character(wchar_t character, const TextProperties &properties); + static bool is_whitespace(wchar_t character, const TextProperties &properties); + private: class ComputedProperties : public ReferenceCount { public: diff --git a/panda/src/text/textGlyph.cxx b/panda/src/text/textGlyph.cxx index b5c57ab4cf..f0bda6f96b 100644 --- a/panda/src/text/textGlyph.cxx +++ b/panda/src/text/textGlyph.cxx @@ -22,3 +22,17 @@ TextGlyph:: ~TextGlyph() { } + +//////////////////////////////////////////////////////////////////// +// Function: TextGlyph::is_whitespace +// Access: Public, Virtual +// Description: Returns true if this glyph represents invisible +// whitespace, or false if it corresponds to some +// visible character. +//////////////////////////////////////////////////////////////////// +bool TextGlyph:: +is_whitespace() const { + // In a static font, there is no explicit glyph for whitespace, so + // all glyphs are non-whitespace. + return false; +} diff --git a/panda/src/text/textGlyph.h b/panda/src/text/textGlyph.h index c2b01a61b1..6652f3ba80 100644 --- a/panda/src/text/textGlyph.h +++ b/panda/src/text/textGlyph.h @@ -42,6 +42,8 @@ public: INLINE const RenderState *get_state() const; INLINE float get_advance() const; + virtual bool is_whitespace() const; + protected: int _character; CPT(Geom) _geom; diff --git a/panda/src/text/textNode.I b/panda/src/text/textNode.I index c27b05383d..1a1e3ddcf2 100644 --- a/panda/src/text/textNode.I +++ b/panda/src/text/textNode.I @@ -1161,7 +1161,7 @@ append_text(const string &text) { // Unicode. //////////////////////////////////////////////////////////////////// INLINE void TextNode:: -append_unicode_char(int character) { +append_unicode_char(wchar_t character) { TextEncoder::append_unicode_char(character); invalidate_with_measure(); } diff --git a/panda/src/text/textNode.cxx b/panda/src/text/textNode.cxx index 2e6ec8abfb..c6a6d1ce71 100644 --- a/panda/src/text/textNode.cxx +++ b/panda/src/text/textNode.cxx @@ -179,7 +179,7 @@ TextNode:: // wide character (greater than 255). //////////////////////////////////////////////////////////////////// float TextNode:: -calc_width(int character) const { +calc_width(wchar_t character) const { TextFont *font = get_font(); if (font == (TextFont *)NULL) { return 0.0f; @@ -188,6 +188,88 @@ calc_width(int character) const { return TextAssembler::calc_width(character, *this); } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::has_exact_character +// Access: Published +// Description: Returns true if the named character exists in the +// font exactly as named, false otherwise. Note that +// because Panda can assemble glyphs together +// automatically using cheesy accent marks, this is not +// a reliable indicator of whether a suitable glyph can +// be rendered for the character. For that, use +// has_character() instead. +// +// This returns true for whitespace and Unicode +// whitespace characters (if they exist in the font), +// but returns false for characters that would render +// with the "invalid glyph". It also returns false for +// characters that would be synthesized within Panda, +// but see has_character(). +//////////////////////////////////////////////////////////////////// +bool TextNode:: +has_exact_character(wchar_t character) const { + TextFont *font = get_font(); + if (font == (TextFont *)NULL) { + return false; + } + + return TextAssembler::has_exact_character(character, *this); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextNode::has_character +// Access: Published +// Description: Returns true if the named character exists in the +// font or can be synthesized by Panda, false otherwise. +// (Panda can synthesize some accented characters by +// combining similar-looking glyphs from the font.) +// +// This returns true for whitespace and Unicode +// whitespace characters (if they exist in the font), +// but returns false for characters that would render +// with the "invalid glyph". +//////////////////////////////////////////////////////////////////// +bool TextNode:: +has_character(wchar_t character) const { + TextFont *font = get_font(); + if (font == (TextFont *)NULL) { + return false; + } + + return TextAssembler::has_character(character, *this); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextNode::is_whitespace +// Access: Published +// Description: Returns true if the indicated character represents +// whitespace in the font, or false if anything visible +// will be rendered for it. +// +// This returns true for whitespace and Unicode +// whitespace characters (if they exist in the font), +// and returns false for any other characters, including +// characters that do not exist in the font (these would +// be rendered with the "invalid glyph", which is +// visible). +// +// Note that this function can be reliably used to +// identify Unicode whitespace characters only if the +// font has all of the whitespace characters defined. +// It will return false for any character not in the +// font, even if it is an official Unicode whitespace +// character. +//////////////////////////////////////////////////////////////////// +bool TextNode:: +is_whitespace(wchar_t character) const { + TextFont *font = get_font(); + if (font == (TextFont *)NULL) { + return false; + } + + return TextAssembler::is_whitespace(character, *this); +} + //////////////////////////////////////////////////////////////////// // Function: TextNode::calc_width // Access: Published diff --git a/panda/src/text/textNode.h b/panda/src/text/textNode.h index 44da4a4d8e..e9d9776a22 100644 --- a/panda/src/text/textNode.h +++ b/panda/src/text/textNode.h @@ -183,7 +183,7 @@ PUBLISHED: INLINE void set_text(const string &text, Encoding encoding); INLINE void clear_text(); INLINE void append_text(const string &text); - INLINE void append_unicode_char(int character); + INLINE void append_unicode_char(wchar_t character); // After the text has been set, you can query this to determine how // it will be wordwrapped. @@ -191,8 +191,12 @@ PUBLISHED: // These methods calculate the width of a single character or a line // of text in the current font. - float calc_width(int character) const; + float calc_width(wchar_t character) const; INLINE float calc_width(const string &line) const; + + bool has_exact_character(wchar_t character) const; + bool has_character(wchar_t character) const; + bool is_whitespace(wchar_t character) const; // Direct support for wide-character strings. INLINE void set_wtext(const wstring &wtext);