Example #1
0
void CGUIFont::DrawText( float x, float y, const vecColors &colors, color_t shadowColor,
                const vecText &text, uint32_t alignment, float maxPixelWidth)
{
  if (!m_font) return;

  bool clip = maxPixelWidth > 0;
  if (clip && ClippedRegionIsEmpty(x, y, maxPixelWidth, alignment))
    return;

  maxPixelWidth = ROUND(maxPixelWidth / g_graphicsContext.GetGUIScaleX());
  vecColors renderColors;
  for (unsigned int i = 0; i < colors.size(); i++)
    renderColors.push_back(g_graphicsContext.MergeAlpha(colors[i] ? colors[i] : m_textColor));
  if (!shadowColor) shadowColor = m_shadowColor;
  if (shadowColor)
  {
    shadowColor = g_graphicsContext.MergeAlpha(shadowColor);
    vecColors shadowColors;
    for (unsigned int i = 0; i < renderColors.size(); i++)
      shadowColors.push_back((renderColors[i] & 0xff000000) != 0 ? shadowColor : 0);
    m_font->DrawTextInternal(x + 1, y + 1, shadowColors, text, alignment, maxPixelWidth, false);
  }
  m_font->DrawTextInternal( x, y, renderColors, text, alignment, maxPixelWidth, false);

  if (clip)
    g_graphicsContext.RestoreClipRegion();
}
Example #2
0
void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, color_t shadowColor,
                const vecText &text, uint32_t alignment, float maxWidth, const CScrollInfo &scrollInfo)
{
  if (!m_font) return;
  if (!shadowColor) shadowColor = m_shadowColor;

  if (!text.size() || ClippedRegionIsEmpty(x, y, maxWidth, alignment))
    return; // nothing to render

  if (!scrollInfo.m_widthValid)
  {
    /* Calculate the pixel width of the complete string */
    scrollInfo.m_textWidth = GetTextWidth(text);
    scrollInfo.m_totalWidth = scrollInfo.m_textWidth + GetTextWidth(scrollInfo.suffix);
    scrollInfo.m_widthValid = true;
  }

  assert(scrollInfo.m_totalWidth != 0);

  float textPixelWidth = ROUND(scrollInfo.m_textWidth / g_graphicsContext.GetGUIScaleX());
  float suffixPixelWidth = ROUND((scrollInfo.m_totalWidth - scrollInfo.m_textWidth) / g_graphicsContext.GetGUIScaleX());

  float offset;
  if(scrollInfo.pixelSpeed >= 0)
    offset = scrollInfo.pixelPos;
  else
    offset = scrollInfo.m_totalWidth - scrollInfo.pixelPos;

  vecColors renderColors;
  for (unsigned int i = 0; i < colors.size(); i++)
    renderColors.push_back(g_graphicsContext.MergeAlpha(colors[i] ? colors[i] : m_textColor));

  bool scroll =  !scrollInfo.waitTime && scrollInfo.pixelSpeed;
  if (shadowColor)
  {
    shadowColor = g_graphicsContext.MergeAlpha(shadowColor);
    vecColors shadowColors;
    for (unsigned int i = 0; i < renderColors.size(); i++)
      shadowColors.push_back((renderColors[i] & 0xff000000) != 0 ? shadowColor : 0);
    for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth)
    {
      m_font->DrawTextInternal(x + dx + 1, y + 1, shadowColors, text, alignment, textPixelWidth, scroll);
      m_font->DrawTextInternal(x + dx + scrollInfo.m_textWidth + 1, y + 1, shadowColors, scrollInfo.suffix, alignment, suffixPixelWidth, scroll);
    }
  }
  for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth)
  {
    m_font->DrawTextInternal(x + dx, y, renderColors, text, alignment, textPixelWidth, scroll);
    m_font->DrawTextInternal(x + dx + scrollInfo.m_textWidth, y, renderColors, scrollInfo.suffix, alignment, suffixPixelWidth, scroll);
  }

  g_graphicsContext.RestoreClipRegion();
}
Example #3
0
void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors, const vecText &text, uint32_t alignment, float maxPixelWidth, bool scrolling)
{
  Begin();

  // save the origin, which is scaled separately
  m_originX = x;
  m_originY = y;

  // Check if we will really need to truncate or justify the text
  if ( alignment & XBFONT_TRUNCATED )
  {
    if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth)
      alignment &= ~XBFONT_TRUNCATED;
  }
  else if ( alignment & XBFONT_JUSTIFIED )
  {
    if ( maxPixelWidth <= 0.0f )
      alignment &= ~XBFONT_JUSTIFIED;
  }

  // calculate sizing information
  float startX = 0;
  float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0;  // vertical centering

  if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) )
  {
    // Get the extent of this line
    float w = GetTextWidthInternal( text.begin(), text.end() );

    if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues
      w = maxPixelWidth;

    if ( alignment & XBFONT_CENTER_X)
      w *= 0.5f;
    // Offset this line's starting position
    startX -= w;
  }

  float spacePerLetter = 0; // for justification effects
  if ( alignment & XBFONT_JUSTIFIED )
  {
    // first compute the size of the text to render in both characters and pixels
    unsigned int lineChars = 0;
    float linePixels = 0;
    for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
    {
      Character *ch = GetCharacter(*pos);
      if (ch)
      { // spaces have multiple times the justification spacing of normal letters
        lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1;
        linePixels += ch->advance;
      }
    }
    if (lineChars > 1)
      spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1);
  }
  float cursorX = 0; // current position along the line

  for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
  {
    // If starting text on a new line, determine justification effects
    // Get the current letter in the CStdString
    color_t color = (*pos & 0xff0000) >> 16;
    if (color >= colors.size())
      color = 0;
    color = colors[color];

    // grab the next character
    Character *ch = GetCharacter(*pos);
    if (!ch) continue;

    if ( alignment & XBFONT_TRUNCATED )
    {
      // Check if we will be exceeded the max allowed width
      if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth )
      {
        // Yup. Let's draw the ellipses, then bail
        // Perhaps we should really bail to the next line in this case??
        Character *period = GetCharacter(L'.');
        if (!period)
          break;

        for (int i = 0; i < 3; i++)
        {
          RenderCharacter(startX + cursorX, startY, period, color, !scrolling);
          cursorX += period->advance;
        }
        break;
      }
    }
    else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
      break;  // exceeded max allowed width - stop rendering

    RenderCharacter(startX + cursorX, startY, ch, color, !scrolling);
    if ( alignment & XBFONT_JUSTIFIED )
    {
      if ((*pos & 0xffff) == L' ')
        cursorX += ch->advance + spacePerLetter * justification_word_weight;
      else
        cursorX += ch->advance + spacePerLetter;
    }
    else
      cursorX += ch->advance;
  }

  End();
}
Example #4
0
void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors, const vecText &text, uint32_t alignment, float maxPixelWidth, bool scrolling)
{
  Begin();

  uint32_t rawAlignment = alignment;
  bool dirtyCache;
  bool hardwareClipping = g_Windowing.ScissorsCanEffectClipping();
  CGUIFontCacheStaticPosition staticPos(x, y);
  CGUIFontCacheDynamicPosition dynamicPos;
  if (hardwareClipping)
  {
    dynamicPos = CGUIFontCacheDynamicPosition(g_graphicsContext.ScaleFinalXCoord(x, y),
                                              g_graphicsContext.ScaleFinalYCoord(x, y),
                                              g_graphicsContext.ScaleFinalZCoord(x, y));
  }
  CVertexBuffer unusedVertexBuffer;
  CVertexBuffer &vertexBuffer = hardwareClipping ?
      m_dynamicCache.Lookup(dynamicPos,
                            colors, text,
                            alignment, maxPixelWidth,
                            scrolling,
                            XbmcThreads::SystemClockMillis(),
                            dirtyCache) :
      unusedVertexBuffer;
  std::shared_ptr<std::vector<SVertex> > tempVertices = std::make_shared<std::vector<SVertex> >();
  std::shared_ptr<std::vector<SVertex> > &vertices = hardwareClipping ?
      tempVertices :
      static_cast<std::shared_ptr<std::vector<SVertex> >&>(m_staticCache.Lookup(staticPos,
                           colors, text,
                           alignment, maxPixelWidth,
                           scrolling,
                           XbmcThreads::SystemClockMillis(),
                           dirtyCache));
  if (dirtyCache)
  {
    // save the origin, which is scaled separately
    m_originX = x;
    m_originY = y;

    // Check if we will really need to truncate or justify the text
    if ( alignment & XBFONT_TRUNCATED )
    {
      if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth)
        alignment &= ~XBFONT_TRUNCATED;
    }
    else if ( alignment & XBFONT_JUSTIFIED )
    {
      if ( maxPixelWidth <= 0.0f )
        alignment &= ~XBFONT_JUSTIFIED;
    }

    // calculate sizing information
    float startX = 0;
    float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0;  // vertical centering

    if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) )
    {
      // Get the extent of this line
      float w = GetTextWidthInternal( text.begin(), text.end() );

      if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues
        w = maxPixelWidth;

      if ( alignment & XBFONT_CENTER_X)
        w *= 0.5f;
      // Offset this line's starting position
      startX -= w;
    }

    float spacePerSpaceCharacter = 0; // for justification effects
    if ( alignment & XBFONT_JUSTIFIED )
    {
      // first compute the size of the text to render in both characters and pixels
      unsigned int numSpaces = 0;
      float linePixels = 0;
      for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
      {
        Character *ch = GetCharacter(*pos);
        if (ch)
        {
          if ((*pos & 0xffff) == L' ')
            numSpaces +=  1;
          linePixels += ch->advance;
        }
      }
      if (numSpaces > 0)
        spacePerSpaceCharacter = (maxPixelWidth - linePixels) / numSpaces;
    }

    float cursorX = 0; // current position along the line
    for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
    {
      // If starting text on a new line, determine justification effects
      // Get the current letter in the CStdString
      color_t color = (*pos & 0xff0000) >> 16;
      if (color >= colors.size())
        color = 0;
      color = colors[color];

      // grab the next character
      Character *ch = GetCharacter(*pos);
      if (!ch) continue;

      if ( alignment & XBFONT_TRUNCATED )
      {
        // Check if we will be exceeded the max allowed width
        if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth )
        {
          // Yup. Let's draw the ellipses, then bail
          // Perhaps we should really bail to the next line in this case??
          Character *period = GetCharacter(L'.');
          if (!period)
            break;

          for (int i = 0; i < 3; i++)
          {
            RenderCharacter(startX + cursorX, startY, period, color, !scrolling, *tempVertices);
            cursorX += period->advance;
          }
          break;
        }
      }
      else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
        break;  // exceeded max allowed width - stop rendering

      RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, *tempVertices);
      if ( alignment & XBFONT_JUSTIFIED )
      {
        if ((*pos & 0xffff) == L' ')
          cursorX += ch->advance + spacePerSpaceCharacter;
        else
          cursorX += ch->advance;
      }
      else
        cursorX += ch->advance;
    }
    if (hardwareClipping)
    {
      CVertexBuffer &vertexBuffer = m_dynamicCache.Lookup(dynamicPos,
                                                          colors, text,
                                                          rawAlignment, maxPixelWidth,
                                                          scrolling,
                                                          XbmcThreads::SystemClockMillis(),
                                                          dirtyCache);
      CVertexBuffer newVertexBuffer = CreateVertexBuffer(*tempVertices);
      vertexBuffer = newVertexBuffer;
      m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertexBuffer, g_graphicsContext.GetClipRegion()));
    }
    else
    {
      m_staticCache.Lookup(staticPos,
                           colors, text,
                           rawAlignment, maxPixelWidth,
                           scrolling,
                           XbmcThreads::SystemClockMillis(),
                           dirtyCache) = *static_cast<CGUIFontCacheStaticValue *>(&tempVertices);
      /* Append the new vertices to the set collected since the first Begin() call */
      m_vertex.insert(m_vertex.end(), tempVertices->begin(), tempVertices->end());
    }
  }
  else
  {
    if (hardwareClipping)
Example #5
0
void CGUITextLayout::ParseText(const CStdStringW &text, uint32_t defaultStyle, color_t defaultColor, vecColors &colors, vecText &parsedText)
{
  // run through the string, searching for:
  // [B] or [/B] -> toggle bold on and off
  // [I] or [/I] -> toggle italics on and off
  // [COLOR ffab007f] or [/COLOR] -> toggle color on and off
  // [CAPS <option>] or [/CAPS] -> toggle capatilization on and off

  uint32_t currentStyle = defaultStyle; // start with the default font's style
  color_t currentColor = 0;

  colors.push_back(defaultColor);
  stack<color_t> colorStack;
  colorStack.push(0);

  // these aren't independent, but that's probably not too much of an issue
  // eg [UPPERCASE]Glah[LOWERCASE]FReD[/LOWERCASE]Georeg[/UPPERCASE] will work (lower case >> upper case)
  // but [LOWERCASE]Glah[UPPERCASE]FReD[/UPPERCASE]Georeg[/LOWERCASE] won't

  int startPos = 0;
  size_t pos = text.Find(L'[');
  while (pos != CStdString::npos && pos + 1 < text.size())
  {
    uint32_t newStyle = 0;
    color_t newColor = currentColor;
    bool colorTagChange = false;
    bool newLine = false;
    // have a [ - check if it's an ON or OFF switch
    bool on(true);
    int endPos = pos++; // finish of string
    if (text[pos] == L'/')
    {
      on = false;
      pos++;
    }
    // check for each type
    if (text.Mid(pos,2) == L"B]")
    { // bold - finish the current text block and assign the bold state
      pos += 2;
      if ((on && text.Find(L"[/B]",pos) >= 0) ||          // check for a matching end point
         (!on && (currentStyle & FONT_STYLE_BOLD)))       // or matching start point
        newStyle = FONT_STYLE_BOLD;
    }
    else if (text.Mid(pos,2) == L"I]")
    { // italics
      pos += 2;
      if ((on && text.Find(L"[/I]",pos) >= 0) ||          // check for a matching end point
         (!on && (currentStyle & FONT_STYLE_ITALICS)))    // or matching start point
        newStyle = FONT_STYLE_ITALICS;
    }
    else if (text.Mid(pos,10) == L"UPPERCASE]")
    {
      pos += 10;
      if ((on && text.Find(L"[/UPPERCASE]",pos) >= 0) ||  // check for a matching end point
         (!on && (currentStyle & FONT_STYLE_UPPERCASE)))  // or matching start point
        newStyle = FONT_STYLE_UPPERCASE;
    }
    else if (text.Mid(pos,10) == L"LOWERCASE]")
    {
      pos += 10;
      if ((on && text.Find(L"[/LOWERCASE]",pos) >= 0) ||  // check for a matching end point
         (!on && (currentStyle & FONT_STYLE_LOWERCASE)))  // or matching start point
        newStyle = FONT_STYLE_LOWERCASE;
    }
    else if (text.Mid(pos,3) == L"CR]" && on)
    {
      newLine = true;
      pos += 3;
    }
    else if (text.Mid(pos,5) == L"COLOR")
    { // color
      size_t finish = text.Find(L']', pos + 5);
      if (on && finish != CStdString::npos && (size_t)text.Find(L"[/COLOR]",finish) != CStdString::npos)
      {
        color_t color = g_colorManager.GetColor(text.Mid(pos + 5, finish - pos - 5));
        vecColors::const_iterator it = std::find(colors.begin(), colors.end(), color);
        if (it == colors.end())
        { // create new color
          if (colors.size() <= 0xFF)
          {
            newColor = colors.size();
            colors.push_back(color);
          }
          else // we have only 8 bits for color index, fallback to first color if reach max.
            newColor = 0;
        }
        else
          // reuse existing color
          newColor = it - colors.begin();
        colorStack.push(newColor);
        colorTagChange = true;
      }
      else if (!on && finish == pos + 5 && colorStack.size() > 1)
      { // revert to previous color
        colorStack.pop();
        newColor = colorStack.top();
        colorTagChange = true;
      }
      if (finish != CStdString::npos)
        pos = finish + 1;
    }

    if (newStyle || colorTagChange || newLine)
    { // we have a new style or a new color, so format up the previous segment
      CStdStringW subText = text.Mid(startPos, endPos - startPos);
      if (currentStyle & FONT_STYLE_UPPERCASE)
        subText.ToUpper();
      if (currentStyle & FONT_STYLE_LOWERCASE)
        subText.ToLower();
      AppendToUTF32(subText, ((currentStyle & 3) << 24) | (currentColor << 16), parsedText);
      if (newLine)
        parsedText.push_back(L'\n');

      // and switch to the new style
      startPos = pos;
      currentColor = newColor;
      if (on)
        currentStyle |= newStyle;
      else
        currentStyle &= ~newStyle;
    }
    pos = text.Find(L'[',pos);
  }
  // now grab the remainder of the string
  CStdStringW subText = text.Mid(startPos, text.GetLength() - startPos);
  if (currentStyle & FONT_STYLE_UPPERCASE)
    subText.ToUpper();
  if (currentStyle & FONT_STYLE_LOWERCASE)
    subText.ToLower();
  AppendToUTF32(subText, ((currentStyle & 3) << 24) | (currentColor << 16), parsedText);
}
Example #6
0
void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, color_t shadowColor,
                                 const vecText &text, uint32_t alignment, float maxWidth, CScrollInfo &scrollInfo)
{
    if (!m_font) return;
    if (!shadowColor) shadowColor = m_shadowColor;

    float spaceWidth = GetCharWidth(L' ');
    // max chars on screen + extra margin chars
    vecText::size_type maxChars =
        std::min<vecText::size_type>(
            (text.size() + (vecText::size_type)scrollInfo.suffix.size()),
            (vecText::size_type)((maxWidth * 1.05f) / spaceWidth));

    if (!text.size() || ClippedRegionIsEmpty(x, y, maxWidth, alignment))
        return; // nothing to render

    maxWidth = ROUND(maxWidth / g_graphicsContext.GetGUIScaleX());

    // draw at our scroll position
    // we handle the scrolling as follows:
    //   We scroll on a per-pixel basis up until we have scrolled the first character outside
    //   of our viewport, whereby we cycle the string around, and reset the scroll position.
    //
    //   pixelPos is the amount in pixels to move the string by.
    //   characterPos is the amount in characters to rotate the string by.
    //
    float offset = scrollInfo.pixelPos;
    if (!scrollInfo.waitTime)
    {
        // move along by the appropriate scroll amount
        float scrollAmount = fabs(scrollInfo.GetPixelsPerFrame() * g_graphicsContext.GetGUIScaleX());

        if (scrollInfo.pixelSpeed > 0)
        {
            // we want to move scrollAmount, grab the next character
            float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
            if (scrollInfo.pixelPos + scrollAmount < charWidth)
                scrollInfo.pixelPos += scrollAmount;  // within the current character
            else
            {   // past the current character, decrement scrollAmount by the charWidth and move to the next character
                while (scrollInfo.pixelPos + scrollAmount >= charWidth)
                {
                    scrollAmount -= (charWidth - scrollInfo.pixelPos);
                    scrollInfo.pixelPos = 0;
                    scrollInfo.characterPos++;
                    if (scrollInfo.characterPos >= text.size() + scrollInfo.suffix.size())
                    {
                        scrollInfo.Reset();
                        break;
                    }
                    charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
                }
            }
            offset = scrollInfo.pixelPos;
        }
        else if (scrollInfo.pixelSpeed < 0)
        {   // scrolling backwards
            // we want to move scrollAmount, grab the next character
            float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
            if (scrollInfo.pixelPos + scrollAmount < charWidth)
                scrollInfo.pixelPos += scrollAmount;  // within the current character
            else
            {   // past the current character, decrement scrollAmount by the charWidth and move to the next character
                while (scrollInfo.pixelPos + scrollAmount >= charWidth)
                {
                    scrollAmount -= (charWidth - scrollInfo.pixelPos);
                    scrollInfo.pixelPos = 0;
                    if (scrollInfo.characterPos == 0)
                    {
                        scrollInfo.Reset();
                        scrollInfo.characterPos = text.size() + scrollInfo.suffix.size() - 1;
                        break;
                    }
                    scrollInfo.characterPos--;
                    charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
                }
            }
            offset = charWidth - scrollInfo.pixelPos;
        }
    }
    else
        scrollInfo.waitTime--;

    // Now rotate our string as needed, only take a slightly larger then visible part of the text.
    unsigned int pos = scrollInfo.characterPos;
    vecText renderText;
    renderText.reserve(maxChars);
    for (vecText::size_type i = 0; i < maxChars; i++)
    {
        if (pos >= text.size() + scrollInfo.suffix.size())
            pos = 0;
        if (pos < text.size())
            renderText.push_back(text[pos]);
        else
            renderText.push_back(scrollInfo.suffix[pos - text.size()]);
        pos++;
    }

    vecColors renderColors;
    for (unsigned int i = 0; i < colors.size(); i++)
        renderColors.push_back(g_graphicsContext.MergeAlpha(colors[i] ? colors[i] : m_textColor));

    bool scroll =  !scrollInfo.waitTime && scrollInfo.pixelSpeed;
    if (shadowColor)
    {
        shadowColor = g_graphicsContext.MergeAlpha(shadowColor);
        vecColors shadowColors;
        for (unsigned int i = 0; i < renderColors.size(); i++)
            shadowColors.push_back((renderColors[i] & 0xff000000) != 0 ? shadowColor : 0);
        m_font->DrawTextInternal(x - offset + 1, y + 1, shadowColors, renderText, alignment, maxWidth + scrollInfo.pixelPos + m_font->GetLineHeight(2.0f), scroll);
    }
    m_font->DrawTextInternal(x - offset, y, renderColors, renderText, alignment, maxWidth + scrollInfo.pixelPos + m_font->GetLineHeight(2.0f), scroll);

    g_graphicsContext.RestoreClipRegion();
}
Example #7
0
void CGUITextLayout::ParseText(const CStdStringW &text, uint32_t defaultStyle, vecColors &colors, vecText &parsedText)
{
  // run through the string, searching for:
  // [B] or [/B] -> toggle bold on and off
  // [I] or [/I] -> toggle italics on and off
  // [COLOR ffab007f] or [/COLOR] -> toggle color on and off
  // [CAPS <option>] or [/CAPS] -> toggle capatilization on and off

//  uint32_t currentStyle = defaultStyle; // start with the default font's style
//  color_t currentColor = 0;

  stack<color_t> colorStack;
  colorStack.push(0);

  // these aren't independent, but that's probably not too much of an issue
  // eg [UPPERCASE]Glah[LOWERCASE]FReD[/LOWERCASE]Georeg[/UPPERCASE] will work (lower case >> upper case)
  // but [LOWERCASE]Glah[UPPERCASE]FReD[/UPPERCASE]Georeg[/LOWERCASE] won't
#define FONT_STYLE_UPPERCASE 4
#define FONT_STYLE_LOWERCASE 8

  int boldCounter = 0;
  int italicsCoutner = 0;
  int upperCounter = 0;
  int lowerCounter = 0;
  color_t color = 0;

  int startPos = 0;
  size_t pos = text.Find(L'[');
  while (pos != CStdString::npos && pos + 1 < text.size())
  {
    int style = 0;

    if (pos - startPos > 0)
    {
      if (boldCounter)
        style |= FONT_STYLE_BOLD;

      if (italicsCoutner)
        style |= FONT_STYLE_ITALICS;

      CStdStringW subText = text.Mid(startPos, pos - startPos);

      if (upperCounter)
      {
#if defined(_LINUX) && !defined(__APPLE__)
        std::transform(subText.begin(), subText.end(), subText.begin(),
                       (gunichar(*)(gunichar)) g_unichar_toupper);
#else
        subText.ToUpper();
#endif
      }

      if (lowerCounter)
      {
#if defined(_LINUX) && !defined(__APPLE__)
        std::transform(subText.begin(), subText.end(), subText.begin(),
                       (gunichar(*)(gunichar)) g_unichar_tolower);
#else
        subText.ToLower();
#endif
      }

      AppendToUTF32(subText, ((style & 3) << 24) | (color << 16), parsedText);

      startPos = pos;
    }

    // have a [ - check if it's an ON or OFF switch
    bool ignoreTag = false;
    ++pos;

    bool on = true;
    if (text[pos] == L'/')
    {
      on = false;
      pos++;
    }

    // check for each type
    if (text.Mid(pos,2) == L"B]")
    { // bold - finish the current text block and assign the bold state
      pos += 2;
      on ? ++boldCounter : --boldCounter;
    }
    else if (text.Mid(pos,2) == L"I]")
    { // italics
      pos += 2;
      on ? ++italicsCoutner : --italicsCoutner;
    }
    else if (text.Mid(pos,10) == L"UPPERCASE]")
    {
      pos += 10;
      on ? ++upperCounter : --upperCounter;
    }
    else if (text.Mid(pos,10) == L"LOWERCASE]")
    {
      pos += 10;
      on ? ++lowerCounter : --lowerCounter;
    }
    else if (text.Mid(pos,3) == L"CR]" && on)
    {
      pos += 3;
      parsedText.push_back(L'\n');
    }
    else if (text.Mid(pos,5) == L"COLOR")
    { // color
      size_t finish = text.Find(L']', pos + 5);
      if (on && finish != CStdString::npos && (size_t) text.Find(L"[/COLOR]",finish) != CStdString::npos)
      { // create new color
        color = colors.size();
        colors.push_back(g_colorManager.GetColor(text.Mid(pos + 5, finish - pos - 5)));
        colorStack.push(color);
      }
      else if (!on && finish == pos + 5 && colorStack.size() > 1)
      { // revert to previous color
        colorStack.pop();
        color = colorStack.top();
      }
      pos = finish + 1;
    }
    else
    {
      ignoreTag = true;
    }

    if (!ignoreTag)
    {
      startPos = pos;
    }

    pos = text.Find(L'[',pos);
  }

  // now grab the remainder of the string
  CStdStringW subText = text.Mid(startPos, text.GetLength() - startPos);
  int style = 0;
  if (upperCounter)
  {
#if defined(_LINUX) && !defined(__APPLE__)
        std::transform(subText.begin(), subText.end(), subText.begin(),
                       (gunichar(*)(gunichar)) g_unichar_toupper);
#else
        subText.ToUpper();
#endif
  }

  if (lowerCounter)
  {
#if defined(_LINUX) && !defined(__APPLE__)
    std::transform(subText.begin(), subText.end(), subText.begin(),
                   (gunichar(*)(gunichar)) g_unichar_tolower);
#else
    subText.ToLower();
#endif
  }

  if (boldCounter)
    style |= FONT_STYLE_BOLD;
  if (italicsCoutner)
    style |= FONT_STYLE_ITALICS;
  AppendToUTF32(subText, ((style & 3) << 24) | (color << 16), parsedText);
}
Example #8
0
void CGUIFontTTFBase::BuildTextCoordinates(float x, float y, const vecColors &colors, color_t shadowColor,
        const vecText &text, uint32_t alignment, float maxPixelWidth, bool scrolling, FontCoordsIndiced& pData)
{
    // Check if we will really need to truncate or justify the text
    m_originX = x;
    m_originY = y;

    if ( alignment & XBFONT_TRUNCATED )
    {
        if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth)
            alignment &= ~XBFONT_TRUNCATED;
    }
    else if ( alignment & XBFONT_JUSTIFIED )
    {
        if ( maxPixelWidth <= 0.0f )
            alignment &= ~XBFONT_JUSTIFIED;
    }

    // calculate sizing information
    float startX = 0;
    float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*(m_cellHeight-2) : 0;  // vertical centering

    if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) )
    {
        // Get the extent of this line
        float w = GetTextWidthInternal( text.begin(), text.end() );

        if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth )
            w = maxPixelWidth;

        if ( alignment & XBFONT_CENTER_X)
            w *= 0.5f;
        // Offset this line's starting position
        startX -= w;
    }

    float spacePerLetter = 0; // for justification effects
#if 0
    if ( alignment & XBFONT_JUSTIFIED )
    {
        // first compute the size of the text to render in both characters and pixels
        unsigned int lineChars = 0;
        float linePixels = 0;
        for (vecText::const_iterator pos = text.begin(); pos != text.end(); pos++)
        {
            Character *ch = GetCharacter(*pos);
            if (ch)
            {   // spaces have multiple times the justification spacing of normal letters
                lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1;
                linePixels += ch->advance;
            }
        }
        if (lineChars > 1)
            spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1);
    }
#endif

    ReloadFace();

#ifdef HAS_HARFBUZZ_NG
    int i = 0;
    wchar_t strW[text.size()];
    for (vecText::const_iterator pos = text.begin(); pos != text.end(); pos++)
    {
        wchar_t letter = (wchar_t)((*pos) & 0xffff);
        strW[i] = letter;
        i++;
    }

    hb_buffer_t *hb_buffer = hb_buffer_create(text.size());
    hb_buffer_set_unicode_funcs(hb_buffer, hb_glib_get_unicode_funcs());
    hb_buffer_add_utf32(hb_buffer, (const uint32_t*) strW, text.size(), 0, text.size());
    hb_buffer_set_direction(hb_buffer, HB_DIRECTION_LTR);

    hb_shape (hb_font, hb_buffer, NULL, 0);
    unsigned int glyph_info_len;
    hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (hb_buffer, &glyph_info_len);
    hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (hb_buffer, &glyph_info_len);

#else /* HAS_HARFBUZZ_NG */
    FT_Vector delta;
    Character* previousCh = NULL;
#endif

    float cursorX = 0; // current position along the line

    for (vecText::const_iterator pos = text.begin(); pos != text.end(); pos++)
    {
        // If starting text on a new line, determine justification effects
        // Get the current letter in the CStdString
        color_t color = (*pos & 0xff0000) >> 16;
        if (color >= colors.size())
            color = 0;
        color = colors[color];

        // grab the next character
        Character *ch = GetCharacter(*pos);
        if (!ch) continue;

        if ( alignment & XBFONT_TRUNCATED )
        {
            // Check if we will be exceeded the max allowed width
            if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth )
            {
                // Yup. Let's draw the ellipses, then bail
                // Perhaps we should really bail to the next line in this case??
                Character *period = GetCharacter(L'.');
                if (!period)
                    break;

                for (int i = 0; i < 3; i++)
                {
                    BuildCharacterCoordinates(startX + cursorX, startY, period, color, shadowColor, !scrolling, pData);
                    cursorX += period->advance;
                }
                break;
            }
        }
        else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
            break;  // exceeded max allowed width - stop rendering

#ifdef HAS_HARFBUZZ_NG
        BuildCharacterCoordinates(startX + cursorX + (hb_position->x_offset * (1./64)), startY - (hb_position->y_offset * (1./64)), ch, color, shadowColor, !scrolling, pData);

        if ( alignment & XBFONT_JUSTIFIED )
        {
            if ((*pos & 0xffff) == L' ')
                cursorX +=  (hb_position->x_advance * (1./64)) + spacePerLetter * justification_word_weight;
            else
                cursorX += (hb_position->x_advance * (1./64)) + spacePerLetter;
        }
        else
            cursorX +=  hb_position->x_advance * (1./64);

        hb_glyph++;
        hb_position++;
#else
        if (previousCh)
        {
            FT_Get_Kerning(m_face, previousCh->glyphIndex, ch->glyphIndex,
                           FT_KERNING_DEFAULT, &delta);
            cursorX += (float) (delta.x / 64);
        }

        BuildCharacterCoordinates(startX + cursorX, startY, ch, color, shadowColor, !scrolling, pData);
        if ( alignment & XBFONT_JUSTIFIED )
        {
            if ((*pos & 0xffff) == L' ')
                cursorX += ch->advance + spacePerLetter * justification_word_weight;
            else
                cursorX += ch->advance + spacePerLetter;
        }
        else
            cursorX += ch->advance;

        previousCh = ch;
#endif
    }

#ifdef HAS_HARFBUZZ_NG
    hb_buffer_destroy(hb_buffer);
#endif
}