Exemple #1
0
void CGUITextLayout::AppendToUTF32(const CStdStringW &utf16, character_t colStyle, vecText &utf32)
{
  // NOTE: Assumes a single line of text
  utf32.reserve(utf32.size() + utf16.size());
  for (unsigned int i = 0; i < utf16.size(); i++)
    utf32.push_back(utf16[i] | colStyle);
}
Exemple #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();
}
Exemple #3
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();
}
Exemple #4
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
}