921 |
921 |
922 for (int i = 0; i < si.num_glyphs; ++i) |
922 for (int i = 0; i < si.num_glyphs; ++i) |
923 si.width += glyphs.advances_x[i]; |
923 si.width += glyphs.advances_x[i]; |
924 } |
924 } |
925 |
925 |
|
926 static inline bool hasCaseChange(const QScriptItem &si) |
|
927 { |
|
928 return si.analysis.flags == QScriptAnalysis::SmallCaps || |
|
929 si.analysis.flags == QScriptAnalysis::Uppercase || |
|
930 si.analysis.flags == QScriptAnalysis::Lowercase; |
|
931 } |
|
932 |
926 #if defined(Q_WS_WINCE) //TODO |
933 #if defined(Q_WS_WINCE) //TODO |
927 // set the glyph attributes heuristically. Assumes a 1 to 1 relationship between chars and glyphs |
934 // set the glyph attributes heuristically. Assumes a 1 to 1 relationship between chars and glyphs |
928 // and no reordering. |
935 // and no reordering. |
929 // also computes logClusters heuristically |
936 // also computes logClusters heuristically |
930 static void heuristicSetGlyphAttributes(const QChar *uc, int length, QGlyphLayout *glyphs, unsigned short *logClusters, int num_glyphs) |
937 static void heuristicSetGlyphAttributes(const QChar *uc, int length, QGlyphLayout *glyphs, unsigned short *logClusters, int num_glyphs) |
1048 if (si.analysis.bidiLevel % 2) |
1055 if (si.analysis.bidiLevel % 2) |
1049 flags |= RightToLeft; |
1056 flags |= RightToLeft; |
1050 if (option.useDesignMetrics()) |
1057 if (option.useDesignMetrics()) |
1051 flags |= DesignMetrics; |
1058 flags |= DesignMetrics; |
1052 |
1059 |
1053 attributes(); // pre-initialize char attributes |
1060 // pre-initialize char attributes |
|
1061 if (! attributes()) |
|
1062 return; |
1054 |
1063 |
1055 const int len = length(item); |
1064 const int len = length(item); |
1056 int num_glyphs = length(item); |
1065 int num_glyphs = length(item); |
1057 const QChar *str = layoutData->string.unicode() + si.position; |
1066 const QChar *str = layoutData->string.unicode() + si.position; |
1058 ushort upperCased[256]; |
1067 ushort upperCased[256]; |
1059 if (si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase |
1068 if (hasCaseChange(si)) { |
1060 || si.analysis.flags == QScriptAnalysis::Lowercase) { |
|
1061 ushort *uc = upperCased; |
1069 ushort *uc = upperCased; |
1062 if (len > 256) |
1070 if (len > 256) |
1063 uc = new ushort[len]; |
1071 uc = new ushort[len]; |
1064 for (int i = 0; i < len; ++i) { |
1072 for (int i = 0; i < len; ++i) { |
1065 if(si.analysis.flags == QScriptAnalysis::Lowercase) |
1073 if(si.analysis.flags == QScriptAnalysis::Lowercase) |
1069 } |
1077 } |
1070 str = reinterpret_cast<const QChar *>(uc); |
1078 str = reinterpret_cast<const QChar *>(uc); |
1071 } |
1079 } |
1072 |
1080 |
1073 while (true) { |
1081 while (true) { |
1074 ensureSpace(num_glyphs); |
1082 if (! ensureSpace(num_glyphs)) { |
|
1083 // If str is converted to uppercase/lowercase form with a new buffer, |
|
1084 // we need to delete that buffer before return for error |
|
1085 const ushort *uc = reinterpret_cast<const ushort *>(str); |
|
1086 if (hasCaseChange(si) && uc != upperCased) |
|
1087 delete [] uc; |
|
1088 return; |
|
1089 } |
1075 num_glyphs = layoutData->glyphLayout.numGlyphs - layoutData->used; |
1090 num_glyphs = layoutData->glyphLayout.numGlyphs - layoutData->used; |
1076 |
1091 |
1077 QGlyphLayout g = availableGlyphs(&si); |
1092 QGlyphLayout g = availableGlyphs(&si); |
1078 unsigned short *log_clusters = logClusters(&si); |
1093 unsigned short *log_clusters = logClusters(&si); |
1079 |
1094 |
1090 si.num_glyphs = num_glyphs; |
1105 si.num_glyphs = num_glyphs; |
1091 |
1106 |
1092 layoutData->used += si.num_glyphs; |
1107 layoutData->used += si.num_glyphs; |
1093 |
1108 |
1094 const ushort *uc = reinterpret_cast<const ushort *>(str); |
1109 const ushort *uc = reinterpret_cast<const ushort *>(str); |
1095 if ((si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase |
1110 if (hasCaseChange(si) && uc != upperCased) |
1096 || si.analysis.flags == QScriptAnalysis::Lowercase) |
|
1097 && uc != upperCased) |
|
1098 delete [] uc; |
1111 delete [] uc; |
1099 } |
1112 } |
1100 #endif |
1113 #endif |
1101 |
1114 |
1102 static inline void moveGlyphData(const QGlyphLayout &destination, const QGlyphLayout &source, int num) |
1115 static inline void moveGlyphData(const QGlyphLayout &destination, const QGlyphLayout &source, int num) |
1131 entire_shaper_item.item.pos = si.position; |
1144 entire_shaper_item.item.pos = si.position; |
1132 entire_shaper_item.item.length = length(item); |
1145 entire_shaper_item.item.length = length(item); |
1133 entire_shaper_item.item.bidiLevel = si.analysis.bidiLevel; |
1146 entire_shaper_item.item.bidiLevel = si.analysis.bidiLevel; |
1134 |
1147 |
1135 HB_UChar16 upperCased[256]; // XXX what about making this 4096, so we don't have to extend it ever. |
1148 HB_UChar16 upperCased[256]; // XXX what about making this 4096, so we don't have to extend it ever. |
1136 if (si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase |
1149 if (hasCaseChange(si)) { |
1137 || si.analysis.flags == QScriptAnalysis::Lowercase) { |
|
1138 HB_UChar16 *uc = upperCased; |
1150 HB_UChar16 *uc = upperCased; |
1139 if (entire_shaper_item.item.length > 256) |
1151 if (entire_shaper_item.item.length > 256) |
1140 uc = new HB_UChar16[entire_shaper_item.item.length]; |
1152 uc = new HB_UChar16[entire_shaper_item.item.length]; |
1141 for (uint i = 0; i < entire_shaper_item.item.length; ++i) { |
1153 for (uint i = 0; i < entire_shaper_item.item.length; ++i) { |
1142 if(si.analysis.flags == QScriptAnalysis::Lowercase) |
1154 if(si.analysis.flags == QScriptAnalysis::Lowercase) |
1154 entire_shaper_item.shaperFlags |= HB_ShaperFlag_NoKerning; |
1166 entire_shaper_item.shaperFlags |= HB_ShaperFlag_NoKerning; |
1155 if (option.useDesignMetrics()) |
1167 if (option.useDesignMetrics()) |
1156 entire_shaper_item.shaperFlags |= HB_ShaperFlag_UseDesignMetrics; |
1168 entire_shaper_item.shaperFlags |= HB_ShaperFlag_UseDesignMetrics; |
1157 |
1169 |
1158 entire_shaper_item.num_glyphs = qMax(layoutData->glyphLayout.numGlyphs - layoutData->used, int(entire_shaper_item.item.length)); |
1170 entire_shaper_item.num_glyphs = qMax(layoutData->glyphLayout.numGlyphs - layoutData->used, int(entire_shaper_item.item.length)); |
1159 ensureSpace(entire_shaper_item.num_glyphs); |
1171 if (! ensureSpace(entire_shaper_item.num_glyphs)) { |
|
1172 if (hasCaseChange(si)) |
|
1173 delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string); |
|
1174 return; |
|
1175 } |
1160 QGlyphLayout initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs); |
1176 QGlyphLayout initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs); |
1161 |
1177 |
1162 if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, font)) { |
1178 if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, font)) { |
1163 ensureSpace(entire_shaper_item.num_glyphs); |
1179 if (! ensureSpace(entire_shaper_item.num_glyphs)) { |
|
1180 if (hasCaseChange(si)) |
|
1181 delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string); |
|
1182 return; |
|
1183 } |
1164 initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs); |
1184 initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs); |
1165 |
1185 |
1166 if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, font)) { |
1186 if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, font)) { |
1167 // ############ if this happens there's a bug in the fontengine |
1187 // ############ if this happens there's a bug in the fontengine |
1168 if ((si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase |
1188 if (hasCaseChange(si) && entire_shaper_item.string != upperCased) |
1169 || si.analysis.flags == QScriptAnalysis::Lowercase) && entire_shaper_item.string != upperCased) |
|
1170 delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string); |
1189 delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string); |
1171 return; |
1190 return; |
1172 } |
1191 } |
1173 } |
1192 } |
1174 |
1193 |
1229 shaper_item.glyphIndicesPresent = true; |
1248 shaper_item.glyphIndicesPresent = true; |
1230 |
1249 |
1231 remaining_glyphs -= shaper_item.initialGlyphCount; |
1250 remaining_glyphs -= shaper_item.initialGlyphCount; |
1232 |
1251 |
1233 do { |
1252 do { |
1234 ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs); |
1253 if (! ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs)) { |
|
1254 if (hasCaseChange(si)) |
|
1255 delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string); |
|
1256 return; |
|
1257 } |
1235 |
1258 |
1236 const QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos); |
1259 const QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos); |
1237 moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs); |
1260 moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs); |
1238 |
1261 |
1239 shaper_item.glyphs = g.glyphs; |
1262 shaper_item.glyphs = g.glyphs; |
1269 // qDebug(" -> item: script=%d num_glyphs=%d", shaper_item.script, shaper_item.num_glyphs); |
1292 // qDebug(" -> item: script=%d num_glyphs=%d", shaper_item.script, shaper_item.num_glyphs); |
1270 si.num_glyphs = glyph_pos; |
1293 si.num_glyphs = glyph_pos; |
1271 |
1294 |
1272 layoutData->used += si.num_glyphs; |
1295 layoutData->used += si.num_glyphs; |
1273 |
1296 |
1274 if ((si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase) |
1297 if (hasCaseChange(si) && entire_shaper_item.string != upperCased) |
1275 && entire_shaper_item.string != upperCased) |
|
1276 delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string); |
1298 delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string); |
1277 } |
1299 } |
1278 |
1300 |
1279 static void init(QTextEngine *e) |
1301 static void init(QTextEngine *e) |
1280 { |
1302 { |
1315 { |
1337 { |
1316 if (layoutData && layoutData->haveCharAttributes) |
1338 if (layoutData && layoutData->haveCharAttributes) |
1317 return (HB_CharAttributes *) layoutData->memory; |
1339 return (HB_CharAttributes *) layoutData->memory; |
1318 |
1340 |
1319 itemize(); |
1341 itemize(); |
1320 ensureSpace(layoutData->string.length()); |
1342 if (! ensureSpace(layoutData->string.length())) |
|
1343 return NULL; |
1321 |
1344 |
1322 QVarLengthArray<HB_ScriptItem> hbScriptItems(layoutData->items.size()); |
1345 QVarLengthArray<HB_ScriptItem> hbScriptItems(layoutData->items.size()); |
1323 |
1346 |
1324 for (int i = 0; i < layoutData->items.size(); ++i) { |
1347 for (int i = 0; i < layoutData->items.size(); ++i) { |
1325 const QScriptItem &si = layoutData->items[i]; |
1348 const QScriptItem &si = layoutData->items[i]; |
1536 |
1559 |
1537 |
1560 |
1538 int QTextEngine::findItem(int strPos) const |
1561 int QTextEngine::findItem(int strPos) const |
1539 { |
1562 { |
1540 itemize(); |
1563 itemize(); |
1541 |
1564 int left = 0; |
1542 // ##### use binary search |
1565 int right = layoutData->items.size()-1; |
1543 int item; |
1566 while(left <= right) { |
1544 for (item = layoutData->items.size()-1; item > 0; --item) { |
1567 int middle = ((right-left)/2)+left; |
1545 if (layoutData->items[item].position <= strPos) |
1568 if (strPos > layoutData->items[middle].position) |
1546 break; |
1569 left = middle+1; |
1547 } |
1570 else if(strPos < layoutData->items[middle].position) |
1548 return item; |
1571 right = middle-1; |
|
1572 else { |
|
1573 return middle; |
|
1574 } |
|
1575 } |
|
1576 return right; |
1549 } |
1577 } |
1550 |
1578 |
1551 QFixed QTextEngine::width(int from, int len) const |
1579 QFixed QTextEngine::width(int from, int len) const |
1552 { |
1580 { |
1553 itemize(); |
1581 itemize(); |
1646 int glyphStart = logClusters[charFrom]; |
1673 int glyphStart = logClusters[charFrom]; |
1647 if (charFrom > 0 && logClusters[charFrom-1] == glyphStart) |
1674 if (charFrom > 0 && logClusters[charFrom-1] == glyphStart) |
1648 while (charFrom < ilen && logClusters[charFrom] == glyphStart) |
1675 while (charFrom < ilen && logClusters[charFrom] == glyphStart) |
1649 charFrom++; |
1676 charFrom++; |
1650 if (charFrom < ilen) { |
1677 if (charFrom < ilen) { |
|
1678 QFontEngine *fe = fontEngine(*si); |
1651 glyphStart = logClusters[charFrom]; |
1679 glyphStart = logClusters[charFrom]; |
1652 int charEnd = from + len - 1 - pos; |
1680 int charEnd = from + len - 1 - pos; |
1653 if (charEnd >= ilen) |
1681 if (charEnd >= ilen) |
1654 charEnd = ilen-1; |
1682 charEnd = ilen-1; |
1655 int glyphEnd = logClusters[charEnd]; |
1683 int glyphEnd = logClusters[charEnd]; |
1862 // justify line |
1885 // justify line |
1863 int maxJustify = 0; |
1886 int maxJustify = 0; |
1864 |
1887 |
1865 // don't include trailing white spaces when doing justification |
1888 // don't include trailing white spaces when doing justification |
1866 int line_length = line.length; |
1889 int line_length = line.length; |
1867 const HB_CharAttributes *a = attributes()+line.from; |
1890 const HB_CharAttributes *a = attributes(); |
|
1891 if (! a) |
|
1892 return; |
|
1893 a += line.from; |
1868 while (line_length && a[line_length-1].whiteSpace) |
1894 while (line_length && a[line_length-1].whiteSpace) |
1869 --line_length; |
1895 --line_length; |
1870 // subtract one char more, as we can't justfy after the last character |
1896 // subtract one char more, as we can't justfy after the last character |
1871 --line_length; |
1897 --line_length; |
1872 |
1898 |
2077 glyphLayout.clear(); |
2103 glyphLayout.clear(); |
2078 memset(memory, 0, space_charAttributes*sizeof(void *)); |
2104 memset(memory, 0, space_charAttributes*sizeof(void *)); |
2079 } |
2105 } |
2080 used = 0; |
2106 used = 0; |
2081 hasBidi = false; |
2107 hasBidi = false; |
2082 inLayout = false; |
2108 layoutState = LayoutEmpty; |
2083 haveCharAttributes = false; |
2109 haveCharAttributes = false; |
2084 } |
2110 } |
2085 |
2111 |
2086 QTextEngine::LayoutData::~LayoutData() |
2112 QTextEngine::LayoutData::~LayoutData() |
2087 { |
2113 { |
2088 if (!memory_on_stack) |
2114 if (!memory_on_stack) |
2089 free(memory); |
2115 free(memory); |
2090 memory = 0; |
2116 memory = 0; |
2091 } |
2117 } |
2092 |
2118 |
2093 void QTextEngine::LayoutData::reallocate(int totalGlyphs) |
2119 bool QTextEngine::LayoutData::reallocate(int totalGlyphs) |
2094 { |
2120 { |
2095 Q_ASSERT(totalGlyphs >= glyphLayout.numGlyphs); |
2121 Q_ASSERT(totalGlyphs >= glyphLayout.numGlyphs); |
2096 if (memory_on_stack && available_glyphs >= totalGlyphs) { |
2122 if (memory_on_stack && available_glyphs >= totalGlyphs) { |
2097 glyphLayout.grow(glyphLayout.data(), totalGlyphs); |
2123 glyphLayout.grow(glyphLayout.data(), totalGlyphs); |
2098 return; |
2124 return true; |
2099 } |
2125 } |
2100 |
2126 |
2101 int space_charAttributes = sizeof(HB_CharAttributes)*string.length()/sizeof(void*) + 1; |
2127 int space_charAttributes = sizeof(HB_CharAttributes)*string.length()/sizeof(void*) + 1; |
2102 int space_logClusters = sizeof(unsigned short)*string.length()/sizeof(void*) + 1; |
2128 int space_logClusters = sizeof(unsigned short)*string.length()/sizeof(void*) + 1; |
2103 int space_glyphs = QGlyphLayout::spaceNeededForGlyphLayout(totalGlyphs)/sizeof(void*) + 2; |
2129 int space_glyphs = QGlyphLayout::spaceNeededForGlyphLayout(totalGlyphs)/sizeof(void*) + 2; |
2104 |
2130 |
2105 int newAllocated = space_charAttributes + space_glyphs + space_logClusters; |
2131 int newAllocated = space_charAttributes + space_glyphs + space_logClusters; |
2106 Q_ASSERT(newAllocated >= allocated); |
2132 // These values can be negative if the length of string/glyphs causes overflow, |
|
2133 // we can't layout such a long string all at once, so return false here to |
|
2134 // indicate there is a failure |
|
2135 if (space_charAttributes < 0 || space_logClusters < 0 || space_glyphs < 0 || newAllocated < allocated) { |
|
2136 layoutState = LayoutFailed; |
|
2137 return false; |
|
2138 } |
|
2139 |
2107 void **newMem = memory; |
2140 void **newMem = memory; |
2108 newMem = (void **)::realloc(memory_on_stack ? 0 : memory, newAllocated*sizeof(void *)); |
2141 newMem = (void **)::realloc(memory_on_stack ? 0 : memory, newAllocated*sizeof(void *)); |
2109 Q_CHECK_PTR(newMem); |
2142 if (!newMem) { |
2110 if (memory_on_stack && newMem) |
2143 layoutState = LayoutFailed; |
|
2144 return false; |
|
2145 } |
|
2146 if (memory_on_stack) |
2111 memcpy(newMem, memory, allocated*sizeof(void *)); |
2147 memcpy(newMem, memory, allocated*sizeof(void *)); |
2112 memory = newMem; |
2148 memory = newMem; |
2113 memory_on_stack = false; |
2149 memory_on_stack = false; |
2114 |
2150 |
2115 void **m = memory; |
2151 void **m = memory; |
2122 memset(memory + allocated, 0, (space_preGlyphLayout - allocated)*sizeof(void *)); |
2158 memset(memory + allocated, 0, (space_preGlyphLayout - allocated)*sizeof(void *)); |
2123 |
2159 |
2124 glyphLayout.grow(reinterpret_cast<char *>(m), totalGlyphs); |
2160 glyphLayout.grow(reinterpret_cast<char *>(m), totalGlyphs); |
2125 |
2161 |
2126 allocated = newAllocated; |
2162 allocated = newAllocated; |
|
2163 return true; |
2127 } |
2164 } |
2128 |
2165 |
2129 // grow to the new size, copying the existing data to the new layout |
2166 // grow to the new size, copying the existing data to the new layout |
2130 void QGlyphLayout::grow(char *address, int totalGlyphs) |
2167 void QGlyphLayout::grow(char *address, int totalGlyphs) |
2131 { |
2168 { |
2153 delete layoutData; |
2190 delete layoutData; |
2154 layoutData = 0; |
2191 layoutData = 0; |
2155 } else { |
2192 } else { |
2156 layoutData->used = 0; |
2193 layoutData->used = 0; |
2157 layoutData->hasBidi = false; |
2194 layoutData->hasBidi = false; |
2158 layoutData->inLayout = false; |
2195 layoutData->layoutState = LayoutEmpty; |
2159 layoutData->haveCharAttributes = false; |
2196 layoutData->haveCharAttributes = false; |
2160 } |
2197 } |
2161 for (int i = 0; i < lines.size(); ++i) { |
2198 for (int i = 0; i < lines.size(); ++i) { |
2162 lines[i].justified = 0; |
2199 lines[i].justified = 0; |
2163 lines[i].gridfitted = 0; |
2200 lines[i].gridfitted = 0; |
2312 QScriptItem &si = layoutData->items[i]; |
2353 QScriptItem &si = layoutData->items[i]; |
2313 if (!si.num_glyphs) |
2354 if (!si.num_glyphs) |
2314 shape(i); |
2355 shape(i); |
2315 |
2356 |
2316 HB_CharAttributes *attributes = const_cast<HB_CharAttributes *>(this->attributes()); |
2357 HB_CharAttributes *attributes = const_cast<HB_CharAttributes *>(this->attributes()); |
|
2358 if (!attributes) |
|
2359 return QString(); |
|
2360 |
2317 unsigned short *logClusters = this->logClusters(&si); |
2361 unsigned short *logClusters = this->logClusters(&si); |
2318 QGlyphLayout glyphs = shapedGlyphs(&si); |
2362 QGlyphLayout glyphs = shapedGlyphs(&si); |
2319 |
2363 |
2320 const int end = si.position + length(&si); |
2364 const int end = si.position + length(&si); |
2321 for (int i = si.position; i < end - 1; ++i) |
2365 for (int i = si.position; i < end - 1; ++i) |