Splitting long text into small parts

This commit is contained in:
Roman Sorokin 2014-09-10 10:04:54 +03:00 committed by Alex Zolotarev
parent c1ef0f2d54
commit 452fde5f26
2 changed files with 160 additions and 76 deletions

View file

@ -113,105 +113,188 @@ TextShape::TextShape(m2::PointF const & basePoint, TextViewParams const & params
m_params(params)
{
}
///Old code
void TextShape::visSplit(strings::UniString const & visText,
buffer_vector<strings::UniString, 3> & res,
char const * delims,
bool splitAllFound) const
{
if (!splitAllFound)
{
size_t count = visText.size();
if (count > 15)
{
// split on two parts
typedef strings::UniString::const_iterator IterT;
IterT const iMiddle = visText.begin() + count/2;
size_t const delimsSize = strlen(delims);
// find next delimeter after middle [m, e)
IterT iNext = find_first_of(iMiddle,
visText.end(),
delims, delims + delimsSize);
// find last delimeter before middle [b, m)
IterT iPrev = find_first_of(reverse_iterator<IterT>(iMiddle),
reverse_iterator<IterT>(visText.begin()),
delims, delims + delimsSize).base();
// don't do split like this:
// xxxx
// xxxxxxxxxxxx
if (4 * distance(visText.begin(), iPrev) <= count)
iPrev = visText.end();
else
--iPrev;
// get closest delimiter to the middle
if (iNext == visText.end() ||
(iPrev != visText.end() && distance(iPrev, iMiddle) < distance(iMiddle, iNext)))
{
iNext = iPrev;
}
// split string on 2 parts
if (iNext != visText.end())
{
ASSERT_NOT_EQUAL(iNext, visText.begin(), ());
res.push_back(strings::UniString(visText.begin(), iNext));
if (++iNext != visText.end())
res.push_back(strings::UniString(iNext, visText.end()));
return;
}
}
res.push_back(visText);
}
else
{
// split string using according to all delimiters
typedef strings::SimpleDelimiter DelimT;
for (strings::TokenizeIterator<DelimT> iter(visText, DelimT(delims)); iter; ++iter)
res.push_back(iter.GetUniString());
}
}
void TextShape::Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const
{
ASSERT(!m_params.m_primaryText.empty(), ());
vector<TextLayout> layouts;
if (m_params.m_secondaryText.empty())
{
TextLayout const primaryLayout(fribidi::log2vis(strings::MakeUniString(m_params.m_primaryText)),
m_params.m_primaryTextFont, textures);
if (primaryLayout.GetGlyphCount() == 0)
strings::UniString text = fribidi::log2vis(strings::MakeUniString(m_params.m_primaryText));
if (text.size() == 0)
return;
DrawSingleLine(batcher, primaryLayout);
buffer_vector<strings::UniString, 3> res;
visSplit(text, res, " \n\t", false);
for (int i = 0; i < res.size(); ++i)
layouts.push_back(TextLayout(res[res.size() - i - 1], m_params.m_primaryTextFont, textures));
vector<bool> dels(layouts.size(), false);
dels[dels.size() - 1] = true;
DrawPolyLine(batcher, layouts, dels);
}
else
{
TextLayout const primaryLayout(fribidi::log2vis(strings::MakeUniString(m_params.m_primaryText)),
m_params.m_primaryTextFont, textures);
TextLayout const secondaryLayout(fribidi::log2vis(strings::MakeUniString(m_params.m_secondaryText)),
m_params.m_secondaryTextFont, textures);
uint32_t primGlyphCount = primaryLayout.GetGlyphCount();
uint32_t secondGlyphCount = secondaryLayout.GetGlyphCount();
strings::UniString primaryText = fribidi::log2vis(strings::MakeUniString(m_params.m_primaryText));
strings::UniString secondaryText = fribidi::log2vis(strings::MakeUniString(m_params.m_secondaryText));
uint32_t primGlyphCount = primaryText.size();
uint32_t secondGlyphCount = secondaryText.size();
buffer_vector<strings::UniString, 3> primRes;
buffer_vector<strings::UniString, 3> secRes;
if (primGlyphCount == 0 && secondGlyphCount == 0)
return;
if (primGlyphCount == 0)
DrawSingleLine(batcher, secondaryLayout);
{
visSplit(secondaryText, secRes, " \n\t", false);
for (int i = 0; i < secRes.size(); ++i)
layouts.push_back(TextLayout(secRes[secRes.size() - i - 1], m_params.m_secondaryTextFont, textures));
vector<bool> dels(layouts.size(), false);
dels[dels.size() - 1] = true;
DrawPolyLine(batcher, layouts, dels);
}
else if (secondGlyphCount == 0)
DrawSingleLine(batcher, primaryLayout);
{
visSplit(primaryText, primRes, " \n\t", false);
for (int i = 0; i < primRes.size(); ++i)
layouts.push_back(TextLayout(primRes[primRes.size() - i - 1], m_params.m_primaryTextFont, textures));
vector<bool> dels(layouts.size(), false);
dels[dels.size() - 1] = true;
DrawPolyLine(batcher, layouts, dels);
}
else
DrawDoubleLine(batcher, primaryLayout, secondaryLayout);
{
visSplit(primaryText, primRes, " \n\t", false);
visSplit(secondaryText, secRes, " \n\t", false);
for (int i = 0; i < secRes.size(); ++i)
layouts.push_back(TextLayout(secRes[secRes.size() - i - 1], m_params.m_secondaryTextFont, textures));
for (int i = 0; i < primRes.size(); ++i)
layouts.push_back(TextLayout(primRes[primRes.size() - i - 1], m_params.m_primaryTextFont, textures));
vector<bool> dels(layouts.size(), false);
dels[secRes.size()-1] = true;
dels[dels.size() - 1] = true;
DrawPolyLine(batcher, layouts, dels);
}
}
}
void TextShape::DrawSingleLine(dp::RefPointer<dp::Batcher> batcher, TextLayout const & layout) const
void TextShape::DrawPolyLine(dp::RefPointer<dp::Batcher> batcher, vector<TextLayout> & layouts, vector<bool> & delims) const
{
size_t glyphCount = layout.GetGlyphCount();
vector<glsl_types::Quad4> positions(glyphCount);
vector<glsl_types::Quad4> texCoord(glyphCount);
vector<glsl_types::Quad4> fontColor(glyphCount);
vector<glsl_types::Quad4> outlineColor(glyphCount);
PointF const pixelOffset = GetShift(m_params.m_anchor, layout.GetPixelLength(), m_params.m_primaryTextFont.m_size) + m_params.m_primaryOffset;
dp::OverlayHandle * handle = layout.LayoutText(m_params.m_featureID, m_basePoint,
pixelOffset, m_params.m_depth,
positions, texCoord, fontColor, outlineColor);
BatchText(batcher, layout.GetTextureSet(),
positions, texCoord,
fontColor, outlineColor,
glyphCount, handle);
}
void TextShape::DrawDoubleLine(dp::RefPointer<dp::Batcher> batcher, TextLayout const & primaryLayout,
TextLayout const & secondaryLayout) const
{
float const primaryTextLength = primaryLayout.GetPixelLength();
float const secondaryTextLength = secondaryLayout.GetPixelLength();
bool const isPrimaryLonger = primaryTextLength > secondaryTextLength;
float const maxLength = max(primaryTextLength, secondaryTextLength);
float const minLength = min(primaryTextLength, secondaryTextLength);
float const halfLengthDiff = (maxLength - minLength) / 2.0;
uint32_t primarySize = m_params.m_primaryTextFont.m_size;
uint32_t secondarySize = m_params.m_secondaryTextFont.m_size;
float const textHeight = TEXT_EXPAND_FACTOR * (primarySize + secondarySize);
PointF const anchorOffset = GetShift(m_params.m_anchor, maxLength, textHeight);
float const primaryDx = isPrimaryLonger ? 0.0f : halfLengthDiff;
float const primaryDy = (1.0f - TEXT_EXPAND_FACTOR) * primarySize - TEXT_EXPAND_FACTOR * secondarySize;
PointF const primaryPixelOffset = PointF(primaryDx, primaryDy) + anchorOffset + m_params.m_primaryOffset;
size_t glyphCount = max(primaryLayout.GetGlyphCount(), secondaryLayout.GetGlyphCount());
vector<glsl_types::Quad4> positions(glyphCount);
vector<glsl_types::Quad4> texCoord(glyphCount);
vector<glsl_types::Quad4> fontColor(glyphCount);
vector<glsl_types::Quad4> outlineColor(glyphCount);
uint32_t const count = layouts.size();
vector<float> lengths(count);
float maxLength = 0.0f;
float textHeight = 0.0f;
uint32_t maxCount = 0;
uint32_t symCount = 0;
vector<uint32_t> heights(count);
for (int i = 0; i < count; ++i)
{
dp::OverlayHandle * handle = primaryLayout.LayoutText(m_params.m_featureID, m_basePoint,
primaryPixelOffset, m_params.m_depth,
positions, texCoord, fontColor, outlineColor);
BatchText(batcher, primaryLayout.GetTextureSet(),
positions, texCoord,
fontColor, outlineColor,
primaryLayout.GetGlyphCount(), handle);
lengths[i] = layouts[i].GetPixelLength();
heights[i] = layouts[i].GetPixelHeight();
textHeight += heights[i];
maxLength = max(maxLength, lengths[i]);
symCount += layouts[i].GetGlyphCount();
maxCount = max(maxCount, layouts[i].GetGlyphCount());
}
float const secondaryDx = isPrimaryLonger ? halfLengthDiff : 0.0f;
PointF const secondaryPixelOffset = PointF(secondaryDx, 0.0f) + anchorOffset + m_params.m_primaryOffset;
PointF const anchorOffset = GetShift(m_params.m_anchor, maxLength, textHeight * TEXT_EXPAND_FACTOR);
vector<glsl_types::Quad4> positions(symCount);
vector<glsl_types::Quad4> texCoord(symCount);
vector<glsl_types::Quad4> fontColor(symCount);
vector<glsl_types::Quad4> outlineColor(symCount);
float dy = (1.0f - TEXT_EXPAND_FACTOR) * heights[0];
vector<PointF> pixelOffset;
uint32_t delSymCount = 0;
uint32_t lastIndex = 0;
ASSERT(delims.back(), ());
for (int i = 0; i < count; ++i)
{
dp::OverlayHandle * handle = secondaryLayout.LayoutText(m_params.m_featureID, m_basePoint,
secondaryPixelOffset, m_params.m_depth,
positions, texCoord, fontColor, outlineColor);
BatchText(batcher, secondaryLayout.GetTextureSet(),
positions, texCoord,
fontColor, outlineColor,
secondaryLayout.GetGlyphCount(), handle);
float const dx = (maxLength - lengths[i]) / 2.0f;
pixelOffset.push_back(PointF(dx, dy) + anchorOffset + m_params.m_primaryOffset);
dy -= heights[i] * TEXT_EXPAND_FACTOR;
delSymCount += layouts[i].GetGlyphCount();
if (delims[i])
{
dp::OverlayHandle * handle = LayoutText(m_params.m_featureID, m_basePoint,
pixelOffset, m_params.m_depth,
positions, texCoord, fontColor, outlineColor, &layouts[lastIndex]);
BatchText(batcher, layouts[0].GetTextureSet(),
positions, texCoord,
fontColor, outlineColor,
delSymCount, handle);
pixelOffset.clear();
delSymCount = 0;
lastIndex = i + 1;
}
}
}

View file

@ -17,11 +17,12 @@ public:
TextShape(m2::PointF const & basePoint, TextViewParams const & params);
void Draw(dp::RefPointer<dp::Batcher> batcher, dp::RefPointer<dp::TextureSetHolder> textures) const;
void visSplit(strings::UniString const & visText,
buffer_vector<strings::UniString, 3> & res,
char const * delims,
bool splitAllFound) const;
private:
void DrawSingleLine(dp::RefPointer<dp::Batcher> batcher, TextLayout const & layout) const;
void DrawDoubleLine(dp::RefPointer<dp::Batcher> batcher, TextLayout const & primaryLayout,
TextLayout const & secondaryLayout) const;
void DrawPolyLine(dp::RefPointer<dp::Batcher> batcher, vector<TextLayout> & layouts, vector<bool> & delims) const;
private:
m2::PointF m_basePoint;