summaryrefslogtreecommitdiffstats
path: root/src/gui/text
diff options
context:
space:
mode:
authorKonstantin Ritt <ritt.ks@gmail.com>2012-08-26 04:09:09 +0300
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-09-22 00:47:40 +0200
commitceb9a8232ca0fe9bc823b61ee3ca8bcdc0aa01c5 (patch)
treed088f6fa8e4025b75ddd034240c74fb987fd7ebe /src/gui/text
parented5fe1b95e818101d00e9415d8881ac836c505eb (diff)
A step out from Harfbuzz (reduce dependency)
Introduce QCharAttributes and use it instead of HB_CharAttributes everywhere in Qt (in Harfbuzz, the HB_CharAttributes is only used in the text segmentation algorithm which has been moved from HB to Qt (well, most of it)). Rename some members to better reflect their meaning, remember to keep HB_CharAttributes in sync with QCharAttributes. Also replace HB_ScriptItem with a (temporary) QUnicodeTools::ScriptItem struct that will be replaced with a more efficient/friendly solution a bit later. The soft hyphen and the mandatory break detection has been factored out of the default text breaking algorithm to a higher level in order to refactor the QCharAttributes bitfields and to optimize the implementation for the common case. Change-Id: Ieb365623ae954430f1c8b2dfcd65c82973143eec Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/gui/text')
-rw-r--r--src/gui/text/qharfbuzz_copy_p.h18
-rw-r--r--src/gui/text/qtextengine.cpp60
-rw-r--r--src/gui/text/qtextengine_p.h6
-rw-r--r--src/gui/text/qtextlayout.cpp25
4 files changed, 45 insertions, 64 deletions
diff --git a/src/gui/text/qharfbuzz_copy_p.h b/src/gui/text/qharfbuzz_copy_p.h
index aa48667e2e..75b1240c3d 100644
--- a/src/gui/text/qharfbuzz_copy_p.h
+++ b/src/gui/text/qharfbuzz_copy_p.h
@@ -66,13 +66,6 @@ typedef enum {
HB_Err_Out_Of_Memory = 0xDEAD
} HB_Error;
-typedef enum {
- HB_NoBreak,
- HB_SoftHyphen,
- HB_Break,
- HB_ForcedBreak
-} HB_LineBreakType;
-
typedef QT_PREPEND_NAMESPACE(quint32) HB_Glyph;
typedef void * HB_Font;
typedef void * HB_Face;
@@ -95,17 +88,6 @@ typedef struct {
hb_bitfield combiningClass :8;
} HB_GlyphAttributes;
-// This struct is strictly not needed, but we replicate it completely in
-// case the compiler tries to get clever with padding.
-typedef struct {
- /*HB_LineBreakType*/ hb_bitfield lineBreakType :2;
- /*HB_Bool*/ hb_bitfield whiteSpace :1; /* A unicode whitespace character, except NBSP, ZWNBSP */
- /*HB_Bool*/ hb_bitfield charStop :1; /* Valid cursor position (for left/right arrow) */
- /*HB_Bool*/ hb_bitfield wordBoundary :1;
- /*HB_Bool*/ hb_bitfield sentenceBoundary :1;
- hb_bitfield unused :2;
-} HB_CharAttributes;
-
}
#endif // ifdef QT_BUILD_GUI_LIB
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index e4572e77a2..b2f760029e 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -52,7 +52,6 @@
#include "qfontengine_p.h"
#include "qstring.h"
#include <private/qunicodetables_p.h>
-#include <private/qunicodetools_p.h>
#include "qtextdocument_p.h"
#include "qrawfont.h"
#include "qrawfont_p.h"
@@ -1198,33 +1197,30 @@ QTextEngine::~QTextEngine()
resetFontEngineCache();
}
-const HB_CharAttributes *QTextEngine::attributes() const
+const QCharAttributes *QTextEngine::attributes() const
{
if (layoutData && layoutData->haveCharAttributes)
- return (HB_CharAttributes *) layoutData->memory;
+ return (QCharAttributes *) layoutData->memory;
itemize();
if (! ensureSpace(layoutData->string.length()))
return NULL;
- QVarLengthArray<HB_ScriptItem> hbScriptItems(layoutData->items.size());
-
+ QVarLengthArray<QUnicodeTools::ScriptItem> scriptItems(layoutData->items.size());
for (int i = 0; i < layoutData->items.size(); ++i) {
const QScriptItem &si = layoutData->items[i];
- hbScriptItems[i].pos = si.position;
- hbScriptItems[i].length = length(i);
- hbScriptItems[i].bidiLevel = si.analysis.bidiLevel;
- hbScriptItems[i].script = (HB_Script)si.analysis.script;
+ scriptItems[i].position = si.position;
+ scriptItems[i].script = si.analysis.script;
}
QUnicodeTools::initCharAttributes(reinterpret_cast<const HB_UChar16 *>(layoutData->string.constData()),
layoutData->string.length(),
- hbScriptItems.data(), hbScriptItems.size(),
- (HB_CharAttributes *)layoutData->memory);
+ scriptItems.data(), scriptItems.size(),
+ (QCharAttributes *)layoutData->memory);
layoutData->haveCharAttributes = true;
- return (HB_CharAttributes *) layoutData->memory;
+ return (QCharAttributes *) layoutData->memory;
}
void QTextEngine::shape(int item) const
@@ -1858,7 +1854,7 @@ void QTextEngine::justify(const QScriptLine &line)
// don't include trailing white spaces when doing justification
int line_length = line.length;
- const HB_CharAttributes *a = attributes();
+ const QCharAttributes *a = attributes();
if (! a)
return;
a += line.from;
@@ -2058,7 +2054,7 @@ QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int
{
allocated = _allocated;
- int space_charAttributes = sizeof(HB_CharAttributes)*string.length()/sizeof(void*) + 1;
+ int space_charAttributes = sizeof(QCharAttributes)*string.length()/sizeof(void*) + 1;
int space_logClusters = sizeof(unsigned short)*string.length()/sizeof(void*) + 1;
available_glyphs = ((int)allocated - space_charAttributes - space_logClusters)*(int)sizeof(void*)/(int)QGlyphLayout::spaceNeededForGlyphLayout(1);
@@ -2100,7 +2096,7 @@ bool QTextEngine::LayoutData::reallocate(int totalGlyphs)
return true;
}
- int space_charAttributes = sizeof(HB_CharAttributes)*string.length()/sizeof(void*) + 1;
+ int space_charAttributes = sizeof(QCharAttributes)*string.length()/sizeof(void*) + 1;
int space_logClusters = sizeof(unsigned short)*string.length()/sizeof(void*) + 1;
int space_glyphs = QGlyphLayout::spaceNeededForGlyphLayout(totalGlyphs)/sizeof(void*) + 2;
@@ -2371,7 +2367,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
if (flags & Qt::TextShowMnemonic) {
itemize();
- HB_CharAttributes *attributes = const_cast<HB_CharAttributes *>(this->attributes());
+ QCharAttributes *attributes = const_cast<QCharAttributes *>(this->attributes());
if (!attributes)
return QString();
for (int i = 0; i < layoutData->items.size(); ++i) {
@@ -2387,9 +2383,9 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
if (layoutData->string.at(i) == QLatin1Char('&')) {
const int gp = logClusters[i - si.position];
glyphs.attributes[gp].dontPrint = true;
- attributes[i + 1].charStop = false;
+ attributes[i + 1].graphemeBoundary = false;
+ attributes[i + 1].lineBreak = false;
attributes[i + 1].whiteSpace = false;
- attributes[i + 1].lineBreakType = HB_NoBreak;
if (layoutData->string.at(i + 1) == QLatin1Char('&'))
++i;
}
@@ -2451,7 +2447,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
if (availableWidth < 0)
return QString();
- const HB_CharAttributes *attributes = this->attributes();
+ const QCharAttributes *attributes = this->attributes();
if (!attributes)
return QString();
@@ -2464,7 +2460,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
pos = nextBreak;
++nextBreak;
- while (nextBreak < layoutData->string.length() && !attributes[nextBreak].charStop)
+ while (nextBreak < layoutData->string.length() && !attributes[nextBreak].graphemeBoundary)
++nextBreak;
currentWidth += this->width(pos, nextBreak - pos);
@@ -2487,7 +2483,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
pos = nextBreak;
--nextBreak;
- while (nextBreak > 0 && !attributes[nextBreak].charStop)
+ while (nextBreak > 0 && !attributes[nextBreak].graphemeBoundary)
--nextBreak;
currentWidth += this->width(nextBreak, pos - nextBreak);
@@ -2516,11 +2512,11 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
rightPos = nextRightBreak;
++nextLeftBreak;
- while (nextLeftBreak < layoutData->string.length() && !attributes[nextLeftBreak].charStop)
+ while (nextLeftBreak < layoutData->string.length() && !attributes[nextLeftBreak].graphemeBoundary)
++nextLeftBreak;
--nextRightBreak;
- while (nextRightBreak > from && !attributes[nextRightBreak].charStop)
+ while (nextRightBreak > from && !attributes[nextRightBreak].graphemeBoundary)
--nextRightBreak;
leftWidth += this->width(leftPos, nextLeftBreak - leftPos);
@@ -2833,12 +2829,12 @@ QFixed QTextEngine::offsetInLigature(const QScriptItem *si, int pos, int max, in
// Scan in logClusters[from..to-1] for glyph_pos
int QTextEngine::getClusterLength(unsigned short *logClusters,
- const HB_CharAttributes *attributes,
+ const QCharAttributes *attributes,
int from, int to, int glyph_pos, int *start)
{
int clusterLength = 0;
for (int i = from; i < to; i++) {
- if (logClusters[i] == glyph_pos && attributes[i].charStop) {
+ if (logClusters[i] == glyph_pos && attributes[i].graphemeBoundary) {
if (*start < 0)
*start = i;
clusterLength++;
@@ -2877,7 +2873,7 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end,
glyph_pos--;
}
- const HB_CharAttributes *attrs = attributes();
+ const QCharAttributes *attrs = attributes();
logClusters = this->logClusters(si);
clusterLength = getClusterLength(logClusters, attrs, 0, end, glyph_pos, &clusterStart);
@@ -2895,8 +2891,8 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end,
if (cursorOnCharacter && closestItem > 0)
closestItem--;
int pos = si->position + clusterStart + closestItem;
- // Jump to the next charStop
- while (pos < end && !attrs[pos].charStop)
+ // Jump to the next grapheme boundary
+ while (pos < end && !attrs[pos].graphemeBoundary)
pos++;
return pos;
}
@@ -2905,21 +2901,21 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end,
int QTextEngine::previousLogicalPosition(int oldPos) const
{
- const HB_CharAttributes *attrs = attributes();
+ const QCharAttributes *attrs = attributes();
if (!attrs || oldPos < 0)
return oldPos;
if (oldPos <= 0)
return 0;
oldPos--;
- while (oldPos && !attrs[oldPos].charStop)
+ while (oldPos && !attrs[oldPos].graphemeBoundary)
oldPos--;
return oldPos;
}
int QTextEngine::nextLogicalPosition(int oldPos) const
{
- const HB_CharAttributes *attrs = attributes();
+ const QCharAttributes *attrs = attributes();
int len = block.isValid() ? block.length() - 1
: layoutData->string.length();
Q_ASSERT(len <= layoutData->string.length());
@@ -2927,7 +2923,7 @@ int QTextEngine::nextLogicalPosition(int oldPos) const
return oldPos;
oldPos++;
- while (oldPos < len && !attrs[oldPos].charStop)
+ while (oldPos < len && !attrs[oldPos].graphemeBoundary)
oldPos++;
return oldPos;
}
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index c2362e6dc5..ac4bc273c0 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -75,6 +75,8 @@
#include "private/qfixed_p.h"
+#include <private/qunicodetools_p.h>
+
#include <stdlib.h>
QT_BEGIN_NAMESPACE
@@ -468,7 +470,7 @@ public:
bool isRightToLeft() const;
static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder);
- const HB_CharAttributes *attributes() const;
+ const QCharAttributes *attributes() const;
void shape(int item) const;
@@ -672,7 +674,7 @@ private:
void resolveAdditionalFormats() const;
int endOfLine(int lineNum);
int beginningOfLine(int lineNum);
- int getClusterLength(unsigned short *logClusters, const HB_CharAttributes *attributes, int from, int to, int glyph_pos, int *start);
+ int getClusterLength(unsigned short *logClusters, const QCharAttributes *attributes, int from, int to, int glyph_pos, int *start);
};
class Q_GUI_EXPORT QStackTextEngine : public QTextEngine {
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index a49b4112d4..7591b46547 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -683,7 +683,7 @@ void QTextLayout::clearLayout()
*/
int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
{
- const HB_CharAttributes *attributes = d->attributes();
+ const QCharAttributes *attributes = d->attributes();
int len = d->block.isValid() ? d->block.length() - 1
: d->layoutData->string.length();
Q_ASSERT(len <= d->layoutData->string.length());
@@ -692,7 +692,7 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
if (mode == SkipCharacters) {
oldPos++;
- while (oldPos < len && !attributes[oldPos].charStop)
+ while (oldPos < len && !attributes[oldPos].graphemeBoundary)
oldPos++;
} else {
if (oldPos < len && d->atWordSeparator(oldPos)) {
@@ -719,13 +719,13 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
*/
int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const
{
- const HB_CharAttributes *attributes = d->attributes();
+ const QCharAttributes *attributes = d->attributes();
if (!attributes || oldPos <= 0 || oldPos > d->layoutData->string.length())
return oldPos;
if (mode == SkipCharacters) {
oldPos--;
- while (oldPos && !attributes[oldPos].charStop)
+ while (oldPos && !attributes[oldPos].graphemeBoundary)
oldPos--;
} else {
while (oldPos && d->atSpace(oldPos-1))
@@ -789,10 +789,10 @@ int QTextLayout::leftCursorPosition(int oldPos) const
*/
bool QTextLayout::isValidCursorPosition(int pos) const
{
- const HB_CharAttributes *attributes = d->attributes();
+ const QCharAttributes *attributes = d->attributes();
if (!attributes || pos < 0 || pos > (int)d->layoutData->string.length())
return false;
- return attributes[pos].charStop;
+ return attributes[pos].graphemeBoundary;
}
/*!
@@ -1770,7 +1770,7 @@ void QTextLine::layout_helper(int maxGlyphs)
Qt::Alignment alignment = eng->option.alignment();
- const HB_CharAttributes *attributes = eng->attributes();
+ const QCharAttributes *attributes = eng->attributes();
if (!attributes)
return;
lbh.currentPosition = line.from;
@@ -1875,17 +1875,18 @@ void QTextLine::layout_helper(int maxGlyphs)
if (lbh.currentPosition >= eng->layoutData->string.length()
|| attributes[lbh.currentPosition].whiteSpace
- || attributes[lbh.currentPosition].lineBreakType != HB_NoBreak) {
+ || attributes[lbh.currentPosition].lineBreak) {
sb_or_ws = true;
break;
- } else if (breakany && attributes[lbh.currentPosition].charStop) {
+ } else if (breakany && attributes[lbh.currentPosition].graphemeBoundary) {
break;
}
} while (lbh.currentPosition < end);
lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw);
if (lbh.currentPosition > 0 && lbh.currentPosition < end
- && attributes[lbh.currentPosition].lineBreakType == HB_SoftHyphen) {
+ && attributes[lbh.currentPosition].lineBreak
+ && eng->layoutData->string.at(lbh.currentPosition - 1).unicode() == QChar::SoftHyphen) {
// if we are splitting up a word because of
// a soft hyphen then we ...
//
@@ -2605,12 +2606,12 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
int lineEnd = line.from + line.length + line.trailingSpaces;
int pos = *cursorPos;
int itm;
- const HB_CharAttributes *attributes = eng->attributes();
+ const QCharAttributes *attributes = eng->attributes();
if (!attributes) {
*cursorPos = 0;
return x.toReal();
}
- while (pos < lineEnd && !attributes[pos].charStop)
+ while (pos < lineEnd && !attributes[pos].graphemeBoundary)
pos++;
if (pos == lineEnd) {
// end of line ensure we have the last item on the line