Qt 4.8
qtextboundaryfinder.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <QtCore/qtextboundaryfinder.h>
42 #include <QtCore/qvarlengtharray.h>
43 #include <private/qunicodetables_p.h>
44 #include <qdebug.h>
45 #include "private/qharfbuzz_p.h"
46 
48 
50 {
51 public:
52  HB_CharAttributes attributes[1];
53 };
54 
55 static void init(QTextBoundaryFinder::BoundaryType type, const QChar *chars, int length, HB_CharAttributes *attributes)
56 {
58 
59  const ushort *string = reinterpret_cast<const ushort *>(chars);
60  const ushort *unicode = string;
61  // correctly assign script, isTab and isObject to the script analysis
62  const ushort *uc = unicode;
63  const ushort *e = uc + length;
65  int lastScript = QUnicodeTables::Common;
66  const ushort *start = uc;
67  while (uc < e) {
68  int s = QUnicodeTables::script(*uc);
70  script = s;
71  if (*uc == QChar::ObjectReplacementCharacter || *uc == QChar::LineSeparator || *uc == 9)
72  script = QUnicodeTables::Common;
73  if (script != lastScript) {
74  if (uc != start) {
75  HB_ScriptItem item;
76  item.pos = start - string;
77  item.length = uc - start;
78  item.script = (HB_Script)lastScript;
79  item.bidiLevel = 0; // ### what's the proper value?
80  scriptItems.append(item);
81  start = uc;
82  }
83  lastScript = script;
84  }
85  ++uc;
86  }
87  if (uc != start) {
88  HB_ScriptItem item;
89  item.pos = start - string;
90  item.length = uc - start;
91  item.script = (HB_Script)lastScript;
92  item.bidiLevel = 0; // ### what's the proper value?
93  scriptItems.append(item);
94  }
95 
96  qGetCharAttributes(string, length, scriptItems.data(), scriptItems.count(), attributes);
97  if (type == QTextBoundaryFinder::Word)
98  HB_GetWordBoundaries(string, length, scriptItems.data(), scriptItems.count(), attributes);
99  else if (type == QTextBoundaryFinder::Sentence)
100  HB_GetSentenceBoundaries(string, length, scriptItems.data(), scriptItems.count(), attributes);
101 }
102 
168  : t(Grapheme)
169  , chars(0)
170  , length(0)
171  , freePrivate(true)
172  , d(0)
173 {
174 }
175 
180  : t(other.t)
181  , s(other.s)
182  , chars(other.chars)
183  , length(other.length)
184  , pos(other.pos)
185  , freePrivate(true)
186 {
187  d = (QTextBoundaryFinderPrivate *) malloc(length*sizeof(HB_CharAttributes));
188  Q_CHECK_PTR(d);
189  memcpy(d, other.d, length*sizeof(HB_CharAttributes));
190 }
191 
196 {
197  if (&other == this)
198  return *this;
199 
200  t = other.t;
201  s = other.s;
202  chars = other.chars;
203  length = other.length;
204  pos = other.pos;
205 
207  realloc(freePrivate ? d : 0, length*sizeof(HB_CharAttributes));
208  Q_CHECK_PTR(newD);
209  freePrivate = true;
210  d = newD;
211  memcpy(d, other.d, length*sizeof(HB_CharAttributes));
212 
213  return *this;
214 }
215 
220 {
221  if (freePrivate)
222  free(d);
223 }
224 
229  : t(type)
230  , s(string)
231  , chars(string.unicode())
232  , length(string.length())
233  , pos(0)
234  , freePrivate(true)
235 {
236  d = (QTextBoundaryFinderPrivate *) malloc(length*sizeof(HB_CharAttributes));
237  Q_CHECK_PTR(d);
238  init(t, chars, length, d->attributes);
239 }
240 
254 QTextBoundaryFinder::QTextBoundaryFinder(BoundaryType type, const QChar *chars, int length, unsigned char *buffer, int bufferSize)
255  : t(type)
256  , chars(chars)
257  , length(length)
258  , pos(0)
259 {
260  if (buffer && (uint)bufferSize >= length*sizeof(HB_CharAttributes)) {
261  d = (QTextBoundaryFinderPrivate *)buffer;
262  freePrivate = false;
263  } else {
264  d = (QTextBoundaryFinderPrivate *) malloc(length*sizeof(HB_CharAttributes));
265  Q_CHECK_PTR(d);
266  freePrivate = true;
267  }
268  init(t, chars, length, d->attributes);
269 }
270 
277 {
278  pos = 0;
279 }
280 
287 {
288  pos = length;
289 }
290 
300 {
301  return pos;
302 }
303 
314 {
315  pos = qBound(0, position, length);
316 }
317 
339 {
340  if (chars == s.unicode() && length == s.length())
341  return s;
342  return QString(chars, length);
343 }
344 
345 
352 {
353  if (!d) {
354  pos = -1;
355  return pos;
356  }
357 
358  if (pos < 0 || pos >= length) {
359  pos = -1;
360  return pos;
361  }
362  ++pos;
363  if (pos == length)
364  return pos;
365 
366  switch(t) {
367  case Grapheme:
368  while (pos < length && !d->attributes[pos].charStop)
369  ++pos;
370  break;
371  case Word:
372  while (pos < length && !d->attributes[pos].wordBoundary)
373  ++pos;
374  break;
375  case Sentence:
376  while (pos < length && !d->attributes[pos].sentenceBoundary)
377  ++pos;
378  break;
379  case Line:
380  Q_ASSERT(pos);
381  while (pos < length && d->attributes[pos-1].lineBreakType < HB_Break)
382  ++pos;
383  break;
384  }
385 
386  return pos;
387 }
388 
395 {
396  if (!d) {
397  pos = -1;
398  return pos;
399  }
400 
401  if (pos <= 0 || pos > length) {
402  pos = -1;
403  return pos;
404  }
405  --pos;
406  if (pos == 0)
407  return pos;
408 
409  switch(t) {
410  case Grapheme:
411  while (pos > 0 && !d->attributes[pos].charStop)
412  --pos;
413  break;
414  case Word:
415  while (pos > 0 && !d->attributes[pos].wordBoundary)
416  --pos;
417  break;
418  case Sentence:
419  while (pos > 0 && !d->attributes[pos].sentenceBoundary)
420  --pos;
421  break;
422  case Line:
423  while (pos > 0 && d->attributes[pos-1].lineBreakType < HB_Break)
424  --pos;
425  break;
426  }
427 
428  return pos;
429 }
430 
435 {
436  if (!d || pos < 0)
437  return false;
438 
439  if (pos == length)
440  return true;
441 
442  switch(t) {
443  case Grapheme:
444  return d->attributes[pos].charStop;
445  case Word:
446  return d->attributes[pos].wordBoundary;
447  case Line:
448  return (pos > 0) ? d->attributes[pos-1].lineBreakType >= HB_Break : true;
449  case Sentence:
450  return d->attributes[pos].sentenceBoundary;
451  }
452  return false;
453 }
454 
458 QTextBoundaryFinder::BoundaryReasons QTextBoundaryFinder::boundaryReasons() const
459 {
460  if (!d)
461  return NotAtBoundary;
462  if (! isAtBoundary())
463  return NotAtBoundary;
464  if (pos == 0) {
465  if (d->attributes[pos].whiteSpace)
466  return NotAtBoundary;
467  return StartWord;
468  }
469  if (pos == length) {
470  if (d->attributes[length-1].whiteSpace)
471  return NotAtBoundary;
472  return EndWord;
473  }
474 
475  const bool nextIsSpace = d->attributes[pos].whiteSpace;
476  const bool prevIsSpace = d->attributes[pos - 1].whiteSpace;
477 
478  if (prevIsSpace && !nextIsSpace)
479  return StartWord;
480  else if (!prevIsSpace && nextIsSpace)
481  return EndWord;
482  else if (!prevIsSpace && !nextIsSpace)
483  return BoundaryReasons(StartWord | EndWord);
484  else
485  return NotAtBoundary;
486 }
487 
double d
Definition: qnumeric_p.h:62
int type
Definition: qmetatype.cpp:239
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void toStart()
Moves the finder to the start of the string.
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
QTextBoundaryFinderPrivate * d
int toPreviousBoundary()
Moves the QTextBoundaryFinder to the previous boundary position and returns that position.
QTextBoundaryFinder()
Constructs an invalid QTextBoundaryFinder object.
void toEnd()
Moves the finder to the end of the string.
The QString class provides a Unicode character string.
Definition: qstring.h:83
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
int position() const
Returns the current position of the QTextBoundaryFinder.
void append(const T &t)
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
QString string() const
Returns the string the QTextBoundaryFinder object operates on.
static void init(QTextBoundaryFinder::BoundaryType type, const QChar *chars, int length, HB_CharAttributes *attributes)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
BoundaryReasons boundaryReasons() const
Returns the reasons for the boundary finder to have chosen the current position as a boundary...
const QChar * unicode() const
Returns a &#39;\0&#39;-terminated Unicode representation of the string.
Definition: qstring.h:706
void setPosition(int position)
Sets the current position of the QTextBoundaryFinder to position.
unsigned int uint
Definition: qglobal.h:996
BoundaryType type() const
Returns the type of the QTextBoundaryFinder.
int count() const
Q_CORE_EXPORT int QT_FASTCALL script(uint ucs4)
#define Q_CHECK_PTR(p)
Definition: qglobal.h:1853
bool isAtBoundary() const
Returns true if the object&#39;s position() is currently at a valid text boundary.
QTextBoundaryFinder & operator=(const QTextBoundaryFinder &other)
Assigns the object, other, to another QTextBoundaryFinder object.
unsigned short ushort
Definition: qglobal.h:995
int toNextBoundary()
Moves the QTextBoundaryFinder to the next boundary position and returns that position.
Q_DECL_CONSTEXPR const T & qBound(const T &min, const T &val, const T &max)
Definition: qglobal.h:1219
~QTextBoundaryFinder()
Destructs the QTextBoundaryFinder object.
void qGetCharAttributes(const HB_UChar16 *string, hb_uint32 stringLength, const HB_ScriptItem *items, hb_uint32 numItems, HB_CharAttributes *attributes)
Definition: qharfbuzz.cpp:133
The QTextBoundaryFinder class provides a way of finding Unicode text boundaries in a string...
HB_CharAttributes attributes[1]