mirror of
https://git.lyx.org/repos/lyx.git
synced 2025-01-11 11:08:41 +00:00
This commit fixes the following bug:
http://bugzilla.lyx.org/show_bug.cgi?id=2900 The only drawback is that it requires about 20Mo extra-memory when loading the UserGuide. If it turns out to be too much, we can switch to a QHash based solution instead of a table. * dimension.[Ch]: - Dimension(LyXFont const, char_typec): new ctor - set(LyXFont const & font, char_type c): new method. * frontends/FontMetrics.h: - width(char_type): is now a pure virtual method. * GuiFontMetrics: - CharMetrics: new structure; - the metrics cache now also cache ascent and descent. This is especially useful for mathed. * MathSupport.[Ch]: - mathed_char_dim(): deleted. We now use Dimension::set() directly instead. * rowpainter.C: fixe empty space. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16124 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
parent
7cf79bc298
commit
8f98ec35e4
@ -36,4 +36,12 @@ void Dimension::clear(LyXFont const & font)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Dimension::set(LyXFont const & font, char_type c)
|
||||||
|
{
|
||||||
|
frontend::FontMetrics const & fm = theFontMetrics(font);
|
||||||
|
des = fm.descent(c);
|
||||||
|
asc = fm.ascent(c);
|
||||||
|
wid = fm.width(c);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace lyx
|
} // namespace lyx
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#ifndef DIMENSION_H
|
#ifndef DIMENSION_H
|
||||||
#define DIMENSION_H
|
#define DIMENSION_H
|
||||||
|
|
||||||
|
#include "support/types.h"
|
||||||
|
|
||||||
namespace lyx {
|
namespace lyx {
|
||||||
|
|
||||||
@ -25,6 +26,8 @@ public:
|
|||||||
/// initialize data
|
/// initialize data
|
||||||
Dimension(int w, int a, int d) : wid(w), asc(a), des(d) {}
|
Dimension(int w, int a, int d) : wid(w), asc(a), des(d) {}
|
||||||
|
|
||||||
|
Dimension(LyXFont const & font, char_type c) { set(font, c); }
|
||||||
|
|
||||||
Dimension & operator=(Dimension const & dim) {
|
Dimension & operator=(Dimension const & dim) {
|
||||||
wid = dim.wid;
|
wid = dim.wid;
|
||||||
asc = dim.asc;
|
asc = dim.asc;
|
||||||
@ -35,8 +38,11 @@ public:
|
|||||||
void operator+=(Dimension const & dim);
|
void operator+=(Dimension const & dim);
|
||||||
/// set to empty box
|
/// set to empty box
|
||||||
void clear() { wid = asc = des = 0; }
|
void clear() { wid = asc = des = 0; }
|
||||||
/// set to empty box suitble for given font
|
/// set to empty box suitble for given font.
|
||||||
void clear(LyXFont const & font);
|
void clear(LyXFont const & font);
|
||||||
|
/// set to a char dimensions for a given font.
|
||||||
|
void set(LyXFont const & font, char_type c);
|
||||||
|
|
||||||
/// get height
|
/// get height
|
||||||
int height() const { return asc + des; }
|
int height() const { return asc + des; }
|
||||||
/// get ascent
|
/// get ascent
|
||||||
|
@ -58,6 +58,8 @@ public:
|
|||||||
virtual int maxAscent() const = 0;
|
virtual int maxAscent() const = 0;
|
||||||
/// return the maximum descent of the font
|
/// return the maximum descent of the font
|
||||||
virtual int maxDescent() const = 0;
|
virtual int maxDescent() const = 0;
|
||||||
|
/// return the width of the char in the font
|
||||||
|
virtual int width(char_type c) const = 0;
|
||||||
/// return the ascent of the char in the font
|
/// return the ascent of the char in the font
|
||||||
virtual int ascent(char_type c) const = 0;
|
virtual int ascent(char_type c) const = 0;
|
||||||
/// return the descent of the char in the font
|
/// return the descent of the char in the font
|
||||||
@ -103,13 +105,6 @@ public:
|
|||||||
return (rbearing(c) - lbearing(c)) / 2;
|
return (rbearing(c) - lbearing(c)) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return the width of the char in the font
|
|
||||||
inline int width(char_type c) const
|
|
||||||
{
|
|
||||||
char_type tmp[2] = { c, L'\0'};
|
|
||||||
return width(tmp, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// return the width of the string in the font
|
/// return the width of the string in the font
|
||||||
inline int width(docstring const & s) const
|
inline int width(docstring const & s) const
|
||||||
{
|
{
|
||||||
|
@ -31,6 +31,8 @@ public:
|
|||||||
|
|
||||||
virtual int maxDescent() const { return 1; }
|
virtual int maxDescent() const { return 1; }
|
||||||
|
|
||||||
|
virtual int width(char_type) const { return 1; }
|
||||||
|
|
||||||
virtual int ascent(char_type) const { return 1; }
|
virtual int ascent(char_type) const { return 1; }
|
||||||
|
|
||||||
int descent(char_type) const { return 1; }
|
int descent(char_type) const { return 1; }
|
||||||
|
@ -19,9 +19,6 @@
|
|||||||
|
|
||||||
#include "support/unicode.h"
|
#include "support/unicode.h"
|
||||||
|
|
||||||
using lyx::char_type;
|
|
||||||
using lyx::docstring;
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
namespace lyx {
|
namespace lyx {
|
||||||
@ -32,8 +29,11 @@ GuiFontMetrics::GuiFontMetrics(QFont const & font)
|
|||||||
: metrics_(font), smallcaps_metrics_(font), smallcaps_shape_(false)
|
: metrics_(font), smallcaps_metrics_(font), smallcaps_shape_(false)
|
||||||
{
|
{
|
||||||
#ifdef USE_LYX_FONTCACHE
|
#ifdef USE_LYX_FONTCACHE
|
||||||
for (int i = 0; i != 65536; ++i)
|
for (int i = 0; i != 65536; ++i) {
|
||||||
widthcache_[i] = -1;
|
metrics_cache_[i].width = -1000;
|
||||||
|
metrics_cache_[i].ascent = -1000;
|
||||||
|
metrics_cache_[i].descent = -1000;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,20 +58,6 @@ int GuiFontMetrics::maxDescent() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int GuiFontMetrics::ascent(char_type c) const
|
|
||||||
{
|
|
||||||
QRect const & r = metrics_.boundingRect(ucs4_to_qchar(c));
|
|
||||||
return -r.top();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int GuiFontMetrics::descent(char_type c) const
|
|
||||||
{
|
|
||||||
QRect const & r = metrics_.boundingRect(ucs4_to_qchar(c));
|
|
||||||
return r.bottom() + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int GuiFontMetrics::lbearing(char_type c) const
|
int GuiFontMetrics::lbearing(char_type c) const
|
||||||
{
|
{
|
||||||
return metrics_.leftBearing(ucs4_to_qchar(c));
|
return metrics_.leftBearing(ucs4_to_qchar(c));
|
||||||
@ -110,19 +96,18 @@ int GuiFontMetrics::width(char_type const * s, size_t ls) const
|
|||||||
// casts in reality.
|
// casts in reality.
|
||||||
|
|
||||||
if (ls == 1 && !smallcaps_shape_) {
|
if (ls == 1 && !smallcaps_shape_) {
|
||||||
QChar const c = ucs4_to_qchar(s[0]);
|
return width(s[0]);
|
||||||
return width(c.unicode());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ucs2;
|
if (smallcaps_shape_) {
|
||||||
ucs4_to_qstring(s, ls, ucs2);
|
QString ucs2;
|
||||||
|
ucs4_to_qstring(s, ls, ucs2);
|
||||||
if (smallcaps_shape_)
|
|
||||||
return smallcapsWidth(ucs2);
|
return smallcapsWidth(ucs2);
|
||||||
|
}
|
||||||
|
|
||||||
int w = 0;
|
int w = 0;
|
||||||
for (unsigned int i = 0; i < ls; ++i)
|
for (unsigned int i = 0; i < ls; ++i)
|
||||||
w += width(ucs2[i].unicode());
|
w += width(s[i]);
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
@ -178,14 +163,64 @@ void GuiFontMetrics::buttonText(docstring const & str,
|
|||||||
descent = metrics_.descent() + d;
|
descent = metrics_.descent() + d;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_LYX_FONTCACHE
|
#ifndef USE_LYX_FONTCACHE
|
||||||
int GuiFontMetrics::width(unsigned short val) const
|
|
||||||
|
int GuiFontMetrics::ascent(char_type c) const
|
||||||
{
|
{
|
||||||
if (widthcache_[val] == -1)
|
QRect const & r = metrics_.boundingRect(ucs4_to_qchar(c));
|
||||||
widthcache_[val] = metrics_.width(QChar(val));
|
return -r.top();
|
||||||
return widthcache_[val];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GuiFontMetrics::descent(char_type c) const
|
||||||
|
{
|
||||||
|
QRect const & r = metrics_.boundingRect(ucs4_to_qchar(c));
|
||||||
|
return r.bottom() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void GuiFontMetrics::fillCache(unsigned short val) const
|
||||||
|
{
|
||||||
|
QRect const & r = metrics_.boundingRect(QChar(val));
|
||||||
|
metrics_cache_[val].descent = r.bottom() + 1;
|
||||||
|
metrics_cache_[val].ascent = -r.top();
|
||||||
|
// We could as well compute the width but this is not really
|
||||||
|
// needed for now as it is done directly in width() below.
|
||||||
|
//metrics_cache_[val].width = metrics_.width(QChar(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GuiFontMetrics::width(char_type c) const
|
||||||
|
{
|
||||||
|
unsigned short val = static_cast<unsigned short>(c);
|
||||||
|
if (metrics_cache_[val].width == -1000)
|
||||||
|
metrics_cache_[val].width = metrics_.width(QChar(val));
|
||||||
|
|
||||||
|
return metrics_cache_[val].width;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GuiFontMetrics::ascent(char_type c) const
|
||||||
|
{
|
||||||
|
unsigned short val = static_cast<unsigned short>(c);
|
||||||
|
if (metrics_cache_[val].ascent == -1000)
|
||||||
|
fillCache(val);
|
||||||
|
|
||||||
|
return metrics_cache_[val].ascent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GuiFontMetrics::descent(char_type c) const
|
||||||
|
{
|
||||||
|
unsigned short val = static_cast<unsigned short>(c);
|
||||||
|
if (metrics_cache_[val].descent == -1000)
|
||||||
|
fillCache(val);
|
||||||
|
|
||||||
|
return metrics_cache_[val].descent;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
} // frontend
|
||||||
}
|
} // lyx
|
||||||
|
@ -27,6 +27,14 @@
|
|||||||
namespace lyx {
|
namespace lyx {
|
||||||
namespace frontend {
|
namespace frontend {
|
||||||
|
|
||||||
|
struct CharMetrics
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int ascent;
|
||||||
|
int descent;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class GuiFontMetrics: public FontMetrics
|
class GuiFontMetrics: public FontMetrics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -38,17 +46,24 @@ public:
|
|||||||
|
|
||||||
virtual int maxAscent() const;
|
virtual int maxAscent() const;
|
||||||
virtual int maxDescent() const;
|
virtual int maxDescent() const;
|
||||||
virtual int ascent(lyx::char_type c) const;
|
#ifndef USE_LYX_FONTCACHE
|
||||||
int descent(lyx::char_type c) const;
|
virtual int width(char_type c) const {
|
||||||
virtual int lbearing(lyx::char_type c) const;
|
return metrics_.width(QChar(static_cast<short int>(c)));
|
||||||
virtual int rbearing(lyx::char_type c) const;
|
}
|
||||||
virtual int width(lyx::char_type const * s, size_t n) const;
|
#else
|
||||||
virtual int signedWidth(lyx::docstring const & s) const;
|
virtual int width(char_type c) const;
|
||||||
virtual void rectText(lyx::docstring const & str,
|
#endif
|
||||||
|
virtual int ascent(char_type c) const;
|
||||||
|
virtual int descent(char_type c) const;
|
||||||
|
virtual int lbearing(char_type c) const;
|
||||||
|
virtual int rbearing(char_type c) const;
|
||||||
|
virtual int width(char_type const * s, size_t n) const;
|
||||||
|
virtual int signedWidth(docstring const & s) const;
|
||||||
|
virtual void rectText(docstring const & str,
|
||||||
int & width,
|
int & width,
|
||||||
int & ascent,
|
int & ascent,
|
||||||
int & descent) const;
|
int & descent) const;
|
||||||
virtual void buttonText(lyx::docstring const & str,
|
virtual void buttonText(docstring const & str,
|
||||||
int & width,
|
int & width,
|
||||||
int & ascent,
|
int & ascent,
|
||||||
int & descent) const;
|
int & descent) const;
|
||||||
@ -64,16 +79,16 @@ private:
|
|||||||
|
|
||||||
bool smallcaps_shape_;
|
bool smallcaps_shape_;
|
||||||
|
|
||||||
#ifndef USE_LYX_FONTCACHE
|
#ifdef USE_LYX_FONTCACHE
|
||||||
/// Return pixel width for the given unicode char
|
/// fill in \c metrics_cache_ at specified value.
|
||||||
int width(unsigned short val) const { return metrics_.width(QChar(val)); }
|
void fillCache(unsigned short val) const;
|
||||||
|
|
||||||
#else
|
|
||||||
/// Return pixel width for the given unicode char
|
|
||||||
int width(unsigned short val) const;
|
|
||||||
|
|
||||||
/// Cache of char widths
|
/// Cache of char widths
|
||||||
mutable int widthcache_[65536];
|
/** This cache adds 20Mo of memory to the LyX executable when
|
||||||
|
* loading UserGuide.lyx which contains a good number of fonts. If
|
||||||
|
* this turns out to be too much, we can switch to a \c QHash based
|
||||||
|
* solution.
|
||||||
|
**/
|
||||||
|
mutable CharMetrics metrics_cache_[65536];
|
||||||
#endif // USE_LYX_FONTCACHE
|
#endif // USE_LYX_FONTCACHE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,8 +46,7 @@ auto_ptr<InsetBase> InsetMathBrace::doClone() const
|
|||||||
bool InsetMathBrace::metrics(MetricsInfo & mi, Dimension & dim) const
|
bool InsetMathBrace::metrics(MetricsInfo & mi, Dimension & dim) const
|
||||||
{
|
{
|
||||||
cell(0).metrics(mi);
|
cell(0).metrics(mi);
|
||||||
Dimension t;
|
Dimension t(mi.base.font, '{');
|
||||||
mathed_char_dim(mi.base.font, '{', t);
|
|
||||||
dim.asc = max(cell(0).ascent(), t.asc);
|
dim.asc = max(cell(0).ascent(), t.asc);
|
||||||
dim.des = max(cell(0).descent(), t.des);
|
dim.des = max(cell(0).descent(), t.des);
|
||||||
dim.wid = cell(0).width() + 2 * t.wid;
|
dim.wid = cell(0).width() + 2 * t.wid;
|
||||||
@ -63,8 +62,7 @@ void InsetMathBrace::draw(PainterInfo & pi, int x, int y) const
|
|||||||
{
|
{
|
||||||
LyXFont font = pi.base.font;
|
LyXFont font = pi.base.font;
|
||||||
font.setColor(LColor::latex);
|
font.setColor(LColor::latex);
|
||||||
Dimension t;
|
Dimension t(font, '{');
|
||||||
mathed_char_dim(font, '{', t);
|
|
||||||
pi.pain.text(x, y, '{', font);
|
pi.pain.text(x, y, '{', font);
|
||||||
cell(0).draw(pi, x + t.wid, y);
|
cell(0).draw(pi, x + t.wid, y);
|
||||||
pi.pain.text(x + t.wid + cell(0).width(), y, '}', font);
|
pi.pain.text(x + t.wid + cell(0).width(), y, '}', font);
|
||||||
|
@ -62,15 +62,15 @@ bool InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const
|
|||||||
#if 1
|
#if 1
|
||||||
if (char_ == '=' && has_math_fonts) {
|
if (char_ == '=' && has_math_fonts) {
|
||||||
FontSetChanger dummy(mi.base, "cmr");
|
FontSetChanger dummy(mi.base, "cmr");
|
||||||
mathed_char_dim(mi.base.font, char_, dim);
|
dim.set(mi.base.font, char_);
|
||||||
} else if ((char_ == '>' || char_ == '<') && has_math_fonts) {
|
} else if ((char_ == '>' || char_ == '<') && has_math_fonts) {
|
||||||
FontSetChanger dummy(mi.base, "cmm");
|
FontSetChanger dummy(mi.base, "cmm");
|
||||||
mathed_char_dim(mi.base.font, char_, dim);
|
dim.set(mi.base.font, char_);
|
||||||
} else if (!slanted(char_) && mi.base.fontname == "mathnormal") {
|
} else if (!slanted(char_) && mi.base.fontname == "mathnormal") {
|
||||||
ShapeChanger dummy(mi.base.font, LyXFont::UP_SHAPE);
|
ShapeChanger dummy(mi.base.font, LyXFont::UP_SHAPE);
|
||||||
mathed_char_dim(mi.base.font, char_, dim);
|
dim.set(mi.base.font, char_);
|
||||||
} else {
|
} else {
|
||||||
mathed_char_dim(mi.base.font, char_, dim);
|
dim.set(mi.base.font, char_);
|
||||||
}
|
}
|
||||||
int const em = mathed_char_width(mi.base.font, 'M');
|
int const em = mathed_char_width(mi.base.font, 'M');
|
||||||
if (isBinaryOp(char_))
|
if (isBinaryOp(char_))
|
||||||
@ -79,7 +79,7 @@ bool InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const
|
|||||||
dim.wid += static_cast<int>(0.1667*em+0.5);
|
dim.wid += static_cast<int>(0.1667*em+0.5);
|
||||||
#else
|
#else
|
||||||
whichFont(font_, code_, mi);
|
whichFont(font_, code_, mi);
|
||||||
mathed_char_dim(font_, char_, dim);
|
dim.set(font_, char_);
|
||||||
if (isBinaryOp(char_, code_))
|
if (isBinaryOp(char_, code_))
|
||||||
width_ += 2 * theFontMetrics(font_).width(' ');
|
width_ += 2 * theFontMetrics(font_).width(' ');
|
||||||
lyxerr << "InsetMathChar::metrics: " << dim << endl;
|
lyxerr << "InsetMathChar::metrics: " << dim << endl;
|
||||||
|
@ -75,7 +75,7 @@ bool InsetMathDelim::metrics(MetricsInfo & mi, Dimension & dim) const
|
|||||||
{
|
{
|
||||||
cell(0).metrics(mi);
|
cell(0).metrics(mi);
|
||||||
Dimension t;
|
Dimension t;
|
||||||
mathed_char_dim(mi.base.font, 'I', t);
|
t.set(mi.base.font, 'I');
|
||||||
int h0 = (t.asc + t.des) / 2;
|
int h0 = (t.asc + t.des) / 2;
|
||||||
int a0 = max(cell(0).ascent(), t.asc) - h0;
|
int a0 = max(cell(0).ascent(), t.asc) - h0;
|
||||||
int d0 = max(cell(0).descent(), t.des) + h0;
|
int d0 = max(cell(0).descent(), t.des) + h0;
|
||||||
|
@ -37,7 +37,7 @@ auto_ptr<InsetBase> InsetMathDots::doClone() const
|
|||||||
|
|
||||||
bool InsetMathDots::metrics(MetricsInfo & mi, Dimension & dim) const
|
bool InsetMathDots::metrics(MetricsInfo & mi, Dimension & dim) const
|
||||||
{
|
{
|
||||||
mathed_char_dim(mi.base.font, 'M', dim);
|
dim.set(mi.base.font, 'M');
|
||||||
dh_ = 0;
|
dh_ = 0;
|
||||||
if (key_->name == "cdots" || key_->name == "dotsb"
|
if (key_->name == "cdots" || key_->name == "dotsb"
|
||||||
|| key_->name == "dotsm" || key_->name == "dotsi")
|
|| key_->name == "dotsm" || key_->name == "dotsi")
|
||||||
|
@ -241,7 +241,7 @@ bool isInside(DocIterator const & it, MathArray const & ar,
|
|||||||
|
|
||||||
void MathArray::metrics(MetricsInfo & mi) const
|
void MathArray::metrics(MetricsInfo & mi) const
|
||||||
{
|
{
|
||||||
mathed_char_dim(mi.base.font, 'I', dim_);
|
dim_.set(mi.base.font, 'I');
|
||||||
|
|
||||||
if (empty())
|
if (empty())
|
||||||
return;
|
return;
|
||||||
|
@ -367,15 +367,6 @@ deco_struct const * search_deco(docstring const & name)
|
|||||||
} // namespace anon
|
} // namespace anon
|
||||||
|
|
||||||
|
|
||||||
void mathed_char_dim(LyXFont const & font, char_type c, Dimension & dim)
|
|
||||||
{
|
|
||||||
frontend::FontMetrics const & fm = theFontMetrics(font);
|
|
||||||
dim.des = fm.descent(c);
|
|
||||||
dim.asc = fm.ascent(c);
|
|
||||||
dim.wid = fm.width(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int mathed_char_width(LyXFont const & font, char_type c)
|
int mathed_char_width(LyXFont const & font, char_type c)
|
||||||
{
|
{
|
||||||
return theFontMetrics(font).width(c);
|
return theFontMetrics(font).width(c);
|
||||||
|
@ -28,7 +28,6 @@ class MathAtom;
|
|||||||
class InsetMath;
|
class InsetMath;
|
||||||
|
|
||||||
|
|
||||||
void mathed_char_dim(LyXFont const &, char_type c, Dimension & dim);
|
|
||||||
int mathed_char_width(LyXFont const &, char_type c);
|
int mathed_char_width(LyXFont const &, char_type c);
|
||||||
|
|
||||||
void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
|
void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h,
|
||||||
|
@ -949,7 +949,7 @@ void paintPar
|
|||||||
rp.paintChangeBar();
|
rp.paintChangeBar();
|
||||||
if (rit == rb)
|
if (rit == rb)
|
||||||
rp.paintFirst();
|
rp.paintFirst();
|
||||||
rp.paintText();
|
rp.paintText();
|
||||||
if (rit + 1 == re)
|
if (rit + 1 == re)
|
||||||
rp.paintLast();
|
rp.paintLast();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user