take the bidi stuff out of lyxtext.h to its own file

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@7966 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Alfredo Braunstein 2003-10-23 13:28:49 +00:00
parent 838ec5d986
commit a370d413af
10 changed files with 323 additions and 249 deletions

212
src/Bidi.C Normal file
View File

@ -0,0 +1,212 @@
/**
* \file Bidi.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Dekel Tsur
*
* Full author contact details are available in file CREDITS.
*/
#include "Bidi.h"
#include "buffer.h"
#include "insets/updatableinset.h"
#include "lyxfont.h"
#include "lyxrow.h"
#include "lyxrow_funcs.h"
#include "lyxrc.h"
#include "paragraph.h"
using lyx::pos_type;
lyx::pos_type Bidi::log2vis(lyx::pos_type pos) const
{
return (start_ == -1) ? pos : log2vis_list_[pos - start_];
}
lyx::pos_type Bidi::vis2log(lyx::pos_type pos) const
{
return (start_ == -1) ? pos : vis2log_list_[pos - start_];
}
lyx::pos_type Bidi::level(lyx::pos_type pos) const
{
return (start_ == -1) ? 0 : levels_[pos - start_];
}
bool Bidi::inRange(lyx::pos_type pos) const
{
return start_ == -1 || (start_ <= pos && pos <= end_);
}
bool Bidi::same_direction() const
{
return same_direction_;
}
void Bidi::computeTables(Paragraph const & par,
Buffer const & buf, Row & row)
{
same_direction_ = true;
if (!lyxrc.rtl_support) {
start_ = -1;
return;
}
InsetOld * inset = par.inInset();
if (inset && inset->owner() &&
inset->owner()->lyxCode() == InsetOld::ERT_CODE) {
start_ = -1;
return;
}
start_ = row.pos();
end_ = lastPos(par, row);
if (start_ > end_) {
start_ = -1;
return;
}
if (end_ + 2 - start_ >
static_cast<pos_type>(log2vis_list_.size())) {
pos_type new_size =
(end_ + 2 - start_ < 500) ?
500 : 2 * (end_ + 2 - start_);
log2vis_list_.resize(new_size);
vis2log_list_.resize(new_size);
levels_.resize(new_size);
}
vis2log_list_[end_ + 1 - start_] = -1;
log2vis_list_[end_ + 1 - start_] = -1;
BufferParams const & bufparams = buf.params();
pos_type stack[2];
bool const rtl_par = par.isRightToLeftPar(bufparams);
int lev = 0;
bool rtl = false;
bool rtl0 = false;
pos_type const body_pos = par.beginningOfBody();
for (pos_type lpos = start_; lpos <= end_; ++lpos) {
bool is_space = par.isLineSeparator(lpos);
pos_type const pos =
(is_space && lpos + 1 <= end_ &&
!par.isLineSeparator(lpos + 1) &&
!par.isNewline(lpos + 1))
? lpos + 1 : lpos;
LyXFont font = par.getFontSettings(bufparams, pos);
if (pos != lpos && 0 < lpos && rtl0 && font.isRightToLeft() &&
font.number() == LyXFont::ON &&
par.getFontSettings(bufparams, lpos - 1).number()
== LyXFont::ON) {
font = par.getFontSettings(bufparams, lpos);
is_space = false;
}
bool new_rtl = font.isVisibleRightToLeft();
bool new_rtl0 = font.isRightToLeft();
int new_level;
if (lpos == body_pos - 1
&& row.pos() < body_pos - 1
&& is_space) {
new_level = rtl_par ? 1 : 0;
new_rtl0 = rtl_par;
new_rtl = rtl_par;
} else if (new_rtl0)
new_level = new_rtl ? 1 : 2;
else
new_level = rtl_par ? 2 : 0;
if (is_space && new_level >= lev) {
new_level = lev;
new_rtl = rtl;
new_rtl0 = rtl0;
}
int new_level2 = new_level;
if (lev == new_level && rtl0 != new_rtl0) {
--new_level2;
log2vis_list_[lpos - start_] = rtl ? 1 : -1;
} else if (lev < new_level) {
log2vis_list_[lpos - start_] = rtl ? -1 : 1;
if (new_level > rtl_par)
same_direction_ = false;
} else
log2vis_list_[lpos - start_] = new_rtl ? -1 : 1;
rtl = new_rtl;
rtl0 = new_rtl0;
levels_[lpos - start_] = new_level;
while (lev > new_level2) {
pos_type old_lpos = stack[--lev];
int delta = lpos - old_lpos - 1;
if (lev % 2)
delta = -delta;
log2vis_list_[lpos - start_] += delta;
log2vis_list_[old_lpos - start_] += delta;
}
while (lev < new_level)
stack[lev++] = lpos;
}
while (lev > 0) {
pos_type const old_lpos = stack[--lev];
int delta = end_ - old_lpos;
if (lev % 2)
delta = -delta;
log2vis_list_[old_lpos - start_] += delta;
}
pos_type vpos = start_ - 1;
for (pos_type lpos = start_; lpos <= end_; ++lpos) {
vpos += log2vis_list_[lpos - start_];
vis2log_list_[vpos - start_] = lpos;
log2vis_list_[lpos - start_] = vpos;
}
}
// This method requires a previous call to computeTables()
bool Bidi::isBoundary(Buffer const & buf, Paragraph const & par,
pos_type pos) const
{
if (!lyxrc.rtl_support || pos == 0)
return false;
if (!inRange(pos - 1)) {
// This can happen if pos is the first char of a row.
// Returning false in this case is incorrect!
return false;
}
bool const rtl = level(pos - 1) % 2;
bool const rtl2 = inRange(pos)
? level(pos) % 2
: par.isRightToLeftPar(buf.params());
return rtl != rtl2;
}
bool Bidi::isBoundary(Buffer const & buf, Paragraph const & par,
pos_type pos, LyXFont const & font) const
{
if (!lyxrc.rtl_support)
return false; // This is just for speedup
bool const rtl = font.isVisibleRightToLeft();
bool const rtl2 = inRange(pos)
? level(pos) % 2
: par.isRightToLeftPar(buf.params());
return rtl != rtl2;
}

66
src/Bidi.h Normal file
View File

@ -0,0 +1,66 @@
// -*- C++ -*-
/**
* \file Bidi.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Dekel Tsur
*
* Full author contact details are available in file CREDITS.
*/
#ifndef BIDI_H
#define BIDI_H
#include <config.h>
#include "support/types.h"
#include <vector>
class Buffer;
class Paragraph;
class Row;
class LyXFont;
/// bidi stuff
struct Bidi {
///
bool isBoundary(Buffer const &, Paragraph const & par,
lyx::pos_type pos) const;
///
bool isBoundary(Buffer const &, Paragraph const & par,
lyx::pos_type pos, LyXFont const & font) const;
///
lyx::pos_type log2vis(lyx::pos_type pos) const;
/** Maps positions in the logical string to positions
* in visual string.
*/
lyx::pos_type vis2log(lyx::pos_type pos) const;
///
lyx::pos_type level(lyx::pos_type pos) const;
///
bool inRange(lyx::pos_type pos) const;
/// same_direction?
bool same_direction() const;
///
void computeTables(Paragraph const & par,
Buffer const &, Row & row);
private:
///
bool same_direction_;
///
std::vector<lyx::pos_type> log2vis_list_;
/** Maps positions in the visual string to positions
* in logical string.
*/
std::vector<lyx::pos_type> vis2log_list_;
///
std::vector<lyx::pos_type> levels_;
///
lyx::pos_type start_;
///
lyx::pos_type end_;
};
#endif // BIDI_H

View File

@ -1,3 +1,9 @@
2003-10-23 Alfredo Braunstein <abraunst@libero.it>
* lyxtext.h: move the bidi stuff from here...
* text.C: and here
* text2.C: and here
* Bidi.[Ch]: ... to here
2003-10-23 André Pönitz <poenitz@gmx.net>

View File

@ -57,6 +57,8 @@ INCLUDES = $(BOOST_INCLUDES)
BUILT_SOURCES = version.C
lyx_SOURCES = \
Bidi.C \
Bidi.h \
BufferView.C \
BufferView.h \
BufferView_pimpl.C \

View File

@ -399,11 +399,12 @@ void toggleAndShow(BufferView * bv, LyXFont const & font, bool toggleall)
if (font.language() != ignore_language ||
font.number() != LyXFont::IGNORE) {
LyXCursor & cursor = text->cursor;
text->computeBidiTables(*text->cursorPar(), *bv->buffer(),
text->bidi.computeTables(*text->cursorPar(), *bv->buffer(),
*text->cursorRow());
if (cursor.boundary() !=
text->isBoundary(*bv->buffer(), *text->cursorPar(), cursor.pos(),
text->real_current_font))
text->bidi.isBoundary(*bv->buffer(), *text->cursorPar(),
cursor.pos(),
text->real_current_font))
text->setCursor(cursor.par(), cursor.pos(),
false, !cursor.boundary());
}

View File

@ -86,7 +86,7 @@ void InsetNewline::draw(PainterInfo & pi, int x, int y) const
// hack, and highly dubious
lyx::pos_type pos = ownerPar(*pi.base.bv->buffer(), this)
.getPositionOfInset(this);
bool const ltr_pos = (pi.base.bv->text->bidi_level(pos) % 2 == 0);
bool const ltr_pos = (pi.base.bv->text->bidi.level(pos) % 2 == 0);
int xp[3];
int yp[3];

View File

@ -15,6 +15,7 @@
#define LYXTEXT_H
#include "bufferview_funcs.h"
#include "Bidi.h"
#include "layout.h"
#include "lyxfont.h"
#include "ParagraphList_fwd.h"
@ -237,13 +238,6 @@ public:
///
void setCurrentFont();
///
bool isBoundary(Buffer const &, Paragraph const & par,
lyx::pos_type pos) const;
///
bool isBoundary(Buffer const &, Paragraph const & par,
lyx::pos_type pos, LyXFont const & font) const;
///
void recUndo(lyx::paroffset_type first, lyx::paroffset_type last) const;
///
@ -352,17 +346,6 @@ public:
///
int workWidth() const;
///
void computeBidiTables(Paragraph const & par,
Buffer const &, Row & row) const;
/// Maps positions in the visual string to positions in logical string.
lyx::pos_type log2vis(lyx::pos_type pos) const;
/// Maps positions in the logical string to positions in visual string.
lyx::pos_type vis2log(lyx::pos_type pos) const;
///
lyx::pos_type bidi_level(lyx::pos_type pos) const;
///
bool bidi_InRange(lyx::pos_type pos) const;
private:
///
float getCursorX(ParagraphList::iterator pit,
@ -400,8 +383,6 @@ public:
/// return the color of the canvas
LColor_color backgroundColor() const;
///
mutable bool bidi_same_direction;
unsigned char transformChar(unsigned char c, Paragraph const & par,
lyx::pos_type pos) const;
@ -446,21 +427,13 @@ private:
/// FIXME
int labelEnd(ParagraphList::iterator pit, Row const & row) const;
///
mutable std::vector<lyx::pos_type> log2vis_list;
///
mutable std::vector<lyx::pos_type> vis2log_list;
///
mutable std::vector<lyx::pos_type> bidi_levels;
///
mutable lyx::pos_type bidi_start;
///
mutable lyx::pos_type bidi_end;
///
void charInserted();
public:
///
mutable Bidi bidi;
///
bool in_inset_;
///

View File

@ -192,7 +192,7 @@ void RowPainter::paintInset(pos_type const pos)
void RowPainter::paintHebrewComposeChar(pos_type & vpos)
{
pos_type pos = text_.vis2log(vpos);
pos_type pos = text_.bidi.vis2log(vpos);
string str;
@ -226,7 +226,7 @@ void RowPainter::paintHebrewComposeChar(pos_type & vpos)
void RowPainter::paintArabicComposeChar(pos_type & vpos)
{
pos_type pos = text_.vis2log(vpos);
pos_type pos = text_.bidi.vis2log(vpos);
string str;
// first char
@ -256,7 +256,7 @@ void RowPainter::paintArabicComposeChar(pos_type & vpos)
void RowPainter::paintChars(pos_type & vpos, bool hebrew, bool arabic)
{
pos_type pos = text_.vis2log(vpos);
pos_type pos = text_.bidi.vis2log(vpos);
pos_type const last = lastPos(*pit_, row_);
LyXFont orig_font = getFont(pos);
@ -274,7 +274,7 @@ void RowPainter::paintChars(pos_type & vpos, bool hebrew, bool arabic)
++vpos;
// collect as much similar chars as we can
while (vpos <= last && (pos = text_.vis2log(vpos)) >= 0) {
while (vpos <= last && (pos = text_.bidi.vis2log(vpos)) >= 0) {
char c = pit_->getChar(pos);
if (!IsPrintableNonspace(c))
@ -331,7 +331,7 @@ void RowPainter::paintForeignMark(double orig_x, LyXFont const & orig_font)
void RowPainter::paintFromPos(pos_type & vpos)
{
pos_type const pos = text_.vis2log(vpos);
pos_type const pos = text_.bidi.vis2log(vpos);
LyXFont const & orig_font = getFont(pos);
@ -393,7 +393,7 @@ void RowPainter::paintSelection()
RowList::iterator startrow = text_.getRow(text_.selection.start);
RowList::iterator endrow = text_.getRow(text_.selection.end);
if (text_.bidi_same_direction) {
if (text_.bidi.same_direction()) {
int x;
int y = yo_;
int w;
@ -439,7 +439,7 @@ void RowPainter::paintSelection()
double tmpx = x_;
for (pos_type vpos = row_.pos(); vpos <= last; ++vpos) {
pos_type pos = text_.vis2log(vpos);
pos_type pos = text_.bidi.vis2log(vpos);
double const old_tmpx = tmpx;
if (body_pos > 0 && pos == body_pos - 1) {
LyXLayout_ptr const & layout = pit_->layout();
@ -921,7 +921,7 @@ void RowPainter::paintText()
while (vpos <= last) {
if (x_ > bv_.workWidth())
break;
pos_type pos = text_.vis2log(vpos);
pos_type pos = text_.bidi.vis2log(vpos);
if (pos >= pit_->size()) {
++vpos;

View File

@ -247,192 +247,6 @@ int LyXText::singleWidth(ParagraphList::iterator pit,
}
lyx::pos_type LyXText::log2vis(lyx::pos_type pos) const
{
return (bidi_start == -1) ? pos : log2vis_list[pos - bidi_start];
}
lyx::pos_type LyXText::vis2log(lyx::pos_type pos) const
{
return (bidi_start == -1) ? pos : vis2log_list[pos - bidi_start];
}
lyx::pos_type LyXText::bidi_level(lyx::pos_type pos) const
{
return (bidi_start == -1) ? 0 : bidi_levels[pos - bidi_start];
}
bool LyXText::bidi_InRange(lyx::pos_type pos) const
{
return bidi_start == -1 || (bidi_start <= pos && pos <= bidi_end);
}
void LyXText::computeBidiTables(Paragraph const & par,
Buffer const & buf, Row & row) const
{
bidi_same_direction = true;
if (!lyxrc.rtl_support) {
bidi_start = -1;
return;
}
InsetOld * inset = par.inInset();
if (inset && inset->owner() &&
inset->owner()->lyxCode() == InsetOld::ERT_CODE) {
bidi_start = -1;
return;
}
bidi_start = row.pos();
bidi_end = lastPos(par, row);
if (bidi_start > bidi_end) {
bidi_start = -1;
return;
}
if (bidi_end + 2 - bidi_start >
static_cast<pos_type>(log2vis_list.size())) {
pos_type new_size =
(bidi_end + 2 - bidi_start < 500) ?
500 : 2 * (bidi_end + 2 - bidi_start);
log2vis_list.resize(new_size);
vis2log_list.resize(new_size);
bidi_levels.resize(new_size);
}
vis2log_list[bidi_end + 1 - bidi_start] = -1;
log2vis_list[bidi_end + 1 - bidi_start] = -1;
BufferParams const & bufparams = buf.params();
pos_type stack[2];
bool const rtl_par = par.isRightToLeftPar(bufparams);
int level = 0;
bool rtl = false;
bool rtl0 = false;
pos_type const body_pos = par.beginningOfBody();
for (pos_type lpos = bidi_start; lpos <= bidi_end; ++lpos) {
bool is_space = par.isLineSeparator(lpos);
pos_type const pos =
(is_space && lpos + 1 <= bidi_end &&
!par.isLineSeparator(lpos + 1) &&
!par.isNewline(lpos + 1))
? lpos + 1 : lpos;
LyXFont font = par.getFontSettings(bufparams, pos);
if (pos != lpos && 0 < lpos && rtl0 && font.isRightToLeft() &&
font.number() == LyXFont::ON &&
par.getFontSettings(bufparams, lpos - 1).number()
== LyXFont::ON) {
font = par.getFontSettings(bufparams, lpos);
is_space = false;
}
bool new_rtl = font.isVisibleRightToLeft();
bool new_rtl0 = font.isRightToLeft();
int new_level;
if (lpos == body_pos - 1
&& row.pos() < body_pos - 1
&& is_space) {
new_level = rtl_par ? 1 : 0;
new_rtl0 = rtl_par;
new_rtl = rtl_par;
} else if (new_rtl0)
new_level = new_rtl ? 1 : 2;
else
new_level = rtl_par ? 2 : 0;
if (is_space && new_level >= level) {
new_level = level;
new_rtl = rtl;
new_rtl0 = rtl0;
}
int new_level2 = new_level;
if (level == new_level && rtl0 != new_rtl0) {
--new_level2;
log2vis_list[lpos - bidi_start] = rtl ? 1 : -1;
} else if (level < new_level) {
log2vis_list[lpos - bidi_start] = rtl ? -1 : 1;
if (new_level > rtl_par)
bidi_same_direction = false;
} else
log2vis_list[lpos - bidi_start] = new_rtl ? -1 : 1;
rtl = new_rtl;
rtl0 = new_rtl0;
bidi_levels[lpos - bidi_start] = new_level;
while (level > new_level2) {
pos_type old_lpos = stack[--level];
int delta = lpos - old_lpos - 1;
if (level % 2)
delta = -delta;
log2vis_list[lpos - bidi_start] += delta;
log2vis_list[old_lpos - bidi_start] += delta;
}
while (level < new_level)
stack[level++] = lpos;
}
while (level > 0) {
pos_type const old_lpos = stack[--level];
int delta = bidi_end - old_lpos;
if (level % 2)
delta = -delta;
log2vis_list[old_lpos - bidi_start] += delta;
}
pos_type vpos = bidi_start - 1;
for (pos_type lpos = bidi_start;
lpos <= bidi_end; ++lpos) {
vpos += log2vis_list[lpos - bidi_start];
vis2log_list[vpos - bidi_start] = lpos;
log2vis_list[lpos - bidi_start] = vpos;
}
}
// This method requires a previous call to ComputeBidiTables()
bool LyXText::isBoundary(Buffer const & buf, Paragraph const & par,
pos_type pos) const
{
if (!lyxrc.rtl_support || pos == 0)
return false;
if (!bidi_InRange(pos - 1)) {
// This can happen if pos is the first char of a row.
// Returning false in this case is incorrect!
return false;
}
bool const rtl = bidi_level(pos - 1) % 2;
bool const rtl2 = bidi_InRange(pos)
? bidi_level(pos) % 2
: par.isRightToLeftPar(buf.params());
return rtl != rtl2;
}
bool LyXText::isBoundary(Buffer const & buf, Paragraph const & par,
pos_type pos, LyXFont const & font) const
{
if (!lyxrc.rtl_support)
return false; // This is just for speedup
bool const rtl = font.isVisibleRightToLeft();
bool const rtl2 = bidi_InRange(pos)
? bidi_level(pos) % 2
: par.isRightToLeftPar(buf.params());
return rtl != rtl2;
}
int LyXText::leftMargin(ParagraphList::iterator pit, Row const & row) const
{
LyXTextClass const & tclass =
@ -1505,7 +1319,7 @@ void LyXText::prepareToPrint(ParagraphList::iterator pit, Row & row) const
}
}
computeBidiTables(*pit, *bv()->buffer(), row);
bidi.computeTables(*pit, *bv()->buffer(), row);
if (is_rtl) {
pos_type body_pos = pit->beginningOfBody();
pos_type last = lastPos(*pit, row);

View File

@ -1347,12 +1347,12 @@ float LyXText::getCursorX(ParagraphList::iterator pit, Row const & row,
? row_pos : last + 1;
else if (pos > row_pos && (pos > last || boundary))
// Place cursor after char at (logical) position pos - 1
cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
? log2vis(pos - 1) + 1 : log2vis(pos - 1);
cursor_vpos = (bidi.level(pos - 1) % 2 == 0)
? bidi.log2vis(pos - 1) + 1 : bidi.log2vis(pos - 1);
else
// Place cursor before char at (logical) position pos
cursor_vpos = (bidi_level(pos) % 2 == 0)
? log2vis(pos) : log2vis(pos) + 1;
cursor_vpos = (bidi.level(pos) % 2 == 0)
? bidi.log2vis(pos) : bidi.log2vis(pos) + 1;
pos_type body_pos = pit->beginningOfBody();
if (body_pos > 0 &&
@ -1360,7 +1360,7 @@ float LyXText::getCursorX(ParagraphList::iterator pit, Row const & row,
body_pos = 0;
for (pos_type vpos = row_pos; vpos < cursor_vpos; ++vpos) {
pos_type pos = vis2log(vpos);
pos_type pos = bidi.vis2log(vpos);
if (body_pos > 0 && pos == body_pos - 1) {
x += fill_label_hfill +
font_metrics::width(
@ -1409,8 +1409,8 @@ void LyXText::setCurrentFont()
else // potentional bug... BUG (Lgb)
if (pit->isSeparator(pos)) {
if (pos > cursorRow()->pos() &&
bidi_level(pos) % 2 ==
bidi_level(pos - 1) % 2)
bidi.level(pos) % 2 ==
bidi.level(pos - 1) % 2)
--pos;
else if (pos + 1 < pit->size())
++pos;
@ -1422,7 +1422,7 @@ void LyXText::setCurrentFont()
real_current_font = getFont(pit, pos);
if (cursor.pos() == pit->size() &&
isBoundary(*bv()->buffer(), *pit, cursor.pos()) &&
bidi.isBoundary(*bv()->buffer(), *pit, cursor.pos()) &&
!cursor.boundary()) {
Language const * lang =
pit->getParLanguage(bufparams);
@ -1466,7 +1466,7 @@ pos_type LyXText::getColumnNearX(ParagraphList::iterator pit,
}
while (vc <= last && tmpx <= x) {
c = vis2log(vc);
c = bidi.vis2log(vc);
last_tmpx = tmpx;
if (body_pos > 0 && c == body_pos - 1) {
tmpx += fill_label_hfill +
@ -1514,20 +1514,20 @@ pos_type LyXText::getColumnNearX(ParagraphList::iterator pit,
(!rtl && !left_side && vc == last + 1 && x > tmpx + 5)))
c = last + 1;
else if (vc == row.pos()) {
c = vis2log(vc);
if (bidi_level(c) % 2 == 1)
c = bidi.vis2log(vc);
if (bidi.level(c) % 2 == 1)
++c;
} else {
c = vis2log(vc - 1);
bool const rtl = (bidi_level(c) % 2 == 1);
c = bidi.vis2log(vc - 1);
bool const rtl = (bidi.level(c) % 2 == 1);
if (left_side == rtl) {
++c;
boundary = isBoundary(*bv()->buffer(), *pit, c);
boundary = bidi.isBoundary(*bv()->buffer(), *pit, c);
}
}
if (row.pos() <= last && c > last && pit->isNewline(last)) {
if (bidi_level(last) % 2 == 0)
if (bidi.level(last) % 2 == 0)
tmpx -= singleWidth(pit, last);
else
tmpx += singleWidth(pit, last);
@ -1573,7 +1573,7 @@ void LyXText::cursorLeft(bool internal)
bool boundary = cursor.boundary();
setCursor(cursor.par(), cursor.pos() - 1, true, false);
if (!internal && !boundary &&
isBoundary(*bv()->buffer(), *cursorPar(), cursor.pos() + 1))
bidi.isBoundary(*bv()->buffer(), *cursorPar(), cursor.pos() + 1))
setCursor(cursor.par(), cursor.pos() + 1, true, true);
} else if (cursor.par() != 0) {
// steps into the paragraph above
@ -1592,8 +1592,8 @@ void LyXText::cursorRight(bool internal)
setCursor(cursor.par(), cursor.pos(), true, false);
else if (!at_end) {
setCursor(cursor.par(), cursor.pos() + 1, true, false);
if (!internal &&
isBoundary(*bv()->buffer(), *cursorPar(), cursor.pos()))
if (!internal && bidi.isBoundary(*bv()->buffer(), *cursorPar(),
cursor.pos()))
setCursor(cursor.par(), cursor.pos(), true, true);
} else if (cursor.par() + 1 != int(ownerParagraphs().size()))
setCursor(cursor.par() + 1, 0);