Introducing FontList.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21062 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Abdelrazak Younes 2007-10-19 14:35:05 +00:00
parent 58d8b766bf
commit 4d9007bd61
4 changed files with 294 additions and 153 deletions

168
src/FontList.cpp Normal file
View File

@ -0,0 +1,168 @@
/**
* \file FontList.cpp
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Asger Alstrup
* \author Lars Gullik Bjønnes
* \author Jean-Marc Lasgouttes
* \author Angus Leeming
* \author John Levon
* \author André Pönitz
* \author Dekel Tsur
* \author Jürgen Vigna
* \author Abdelrazak Younes
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "FontList.h"
#include <boost/next_prior.hpp>
#include <algorithm>
using std::distance;
using std::endl;
using std::string;
using std::ostream;
namespace lyx {
FontList::iterator FontList::fontIterator(pos_type pos)
{
static Font dummy;
FontTable search_elem(pos, dummy);
return lower_bound(list_.begin(), list_.end(), search_elem,
matchFT());
}
FontList::const_iterator FontList::fontIterator(pos_type pos) const
{
static Font dummy;
FontTable search_elem(pos, dummy);
return lower_bound(list_.begin(), list_.end(), search_elem,
matchFT());
}
Font & FontList::get(pos_type pos)
{
iterator end = list_.end();
iterator it = fontIterator(pos);
if (it != end && it->pos == pos)
return it->font_;
static Font dummy;
return dummy;
}
void FontList::erase(pos_type pos)
{
// Erase entries in the tables.
iterator it = fontIterator(pos);
iterator beg = list_.begin();
if (it != list_.end() && it->pos() == pos
&& (pos == 0
|| (it != beg && boost::prior(it)->pos() == pos - 1))) {
// If it is a multi-character font
// entry, we just make it smaller
// (see update below), otherwise we
// should delete it.
unsigned int const i = it - beg;
list_.erase(beg + i);
it = beg + i;
if (i > 0 && i < list_.size() &&
list_[i - 1].font() == list_[i].font()) {
list_.erase(beg + i - 1);
it = beg + i - 1;
}
}
// Update all other entries
iterator end = list_.end();
for (; it != end; ++it)
it->pos(it->pos() - 1);
}
void FontList::increasePosAfterPos(pos_type pos)
{
List::iterator end = list_.end();
List::iterator it = fontIterator(pos);
for (; it != end; ++it)
++it->pos_;
}
void FontList::decreasePosAfterPos(pos_type pos)
{
List::iterator end = list_.end();
List::iterator it = fontIterator(pos);
for (; it != end; ++it)
--it->pos_;
}
void FontList::set(pos_type pos, Font const & font)
{
// No need to simplify this because it will disappear
// in a new kernel. (Asger)
// Next search font table
iterator beg = list_.begin();
iterator it = beg;
iterator endit = list_.end();
for (; it != endit; ++it) {
if (it->pos() >= pos)
break;
}
size_t const i = distance(beg, it);
bool notfound = (it == endit);
if (!notfound && list_[i].font() == font)
return;
bool begin = pos == 0 || notfound ||
(i > 0 && list_[i - 1].pos() == pos - 1);
// Is position pos is a beginning of a font block?
bool end = !notfound && list_[i].pos() == pos;
// Is position pos is the end of a font block?
if (begin && end) { // A single char block
if (i + 1 < list_.size() &&
list_[i + 1].font() == font) {
// Merge the singleton block with the next block
list_.erase(list_.begin() + i);
if (i > 0 && list_[i - 1].font() == font)
list_.erase(list_.begin() + i - 1);
} else if (i > 0 && list_[i - 1].font() == font) {
// Merge the singleton block with the previous block
list_[i - 1].pos(pos);
list_.erase(list_.begin() + i);
} else
list_[i].font(font);
} else if (begin) {
if (i > 0 && list_[i - 1].font() == font)
list_[i - 1].pos(pos);
else
list_.insert(list_.begin() + i,
FontTable(pos, font));
} else if (end) {
list_[i].pos(pos - 1);
if (!(i + 1 < list_.size() &&
list_[i + 1].font() == font))
list_.insert(list_.begin() + i + 1,
FontTable(pos, font));
} else { // The general case. The block is splitted into 3 blocks
list_.insert(list_.begin() + i,
FontTable(pos - 1, list_[i].font()));
list_.insert(list_.begin() + i + 1,
FontTable(pos, font));
}
}
} // namespace lyx

116
src/FontList.h Normal file
View File

@ -0,0 +1,116 @@
/**
* \file FontList.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Abdelrazak Younes
*
* Full author contact details are available in file CREDITS.
*/
#ifndef FONT_LIST_H
#define FONT_LIST_H
#include "Font.h"
#include "support/types.h"
#include <vector>
namespace lyx {
/** A font entry covers a range of positions. Notice that the
entries in the list are inserted in random order.
I don't think it's worth the effort to implement a more effective
datastructure, because the number of different fonts in a paragraph
is limited. (Asger)
Nevertheless, I decided to store fontlist_ using a sorted vector:
fontlist_ = { {pos_1,font_1} , {pos_2,font_2} , ... } where
pos_1 < pos_2 < ..., font_{i-1} != font_i for all i,
and font_i covers the chars in positions pos_{i-1}+1,...,pos_i
(font_1 covers the chars 0,...,pos_1) (Dekel)
*/
class FontTable
{
public:
///
FontTable(pos_type p, Font const & f)
: pos_(p), font_(f)
{}
///
pos_type pos() const { return pos_; }
///
void pos(pos_type p) { pos_ = p; }
///
Font const & font() const { return font_; }
///
void font(Font const & f) { font_ = f;}
private:
friend class FontList;
/// End position of paragraph this font attribute covers
pos_type pos_;
/** Font. Interpretation of the font values:
If a value is Font::INHERIT_*, it means that the font
attribute is inherited from either the layout of this
paragraph or, in the case of nested paragraphs, from the
layout in the environment one level up until completely
resolved.
The values Font::IGNORE_* and Font::TOGGLE are NOT
allowed in these font tables.
*/
Font font_;
};
class matchFT
{
public:
/// used by lower_bound and upper_bound
int operator()(FontTable const & a, FontTable const & b) const {
return a.pos() < b.pos();
}
};
///
class FontList
{
public:
typedef std::vector<FontTable> List;
///
typedef List::iterator iterator;
///
typedef List::const_iterator const_iterator;
///
iterator begin() { return list_.begin(); }
///
iterator end() { return list_.end(); }
///
const_iterator begin() const { return list_.begin(); }
///
const_iterator end() const { return list_.end(); }
///
bool empty() const { return list_.empty(); }
///
void erase(pos_type pos);
///
iterator fontIterator(pos_type pos);
///
const_iterator fontIterator(pos_type pos) const;
///
Font & get(pos_type pos);
///
void set(pos_type pos, Font const & font);
///
void increasePosAfterPos(pos_type pos);
///
void decreasePosAfterPos(pos_type pos);
private:
///
List list_;
};
} // namespace lyx
#endif

View File

@ -142,6 +142,8 @@ liblyxcore_la_SOURCES = \
Font.h \
FontIterator.cpp \
FontIterator.h \
FontList.cpp \
FontList.h \
Format.cpp \
Format.h \
FuncRequest.cpp \

View File

@ -33,6 +33,7 @@
#include "Layout.h"
#include "Length.h"
#include "Font.h"
#include "FontList.h"
#include "LyXRC.h"
#include "Messages.h"
#include "OutputParams.h"
@ -73,63 +74,6 @@ using support::suffixIs;
using support::rsplit;
using support::rtrim;
namespace {
/** A font entry covers a range of positions. Notice that the
entries in the list are inserted in random order.
I don't think it's worth the effort to implement a more effective
datastructure, because the number of different fonts in a paragraph
is limited. (Asger)
Nevertheless, I decided to store fontlist_ using a sorted vector:
fontlist_ = { {pos_1,font_1} , {pos_2,font_2} , ... } where
pos_1 < pos_2 < ..., font_{i-1} != font_i for all i,
and font_i covers the chars in positions pos_{i-1}+1,...,pos_i
(font_1 covers the chars 0,...,pos_1) (Dekel)
*/
class FontTable
{
public:
///
FontTable(pos_type p, Font const & f)
: pos_(p), font_(f)
{}
///
pos_type pos() const { return pos_; }
///
void pos(pos_type p) { pos_ = p; }
///
Font const & font() const { return font_; }
///
void font(Font const & f) { font_ = f;}
private:
/// End position of paragraph this font attribute covers
pos_type pos_;
/** Font. Interpretation of the font values:
If a value is Font::INHERIT_*, it means that the font
attribute is inherited from either the layout of this
paragraph or, in the case of nested paragraphs, from the
layout in the environment one level up until completely
resolved.
The values Font::IGNORE_* and Font::TOGGLE are NOT
allowed in these font tables.
*/
Font font_;
};
class matchFT
{
public:
/// used by lower_bound and upper_bound
int operator()(FontTable const & a, FontTable const & b) const {
return a.pos() < b.pos();
}
};
typedef std::vector<FontTable> FontList;
}
/////////////////////////////////////////////////////////////////////
//
@ -137,10 +81,6 @@ typedef std::vector<FontTable> FontList;
//
/////////////////////////////////////////////////////////////////////
class Encoding;
class Layout;
class Paragraph::Private
{
public:
@ -441,13 +381,7 @@ void Paragraph::Private::insertChar(pos_type pos, value_type c,
owner_->text_.insert(owner_->text_.begin() + pos, c);
// Update the font table.
FontTable search_font(pos, Font());
for (FontList::iterator it
= lower_bound(fontlist_.begin(), fontlist_.end(), search_font, matchFT());
it != fontlist_.end(); ++it)
{
it->pos(it->pos() + 1);
}
fontlist_.increasePosAfterPos(pos);
// Update the insets
insetlist_.increasePosAfterPos(pos);
@ -461,7 +395,7 @@ void Paragraph::insertInset(pos_type pos, Inset * inset,
BOOST_ASSERT(pos >= 0 && pos <= size());
d->insertChar(pos, META_INSET, change);
BOOST_ASSERT(d->owner_->text_[pos] == META_INSET);
BOOST_ASSERT(text_[pos] == META_INSET);
// Add a new entry in the insetlist_.
d->insetlist_.insert(inset, pos);
@ -507,36 +441,8 @@ bool Paragraph::eraseChar(pos_type pos, bool trackChanges)
text_.erase(text_.begin() + pos);
// Erase entries in the tables.
FontTable search_font(pos, Font());
FontList::iterator it =
lower_bound(d->fontlist_.begin(),
d->fontlist_.end(),
search_font, matchFT());
FontList::iterator begin = d->fontlist_.begin();
if (it != d->fontlist_.end() && it->pos() == pos &&
(pos == 0 ||
(it != begin
&& boost::prior(it)->pos() == pos - 1))) {
// If it is a multi-character font
// entry, we just make it smaller
// (see update below), otherwise we
// should delete it.
unsigned int const i = it - begin;
d->fontlist_.erase(begin + i);
it = begin + i;
if (i > 0 && i < d->fontlist_.size() &&
d->fontlist_[i - 1].font() == d->fontlist_[i].font()) {
d->fontlist_.erase(begin + i - 1);
it = begin + i - 1;
}
}
// Update all other entries
FontList::iterator fend = d->fontlist_.end();
for (; it != fend; ++it)
it->pos(it->pos() - 1);
// Update the fontlist_
d->fontlist_.erase(pos);
// Update the insetlist_
d->insetlist_.decreasePosAfterPos(pos);
@ -1380,7 +1286,7 @@ FontSpan Paragraph::fontSpan(pos_type pos) const
Font const Paragraph::getFirstFontSettings(BufferParams const & bparams) const
{
if (!empty() && !d->fontlist_.empty())
return d->fontlist_[0].font();
return d->fontlist_.begin()->font();
return Font(Font::ALL_INHERIT, bparams.language);
}
@ -1516,59 +1422,8 @@ void Paragraph::setFont(pos_type pos, Font const & font)
// First, reduce font against layout/label font
// Update: The setCharFont() routine in text2.cpp already
// reduces font, so we don't need to do that here. (Asger)
// No need to simplify this because it will disappear
// in a new kernel. (Asger)
// Next search font table
FontList::iterator beg = d->fontlist_.begin();
FontList::iterator it = beg;
FontList::iterator endit = d->fontlist_.end();
for (; it != endit; ++it) {
if (it->pos() >= pos)
break;
}
size_t const i = distance(beg, it);
bool notfound = (it == endit);
if (!notfound && d->fontlist_[i].font() == font)
return;
bool begin = pos == 0 || notfound ||
(i > 0 && d->fontlist_[i - 1].pos() == pos - 1);
// Is position pos is a beginning of a font block?
bool end = !notfound && d->fontlist_[i].pos() == pos;
// Is position pos is the end of a font block?
if (begin && end) { // A single char block
if (i + 1 < d->fontlist_.size() &&
d->fontlist_[i + 1].font() == font) {
// Merge the singleton block with the next block
d->fontlist_.erase(d->fontlist_.begin() + i);
if (i > 0 && d->fontlist_[i - 1].font() == font)
d->fontlist_.erase(d->fontlist_.begin() + i - 1);
} else if (i > 0 && d->fontlist_[i - 1].font() == font) {
// Merge the singleton block with the previous block
d->fontlist_[i - 1].pos(pos);
d->fontlist_.erase(d->fontlist_.begin() + i);
} else
d->fontlist_[i].font(font);
} else if (begin) {
if (i > 0 && d->fontlist_[i - 1].font() == font)
d->fontlist_[i - 1].pos(pos);
else
d->fontlist_.insert(d->fontlist_.begin() + i,
FontTable(pos, font));
} else if (end) {
d->fontlist_[i].pos(pos - 1);
if (!(i + 1 < d->fontlist_.size() &&
d->fontlist_[i + 1].font() == font))
d->fontlist_.insert(d->fontlist_.begin() + i + 1,
FontTable(pos, font));
} else { // The general case. The block is splitted into 3 blocks
d->fontlist_.insert(d->fontlist_.begin() + i,
FontTable(pos - 1, d->fontlist_[i].font()));
d->fontlist_.insert(d->fontlist_.begin() + i + 1,
FontTable(pos, font));
}
d->fontlist_.set(pos, font);
}