diff options
author | Michele Calgaro <[email protected]> | 2025-02-04 17:59:57 +0900 |
---|---|---|
committer | Michele Calgaro <[email protected]> | 2025-02-04 17:59:57 +0900 |
commit | c7d887bde61931f3b73298ffa3d1d7b4e8137c01 (patch) | |
tree | 699168b068615dd24794e20b6d2a38ec44d9a1e3 | |
parent | c5cda03125a6d34c179d968011083bceb87976bd (diff) | |
download | tqt3-feat/improve-unicode-support.tar.gz tqt3-feat/improve-unicode-support.zip |
Extend work on supporting surrogate characters done in commit e0a38072feat/improve-unicode-support
Signed-off-by: Michele Calgaro <[email protected]>
-rw-r--r-- | src/kernel/tqfont_x11.cpp | 32 | ||||
-rw-r--r-- | src/kernel/tqfontengine_p.h | 2 | ||||
-rw-r--r-- | src/kernel/tqfontengine_x11.cpp | 58 | ||||
-rw-r--r-- | src/kernel/tqfontmetrics.h | 2 | ||||
-rw-r--r-- | src/kernel/tqscriptengine.cpp | 21 | ||||
-rw-r--r-- | src/kernel/tqtextengine.cpp | 107 |
6 files changed, 117 insertions, 105 deletions
diff --git a/src/kernel/tqfont_x11.cpp b/src/kernel/tqfont_x11.cpp index 6f4097029..92cd8b113 100644 --- a/src/kernel/tqfont_x11.cpp +++ b/src/kernel/tqfont_x11.cpp @@ -675,22 +675,32 @@ int TQFontMetrics::width( TQChar ch ) const return advances[0]; } - int TQFontMetrics::charWidth( const TQString &str, int pos ) const { - if ( pos < 0 || pos > (int)str.length() ) + if ( pos < 0 || pos >= (int)str.length() ) return 0; - const TQChar &ch = str.unicode()[ pos ]; - if ( ch.unicode() < TQFontEngineData::widthCacheSize && - d->engineData && d->engineData->widthCache[ ch.unicode() ] ) - return d->engineData->widthCache[ ch.unicode() ]; + uint uc; + bool isSurrogate; + if (str[pos].isHighSurrogate() && pos < (str.length() - 1) && str[pos + 1].isLowSurrogate()) + { + isSurrogate = true; + uc = TQChar::surrogateToUcs4(str[pos], str[pos + 1]); + } + else + { + isSurrogate = false; + uc = str[pos].unicode(); + } + if ( uc < TQFontEngineData::widthCacheSize && + d->engineData && d->engineData->widthCache[ uc ] ) + return d->engineData->widthCache[ uc ]; + const TQChar &ch = str.unicode()[ pos ]; TQFont::Script script; SCRIPT_FOR_CHAR( script, ch ); int width; - if ( script >= TQFont::Arabic && script <= TQFont::Khmer ) { // complex script shaping. Have to do some hard work int from = TQMAX( 0, pos - 8 ); @@ -700,7 +710,7 @@ int TQFontMetrics::charWidth( const TQString &str, int pos ) const layout.itemize( TQTextEngine::WidthOnly ); width = layout.width( pos-from, 1 ); } else if ( ::category( ch ) == TQChar::Mark_NonSpacing || qIsZeroWidthChar(ch.unicode())) { - width = 0; + width = 0; } else { TQFontEngine *engine = d->engineForScript( script ); #ifdef QT_CHECK_STATE @@ -710,10 +720,10 @@ int TQFontMetrics::charWidth( const TQString &str, int pos ) const glyph_t glyphs[8]; advance_t advances[8]; int nglyphs = 7; - engine->stringToCMap( &ch, 1, glyphs, advances, &nglyphs, FALSE ); + engine->stringToCMap( &ch, isSurrogate ? 2 : 1, glyphs, advances, &nglyphs, FALSE ); width = advances[0]; } - if ( ch.unicode() < TQFontEngineData::widthCacheSize && width > 0 && width < 0x100 ) - d->engineData->widthCache[ ch.unicode() ] = width; + if ( uc < TQFontEngineData::widthCacheSize && width > 0 && width < 0x100 ) + d->engineData->widthCache[ uc ] = width; return width; } diff --git a/src/kernel/tqfontengine_p.h b/src/kernel/tqfontengine_p.h index fe8714ef3..86fdda8f0 100644 --- a/src/kernel/tqfontengine_p.h +++ b/src/kernel/tqfontengine_p.h @@ -284,7 +284,7 @@ public: FT_Face face() const { return _face; } XftFont *font() const { return _font; } - void recalcAdvances( int len, glyph_t *glyphs, advance_t *advances ); + void recalcAdvances( int len, glyph_t *glyphs, advance_t *advances ) const; private: friend class TQFontPrivate; diff --git a/src/kernel/tqfontengine_x11.cpp b/src/kernel/tqfontengine_x11.cpp index 47078dea9..aa116b93d 100644 --- a/src/kernel/tqfontengine_x11.cpp +++ b/src/kernel/tqfontengine_x11.cpp @@ -1531,12 +1531,11 @@ static glyph_t getAdobeCharIndex(XftFont *font, int cmap, uint ucs4) return g; } -static uint getUnicode(const TQChar *str, int &i, const int len) +static uint getCodepoint(const TQChar *str, int &i, const int len) { if (str[i].isHighSurrogate() && i < (len - 1) && str[i + 1].isLowSurrogate()) { - ++i; // Don't delete this: it is required for correct - // advancement when handling surrogate pairs + ++i; // This is required for correct advancement when handling surrogate pairs return TQChar::surrogateToUcs4(str[i - 1], str[i]); } return str[i].unicode(); @@ -1551,7 +1550,7 @@ TQFontEngine::Error TQFontEngineXft::stringToCMap( const TQChar *str, int len, g int glyph_pos = 0; for ( int i = 0; i < len; ++i ) { - uint uc = getUnicode(str, i, len); + uint uc = getCodepoint(str, i, len); if ( uc == 0xa0 ) uc = 0x20; if ( mirrored ) @@ -1575,32 +1574,17 @@ TQFontEngine::Error TQFontEngineXft::stringToCMap( const TQChar *str, int len, g ++glyph_pos; } - if ( advances ) { - for ( int i = 0; i < glyph_pos; i++ ) { - glyph_t glyph = *(glyphs + i); - advances[i] = (glyph < widthCacheSize) ? widthCache[glyph] : 0; - if ( !advances[i] ) { - XGlyphInfo gi; - XftGlyphExtents( TQPaintDevice::x11AppDisplay(), _font, &glyph, 1, &gi ); - advances[i] = gi.xOff; - if ( glyph < widthCacheSize && gi.xOff > 0 && gi.xOff < 0x100 ) - ((TQFontEngineXft *)this)->widthCache[glyph] = gi.xOff; - } - } - if ( _scale != 1. ) { - for ( int i = 0; i < len; i++ ) - advances[i] = tqRound(advances[i]*_scale); - } + if ( advances ) + { + recalcAdvances(glyph_pos, glyphs, advances); } *nglyphs = glyph_pos; return NoError; } - -void TQFontEngineXft::recalcAdvances( int len, glyph_t *glyphs, advance_t *advances ) +void TQFontEngineXft::recalcAdvances( int len, glyph_t *glyphs, advance_t *advances ) const { - for ( int i = 0; i < len; i++ ) { FT_UInt glyph = *(glyphs + i); advances[i] = (glyph < widthCacheSize) ? widthCache[glyph] : 0; @@ -1999,20 +1983,22 @@ bool TQFontEngineXft::canRender( const TQChar *string, int len ) bool allExist = TRUE; if (_cmap != -1) { - for ( int i = 0; i < len; i++ ) { - if (!XftCharExists(0, _font, string[i].unicode()) - && getAdobeCharIndex(_font, _cmap, string[i].unicode()) == 0) { - allExist = FALSE; - break; - } - } + for ( int i = 0; i < len; i++ ) { + uint uc = getCodepoint(string, i, len); + if (!XftCharExists(0, _font, uc) + && getAdobeCharIndex(_font, _cmap, uc) == 0) { + allExist = FALSE; + break; + } + } } else { - for ( int i = 0; i < len; i++ ) { - if (!XftCharExists(0, _font, string[i].unicode())) { - allExist = FALSE; - break; - } - } + for ( int i = 0; i < len; i++ ) { + uint uc = getCodepoint(string, i, len); + if (!XftCharExists(0, _font, uc)) { + allExist = FALSE; + break; + } + } } return allExist; diff --git a/src/kernel/tqfontmetrics.h b/src/kernel/tqfontmetrics.h index b635a864e..35d09f5e8 100644 --- a/src/kernel/tqfontmetrics.h +++ b/src/kernel/tqfontmetrics.h @@ -79,7 +79,7 @@ public: int width( char c ) const { return width( (TQChar) c ); } #endif - int charWidth( const TQString &str, int pos ) const; + int charWidth( const TQString &str, int pos ) const; TQRect boundingRect( const TQString &, int len = -1 ) const; TQRect boundingRect( TQChar ) const; TQRect boundingRect( int x, int y, int w, int h, int flags, diff --git a/src/kernel/tqscriptengine.cpp b/src/kernel/tqscriptengine.cpp index 588596716..36df1fa77 100644 --- a/src/kernel/tqscriptengine.cpp +++ b/src/kernel/tqscriptengine.cpp @@ -288,10 +288,21 @@ static void heuristicSetGlyphAttributes(TQShaperItem *item, const TQChar *uc, in Q_ASSERT(item->num_glyphs <= length); unsigned short *logClusters = item->log_clusters; - - int i; - for (i = 0; i < length; ++i) - logClusters[i] = i; + int glyph_pos = 0; + for (int i = 0; i < length; i++) + { + if (uc[i].isHighSurrogate() && i < (length - 1) && uc[i+1].isLowSurrogate()) + { + logClusters[i] = glyph_pos; + logClusters[++i] = glyph_pos; + } + else + { + logClusters[i] = glyph_pos; + } + ++glyph_pos; + } + Q_ASSERT(glyph_pos == item->num_glyphs); // first char in a run is never (treated as) a mark int cStart = 0; @@ -307,7 +318,7 @@ static void heuristicSetGlyphAttributes(TQShaperItem *item, const TQChar *uc, in } int lastCat = ::category(uc[0]); - for (i = 1; i < length; ++i) { + for (int i = 1; i < length; ++i) { int cat = ::category(uc[i]); if (qIsZeroWidthChar(uc[i].unicode())) { item->attributes[i].mark = FALSE; diff --git a/src/kernel/tqtextengine.cpp b/src/kernel/tqtextengine.cpp index 05cdbcc13..067a21740 100644 --- a/src/kernel/tqtextengine.cpp +++ b/src/kernel/tqtextengine.cpp @@ -800,72 +800,77 @@ static void calcLineBreaks(const TQString &str, TQCharAttributes *charAttributes { int len = str.length(); if (!len) - return; + return; const TQChar *uc = str.unicode(); int cls = lineBreakClass(*uc); if (cls >= TQUnicodeTables::LineBreak_CM) - cls = TQUnicodeTables::LineBreak_ID; + cls = TQUnicodeTables::LineBreak_ID; charAttributes[0].softBreak = FALSE; charAttributes[0].whiteSpace = (cls == TQUnicodeTables::LineBreak_SP); charAttributes[0].charStop = TRUE; - for (int i = 1; i < len; ++i) { - int ncls = ::lineBreakClass(uc[i]); - int category = ::category(uc[i]); - if (category == TQChar::Mark_NonSpacing) - goto nsm; - - if (category == TQChar::Other_Surrogate) { - // char stop only on first pair - if (uc[i].isHighSurrogate() && i < (len - 1) && uc[i + 1].isLowSurrogate()) - goto nsm; - // ### correctly handle second surrogate - } - - if (ncls == TQUnicodeTables::LineBreak_SP) { - charAttributes[i].softBreak = FALSE; - charAttributes[i].whiteSpace = TRUE; - charAttributes[i].charStop = TRUE; - cls = ncls; - continue; - } + bool prevIsHighSurrogate = uc[0].isHighSurrogate(); + for (int i = 1; i < len; ++i) + { + // Don't stop on low surrogate characters of complete valid pairs + if (prevIsHighSurrogate && uc[i].isLowSurrogate()) + { + prevIsHighSurrogate = false; + charAttributes[i].softBreak = FALSE; + charAttributes[i].whiteSpace = FALSE; + charAttributes[i].charStop = FALSE; + continue; + } + prevIsHighSurrogate = uc[i].isHighSurrogate(); + int ncls = ::lineBreakClass(uc[i]); + int category = ::category(uc[i]); + if (category == TQChar::Mark_NonSpacing) + { + charAttributes[i].softBreak = FALSE; + charAttributes[i].whiteSpace = FALSE; + charAttributes[i].charStop = FALSE; + continue; + } - if (cls == TQUnicodeTables::LineBreak_SA && ncls == TQUnicodeTables::LineBreak_SA) { - // two complex chars (thai or lao), thai_attributes might override, but here - // we do a best guess - charAttributes[i].softBreak = TRUE; - charAttributes[i].whiteSpace = FALSE; - charAttributes[i].charStop = TRUE; - cls = ncls; - continue; - } - { - int tcls = ncls; - if (tcls >= TQUnicodeTables::LineBreak_SA) - tcls = TQUnicodeTables::LineBreak_ID; - if (cls >= TQUnicodeTables::LineBreak_SA) - cls = TQUnicodeTables::LineBreak_ID; - - bool softBreak; - int brk = breakTable[cls][tcls]; - if (brk == Ibk) - softBreak = (cls == TQUnicodeTables::LineBreak_SP); - else - softBreak = (brk == Dbk); -// tqDebug("char = %c %04x, cls=%d, ncls=%d, brk=%d soft=%d", uc[i].cell(), uc[i].unicode(), cls, ncls, brk, charAttributes[i].softBreak); - charAttributes[i].softBreak = softBreak; + if (ncls == TQUnicodeTables::LineBreak_SP) { + charAttributes[i].softBreak = FALSE; + charAttributes[i].whiteSpace = TRUE; + charAttributes[i].charStop = TRUE; + cls = ncls; + continue; + } + + if (cls == TQUnicodeTables::LineBreak_SA && ncls == TQUnicodeTables::LineBreak_SA) + { + // two complex chars (thai or lao), thai_attributes might override, but here + // we do a best guess + charAttributes[i].softBreak = TRUE; charAttributes[i].whiteSpace = FALSE; charAttributes[i].charStop = TRUE; cls = ncls; + continue; } - continue; - nsm: - charAttributes[i].softBreak = FALSE; - charAttributes[i].whiteSpace = FALSE; - charAttributes[i].charStop = FALSE; + + int tcls = ncls; + if (tcls >= TQUnicodeTables::LineBreak_SA) + tcls = TQUnicodeTables::LineBreak_ID; + if (cls >= TQUnicodeTables::LineBreak_SA) + cls = TQUnicodeTables::LineBreak_ID; + + bool softBreak; + int brk = breakTable[cls][tcls]; + if (brk == Ibk) + softBreak = (cls == TQUnicodeTables::LineBreak_SP); + else + softBreak = (brk == Dbk); + // tqDebug("char = %c %04x, cls=%d, ncls=%d, brk=%d soft=%d", uc[i].cell(), uc[i].unicode(), cls, ncls, brk, charAttributes[i].softBreak); + charAttributes[i].softBreak = softBreak; + charAttributes[i].whiteSpace = FALSE; + charAttributes[i].charStop = TRUE; + cls = ncls; } } |