#include "support/textutils.h"
+#include <boost/crc.hpp>
+
using lyx::pos_type;
using lyx::pit_type;
void paintText();
private:
- void paintForeignMark(double orig_x, LyXFont const & font);
+ void paintForeignMark(double orig_x, LyXFont const & font, int desc = 0);
void paintHebrewComposeChar(lyx::pos_type & vpos, LyXFont const & font);
void paintArabicComposeChar(lyx::pos_type & vpos, LyXFont const & font);
void paintChars(lyx::pos_type & vpos, LyXFont font,
}
+bool isTrueTextInset(InsetBase * in)
+{
+ // Math and tabular insets have isTextInset = true, though they are
+ // not derived from InsetText. Paint them fully
+ return (in && in->isTextInset() && in->asMathInset() == 0
+ && in->lyxCode() != InsetBase::TABULAR_CODE);
+}
+
+
void RowPainter::paintInset(pos_type const pos, LyXFont const & font)
{
InsetBase const * inset = par_.getInset(pos);
// FIXME: We should always use font, see documentation of
// noFontChange() in insetbase.h.
pi.base.font = inset->noFontChange() ?
- bv_.buffer()->params().getLyXTextClass().defaultfont() :
+ bv_.buffer()->params().getFont() :
font;
pi.ltr_pos = (text_.bidi.level(pos) % 2 == 0);
pi.erased_ = erased_ || isDeletedText(par_, pos);
theCoords.insets().add(inset, int(x_), yo_);
- inset->drawSelection(pi, int(x_), yo_);
+ InsetBase * in = const_cast<InsetBase *>(inset);
+ // non-wide insets are painted completely. Recursive
+ bool tmp = bv_.repaintAll();
+ if (!isTrueTextInset(in) || !static_cast<InsetText*>(in)->Wide())
+ bv_.repaintAll(true);
+ if (bv_.repaintAll())
+ inset->drawSelection(pi, int(x_), yo_);
inset->draw(pi, int(x_), yo_);
+ bv_.repaintAll(tmp);
x_ += inset->width();
}
}
-void RowPainter::paintForeignMark(double orig_x, LyXFont const & font)
+void RowPainter::paintForeignMark(double orig_x, LyXFont const & font, int desc)
{
if (!lyxrc.mark_foreign_language)
return;
if (font.language() == bv_.buffer()->params().language)
return;
- int const y = yo_ + 1;
+ int const y = yo_ + 1 + desc;
pain_.line(int(orig_x), y, int(x_), y, LColor::language);
}
{
pos_type const pos = text_.bidi.vis2log(vpos);
LyXFont orig_font = text_.getFont(par_, pos);
- text_.applyOuterFont(orig_font);
double const orig_x = x_;
if (par_.isInset(pos)) {
paintInset(pos, orig_font);
++vpos;
- paintForeignMark(orig_x, orig_font);
+ paintForeignMark(orig_x, orig_font,
+ par_.getInset(pos)->descent());
return;
}
pos_type const start = row_.pos();
pos_type const end = row_.endpos();
- if (start == end || !par_.isChanged(start, end - 1))
+ if (start == end || !par_.isChanged(start, end))
return;
int const height = text_.isLastRow(pit_, row_)
if (running_strikeout && (highly_editable_inset || !is_struckout)) {
// Calculate 1/3 height of the buffer's default font
int const middle =
- yo_ - font_metrics::maxAscent(text_.defaultfont_) / 3;
+ yo_ -
+ font_metrics::maxAscent(bv_.buffer()->params().getFont()) / 3;
pain_.line(last_strikeout_x, middle, int(x_), middle,
LColor::strikeout, Painter::line_solid, Painter::line_thin);
running_strikeout = false;
if (running_strikeout) {
// calculate 1/3 height of the buffer's default font
int const middle =
- yo_ - font_metrics::maxAscent(text_.defaultfont_) / 3;
+ yo_ -
+ font_metrics::maxAscent(bv_.buffer()->params().getFont()) / 3;
pain_.line(last_strikeout_x, middle, int(x_), middle,
LColor::strikeout, Painter::line_solid, Painter::line_thin);
running_strikeout = false;
}
+lyx::size_type calculateRowSignature(Row const & row, Paragraph const & par,
+ int x, int y)
+{
+ boost::crc_32_type crc;
+ for (lyx::pos_type i = row.pos(); i < row.endpos(); ++i) {
+ const unsigned char b[] = { par.getChar(i) };
+ crc.process_bytes(b, 1);
+ }
+ const unsigned char b[] = { x, y, row.width() };
+ crc.process_bytes(b, 3);
+ return crc.checksum();
+}
+
+
+bool CursorOnRow(PainterInfo & pi, pit_type const pit,
+ RowList::const_iterator rit, LyXText const & text)
+{
+ // Is there a cursor on this row (or inside inset on row)
+ LCursor & cur = pi.base.bv->cursor();
+ for (lyx::size_type d = 0; d < cur.depth(); d++) {
+ CursorSlice const & sl = cur[d];
+ if (sl.text() == &text
+ && sl.pit() == pit
+ && sl.pos() >= rit->pos()
+ && sl.pos() < rit->endpos())
+ return true;
+ }
+ return false;
+}
+
+
+bool innerCursorOnRow(PainterInfo & pi, pit_type pit,
+ RowList::const_iterator rit, LyXText const & text)
+{
+ // Is there a cursor inside an inset on this row, and is this inset
+ // the only "character" on this row
+ LCursor & cur = pi.base.bv->cursor();
+ if (rit->pos() + 1 != rit->endpos())
+ return false;
+ for (lyx::size_type d = 0; d < cur.depth(); d++) {
+ CursorSlice const & sl = cur[d];
+ if (sl.text() == &text
+ && sl.pit() == pit
+ && sl.pos() == rit->pos())
+ return d < cur.depth() - 1;
+ }
+ return false;
+}
+
+
void paintPar
- (PainterInfo & pi, LyXText const & text, pit_type pit, int x, int y)
+ (PainterInfo & pi, LyXText const & text, pit_type pit, int x, int y,
+ bool repaintAll)
{
// lyxerr << " paintPar: pit: " << pit << " at y: " << y << endl;
static NullPainter nop;
theCoords.parPos()[&text][pit] = Point(x, y);
y -= rb->ascent();
- for (RowList::const_iterator rit = rb; rit != re; ++rit) {
+ lyx::size_type rowno(0);
+ for (RowList::const_iterator rit = rb; rit != re; ++rit, ++rowno) {
y += rit->ascent();
- bool const inside = (y + rit->descent() >= 0
- && y - rit->ascent() < ww);
- RowPainter rp(inside ? pi : nullpi, text, pit, *rit, x, y);
+ // Allow setting of bv->repaintAll() for nested insets in
+ // this row only
+ bool tmp = pi.base.bv->repaintAll();
+
+ // Row signature; has row changed since last paint?
+ lyx::size_type const row_sig = calculateRowSignature(*rit, par, x, y);
+ bool row_has_changed = par.rowSignature()[rowno] != row_sig;
+
+ bool cursor_on_row = CursorOnRow(pi, pit, rit, text);
+ bool in_inset_alone_on_row = innerCursorOnRow(pi, pit, rit,
+ text);
+
+ // If this is the only object on the row, we can make it wide
+ for (pos_type i = rit->pos() ; i != rit->endpos(); ++i) {
+ InsetBase* in
+ = const_cast<InsetBase*>(par.getInset(i));
+ if (isTrueTextInset(in))
+ static_cast<InsetText*>(in)->Wide()
+ = in_inset_alone_on_row;
+ }
+ // If selection is on, the current row signature differs
+ // from cache, or cursor is inside an inset _on this row_,
+ // then paint the row
+ if (repaintAll || row_has_changed || cursor_on_row) {
+ // Add to row signature cache
+ par.rowSignature()[rowno] = row_sig;
+
+ bool const inside = (y + rit->descent() >= 0
+ && y - rit->ascent() < ww);
+ RowPainter rp(inside ? pi : nullpi, text, pit, *rit, x, y);
+ // Clear background of this row
+ // (if paragraph background was not cleared)
+ if (!repaintAll &&
+ (!in_inset_alone_on_row || row_has_changed)) {
+ pi.pain.fillRectangle(( rowno ? 0 : x - 10 ), y - rit->ascent(),
+ pi.base.bv->workWidth(), rit->height(),
+ text.backgroundColor());
+ // If outer row has changed, force nested
+ // insets to repaint completely
+ if (row_has_changed)
+ pi.base.bv->repaintAll(true);
+ }
+
+ // Instrumentation for testing row cache (see also
+ // 12 lines lower):
+ if (text.isMainText())
+ lyxerr[Debug::PAINTING] << "#";
+ else
+ lyxerr[Debug::PAINTING] << "[" <<
+ repaintAll << row_has_changed <<
+ cursor_on_row << "]";
+ rp.paintAppendix();
+ rp.paintDepthBar();
+ rp.paintChangeBar();
+ if (rit == rb)
+ rp.paintFirst();
+ if (rit + 1 == re)
+ rp.paintLast();
+ rp.paintText();
+ }
y += rit->descent();
- rp.paintAppendix();
- rp.paintDepthBar();
- rp.paintChangeBar();
- if (rit == rb)
- rp.paintFirst();
- if (rit + 1 == re)
- rp.paintLast();
- rp.paintText();
+ // Restore, see above
+ pi.base.bv->repaintAll(tmp);
}
+ lyxerr[Debug::PAINTING] << "." << endl;
}
} // namespace anon
{
Painter & pain = bv.painter();
LyXText * const text = bv.text();
+ bool const select = bv.cursor().selection();
- // clear background
- pain.fillRectangle(0, vi.y1, bv.workWidth(), vi.y2 - vi.y1,
- LColor::background);
-
- // draw selection
PainterInfo pi(const_cast<BufferView *>(&bv), pain);
-
- text->drawSelection(pi, 0, 0);
+ // Should the whole screen, including insets, be refreshed?
+ bool repaintAll(select || !vi.singlepar);
+
+ if (repaintAll) {
+ // Clear background (if not delegated to rows)
+ pain.fillRectangle(0, vi.y1, bv.workWidth(), vi.y2 - vi.y1,
+ text->backgroundColor());
+ }
+ if (select) {
+ text->drawSelection(pi, 0, 0);
+ }
int yy = vi.y1;
// draw contents
for (pit_type pit = vi.p1; pit <= vi.p2; ++pit) {
- yy += text->getPar(pit).ascent();
- paintPar(pi, *bv.text(), pit, 0, yy);
- yy += text->getPar(pit).descent();
+ bv.repaintAll(repaintAll);
+ Paragraph const & par = text->getPar(pit);
+ yy += par.ascent();
+ paintPar(pi, *bv.text(), pit, 0, yy, repaintAll);
+ yy += par.descent();
}
// Cache one paragraph above and one below
// lyxerr << " paintTextInset: y: " << y << endl;
y -= text.getPar(0).ascent();
+ // This flag can not be set from within same inset:
+ bool repaintAll = pi.base.bv->repaintAll();
for (int pit = 0; pit < int(text.paragraphs().size()); ++pit) {
y += text.getPar(pit).ascent();
- paintPar(pi, text, pit, x, y);
+ paintPar(pi, text, pit, x, y, repaintAll);
y += text.getPar(pit).descent();
}
}