[graphics] Significantly removed memory pressure in StraightTextElement.

This commit is contained in:
vng 2014-08-27 12:21:05 +03:00 committed by Alex Zolotarev
parent 3b3c70a9b7
commit 6f28783996
8 changed files with 156 additions and 208 deletions

View file

@ -7,23 +7,14 @@
namespace graphics
{
GlyphLayout::GlyphLayout()
{}
GlyphLayout::GlyphLayout(GlyphCache * glyphCache,
FontDesc const & fontDesc,
m2::PointD const & pt,
strings::UniString const & visText,
graphics::EPosition pos)
GlyphLayout::GlyphLayout(FontDesc const & font)
: m_firstVisible(0),
m_lastVisible(visText.size()),
m_fontDesc(fontDesc),
m_pivot(pt),
m_lastVisible(0),
m_fontDesc(font),
m_pivot(0, 0),
m_offset(0, 0),
m_textLength(0),
m_textOffset(0)
m_textLength(0)
{
initStraigthText(glyphCache, fontDesc, pt, visText, pos, numeric_limits<unsigned>::max());
}
GlyphLayout::GlyphLayout(GlyphCache * glyphCache,
@ -37,27 +28,23 @@ namespace graphics
m_fontDesc(fontDesc),
m_pivot(pt),
m_offset(0, 0),
m_textLength(0),
m_textOffset(0)
m_textLength(0)
{
initStraigthText(glyphCache, fontDesc, pt, visText, pos, maxWidth);
}
GlyphLayout::GlyphLayout(GlyphLayout const & src,
math::Matrix<double, 3, 3> const & m)
: m_firstVisible(0),
m_lastVisible(0),
GlyphLayoutPath::GlyphLayoutPath(GlyphLayoutPath const & src,
math::Matrix<double, 3, 3> const & m)
: GlyphLayout(src.m_fontDesc),
m_path(src.m_path, m),
m_visText(src.m_visText),
m_fontDesc(src.m_fontDesc),
m_metrics(src.m_metrics),
m_pivot(0, 0),
m_offset(0, 0),
m_textLength(src.m_textLength)
m_visText(src.m_visText)
{
if (!m_fontDesc.IsValid())
return;
m_metrics = src.m_metrics;
m_textLength = src.m_textLength;
m_boundRects.push_back(m2::AnyRectD(m2::RectD(0, 0, 0, 0)));
m_textOffset = (m2::PointD(0, src.m_textOffset) * m).Length(m2::PointD(0, 0) * m);
@ -69,22 +56,17 @@ namespace graphics
recalcAlongPath();
}
GlyphLayout::GlyphLayout(GlyphCache * glyphCache,
FontDesc const & fontDesc,
m2::PointD const * pts,
size_t ptsCount,
strings::UniString const & visText,
double fullLength,
double pathOffset,
double textOffset)
: m_firstVisible(0),
m_lastVisible(0),
GlyphLayoutPath::GlyphLayoutPath(GlyphCache * glyphCache,
FontDesc const & fontDesc,
m2::PointD const * pts,
size_t ptsCount,
strings::UniString const & visText,
double fullLength,
double pathOffset,
double textOffset)
: GlyphLayout(fontDesc),
m_path(pts, ptsCount, fullLength, pathOffset),
m_visText(visText),
m_fontDesc(fontDesc),
m_pivot(0, 0),
m_offset(0, 0),
m_textLength(0),
m_textOffset(textOffset)
{
if (!m_fontDesc.IsValid())
@ -224,7 +206,7 @@ namespace graphics
m_boundRects.push_back(m2::AnyRectD(boundRect));
}
void GlyphLayout::recalcAlongPath()
void GlyphLayoutPath::recalcAlongPath()
{
size_t const count = m_visText.size();
if (count == 0 || m_path.fullLength() < m_textLength)
@ -321,7 +303,7 @@ namespace graphics
}
// storing glyph coordinates relative to pivot point.
for (unsigned i = m_firstVisible; i < m_lastVisible; ++i)
for (size_t i = m_firstVisible; i < m_lastVisible; ++i)
m_entries[i].m_pt -= m_pivot;
computeBoundRects();
@ -331,7 +313,7 @@ namespace graphics
{
map<double, m2::AnyRectD> rects;
for (unsigned i = m_firstVisible; i < m_lastVisible; ++i)
for (size_t i = m_firstVisible; i < m_lastVisible; ++i)
{
if (m_metrics[i].m_width != 0)
{
@ -383,16 +365,6 @@ namespace graphics
return m_lastVisible;
}
buffer_vector<GlyphLayoutElem, 32> const & GlyphLayout::entries() const
{
return m_entries;
}
buffer_vector<m2::AnyRectD, 16> const & GlyphLayout::boundRects() const
{
return m_boundRects;
}
m2::PointD const & GlyphLayout::pivot() const
{
return m_pivot;
@ -400,7 +372,7 @@ namespace graphics
void GlyphLayout::setPivot(m2::PointD const & pivot)
{
for (unsigned i = 0; i < m_boundRects.size(); ++i)
for (size_t i = 0; i < m_boundRects.size(); ++i)
m_boundRects[i].Offset(pivot - m_pivot);
m_pivot = pivot;
@ -413,7 +385,7 @@ namespace graphics
void GlyphLayout::setOffset(m2::PointD const & offset)
{
for (unsigned i = 0; i < m_boundRects.size(); ++i)
for (size_t i = 0; i < m_boundRects.size(); ++i)
m_boundRects[i].Offset(offset - m_offset);
m_offset = offset;
@ -432,4 +404,9 @@ namespace graphics
return -result;
}
bool GlyphLayoutPath::IsFullVisible() const
{
return (m_firstVisible == 0 && m_lastVisible == m_visText.size());
}
}

View file

@ -28,38 +28,29 @@ namespace graphics
class GlyphLayout
{
private:
protected:
size_t m_firstVisible;
size_t m_lastVisible;
TextPath m_path;
strings::UniString m_visText;
graphics::FontDesc m_fontDesc;
buffer_vector<GlyphMetrics, 32> m_metrics;
buffer_vector<GlyphLayoutElem, 32> m_entries;
buffer_vector<m2::AnyRectD, 16> m_boundRects;
buffer_vector<GlyphMetrics, 8> m_metrics;
buffer_vector<GlyphLayoutElem, 8> m_entries;
buffer_vector<m2::AnyRectD, 1> m_boundRects;
m2::PointD m_pivot;
m2::PointD m_offset;
double m_textLength;
double m_textOffset;
void computeBoundRects();
void recalcPivot();
void recalcAlongPath();
inline void addGlyph(GlyphCache * glyphCache,
GlyphKey const & key,
bool isFirst,
strings::UniChar symbol,
m2::RectD & boundRect,
m2::PointD & curPt);
void addGlyph(GlyphCache * glyphCache,
GlyphKey const & key,
bool isFirst,
strings::UniChar symbol,
m2::RectD & boundRect,
m2::PointD & curPt);
void initStraigthText(GlyphCache * glyphCache,
FontDesc const & font,
@ -68,40 +59,27 @@ namespace graphics
graphics::EPosition pos,
unsigned maxWidth);
protected:
GlyphLayout(FontDesc const & font);
public:
GlyphLayout();
GlyphLayout(GlyphLayout const & layout,
math::Matrix<double, 3, 3> const & m);
GlyphLayout(GlyphCache * glyphCache,
FontDesc const & font,
m2::PointD const & pt,
strings::UniString const & visText,
graphics::EPosition pos);
GlyphLayout() {}
GlyphLayout(GlyphCache * glyphCache,
FontDesc const & font,
m2::PointD const & pt,
strings::UniString const & visText,
graphics::EPosition pos,
unsigned maxWidth);
GlyphLayout(GlyphCache * glyphCache,
FontDesc const & font,
m2::PointD const * pts,
size_t ptsCount,
strings::UniString const & visText,
double fullLength,
double pathOffset,
double textOffset);
unsigned maxWidth = numeric_limits<unsigned>::max());
size_t firstVisible() const;
size_t lastVisible() const;
buffer_vector<GlyphLayoutElem, 32> const & entries() const;
buffer_vector<m2::AnyRectD, 16> const & boundRects() const;
buffer_vector<GlyphLayoutElem, 8> const & entries() const { return m_entries; }
buffer_vector<m2::AnyRectD, 1> const & boundRects() const { return m_boundRects; }
/// @note! Used only in StraightTextElement.
m2::RectD GetLastGlobalRect() const { return m_boundRects.back().GetGlobalRect(); }
graphics::FontDesc const & fontDesc() const;
@ -113,4 +91,31 @@ namespace graphics
int baseLineOffset();
};
class GlyphLayoutPath : public GlyphLayout
{
TextPath m_path;
strings::UniString m_visText;
double m_textOffset;
void recalcAlongPath();
public:
GlyphLayoutPath() {}
GlyphLayoutPath(GlyphLayoutPath const & layout,
math::Matrix<double, 3, 3> const & m);
GlyphLayoutPath(GlyphCache * glyphCache,
FontDesc const & font,
m2::PointD const * pts,
size_t ptsCount,
strings::UniString const & visText,
double fullLength,
double pathOffset,
double textOffset);
bool IsFullVisible() const;
};
}

View file

@ -13,18 +13,18 @@ namespace graphics
{}
PathTextElement::PathTextElement(Params const & p)
: TextElement(p),
m_glyphLayout(p.m_glyphCache,
p.m_fontDesc,
p.m_pts,
p.m_ptsCount,
visText(),
p.m_fullLength,
p.m_pathOffset,
p.m_textOffset)
: TextElement(p)
{
strings::UniString visText, auxVisText;
(void) p.GetVisibleTexts(visText, auxVisText);
m_glyphLayout = GlyphLayoutPath(p.m_glyphCache, p.m_fontDesc,
p.m_pts, p.m_ptsCount,
visText, p.m_fullLength,
p.m_pathOffset, p.m_textOffset);
setPivot(m_glyphLayout.pivot());
setIsValid((m_glyphLayout.firstVisible() == 0) && (m_glyphLayout.lastVisible() == visText().size()));
setIsValid(m_glyphLayout.IsFullVisible());
}
vector<m2::AnyRectD> const & PathTextElement::boundRects() const
@ -86,9 +86,9 @@ namespace graphics
void PathTextElement::setTransformation(const math::Matrix<double, 3, 3> & m)
{
m_glyphLayout = GlyphLayout(m_glyphLayout, getResetMatrix() * m);
m_glyphLayout = GlyphLayoutPath(m_glyphLayout, getResetMatrix() * m);
TextElement::setPivot(m_glyphLayout.pivot());
setIsValid((m_glyphLayout.firstVisible() == 0) && (m_glyphLayout.lastVisible() == visText().size()));
setIsValid(m_glyphLayout.IsFullVisible());
TextElement::setTransformation(m);
}
}

View file

@ -10,7 +10,7 @@ namespace graphics
{
private:
GlyphLayout m_glyphLayout;
GlyphLayoutPath m_glyphLayout;
public:

View file

@ -80,51 +80,54 @@ namespace graphics
double allElemWidth = 0;
double allElemHeight = 0;
if (!visText().empty())
strings::UniString visText, auxVisText;
pair<bool, bool> const isBidi = p.GetVisibleTexts(visText, auxVisText);
if (!visText.empty())
{
buffer_vector<strings::UniString, 3> res;
if (p.m_doForceSplit || (p.m_doSplit && !isBidi()))
if (p.m_doForceSplit || (p.m_doSplit && !isBidi.first))
{
res.clear();
if (!p.m_delimiters.empty())
visSplit(visText(), res, p.m_delimiters.c_str(), p.m_useAllParts);
visSplit(visText, res, p.m_delimiters.c_str(), p.m_useAllParts);
else
visSplit(visText(), res, " \n\t", p.m_useAllParts);
visSplit(visText, res, " \n\t", p.m_useAllParts);
}
else
res.push_back(visText());
res.push_back(visText);
for (unsigned i = 0; i < res.size(); ++i)
for (size_t i = 0; i < res.size(); ++i)
{
m_glyphLayouts.push_back(GlyphLayout(p.m_glyphCache, p.m_fontDesc, m2::PointD(0, 0), res[i], graphics::EPosCenter, p.m_maxPixelWidth));
m2::RectD r = m_glyphLayouts.back().boundRects().back().GetGlobalRect();
m2::RectD const r = m_glyphLayouts.back().GetLastGlobalRect();
allElemWidth = max(r.SizeX(), allElemWidth);
allElemHeight += r.SizeY();
}
}
if (p.m_auxFontDesc.IsValid() && !auxVisText().empty())
if (p.m_auxFontDesc.IsValid() && !auxVisText.empty())
{
buffer_vector<strings::UniString, 3> auxRes;
GlyphLayout l(p.m_glyphCache, p.m_auxFontDesc, m2::PointD(0, 0), auxVisText(), graphics::EPosCenter);
if (l.boundRects().back().GetGlobalRect().SizeX() > allElemWidth)
GlyphLayout l(p.m_glyphCache, p.m_auxFontDesc, m2::PointD(0, 0), auxVisText, graphics::EPosCenter);
if (l.GetLastGlobalRect().SizeX() > allElemWidth)
{
// should split
if (p.m_doSplit && !isAuxBidi())
if (p.m_doSplit && !isBidi.second)
{
if (!p.m_delimiters.empty())
visSplit(auxVisText(), auxRes, p.m_delimiters.c_str(), p.m_useAllParts);
visSplit(auxVisText, auxRes, p.m_delimiters.c_str(), p.m_useAllParts);
else
visSplit(auxVisText(), auxRes, " \n\t", p.m_useAllParts);
visSplit(auxVisText, auxRes, " \n\t", p.m_useAllParts);
}
else
auxRes.push_back(auxVisText());
auxRes.push_back(auxVisText);
}
else
auxRes.push_back(auxVisText());
auxRes.push_back(auxVisText);
for (int i = 0; i < auxRes.size(); ++i)
for (size_t i = 0; i < auxRes.size(); ++i)
m_glyphLayouts.push_back(GlyphLayout(p.m_glyphCache, p.m_auxFontDesc, m2::PointD(0, 0), auxRes[i], graphics::EPosCenter));
}
@ -133,32 +136,31 @@ namespace graphics
double curShift = allElemHeight / 2;
/// performing aligning of glyphLayouts as for the center position
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
// performing aligning of glyphLayouts as for the center position
for (size_t i = 0; i < m_glyphLayouts.size(); ++i)
{
double elemSize = m_glyphLayouts[i].boundRects().back().GetGlobalRect().SizeY();
double const elemSize = m_glyphLayouts[i].GetLastGlobalRect().SizeY();
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + m2::PointD(0, -curShift + elemSize / 2) + p.m_offset);
curShift -= elemSize;
}
if (position() & graphics::EPosLeft)
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
for (size_t i = 0; i < m_glyphLayouts.size(); ++i)
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + m2::PointD(-allElemWidth / 2, 0));
if (position() & graphics::EPosRight)
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
for (size_t i = 0; i < m_glyphLayouts.size(); ++i)
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + m2::PointD(allElemWidth / 2, 0));
if (position() & graphics::EPosAbove)
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
for (size_t i = 0; i < m_glyphLayouts.size(); ++i)
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + m2::PointD(0, -allElemHeight / 2));
if (position() & graphics::EPosUnder)
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
for (size_t i = 0; i < m_glyphLayouts.size(); ++i)
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + m2::PointD(0, allElemHeight / 2));
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
for (size_t i = 0; i < m_glyphLayouts.size(); ++i)
{
m_offsets.push_back(m_glyphLayouts[i].pivot());
m_glyphLayouts[i].setPivot(m_offsets[i] + pivot());
@ -209,7 +211,7 @@ namespace graphics
doffs += 1;
for (unsigned i = 0 ; i < boundRects().size(); ++i)
for (size_t i = 0 ; i < boundRects().size(); ++i)
screen->drawRectangle(boundRects()[i], c, depth() + doffs);
doffs += 1;
@ -218,7 +220,7 @@ namespace graphics
if (!isNeedRedraw())
return;
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
for (size_t i = 0; i < m_glyphLayouts.size(); ++i)
{
if (m_glyphLayouts[i].fontDesc().m_isMasked)
drawTextImpl(m_glyphLayouts[i], screen, m, true, true, m_glyphLayouts[i].fontDesc(), depth() + doffs);
@ -226,7 +228,7 @@ namespace graphics
doffs += 1;
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
for (size_t i = 0; i < m_glyphLayouts.size(); ++i)
{
graphics::FontDesc fontDesc = m_glyphLayouts[i].fontDesc();
fontDesc.m_isMasked = false;
@ -241,7 +243,7 @@ namespace graphics
TextElement::setPivot(pv);
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
for (size_t i = 0; i < m_glyphLayouts.size(); ++i)
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + offs);
}
@ -249,7 +251,7 @@ namespace graphics
{
setPivot(pivot() * getResetMatrix() * m);
for (unsigned i = 0; i < m_glyphLayouts.size(); ++i)
for (size_t i = 0; i < m_glyphLayouts.size(); ++i)
{
m_glyphLayouts[i].setPivot(pivot());
m_glyphLayouts[i].setOffset(m_offsets[i]);

View file

@ -10,9 +10,10 @@ namespace graphics
{
private:
/// glyph layout of the text parts.
vector<GlyphLayout> m_glyphLayouts;
vector<m2::PointD> m_offsets;
// Glyph layout of the text parts.
// In 99% cases cantainers will hold 1 element.
buffer_vector<GlyphLayout, 1> m_glyphLayouts;
buffer_vector<m2::PointD, 1> m_offsets;
public:

View file

@ -11,44 +11,30 @@ namespace graphics
TextElement::TextElement(Params const & p)
: OverlayElement(p),
m_fontDesc(p.m_fontDesc),
m_auxFontDesc(p.m_auxFontDesc),
m_logText(p.m_logText),
m_auxLogText(p.m_auxLogText),
m_log2vis(p.m_log2vis)
m_auxFontDesc(p.m_auxFontDesc)
{
}
pair<bool, bool> TextElement::Params::GetVisibleTexts(
strings::UniString & visText, strings::UniString & auxVisText) const
{
if (m_log2vis)
{
m_visText = p.m_glyphCache->log2vis(m_logText);
visText = m_glyphCache->log2vis(m_logText);
if (!m_auxLogText.empty())
m_auxVisText = p.m_glyphCache->log2vis(m_auxLogText);
auxVisText = m_glyphCache->log2vis(m_auxLogText);
return make_pair(visText != m_logText, auxVisText != m_auxLogText);
}
else
{
m_visText = m_logText;
m_auxVisText = m_auxLogText;
visText = m_logText;
auxVisText = m_auxLogText;
return make_pair(false, false);
}
}
strings::UniString const & TextElement::logText() const
{
return m_logText;
}
strings::UniString const & TextElement::auxLogText() const
{
return m_auxLogText;
}
strings::UniString const & TextElement::visText() const
{
return m_visText;
}
strings::UniString const & TextElement::auxVisText() const
{
return m_auxVisText;
}
FontDesc const & TextElement::fontDesc() const
{
return m_fontDesc;
@ -59,16 +45,6 @@ namespace graphics
return m_auxFontDesc;
}
bool TextElement::isBidi() const
{
return m_logText != m_visText;
}
bool TextElement::isAuxBidi() const
{
return m_auxLogText != m_auxVisText;
}
void TextElement::drawTextImpl(GlyphLayout const & layout,
OverlayRenderer * screen,
math::Matrix<double, 3, 3> const & m,
@ -96,17 +72,17 @@ namespace graphics
deltaA = (ang::AngleD(0) * m).val();
}
size_t cnt = layout.entries().size();
size_t const cnt = layout.entries().size();
buffer_vector<Glyph::Info, 32> glyphInfos(cnt);
buffer_vector<Resource::Info const *, 32> resInfos(cnt);
buffer_vector<uint32_t, 32> glyphIDs(cnt);
unsigned firstVis = layout.firstVisible();
unsigned lastVis = layout.lastVisible();
size_t const firstVis = layout.firstVisible();
size_t const lastVis = layout.lastVisible();
/// collecting all glyph infos in one array and packing them as a whole.
for (unsigned i = firstVis; i < lastVis; ++i)
for (size_t i = firstVis; i < lastVis; ++i)
{
GlyphKey glyphKey(layout.entries()[i].m_sym,
fontDesc.m_size,
@ -117,16 +93,16 @@ namespace graphics
resInfos[i] = &glyphInfos[i];
}
if ((firstVis != lastVis)
&& !screen->mapInfo(&resInfos[firstVis],
&glyphIDs[firstVis],
lastVis - firstVis))
if (firstVis != lastVis &&
!screen->mapInfo(&resInfos[firstVis],
&glyphIDs[firstVis],
lastVis - firstVis))
{
LOG(LDEBUG, ("cannot render string", lastVis - firstVis, "characters long"));
return;
}
for (unsigned i = firstVis; i < lastVis; ++i)
for (size_t i = firstVis; i < lastVis; ++i)
{
GlyphLayoutElem const & elem = layout.entries()[i];
Glyph const * glyph = static_cast<Glyph const *>(screen->fromID(glyphIDs[i]));

View file

@ -16,23 +16,10 @@ namespace graphics
{
protected:
/// text-element specific
FontDesc m_fontDesc;
FontDesc m_auxFontDesc;
strings::UniString m_logText; //< logical string
strings::UniString m_auxLogText;
strings::UniString m_visText; //< visual string, BIDI processed
strings::UniString m_auxVisText;
bool m_log2vis;
FontDesc m_fontDesc, m_auxFontDesc;
mutable vector<m2::AnyRectD> m_boundRects;
bool isBidi() const;
bool isAuxBidi() const;
public:
struct Params : OverlayElement::Params
@ -45,6 +32,9 @@ namespace graphics
bool m_log2vis;
GlyphCache * m_glyphCache;
pair<bool, bool> GetVisibleTexts(strings::UniString & visText,
strings::UniString & auxVisText) const;
};
TextElement(Params const & p);
@ -56,10 +46,7 @@ namespace graphics
bool doAlignPivot,
FontDesc const & desc,
double depth) const;
strings::UniString const & logText() const;
strings::UniString const & auxLogText() const;
strings::UniString const & visText() const;
strings::UniString const & auxVisText() const;
FontDesc const & fontDesc() const;
FontDesc const & auxFontDesc() const;
};