--- /dev/null
+/**
+ * \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;
+}
--- /dev/null
+// -*- 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
+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>
BUILT_SOURCES = version.C
lyx_SOURCES = \
+ Bidi.C \
+ Bidi.h \
BufferView.C \
BufferView.h \
BufferView_pimpl.C \
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());
}
// 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];
#define LYXTEXT_H
#include "bufferview_funcs.h"
+#include "Bidi.h"
#include "layout.h"
#include "lyxfont.h"
#include "ParagraphList_fwd.h"
///
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;
///
///
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,
/// 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;
/// 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_;
///
void RowPainter::paintHebrewComposeChar(pos_type & vpos)
{
- pos_type pos = text_.vis2log(vpos);
+ pos_type pos = text_.bidi.vis2log(vpos);
string str;
void RowPainter::paintArabicComposeChar(pos_type & vpos)
{
- pos_type pos = text_.vis2log(vpos);
+ pos_type pos = text_.bidi.vis2log(vpos);
string str;
// first char
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);
++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))
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);
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;
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();
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;
}
-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 =
}
}
- 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);
? 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 &&
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(
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;
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);
}
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 +
(!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);
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
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);