diff --git a/drape_frontend/text_shape.cpp b/drape_frontend/text_shape.cpp index 798ac7065c..74cb381dc1 100644 --- a/drape_frontend/text_shape.cpp +++ b/drape_frontend/text_shape.cpp @@ -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 & 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(iMiddle), + reverse_iterator(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 iter(visText, DelimT(delims)); iter; ++iter) + res.push_back(iter.GetUniString()); + } +} void TextShape::Draw(dp::RefPointer batcher, dp::RefPointer textures) const { ASSERT(!m_params.m_primaryText.empty(), ()); + vector 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 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 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 primRes; + buffer_vector 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 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 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 dels(layouts.size(), false); + dels[secRes.size()-1] = true; + dels[dels.size() - 1] = true; + DrawPolyLine(batcher, layouts, dels); + } } } -void TextShape::DrawSingleLine(dp::RefPointer batcher, TextLayout const & layout) const +void TextShape::DrawPolyLine(dp::RefPointer batcher, vector & layouts, vector & delims) const { - size_t glyphCount = layout.GetGlyphCount(); - vector positions(glyphCount); - vector texCoord(glyphCount); - vector fontColor(glyphCount); - vector 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 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 positions(glyphCount); - vector texCoord(glyphCount); - vector fontColor(glyphCount); - vector outlineColor(glyphCount); - + uint32_t const count = layouts.size(); + vector lengths(count); + float maxLength = 0.0f; + float textHeight = 0.0f; + uint32_t maxCount = 0; + uint32_t symCount = 0; + vector 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 positions(symCount); + vector texCoord(symCount); + vector fontColor(symCount); + vector outlineColor(symCount); + + float dy = (1.0f - TEXT_EXPAND_FACTOR) * heights[0]; + vector 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; + } } } diff --git a/drape_frontend/text_shape.hpp b/drape_frontend/text_shape.hpp index baa5a349ed..168a52688f 100644 --- a/drape_frontend/text_shape.hpp +++ b/drape_frontend/text_shape.hpp @@ -17,11 +17,12 @@ public: TextShape(m2::PointF const & basePoint, TextViewParams const & params); void Draw(dp::RefPointer batcher, dp::RefPointer textures) const; - + void visSplit(strings::UniString const & visText, + buffer_vector & res, + char const * delims, + bool splitAllFound) const; private: - void DrawSingleLine(dp::RefPointer batcher, TextLayout const & layout) const; - void DrawDoubleLine(dp::RefPointer batcher, TextLayout const & primaryLayout, - TextLayout const & secondaryLayout) const; + void DrawPolyLine(dp::RefPointer batcher, vector & layouts, vector & delims) const; private: m2::PointF m_basePoint;