]> git.lyx.org Git - lyx.git/blobdiff - src/TextMetrics.cpp
Get package things working with modules prior to UI patch.
[lyx.git] / src / TextMetrics.cpp
index 9fd56f6b6f1e209ee2b4c5fcf34a8d34a98632ce..5bdd4c2755f98f286ff6b5ad31cc1dd073ed01ed 100644 (file)
 #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<int, int> 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();