summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichele Calgaro <[email protected]>2025-02-04 17:59:57 +0900
committerMichele Calgaro <[email protected]>2025-02-04 17:59:57 +0900
commitc7d887bde61931f3b73298ffa3d1d7b4e8137c01 (patch)
tree699168b068615dd24794e20b6d2a38ec44d9a1e3
parentc5cda03125a6d34c179d968011083bceb87976bd (diff)
downloadtqt3-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.cpp32
-rw-r--r--src/kernel/tqfontengine_p.h2
-rw-r--r--src/kernel/tqfontengine_x11.cpp58
-rw-r--r--src/kernel/tqfontmetrics.h2
-rw-r--r--src/kernel/tqscriptengine.cpp21
-rw-r--r--src/kernel/tqtextengine.cpp107
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;
}
}