X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FTextMetrics.cpp;h=5bdd4c2755f98f286ff6b5ad31cc1dd073ed01ed;hb=7f17f13bfc2ad4e7cdd8ecfce23374e2b3d0c646;hp=9fd56f6b6f1e209ee2b4c5fcf34a8d34a98632ce;hpb=dfd9a1d53de2bbff6a5eb0c40383df92a1eac733;p=lyx.git diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 9fd56f6b6f..5bdd4c2755 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -22,18 +22,19 @@ #include "Buffer.h" #include "BufferParams.h" #include "BufferView.h" -#include "paragraph_funcs.h" -#include "ParIterator.h" +#include "Color.h" #include "CoordCache.h" #include "debug.h" -#include "FuncRequest.h" #include "FontIterator.h" -#include "Color.h" +#include "FuncRequest.h" #include "Length.h" #include "LyXRC.h" -#include "Text.h" #include "MetricsInfo.h" +#include "paragraph_funcs.h" #include "ParagraphParameters.h" +#include "ParIterator.h" +#include "rowpainter.h" +#include "Text.h" #include "VSpace.h" #include "frontends/FontMetrics.h" @@ -115,7 +116,7 @@ TextMetrics::TextMetrics(BufferView * bv, Text * text) dim_.asc = 10; dim_.des = 10; - //text_->updateLabels(*bv->buffer()); + //text_->updateLabels(bv->buffer()); } @@ -147,21 +148,21 @@ bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim) //lyxerr << "Text::metrics: width: " << mi.base.textwidth // << " maxWidth: " << max_width_ << "\nfont: " << mi.base.font << endl; - + bool changed = false; unsigned int h = 0; unsigned int w = 0; for (pit_type pit = 0, n = text_->paragraphs().size(); pit != n; ++pit) { changed |= redoParagraph(pit); - ParagraphMetrics const & pm = parMetrics(pit); + ParagraphMetrics const & pm = par_metrics_[pit]; h += pm.height(); if (w < pm.width()) w = pm.width(); } dim.wid = w; - dim.asc = parMetrics(0).ascent(); + dim.asc = par_metrics_[0].ascent(); dim.des = h - dim.asc; changed |= dim_ != dim; @@ -172,25 +173,31 @@ bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim) int TextMetrics::rightMargin(ParagraphMetrics const & pm) const { - return main_text_? pm.rightMargin(*bv_->buffer()) : 0; + return main_text_? pm.rightMargin(bv_->buffer()) : 0; } int TextMetrics::rightMargin(pit_type const pit) const { - return main_text_? par_metrics_[pit].rightMargin(*bv_->buffer()) : 0; + return main_text_? par_metrics_[pit].rightMargin(bv_->buffer()) : 0; } bool TextMetrics::redoParagraph(pit_type const pit) { Paragraph & par = text_->getPar(pit); - ParagraphMetrics pm(par); - Buffer & buffer = *bv_->buffer(); + // IMPORTANT NOTE: We pass 'false' explicitely in order to not call + // redoParagraph() recursively inside parMetrics. + Dimension old_dim = parMetrics(pit, false).dim(); + ParagraphMetrics & pm = par_metrics_[pit]; + pm.reset(par); + + Buffer & buffer = bv_->buffer(); + BufferParams const & bparams = buffer.params(); main_text_ = (text_ == &buffer.text()); bool changed = false; - // FIXME This check ought to be done somewhere else. It is the reason + // FIXME This check ought to be done somewhere else. It is the reason // why text_ is not const. But then, where else to do it? // Well, how can you end up with either (a) a biblio environment that // has no InsetBibitem or (b) a biblio environment with more than one @@ -216,6 +223,7 @@ bool TextMetrics::redoParagraph(pit_type const pit) InsetList::const_iterator ii = par.insetlist.begin(); InsetList::const_iterator iend = par.insetlist.end(); for (; ii != iend; ++ii) { + Dimension old_dim = ii->inset->dimension(); Dimension dim; int const w = max_width_ - text_->leftMargin(buffer, max_width_, pit, ii->pos) - right_margin; @@ -223,75 +231,78 @@ bool TextMetrics::redoParagraph(pit_type const pit) bufferfont : text_->getFont(buffer, par, ii->pos); MetricsInfo mi(bv_, font, w); changed |= ii->inset->metrics(mi, dim); + changed |= (old_dim != dim); } - // rebreak the paragraph - pm.rows().clear(); - par.setBeginOfBody(); - pos_type z = 0; + pos_type first = 0; + size_t row_index = 0; // maximum pixel width of a row int width = max_width_ - right_margin; // - leftMargin(buffer, max_width_, pit, row); do { - Row row(z); - rowBreakPoint(width, pit, row); - setRowWidth(right_margin, pit, row); - setHeightOfRow(pit, row); - pm.rows().push_back(row); - pm.dim().wid = std::max(pm.dim().wid, row.width()); - pm.dim().des += row.height(); - z = row.endpos(); - } while (z < par.size()); + Dimension dim; + pos_type end = rowBreakPoint(width, pit, first); + dim.wid = rowWidth(right_margin, pit, first, end); + boost::tie(dim.asc, dim.des) = rowHeight(pit, first, end); + if (row_index == pm.rows().size()) + pm.rows().push_back(Row()); + Row & row = pm.rows()[row_index]; + row.pos(first); + row.endpos(end); + row.setDimension(dim); + computeRowMetrics(pit, row); + pm.computeRowSignature(row, bparams); + first = end; + ++row_index; + + pm.dim().wid = std::max(pm.dim().wid, dim.wid); + pm.dim().des += dim.height(); + } while (first < par.size()); + + if (row_index < pm.rows().size()) + pm.rows().resize(row_index); // Make sure that if a par ends in newline, there is one more row // under it - // FIXME this is a dirty trick. Now the _same_ position in the - // paragraph occurs in _two_ different rows, and has two different - // display positions, leading to weird behaviour when moving up/down. - if (z > 0 && par.isNewline(z - 1)) { - Row row(z - 1); - row.endpos(z - 1); - setRowWidth(right_margin, pit, row); - setHeightOfRow(pit, row); - pm.rows().push_back(row); - pm.dim().des += row.height(); + if (first > 0 && par.isNewline(first - 1)) { + Dimension dim; + dim.wid = rowWidth(right_margin, pit, first, first); + boost::tie(dim.asc, dim.des) = rowHeight(pit, first, first); + if (row_index == pm.rows().size()) + pm.rows().push_back(Row()); + Row & row = pm.rows()[row_index]; + row.pos(first); + row.endpos(first); + row.setDimension(dim); + computeRowMetrics(pit, row); + pm.computeRowSignature(row, bparams); + pm.dim().des += dim.height(); } pm.dim().asc += pm.rows()[0].ascent(); pm.dim().des -= pm.rows()[0].ascent(); - // IMPORTANT NOTE: We pass 'false' explicitely in order to not call - // redoParagraph() recursively inside parMetrics. - Dimension old_dim = parMetrics(pit, false).dim(); - changed |= old_dim.height() != pm.dim().height(); - par_metrics_[pit] = pm; - - // Update the row change statuses. The painter will need that info - // in order to know which row has to be repainted. - par_metrics_[pit].updateRowChangeStatus(); - return changed; } -RowMetrics TextMetrics::computeRowMetrics(pit_type const pit, - Row const & row) const +void TextMetrics::computeRowMetrics(pit_type const pit, + Row & row) const { - RowMetrics result; - Buffer & buffer = *bv_->buffer(); + Buffer & buffer = bv_->buffer(); Paragraph const & par = text_->getPar(pit); double w = dim_.wid - row.width(); bool const is_rtl = text_->isRTL(buffer, par); if (is_rtl) - result.x = rightMargin(pit); + row.x = rightMargin(pit); else - result.x = text_->leftMargin(buffer, max_width_, pit, row.pos()); + row.x = text_->leftMargin(buffer, max_width_, pit, row.pos()); // is there a manual margin with a manual label - Layout_ptr const & layout = par.layout(); + LayoutPtr const & layout = par.layout(); if (layout->margintype == MARGIN_MANUAL && layout->labeltype == LABEL_MANUAL) { @@ -307,7 +318,7 @@ RowMetrics TextMetrics::computeRowMetrics(pit_type const pit, ++nlh; if (nlh && !par.getLabelWidthString().empty()) - result.label_hfill = labelFill(par, row) / double(nlh); + row.label_hfill = labelFill(pit, row) / double(nlh); } // are there any hfills in the row? @@ -315,7 +326,7 @@ RowMetrics TextMetrics::computeRowMetrics(pit_type const pit, if (nh) { if (w > 0) - result.hfill = w / nh; + row.hfill = w / nh; // we don't have to look at the alignment if it is ALIGN_LEFT and // if the row is already larger then the permitted width as then // we force the LEFT_ALIGN'edness! @@ -332,7 +343,7 @@ RowMetrics TextMetrics::computeRowMetrics(pit_type const pit, // The test on par.size() is to catch zero-size pars, which // would trigger the assert in Paragraph::getInset(). //inset = par.size() ? par.getInset(row.pos()) : 0; - if (!par.empty() + if (row.pos() < par.size() && par.isInset(row.pos())) { switch(par.getInset(row.pos())->display()) { @@ -342,8 +353,11 @@ RowMetrics TextMetrics::computeRowMetrics(pit_type const pit, case Inset::AlignCenter: align = LYX_ALIGN_CENTER; break; - // other types unchanged (use align) - } + case Inset::Inline: + case Inset::AlignRight: + // unchanged (use align) + break; + } } switch (align) { @@ -363,22 +377,21 @@ RowMetrics TextMetrics::computeRowMetrics(pit_type const pit, && !par.isNewline(row.endpos() - 1) && !disp_inset ) { - result.separator = w / ns; + row.separator = w / ns; } else if (is_rtl) { - result.x += w; + row.x += w; } break; } case LYX_ALIGN_RIGHT: - result.x += w; + row.x += w; break; case LYX_ALIGN_CENTER: - result.x += w / 2; + row.x += w / 2; break; } } - text_->bidi.computeTables(par, buffer, row); if (is_rtl) { pos_type body_pos = par.beginOfBody(); pos_type end = row.endpos(); @@ -386,20 +399,19 @@ RowMetrics TextMetrics::computeRowMetrics(pit_type const pit, if (body_pos > 0 && (body_pos > end || !par.isLineSeparator(body_pos - 1))) { - docstring const lsep = from_utf8(layout->labelsep); - result.x += theFontMetrics(text_->getLabelFont(buffer, par)).width(lsep); + row.x += theFontMetrics(text_->getLabelFont(buffer, par)). + width(layout->labelsep); if (body_pos <= end) - result.x += result.label_hfill; + row.x += row.label_hfill; } } - - return result; } -int TextMetrics::labelFill(Paragraph const & par, Row const & row) const +int TextMetrics::labelFill(pit_type const pit, Row const & row) const { - Buffer & buffer = *bv_->buffer(); + Buffer & buffer = bv_->buffer(); + Paragraph const & par = text_->getPar(pit); pos_type last = par.beginOfBody(); BOOST_ASSERT(last > 0); @@ -413,13 +425,13 @@ int TextMetrics::labelFill(Paragraph const & par, Row const & row) const int w = 0; for (pos_type i = row.pos(); i <= last; ++i) - w += text_->singleWidth(buffer, par, i); + w += singleWidth(pit, i); docstring const & label = par.params().labelWidthString(); if (label.empty()) return 0; - FontMetrics const & fm + FontMetrics const & fm = theFontMetrics(text_->getLabelFont(buffer, par)); return max(0, fm.width(label) - w); @@ -449,33 +461,24 @@ int TextMetrics::labelEnd(pit_type const pit) const if (text_->getPar(pit).layout()->margintype != MARGIN_MANUAL) return 0; // return the beginning of the body - return text_->leftMargin(*bv_->buffer(), max_width_, pit); + return text_->leftMargin(bv_->buffer(), max_width_, pit); } -void TextMetrics::rowBreakPoint(int width, pit_type const pit, - Row & row) const +pit_type TextMetrics::rowBreakPoint(int width, pit_type const pit, + pit_type pos) const { - Buffer & buffer = *bv_->buffer(); + Buffer & buffer = bv_->buffer(); + ParagraphMetrics const & pm = par_metrics_[pit]; Paragraph const & par = text_->getPar(pit); pos_type const end = par.size(); - pos_type const pos = row.pos(); - if (pos == end) { - row.endpos(end); - return; - } + if (pos == end || width < 0) + return end; - if (width < 0) { - row.endpos(end); - return; - } + LayoutPtr const & layout = par.layout(); - Layout_ptr const & layout = par.layout(); - - if (layout->margintype == MARGIN_RIGHT_ADDRESS_BOX) { - row.endpos(addressBreakPoint(pos, par)); - return; - } + if (layout->margintype == MARGIN_RIGHT_ADDRESS_BOX) + return addressBreakPoint(pos, par); pos_type const body_pos = par.beginOfBody(); @@ -494,17 +497,16 @@ void TextMetrics::rowBreakPoint(int width, pit_type const pit, FontIterator fi = FontIterator(buffer, *text_, par, pos); pos_type point = end; pos_type i = pos; - FontMetrics const & fm = theFontMetrics(text_->getLabelFont(buffer, par)); for ( ; i < end; ++i, ++fi) { - char_type const c = par.getChar(i); - int thiswidth = text_->singleWidth(par, i, c, *fi); + int thiswidth = pm.singleWidth(i, *fi); // add the auto-hfill from label end to the body if (body_pos && i == body_pos) { - docstring lsep = from_utf8(layout->labelsep); - int add = fm.width(lsep); + FontMetrics const & fm = theFontMetrics( + text_->getLabelFont(buffer, par)); + int add = fm.width(layout->labelsep); if (par.isLineSeparator(i - 1)) - add -= text_->singleWidth(buffer, par, i - 1); + add -= singleWidth(pit, i - 1); add = std::max(add, label_end - x); thiswidth += add; @@ -565,54 +567,53 @@ void TextMetrics::rowBreakPoint(int width, pit_type const pit, if (body_pos && point < body_pos) point = body_pos; - row.endpos(point); + return point; } -void TextMetrics::setRowWidth(int right_margin, - pit_type const pit, Row & row) const +int TextMetrics::rowWidth(int right_margin, pit_type const pit, + pos_type const first, pos_type const end) const { - Buffer & buffer = *bv_->buffer(); + Buffer & buffer = bv_->buffer(); // get the pure distance - pos_type const end = row.endpos(); - + ParagraphMetrics const & pm = par_metrics_[pit]; Paragraph const & par = text_->getPar(pit); - docstring const labelsep = from_utf8(par.layout()->labelsep); - int w = text_->leftMargin(buffer, max_width_, pit, row.pos()); + int w = text_->leftMargin(buffer, max_width_, pit, first); int label_end = labelEnd(pit); pos_type const body_pos = par.beginOfBody(); - pos_type i = row.pos(); - - FontMetrics const & fm = theFontMetrics(text_->getLabelFont(buffer, par)); + pos_type i = first; if (i < end) { FontIterator fi = FontIterator(buffer, *text_, par, i); for ( ; i < end; ++i, ++fi) { if (body_pos > 0 && i == body_pos) { - w += fm.width(labelsep); + FontMetrics const & fm = theFontMetrics( + text_->getLabelFont(buffer, par)); + w += fm.width(par.layout()->labelsep); if (par.isLineSeparator(i - 1)) - w -= text_->singleWidth(buffer, par, i - 1); + w -= singleWidth(pit, i - 1); w = max(w, label_end); } - char_type const c = par.getChar(i); - w += text_->singleWidth(par, i, c, *fi); + w += pm.singleWidth(i, *fi); } } if (body_pos > 0 && body_pos >= end) { - w += fm.width(labelsep); + FontMetrics const & fm = theFontMetrics( + text_->getLabelFont(buffer, par)); + w += fm.width(par.layout()->labelsep); if (end > 0 && par.isLineSeparator(end - 1)) - w -= text_->singleWidth(buffer, par, end - 1); + w -= singleWidth(pit, end - 1); w = max(w, label_end); } - row.width(w + right_margin); + return w + right_margin; } -void TextMetrics::setHeightOfRow(pit_type const pit, - Row & row) +boost::tuple TextMetrics::rowHeight(pit_type const pit, pos_type const first, + pos_type const end) const { Paragraph const & par = text_->getPar(pit); // get the maximum ascent and the maximum descent @@ -623,14 +624,14 @@ void TextMetrics::setHeightOfRow(pit_type const pit, // ok, let us initialize the maxasc and maxdesc value. // Only the fontsize count. The other properties // are taken from the layoutfont. Nicer on the screen :) - Layout_ptr const & layout = par.layout(); + LayoutPtr const & layout = par.layout(); // as max get the first character of this row then it can // increase but not decrease the height. Just some point to // start with so we don't have to do the assignment below too // often. - Buffer const & buffer = *bv_->buffer(); - Font font = text_->getFont(buffer, par, row.pos()); + Buffer const & buffer = bv_->buffer(); + Font font = text_->getFont(buffer, par, first); Font::FONT_SIZE const tmpsize = font.size(); font = text_->getLayoutFont(buffer, pit); Font::FONT_SIZE const size = font.size(); @@ -652,7 +653,7 @@ void TextMetrics::setHeightOfRow(pit_type const pit, InsetList::const_iterator ii = par.insetlist.begin(); InsetList::const_iterator iend = par.insetlist.end(); for ( ; ii != iend; ++ii) { - if (ii->pos >= row.pos() && ii->pos < row.endpos()) { + if (ii->pos >= first && ii->pos < end) { maxasc = max(maxasc, ii->inset->ascent()); maxdesc = max(maxdesc, ii->inset->descent()); } @@ -662,25 +663,26 @@ void TextMetrics::setHeightOfRow(pit_type const pit, // This is not completely correct, but we can live with the small, // cosmetic error for now. int labeladdon = 0; - pos_type const pos_end = row.endpos(); Font::FONT_SIZE maxsize = - par.highestFontInRange(row.pos(), pos_end, size); + par.highestFontInRange(first, end, size); if (maxsize > font.size()) { - font.setSize(maxsize); - maxasc = max(maxasc, fontmetrics.maxAscent()); - maxdesc = max(maxdesc, fontmetrics.maxDescent()); + // use standard paragraph font with the maximal size + Font maxfont = font; + maxfont.setSize(maxsize); + FontMetrics const & maxfontmetrics = theFontMetrics(maxfont); + maxasc = max(maxasc, maxfontmetrics.maxAscent()); + maxdesc = max(maxdesc, maxfontmetrics.maxDescent()); } // This is nicer with box insets: ++maxasc; ++maxdesc; - row.ascent(maxasc); ParagraphList const & pars = text_->paragraphs(); // is it a top line? - if (row.pos() == 0) { + if (first == 0) { BufferParams const & bufparams = buffer.params(); // some parskips VERY EASY IMPLEMENTATION if (bufparams.paragraph_separation @@ -733,7 +735,7 @@ void TextMetrics::setHeightOfRow(pit_type const pit, && prevpar.getLabelWidthString() == par.getLabelWidthString()) { layoutasc = layout->itemsep * dh; - } else if (pit != 0 || row.pos() != 0) { + } else if (pit != 0 || first != 0) { if (layout->topsep > 0) layoutasc = layout->topsep * dh; } @@ -751,7 +753,7 @@ void TextMetrics::setHeightOfRow(pit_type const pit, } // is it a bottom line? - if (row.endpos() >= par.size()) { + if (end >= par.size()) { // add the layout spaces, for example before and after // a section, or between the items of a itemize or enumerate // environment @@ -782,20 +784,20 @@ void TextMetrics::setHeightOfRow(pit_type const pit, maxasc += int(layoutasc * 2 / (2 + pars[pit].getDepth())); maxdesc += int(layoutdesc * 2 / (2 + pars[pit].getDepth())); - // FIXME: the correct way is to do the following is to move the - // following code in another method specially tailored for the + // FIXME: the correct way is to do the following is to move the + // following code in another method specially tailored for the // main Text. The following test is thus bogus. // Top and bottom margin of the document (only at top-level) if (main_text_) { - if (pit == 0 && row.pos() == 0) + if (pit == 0 && first == 0) maxasc += 20; if (pit + 1 == pit_type(pars.size()) && - row.endpos() == par.size()) + end == par.size() && + !(end > 0 && par.isNewline(end - 1))) maxdesc += 20; } - row.ascent(maxasc + labeladdon); - row.descent(maxdesc); + return boost::make_tuple(maxasc + labeladdon, maxdesc); } @@ -805,26 +807,27 @@ void TextMetrics::setHeightOfRow(pit_type const pit, pos_type TextMetrics::getColumnNearX(pit_type const pit, Row const & row, int & x, bool & boundary) const { - Buffer const & buffer = *bv_->buffer(); + Buffer const & buffer = bv_->buffer(); /// For the main Text, it is possible that this pit is not /// yet in the CoordCache when moving cursor up. /// x Paragraph coordinate is always 0 for main text anyway. int const xo = main_text_? 0 : bv_->coordCache().get(text_, pit).x_; x -= xo; - RowMetrics const r = computeRowMetrics(pit, row); Paragraph const & par = text_->getPar(pit); + Bidi bidi; + bidi.computeTables(par, buffer, row); pos_type vc = row.pos(); pos_type end = row.endpos(); pos_type c = 0; - Layout_ptr const & layout = par.layout(); + LayoutPtr const & layout = par.layout(); bool left_side = false; pos_type body_pos = par.beginOfBody(); - double tmpx = r.x; + double tmpx = row.x; double last_tmpx = tmpx; if (body_pos > 0 && @@ -837,32 +840,29 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit, return 0; } - frontend::FontMetrics const & fm - = theFontMetrics(text_->getLabelFont(buffer, par)); - while (vc < end && tmpx <= x) { - c = text_->bidi.vis2log(vc); + c = bidi.vis2log(vc); last_tmpx = tmpx; if (body_pos > 0 && c == body_pos - 1) { - // FIXME UNICODE - docstring const lsep = from_utf8(layout->labelsep); - tmpx += r.label_hfill + fm.width(lsep); + FontMetrics const & fm = theFontMetrics( + text_->getLabelFont(buffer, par)); + tmpx += row.label_hfill + fm.width(layout->labelsep); if (par.isLineSeparator(body_pos - 1)) - tmpx -= text_->singleWidth(buffer, par, body_pos - 1); + tmpx -= singleWidth(pit, body_pos - 1); } if (par.hfillExpansion(row, c)) { - tmpx += text_->singleWidth(buffer, par, c); + tmpx += singleWidth(pit, c); if (c >= body_pos) - tmpx += r.hfill; + tmpx += row.hfill; else - tmpx += r.label_hfill; + tmpx += row.label_hfill; } else if (par.isSeparator(c)) { - tmpx += text_->singleWidth(buffer, par, c); + tmpx += singleWidth(pit, c); if (c >= body_pos) - tmpx += r.separator; + tmpx += row.separator; } else { - tmpx += text_->singleWidth(buffer, par, c); + tmpx += singleWidth(pit, c); } ++vc; } @@ -887,15 +887,15 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit, (!rtl && !left_side && vc == end && x > tmpx + 5))) c = end; else if (vc == row.pos()) { - c = text_->bidi.vis2log(vc); - if (text_->bidi.level(c) % 2 == 1) + c = bidi.vis2log(vc); + if (bidi.level(c) % 2 == 1) ++c; } else { - c = text_->bidi.vis2log(vc - 1); - bool const rtl = (text_->bidi.level(c) % 2 == 1); + c = bidi.vis2log(vc - 1); + bool const rtl = (bidi.level(c) % 2 == 1); if (left_side == rtl) { ++c; - boundary = text_->bidi.isBoundary(buffer, par, c); + boundary = text_->isRTLBoundary(buffer, par, c); } } @@ -908,10 +908,10 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit, // specially, so cursor up/down doesn't get stuck in an air gap -- MV // Newline inset, air gap below: if (row.pos() < end && c >= end && par.isNewline(end - 1)) { - if (text_->bidi.level(end -1) % 2 == 0) - tmpx -= text_->singleWidth(buffer, par, end - 1); + if (bidi.level(end -1) % 2 == 0) + tmpx -= singleWidth(pit, end - 1); else - tmpx += text_->singleWidth(buffer, par, end - 1); + tmpx += singleWidth(pit, end - 1); c = end - 1; } @@ -944,7 +944,7 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit, pos_type TextMetrics::x2pos(pit_type pit, int row, int x) const { - ParagraphMetrics const & pm = parMetrics(pit); + ParagraphMetrics const & pm = par_metrics_[pit]; BOOST_ASSERT(!pm.rows().empty()); BOOST_ASSERT(row < int(pm.rows().size())); bool bound = false; @@ -953,9 +953,99 @@ pos_type TextMetrics::x2pos(pit_type pit, int row, int x) const } +int TextMetrics::singleWidth(pit_type pit, pos_type pos) const +{ + Buffer const & buffer = bv_->buffer(); + ParagraphMetrics const & pm = par_metrics_[pit]; + + return pm.singleWidth(pos, text_->getFont(buffer, text_->getPar(pit), pos)); +} + + +// only used for inset right now. should also be used for main text +void TextMetrics::draw(PainterInfo & pi, int x, int y) const +{ + if (par_metrics_.empty()) + return; + ParMetricsCache::const_iterator it = par_metrics_.begin(); + ParMetricsCache::const_iterator const end = par_metrics_.end(); + y -= it->second.ascent(); + for (; it != end; ++it) { + ParagraphMetrics const & pmi = it->second; + y += pmi.ascent(); + drawParagraph(pi, it->first, x, y, true); + y += pmi.descent(); + } +} + + +void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y, + bool repaintAll) const +{ +// lyxerr << " paintPar: pit: " << pit << " at y: " << y << endl; + int const ww = bv_->workHeight(); + + bv_->coordCache().parPos()[text_][pit] = Point(x, y); + + ParagraphMetrics const & pm = par_metrics_[pit]; + if (pm.rows().empty()) + return; + + RowList::const_iterator const rb = pm.rows().begin(); + RowList::const_iterator const re = pm.rows().end(); + + Bidi bidi; + + y -= rb->ascent(); + for (RowList::const_iterator rit = rb; rit != re; ++rit) { + y += rit->ascent(); + // Row signature; has row changed since last paint? + bool row_has_changed = rit->changed(); + + // Paint the row if a full repaint has been requested or it has + // changed. + if (repaintAll || row_has_changed) { + bool const inside = (y + rit->descent() >= 0 + && y - rit->ascent() < ww); + // it is not needed to draw on screen if we are not inside. + pi.pain.setDrawingEnabled(inside); + RowPainter rp(pi, *text_, pit, *rit, bidi, x, y); + // Clear background of this row + // (if paragraph background was not cleared) + if (!repaintAll && row_has_changed) + pi.pain.fillRectangle(x, y - rit->ascent(), + width(), rit->height(), + text_->backgroundColor()); + + // Instrumentation for testing row cache (see also + // 12 lines lower): + if (lyxerr.debugging(Debug::PAINTING)) { + if (text_->isMainText(bv_->buffer())) + LYXERR(Debug::PAINTING) << "#"; + else + LYXERR(Debug::PAINTING) << "[" << + repaintAll << row_has_changed << "]"; + } + rp.paintAppendix(); + rp.paintDepthBar(); + rp.paintChangeBar(); + if (rit == rb) + rp.paintFirst(); + rp.paintText(); + if (rit + 1 == re) + rp.paintLast(); + } + y += rit->descent(); + } + // Re-enable screen drawing for future use of the painter. + pi.pain.setDrawingEnabled(true); + + LYXERR(Debug::PAINTING) << "." << endl; +} + //int Text::pos2x(pit_type pit, pos_type pos) const //{ -// ParagraphMetrics const & pm = parMetrics(pit); +// ParagraphMetrics const & pm = par_metrics_[pit]; // Row const & r = pm.rows()[row]; // int x = 0; // pos -= r.pos();