Exemple #1
0
void
Canvas::text_transparent(PixelScalar x, PixelScalar y, const TCHAR *text)
{
  assert(text != NULL);
  assert(ValidateUTF8(text));

#ifdef HAVE_GLES
  assert(x_offset == OpenGL::translate_x);
  assert(y_offset == OpenGL::translate_y);
#endif

  if (font == NULL)
    return;

  GLTexture *texture = TextCache::Get(font, text);
  if (texture == NULL)
    return;

  GLEnable scope(GL_TEXTURE_2D);
  texture->Bind();
  GLLogicOp logic_op(GL_AND_INVERTED);

  /* cut out the shape in black */
  OpenGL::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  texture->Draw(x, y);

  if (text_color != COLOR_BLACK) {
    /* draw the text color on top */
    OpenGL::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    logic_op.set(GL_OR);
    text_color.Set();
    texture->Draw(x, y);
  }
}
Exemple #2
0
void
Canvas::DrawTransparentText(int x, int y, const TCHAR *text)
{
  assert(text != nullptr);
  assert(ValidateUTF8(text));

#ifdef HAVE_GLES
  assert(offset == OpenGL::translate);
#endif

  if (font == nullptr)
    return;

  GLTexture *texture = TextCache::Get(*font, text);
  if (texture == nullptr)
    return;

  PrepareColoredAlphaTexture(text_color);

#ifndef USE_GLSL
  GLEnable scope(GL_TEXTURE_2D);
#endif

  const GLBlend blend(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  texture->Bind();
  texture->Draw(x, y);
}
Exemple #3
0
void
Canvas::DrawText(int x, int y, const TCHAR *text)
{
  assert(text != nullptr);
  assert(ValidateUTF8(text));

#ifdef HAVE_GLES
  assert(offset == OpenGL::translate);
#endif

  if (font == nullptr)
    return;

  GLTexture *texture = TextCache::Get(*font, text);
  if (texture == nullptr)
    return;

  if (background_mode == OPAQUE)
    DrawFilledRectangle(x, y,
                        x + texture->GetWidth(), y + texture->GetHeight(),
                        background_color);

  PrepareColoredAlphaTexture(text_color);

#ifndef USE_GLSL
  GLEnable scope(GL_TEXTURE_2D);
#endif

  const GLBlend blend(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  texture->Bind();
  texture->Draw(x, y);
}
Exemple #4
0
void
Canvas::DrawText(int x, int y, const TCHAR *text)
{
    assert(text != nullptr);
#ifndef UNICODE
    assert(ValidateUTF8(text));
#endif

    auto s = RenderText(font, text);
    if (s.data == nullptr)
        return;

    SDLRasterCanvas canvas(buffer);

    if (background_mode == OPAQUE) {
        OpaqueAlphaPixelOperations<SDLPixelTraits, GreyscalePixelTraits>
        opaque(canvas.Import(background_color), canvas.Import(text_color));
        canvas.CopyRectangle<decltype(opaque), GreyscalePixelTraits>
        (x, y, s.width, s.height,
         GreyscalePixelTraits::const_pointer_type(s.data),
         s.pitch, opaque);
    } else {
        ColoredAlphaPixelOperations<SDLPixelTraits, GreyscalePixelTraits>
        transparent(canvas.Import(text_color));
        canvas.CopyRectangle<decltype(transparent), GreyscalePixelTraits>
        (x, y, s.width, s.height,
         GreyscalePixelTraits::const_pointer_type(s.data),
         s.pitch, transparent);
    }
}
Exemple #5
0
void
Canvas::DrawClippedText(int x, int y,
                        unsigned width, unsigned height,
                        const TCHAR *text)
{
  assert(text != nullptr);
  assert(ValidateUTF8(text));

#ifdef HAVE_GLES
  assert(offset == OpenGL::translate);
#endif

  if (font == nullptr)
    return;

  GLTexture *texture = TextCache::Get(*font, text);
  if (texture == nullptr)
    return;

  if (texture->GetHeight() < height)
    height = texture->GetHeight();
  if (texture->GetWidth() < width)
    width = texture->GetWidth();

  PrepareColoredAlphaTexture(text_color);

#ifndef USE_GLSL
  GLEnable scope(GL_TEXTURE_2D);
#endif

  const GLBlend blend(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  texture->Bind();
  texture->Draw(x, y, width, height, 0, 0, width, height);
}
Exemple #6
0
static TCHAR *
import_label(const char *src)
{
  if (src == nullptr)
    return nullptr;

  src = TrimLeft(src);
  if (strcmp(src, "RAILWAY STATION") == 0 ||
      strcmp(src, "RAILROAD STATION") == 0 ||
      strcmp(src, "UNK") == 0)
    return nullptr;

#ifdef _UNICODE
  size_t length = strlen(src);
  TCHAR *dest = new TCHAR[length + 1];
  if (::MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, length + 1) <= 0) {
    delete[] dest;
    return nullptr;
  }

  return dest;
#else
  if (!ValidateUTF8(src))
    return nullptr;

  return strdup(src);
#endif
}
Exemple #7
0
void
Canvas::DrawTransparentText(int x, int y, const TCHAR *text)
{
  assert(text != nullptr);
#ifndef UNICODE
  assert(ValidateUTF8(text));
#endif

#ifdef ENABLE_OPENGL
  /*
   * RenderText return buffer owned by TextCache, this can be delete by GUI Thread
   *  lock is need for avoid to used alredy deleted buffer.
   */
  TextCache::Lock();
#endif
  
  auto s = RenderText(font, text);
  if (s.data != nullptr) {

    SDLRasterCanvas canvas(buffer);
    ColoredAlphaPixelOperations<ActivePixelTraits, GreyscalePixelTraits>
      transparent(canvas.Import(text_color));
    canvas.CopyRectangle<decltype(transparent), GreyscalePixelTraits>
      (x, y, s.width, s.height,
       GreyscalePixelTraits::const_pointer_type(s.data),
       s.pitch, transparent);
  }
  
#ifdef ENABLE_OPENGL  
  TextCache::Unlock();
#endif  
}
Exemple #8
0
void
Canvas::DrawClippedText(int x, int y, unsigned max_width, const TCHAR *text)
{
  static TCHAR text_buffer[256];
  assert(text != NULL);
#ifndef UNICODE
  assert(ValidateUTF8(text));
#endif
  const TCHAR *clipped_text = text;
  unsigned width = Canvas::CalcTextWidth(text);
  if (width > max_width) {
    #warning "that wrong, does not handle multibyte char."
    unsigned new_size;
    fixed target_percent = fixed(max_width) / fixed(width);
    new_size = fixed(StringLength(text)) * target_percent;
    CopyString(text_buffer, text, std::min(new_size, 256u));
    clipped_text = text_buffer;
  }
  
#ifndef UNICODE
  assert(ValidateUTF8(clipped_text));
#endif
  
  auto s = RenderText(font, clipped_text);
  if (s.data == nullptr)
    return;

  SDLRasterCanvas canvas(buffer);
  if (background_mode == OPAQUE) {
    OpaqueAlphaPixelOperations<ActivePixelTraits, GreyscalePixelTraits>
      opaque(canvas.Import(background_color), canvas.Import(text_color));
    canvas.CopyRectangle<decltype(opaque), GreyscalePixelTraits>
      (x, y, s.width, s.height,
       GreyscalePixelTraits::const_pointer_type(s.data),
       s.pitch, opaque);
  } else {
    ColoredAlphaPixelOperations<ActivePixelTraits, GreyscalePixelTraits>
      transparent(canvas.Import(text_color));
    canvas.CopyRectangle<decltype(transparent), GreyscalePixelTraits>
      (x, y, s.width, s.height,
       GreyscalePixelTraits::const_pointer_type(s.data),
       s.pitch, transparent);
  }
}
Exemple #9
0
//------------------------------------------------------------------------------
PixelSize
Font::TextSize(const TCHAR *text) const
  {
  assert(text != nullptr);
#ifndef _UNICODE
  assert(ValidateUTF8(text));
#endif
  QFontMetrics m(this->font);
  return { m.width(text), m.height() };
  }
Exemple #10
0
  gcc_pure
  bool IsValid() const {
#ifdef _UNICODE
    return value != nullptr;
#else
    assert(value != nullptr);

    return ValidateUTF8(value);
#endif
  }
Exemple #11
0
/**
 * Looks up a string of text from the current language file
 *
 * Currently very simple. Looks up the current string and current language
 * to find the appropriate string response. On failure will return
 * the string itself.
 *
 * NOTES CACHING:
 * - Could load the whole file or part
 * - qsort/bsearch good idea
 * - cache misses in data structure for future use
 * @param text The text to search for
 * @return The translation if found, otherwise the text itself
 */
const TCHAR*
gettext(const TCHAR* text)
{
  assert(language_allowed);
  assert(text != NULL);

  // If empty string or no language file is loaded -> skip the translation
  if (StringIsEmpty(text) || mo_file == NULL)
    return text;

#ifdef _UNICODE
  // Try to lookup the english string in the map of cached TCHAR translations
  const tstring text2(text);
  translation_map::const_iterator it = translations.find(text2);
  if (it != translations.end())
    // Return the looked up translation
    return it->second.c_str();

  // Convert the english TCHAR string to char
  size_t wide_length = _tcslen(text);
  char original[wide_length * 4 + 1];

  // If the conversion failed -> use the english original string
  if (::WideCharToMultiByte(CP_UTF8, 0, text, -1,
                            original, sizeof(original), NULL, NULL) <= 0)
    return text;

  // Lookup the converted english char string in the MO file
  const char *translation = mo_file->lookup(original);
  // If the lookup failed -> use the english original string
  if (translation == NULL || *translation == 0 ||
      strcmp(original, translation) == 0)
    return text;

  // Convert the translated char string to TCHAR
  TCHAR translation2[strlen(translation) + 1];
  if (::MultiByteToWideChar(CP_UTF8, 0, translation, -1, translation2,
                            ARRAY_SIZE(translation2)) <= 0)
    return text;

  // Add the translated TCHAR string to the cache map for the next time
  translations[text2] = translation2;

  // Return the translated TCHAR string
  return translations[text2].c_str();
#else
  // Search for the english original string in the MO file
  const char *translation = mo_file->lookup(text);
  // Return either the translated string if found or the original
  return translation != NULL && *translation != 0 && ValidateUTF8(translation)
    ? translation
    : text;
#endif
}
Exemple #12
0
void
Canvas::DrawOpaqueText(int x, int y, const PixelRect &rc,
                       const TCHAR *_text)
{
  assert(_text != nullptr);
#ifndef UNICODE
  assert(ValidateUTF8(_text));
#endif

  DrawFilledRectangle(rc, background_color);
  DrawTransparentText(x, y, _text);
}
Exemple #13
0
void
Canvas::DrawText(int x, int y,
                 const TCHAR *_text, size_t length)
{
  assert(_text != nullptr);

  TCHAR copy[length + 1];
  *std::copy_n(_text, length, copy) = _T('\0');

#ifndef UNICODE
  assert(ValidateUTF8(copy));
#endif

  DrawText(x, y, copy);
}
Exemple #14
0
inline void
SkyLinesTracking::Client::OnUserNameReceived(const UserNameResponsePacket &packet,
                                             size_t length)
{
  if (length != sizeof(packet) + packet.name_length)
    return;

  /* the name follows the UserNameResponsePacket object */
  const char *_name = (const char *)(&packet + 1);
  const std::string name(_name, packet.name_length);
  if (!ValidateUTF8(name.c_str()))
    return;

  UTF8ToWideConverter tname(name.c_str());
  handler->OnUserName(FromBE32(packet.user_id), tname);
}
Exemple #15
0
void
Canvas::DrawText(PixelScalar x, PixelScalar y,
                 const TCHAR *_text, size_t length)
{
    assert(_text != NULL);

    TCHAR copy[length + 1];
    std::copy(_text, _text + length, copy);
    copy[length] = _T('\0');

#ifndef UNICODE
    assert(ValidateUTF8(copy));
#endif

    DrawText(x, y, copy);
}
Exemple #16
0
const PixelSize
Canvas::CalcTextSize(const TCHAR *text, size_t length) const
{
  assert(text != nullptr);

  TCHAR *duplicated = _tcsdup(text);
  duplicated[length] = 0;

#ifndef UNICODE
  assert(ValidateUTF8(duplicated));
#endif

  const PixelSize size = CalcTextSize(duplicated);
  free(duplicated);

  return size;
}
Exemple #17
0
void
Canvas::DrawTransparentText(int x, int y, const TCHAR *text)
{
  assert(text != nullptr);
#ifndef UNICODE
  assert(ValidateUTF8(text));
#endif

  auto s = RenderText(font, text);
  if (s.data == nullptr)
    return;

  SDLRasterCanvas canvas(buffer);
  ColoredAlphaPixelOperations<ActivePixelTraits, GreyscalePixelTraits>
    transparent(canvas.Import(text_color));
  CopyTextRectangle(canvas, x, y, s.width, s.height, transparent, s);
}
Exemple #18
0
void
Canvas::DrawText(int x, int y, const TCHAR *text)
{
  assert(text != nullptr);
#ifndef UNICODE
  assert(ValidateUTF8(text));
#endif

  auto s = RenderText(font, text);
  if (s.data == nullptr)
    return;

  SDLRasterCanvas canvas(buffer);
  CopyTextRectangle(canvas, x, y, s.width, s.height, s,
                    text_color, background_color,
                    background_mode == OPAQUE);
}
Exemple #19
0
/**
 * Decodes the FlarmNet.org file and puts the wanted
 * characters into the res pointer
 * @param file File handle
 * @param charCount Number of character to decode
 * @param res Pointer to be written in
 */
static void
LoadString(const char *bytes, size_t length, TCHAR *res, size_t res_size)
{
  const char *const end = bytes + length * 2;

#ifndef _UNICODE
  const char *const limit = res + res_size - 2;
#endif

  TCHAR *p = res;

  char tmp[3];
  tmp[2] = 0;

  while (bytes < end) {
    tmp[0] = *bytes++;
    tmp[1] = *bytes++;

    /* FLARMNet files are ISO-Latin-1, which is kind of short-sighted */

    const unsigned char ch = (unsigned char)strtoul(tmp, NULL, 16);
#ifdef _UNICODE
    /* Latin-1 can be converted to WIN32 wchar_t by casting */
    *p++ = ch;
#else
    /* convert to UTF-8 on all other platforms */

    if (p >= limit)
      break;

    p = Latin1ToUTF8(ch, p);
#endif
  }

  *p = 0;

#ifndef _UNICODE
  assert(ValidateUTF8(res));
#endif

  // Trim the string of any additional spaces
  StripRight(res);
}
Exemple #20
0
void
Canvas::text(PixelScalar x, PixelScalar y, const TCHAR *text)
{
  assert(text != NULL);
  assert(ValidateUTF8(text));

#ifdef HAVE_GLES
  assert(x_offset == OpenGL::translate_x);
  assert(y_offset == OpenGL::translate_y);
#endif

  if (font == NULL)
    return;

  GLTexture *texture = TextCache::Get(font, text);
  if (texture == NULL)
    return;

  if (background_mode == OPAQUE)
    /* draw the opaque background */
    DrawFilledRectangle(x, y,
                        x + texture->GetWidth(), y + texture->GetHeight(),
                        background_color);

  GLEnable scope(GL_TEXTURE_2D);
  texture->Bind();
  GLLogicOp logic_op(GL_AND_INVERTED);

  if (background_mode != OPAQUE || background_color != COLOR_BLACK) {
    /* cut out the shape in black */
    OpenGL::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    texture->Draw(x, y);
  }

  if (text_color != COLOR_BLACK) {
    /* draw the text color on top */
    OpenGL::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    logic_op.set(GL_OR);
    text_color.Set();
    texture->Draw(x, y);
  }
}
Exemple #21
0
const PixelSize
Canvas::CalcTextSize(const TCHAR *text) const
{
  assert(text != nullptr);
#ifndef UNICODE
  assert(ValidateUTF8(text));
#endif

  PixelSize size = { 0, 0 };

  if (font == nullptr)
    return size;

  /* see if the TextCache can handle this request */
  size = TextCache::LookupSize(*font, text);
  if (size.cy > 0)
    return size;

  return TextCache::GetSize(*font, text);
}
Exemple #22
0
bool
ProfileMap::Get(const char *key, TCHAR *value, size_t max_size) const
{
    const char *src = Get(key);
    if (src == nullptr) {
        value[0] = _T('\0');
        return false;
    }

#ifdef _UNICODE
    int result = MultiByteToWideChar(CP_UTF8, 0, src, -1,
                                     value, max_size);
    return result > 0;
#else
    if (!ValidateUTF8(src))
        return false;

    CopyString(value, src, max_size);
    return true;
#endif
}
Exemple #23
0
static TCHAR *
import_label(const char *src)
{
  if (src == NULL || strcmp(src, "UNK") == 0 ||
      strcmp(src, "RAILWAY STATION") == 0 ||
      strcmp(src, "RAILROAD STATION") == 0)
    return NULL;

  if (ispunct(src[0])) {
    fixed value(strtod(src + 1, NULL));
    value = Units::ToUserAltitude(value);

    TCHAR buffer[32];
    if (value > fixed(999))
      _stprintf(buffer, _T("%.1f"), (double)(value / 1000));
    else
      _stprintf(buffer, _T("%d"), (int)value);

    return _tcsdup(buffer);
  }

#ifdef _UNICODE
  size_t length = strlen(src);
  TCHAR *dest = new TCHAR[length + 1];
  if (::MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, length + 1) <= 0) {
    delete[] dest;
    return NULL;
  }

  return dest;
#else
  if (!ValidateUTF8(src))
    return NULL;

  return strdup(src);
#endif
}
Exemple #24
0
int main(int argc, char **argv)
{
  plan_tests(2 * ARRAY_SIZE(valid) +
             2 * ARRAY_SIZE(invalid) +
             2 * ARRAY_SIZE(length) +
             4 * ARRAY_SIZE(crop) +
             ARRAY_SIZE(latin1_chars) +
#ifndef _UNICODE
             ARRAY_SIZE(truncate_string_tests) +
#endif
             9 + 27);

  for (auto i : valid) {
    ok1(ValidateUTF8(i));
    ok1(LengthUTF8(i) == MyLengthUTF8(i));
  }

  for (auto i : invalid) {
    ok1(!ValidateUTF8(i));
    ok1(!MyValidateUTF8(i));
  }

  for (auto &l : length) {
    ok1(l.length == LengthUTF8(l.value));
    ok1(l.length == MyLengthUTF8(l.value));
  }

  char buffer[64];

  for (auto &l : latin1_chars) {
    *Latin1ToUTF8(l.ch, buffer) = 0;
    ok1(strcmp(l.utf8, buffer) == 0);
  }

  for (auto &c : crop) {
    strcpy(buffer, c.input);
    auto *end = CropIncompleteUTF8(buffer);
    ok1(strcmp(c.output, buffer) == 0);
    ok1(end != nullptr);
    ok1(*end == '\0');
    ok1(end == buffer + strlen(buffer));
  }

#ifndef _UNICODE
  TestTruncateString();
#endif

  {
    const char *p = "foo\xe7\x9b\xae";
    auto n = NextUTF8(p);
    ok1(n.first == 'f');
    ok1(n.second == p + 1);

    n = NextUTF8(p + 1);
    ok1(n.first == 'o');
    ok1(n.second == p + 2);

    n = NextUTF8(p + 2);
    ok1(n.first == 'o');
    ok1(n.second == p + 3);

    n = NextUTF8(p + 3);
    ok1(n.first == 30446);
    ok1(n.second == p + 6);

    n = NextUTF8(p + 6);
    ok1(n.first == 0);
  }

  /* test UnicodeToUTF8() */

  buffer[0] = 1;
  ok1(UnicodeToUTF8(0, buffer) == buffer + 1);
  ok1(buffer[0] == 0);

  ok1(UnicodeToUTF8(' ', buffer) == buffer + 1);
  ok1(buffer[0] == ' ');

  ok1(UnicodeToUTF8(0x7f, buffer) == buffer + 1);
  ok1(buffer[0] == 0x7f);

  ok1(UnicodeToUTF8(0xa2, buffer) == buffer + 2);
  ok1(buffer[0] == char(0xc2));
  ok1(buffer[1] == char(0xa2));

  ok1(UnicodeToUTF8(0x6fb3, buffer) == buffer + 3);
  ok1(buffer[0] == char(0xe6));
  ok1(buffer[1] == char(0xbe));
  ok1(buffer[2] == char(0xb3));

  ok1(UnicodeToUTF8(0xffff, buffer) == buffer + 3);
  ok1(buffer[0] == char(0xef));
  ok1(buffer[1] == char(0xbf));
  ok1(buffer[2] == char(0xbf));

  ok1(UnicodeToUTF8(0x10000, buffer) == buffer + 4);
  ok1(buffer[0] == char(0xf0));
  ok1(buffer[1] == char(0x90));
  ok1(buffer[2] == char(0x80));
  ok1(buffer[3] == char(0x80));

  ok1(UnicodeToUTF8(0x10ffff, buffer) == buffer + 4);
  ok1(buffer[0] == char(0xf4));
  ok1(buffer[1] == char(0x8f));
  ok1(buffer[2] == char(0xbf));
  ok1(buffer[3] == char(0xbf));

  return exit_status();
}
Exemple #25
0
void
Canvas::DrawFormattedText(PixelRect *rc, const TCHAR *text, unsigned format)
{
  assert(text != nullptr);
#ifndef UNICODE
  assert(ValidateUTF8(text));
#endif

  if (font == nullptr)
    return;

  unsigned skip = font->GetLineSpacing();
  unsigned max_lines = (format & DT_CALCRECT) ? -1 :
                       (rc->bottom - rc->top + skip - 1) / skip;

  size_t len = _tcslen(text);
  TCHAR *duplicated = new TCHAR[len + 1], *p = duplicated;
  unsigned lines = 1;
  for (const TCHAR *i = text; *i != _T('\0'); ++i) {
    TCHAR ch = *i;
    if (ch == _T('\n')) {
      /* explicit line break */

      if (++lines >= max_lines)
        break;

      ch = _T('\0');
    } else if (ch == _T('\r'))
      /* skip */
      continue;
    else if ((unsigned)ch < 0x20)
      /* replace non-printable characters */
      ch = _T(' ');

    *p++ = ch;
  }

  *p = _T('\0');
  len = p - duplicated;

  // simple wordbreak algorithm. looks for single spaces only, no tabs,
  // no grouping of multiple spaces
  if (format & DT_WORDBREAK) {
    for (size_t i = 0; i < len; i += _tcslen(duplicated + i) + 1) {
      PixelSize sz = CalcTextSize(duplicated + i);
      TCHAR *prev_p = nullptr;

      // remove words from behind till line fits or no more space is found
      while (sz.cx > rc->right - rc->left &&
             (p = StringFindLast(duplicated + i, _T(' '))) != nullptr) {
        if (prev_p)
          *prev_p = _T(' ');
        *p = _T('\0');
        prev_p = p;
        sz = CalcTextSize(duplicated + i);
      }

      if (prev_p) {
        lines++;
        if (lines >= max_lines)
          break;
      }
    }
  }

  if (format & DT_CALCRECT) {
    rc->bottom = rc->top + lines * skip;
    delete[] duplicated;
    return;
  }

  int y = (format & DT_VCENTER) && lines < max_lines
    ? (rc->top + rc->bottom - lines * skip) / 2
    : rc->top;
  for (size_t i = 0; i < len; i += _tcslen(duplicated + i) + 1) {
    if (duplicated[i] != _T('\0')) {
      int x;
      if (format & (DT_RIGHT | DT_CENTER)) {
        PixelSize sz = CalcTextSize(duplicated + i);
        x = (format & DT_CENTER) ? (rc->left + rc->right - sz.cx)/2 :
                                    rc->right - sz.cx;  // DT_RIGHT
      } else {  // default is DT_LEFT
        x = rc->left;
      }

      TextAutoClipped(x, y, duplicated + i);

      if (format & DT_UNDERLINE)
        DrawHLine(x, x + CalcTextWidth(duplicated + i),
                  y + font->GetAscentHeight() + 1, text_color);
    }
    y += skip;
    if (y >= rc->bottom)
      break;
  }

  delete[] duplicated;
}
Exemple #26
0
//
// 2015-04-18  note by Paolo
//
// The original code from xcsoar was not spacing characters correctly in LK.
// I have no idea if the problem exists in xcsoar, but we had to fix it here.
// After quite some time, and frustration reading the confusing docs of FreeType,
// I came to this solution which is much more accurate.
// We use subpixels assuming we are always grid-aligned, which is true for our case.
// Kerning does work, but we must always check that we are not going below the 
// available space, to avoid overlapping previous glyph. This is necessary since
// the bitmap operations are copying, not merging, bitmaps. I have no idea how 
// Windows is doing this, apparently microsoft does not merge glyphs too.
// Hinting is required to keep vertical alignement, which may hide a bug.
// I am not sure if all of this (long and complicated) work is correct or it is instead
// a workaround for a more complex problem existing elsewhere.
// However it does work for us, against all odds.
// Update april 21st: merging instead of copying makes the kerning process working fine.
//
void
Font::Render(const TCHAR *text, const PixelSize size, void *_buffer) const
{
  assert(text != nullptr);
#ifndef _UNICODE
  assert(ValidateUTF8(text));
#endif

  uint8_t *buffer = (uint8_t *)_buffer;
  std::fill_n(buffer, BufferSize(size), 0);

  const FT_Face face = this->face;
  const FT_GlyphSlot glyph = face->glyph;

#ifdef USE_KERNING
  bool use_kerning = FT_HAS_KERNING(face);
  unsigned prev_index = 0;
#endif

  int x = 0;
#ifdef FIX_HINTING
  FT_Pos prev_rsb_delta=0;
#endif


#ifndef ENABLE_OPENGL
  const Poco::ScopedLock<Poco::Mutex> protect(freetype_mutex);
#endif


  while (true) {
    const auto n = NextChar(text);
    if (n.first == 0)
      break;

    const unsigned ch = n.first;
    text = n.second;

    FT_UInt i = FT_Get_Char_Index(face, ch);
    if (i == 0)
      continue;

    FT_Error error = FT_Load_Glyph(face, i, load_flags);
    if (error)
      continue;

    const FT_Glyph_Metrics metrics = glyph->metrics;

#ifdef USE_KERNING
    if (use_kerning && x) {
      if (prev_index != 0) {
        FT_Vector delta;
        FT_Get_Kerning(face, prev_index, i, ft_kerning_default, &delta);
        #ifdef LIGHT_KERNING
        if (-delta.x <= metrics.horiBearingX)
            x += delta.x ;
        else
            x -= (metrics.horiBearingX + 64);
        #else
            x += delta.x;
        #endif
      }
    }
    prev_index = i;
#endif


#ifdef FIX_HINTING
    if (prev_rsb_delta - glyph->lsb_delta >= 32 )
        x -= 64;// >> 6;
    else if ( prev_rsb_delta - glyph->lsb_delta < -32 )
        x += 64;// >> 6;

    prev_rsb_delta = glyph->rsb_delta;
#endif

    error = FT_Render_Glyph(glyph, render_mode);
    if (error)
      continue;
    /* 
     *  32,  0  = Microsoft GDI weight=600 (64=32)
     */
    if (demibold) FT_Bitmap_Embolden(ft_library,&glyph->bitmap, 32,0);

    RenderGlyph((uint8_t *)buffer, size.cx, size.cy,
#ifdef USE_KERNING
        glyph, (x >> 6)+glyph->bitmap_left , ascent_height - FT_FLOOR(metrics.horiBearingY));

    x += glyph->advance.x; // equivalent to metrics.horiAdvance
#else
        glyph, (x + metrics.horiBearingX ) >> 6 , ascent_height - FT_FLOOR(metrics.horiBearingY));

    x += (metrics.width > metrics.horiAdvance ? metrics.width : metrics.horiAdvance);
#endif

  }
}
Exemple #27
0
TCHAR *
ConvertLineReader::ReadLine()
{
    char *narrow = source.ReadLine();

    if (narrow == nullptr)
        return nullptr;

    // Check if there is byte order mark in front
    if (narrow[0] == (char)0xEF &&
            narrow[1] == (char)0xBB &&
            narrow[2] == (char)0xBF &&
            (charset == Charset::AUTO || charset == Charset::UTF8)) {
        // -> if so, skip it
        narrow += 3;

        /* if it was "AUTO", then explicitly switch to UTF-8 now */
        charset = Charset::UTF8;
    }

    if (charset == Charset::AUTO && !ValidateUTF8(narrow))
        /* invalid UTF-8 sequence detected: switch to ISO-Latin-1 */
        charset = Charset::ISO_LATIN_1;

#ifdef _UNICODE
    size_t narrow_length = strlen(narrow);

    TCHAR *t = tbuffer.get(narrow_length + 1);
    if (t == nullptr)
        return nullptr;

    if (narrow_length == 0) {
        t[0] = _T('\0');
        return t;
    }

    switch (charset) {
    case Charset::ISO_LATIN_1:
        iso_latin_1_to_tchar(t, narrow);
        break;

    default:
        int length = MultiByteToWideChar(CP_UTF8, 0, narrow, narrow_length,
                                         t, narrow_length);
        if (length == 0)
            return nullptr;

        t[length] = _T('\0');

        break;
    }

    return t;
#else
    switch (charset) {
        size_t buffer_size;
        const char *utf8;

    case Charset::ISO_LATIN_1:
        buffer_size = strlen(narrow) * 2 + 1;
        utf8 = Latin1ToUTF8(narrow, tbuffer.get(buffer_size), buffer_size);
        if (utf8 == nullptr)
            return narrow;
        return const_cast<char *>(utf8);

    case Charset::UTF8:
        if (!ValidateUTF8(narrow))
            /* abort on invalid UTF-8 sequence */
            return nullptr;

    /* fall through ... */

    case Charset::AUTO:
        return narrow;
    }

    /* unreachable */
    gcc_unreachable();
#endif
}
Exemple #28
0
/**
 * @brief Load language MSG file into memory
 *
 * @param fillup Switch value:
 *	- false - load from scratch removing anything existing
 *	-  true - load over existing messages, adding only missing items filling up gaps
 *
 * @return @c false if language file problem, in this case english is reloaded from calling function
 */
bool LKLoadMessages(bool fillup) {
  TCHAR sFile[MAX_PATH];
  TCHAR sPath[MAX_PATH];
  TCHAR suffix[20];
  #if DEBUG_GETTEXT
  int maxsize=0;
  #endif

  static bool doinit=true;

  if (doinit) {
    std::fill(std::begin(LKMessages), std::end(LKMessages), (TCHAR*)NULL);
	doinit=false;
  } else {
	if (!fillup) {
		// init data when reloading language files or changing it
		// but not in fillup mode of course
        LKUnloadMessage();
	}
  }

  LocalPath(sPath,_T(LKD_LANGUAGE));
  _tcscpy(suffix,_T("_MSG.TXT"));
  _stprintf(sFile,_T("%s%s%s%s"), sPath, _T(DIRSEP), LKLangSuffix, suffix);

  ZZIP_FILE *hFile = openzip(sFile, "rt");
	if (hFile == NULL) {
	StartupStore(_T("... LoadText Missing Language File: <%s>%s"),sFile,NEWLINE);
	return false;
  } else {
	if (fillup)
		StartupStore(_T(". Language fillup load file: <%s>%s"),sFile,NEWLINE);
	else
		StartupStore(_T(". Language load file: <%s>%s"),sFile,NEWLINE);
  }

  // search for beginning of code index, in the range _@M1_  _@M9999_
  TCHAR sTmp[300];
  TCHAR scapt[MAX_MESSAGE_SIZE+1];
  TCHAR scaptraw[MAX_MESSAGE_SIZE+1];

  bool havewarned=false;
  while (ReadULine(hFile, sTmp, array_size(sTmp))) {

	unsigned int slen=_tcslen(sTmp); // includes cr or lf or both
	if ( (slen<9) || (sTmp[0]!='_') || (sTmp[1]!='@') || (sTmp[2]!='M') ) {
        #if DEBUG_GETTEXT
        if(slen>0 && sTmp[0]!='#') {
            StartupStore(_T(".... MSG_ENG missing _@M line <%s>\n"),sTmp);
        }
        #endif
		continue;
	}

    // get the item index number, quick conversion from unicode
    unsigned short inumber = 0;
    for (unsigned int i = 0; i < slen - 4 && isdigit(sTmp[3 + i]); i++) {
        inumber = (inumber * 10) + ((char)sTmp[3 + i] - '0');
    }

	if (inumber >=MAX_MESSAGES) {
		if (!havewarned) {
			StartupStore(_T("...... ERROR LOADING NON-COMPATIBLE MSG FILE!%s"),NEWLINE);
			havewarned=true;
		}
		StartupStore(_T("...... MSG token <%d> over limit! <%s>%s"),inumber,sTmp,NEWLINE);
		continue;
	}

	int start=0;
	for (unsigned i=3; i<slen; i++) {
		if (sTmp[i]=='\"') {
			start=i;
			break;
		}
	}

	int end=0;
	if (start==0) {
		#if DEBUG_GETTEXT
		StartupStore(_T(".... MSG_ENG no start\n"));
		#endif
		continue;
	}
	for (unsigned i=start+1; i<slen; i++) {
		if (sTmp[i]=='\"') {
			sTmp[i]='\0';
			end=i;
			break;
		}
	}
	if (end==0) {
		#if DEBUG_GETTEXT
		StartupStore(_T(".... MSG_ENG no end <%s> start=%d\n"),sTmp,start);
		#endif
		continue;
	}
	int newlen;
	newlen=_tcslen(&sTmp[start+1]);
	if (newlen>MAX_MESSAGE_SIZE) {
		#if DEBUG_GETTEXT
		StartupStore(_T(".... MSG_ENG caption too big, len=%d\n"),newlen);
		#endif
		continue;
	}
	if (newlen==0) {
        #if DEBUG_GETTEXT
		StartupStore(_T(".... MSG_ENG TOKEN # %d : caption is empty, null text.\n"),inumber);
		#endif
		continue;
	}
    #if DEBUG_GETTEXT
	if (newlen>maxsize) maxsize=newlen;
    #endif

	// transcode special charcaters while loading from file
	TCHAR tcode;
	bool donetcode;
	_tcscpy(scaptraw,&sTmp[start+1]);
    unsigned j=0;
	for (unsigned i=0; i<_tcslen(scaptraw); i++) {
		donetcode=false;
		if (scaptraw[i] == '\\') {
			if ( (i+1) <_tcslen(scaptraw)) {
				switch(scaptraw[i+1]) {
					case 'n':
						tcode='\n';
						i++;
						break;
					case 'r':
						tcode='\r';
						i++;
						break;
					default:
						tcode='\\';
						break;
				}
				scapt[j++]=tcode;
				donetcode=true;
			}
		}
		if (!donetcode) {
			scapt[j++]=scaptraw[i];
		}
	}
	scapt[j]='\0';

	if (LKMessages[inumber]) {
		// only for debugging translations
		#if TESTBENCH
		if (!fillup)
			StartupStore(_T("... INVALID LANGUAGE MESSAGE INDEX <%d> duplicated!\n"),inumber);
		#endif
		continue;
	}
	#if TESTBENCH
	#if (WINDOWSPC>0)
	// CAUTION, on a PNA this would freeze the device if language file is not updated!
	// StartupStore is locking and unlocking threads at each run!!
	if (fillup)
		StartupStore(_T("... Fillup: message index %d is missing from translation\n"),inumber);
	#endif
	#endif

#ifndef UNICODE
    LKASSERT(ValidateUTF8(scapt));
#endif

	LKMessages[inumber] = (TCHAR *)malloc((_tcslen(scapt)+1)*sizeof(TCHAR));
	LKASSERT(LKMessages[inumber]!=NULL);
	_tcscpy(LKMessages[inumber],scapt);
	if (inumber>=MAX_MESSAGES) {
		#if TESTBENCH
		StartupStore(_T("... TOO MANY MESSAGES, MAX %d%s"), MAX_MESSAGES, NEWLINE);
		#endif
		break;
	}

  }
  zzip_fclose(hFile);
  return true;
}
Exemple #29
0
PixelSize
Font::TextSize(const TCHAR *text) const
{
  assert(text != nullptr);
#ifndef _UNICODE
  assert(ValidateUTF8(text));
#endif

  const FT_Face face = this->face;
  const bool use_kerning = FT_HAS_KERNING(face);

  int x = 0, minx = 0, maxx = 0;
  unsigned prev_index = 0;

#ifndef ENABLE_OPENGL
  const ScopeLock protect(freetype_mutex);
#endif

  while (true) {
    const auto n = NextChar(text);
    if (n.first == 0)
      break;

    const unsigned ch = n.first;
    text = n.second;

    FT_UInt i = FT_Get_Char_Index(face, ch);
    if (i == 0)
      continue;

    FT_Error error = FT_Load_Glyph(face, i, load_flags);
    if (error)
      continue;

    const FT_GlyphSlot glyph = face->glyph;
    const FT_Glyph_Metrics &metrics = glyph->metrics;

    if (use_kerning) {
      if (prev_index != 0 && i != 0) {
        FT_Vector delta;
        FT_Get_Kerning(face, prev_index, i, ft_kerning_default,
                       &delta);
        x += delta.x >> 6;
      }

      prev_index = i;
    }

    const int glyph_minx = FT_FLOOR(metrics.horiBearingX);
    const int glyph_maxx = minx + FT_CEIL(metrics.width);
    const int glyph_advance = FT_CEIL(metrics.horiAdvance);

    int z = x + glyph_minx;
    if (z < minx)
      minx = z;

    z = x + std::max(glyph_maxx, glyph_advance);
    if (z > maxx)
      maxx = z;

    x += glyph_advance;
  }
Exemple #30
0
int main(int argc, char **argv)
{
  plan_tests(ARRAY_SIZE(valid) + ARRAY_SIZE(invalid) +
             ARRAY_SIZE(length) +
             ARRAY_SIZE(crop) +
             ARRAY_SIZE(latin1_chars) +
             9 + 27);

  for (auto i : valid)
    ok1(ValidateUTF8(i));

  for (auto i : invalid)
    ok1(!ValidateUTF8(i));

  for (auto &l : length)
    ok1(l.length == LengthUTF8(l.value));

  char buffer[64];

  for (auto &l : latin1_chars) {
    *Latin1ToUTF8(l.ch, buffer) = 0;
    ok1(strcmp(l.utf8, buffer) == 0);
  }

  for (auto &c : crop) {
    strcpy(buffer, c.input);
    CropIncompleteUTF8(buffer);
    ok1(strcmp(c.output, buffer) == 0);
  }

  {
    const char *p = "foo\xe7\x9b\xae";
    auto n = NextUTF8(p);
    ok1(n.first == 'f');
    ok1(n.second == p + 1);

    n = NextUTF8(p + 1);
    ok1(n.first == 'o');
    ok1(n.second == p + 2);

    n = NextUTF8(p + 2);
    ok1(n.first == 'o');
    ok1(n.second == p + 3);

    n = NextUTF8(p + 3);
    ok1(n.first == 30446);
    ok1(n.second == p + 6);

    n = NextUTF8(p + 6);
    ok1(n.first == 0);
  }

  /* test UnicodeToUTF8() */

  buffer[0] = 1;
  ok1(UnicodeToUTF8(0, buffer) == buffer + 1);
  ok1(buffer[0] == 0);

  ok1(UnicodeToUTF8(' ', buffer) == buffer + 1);
  ok1(buffer[0] == ' ');

  ok1(UnicodeToUTF8(0x7f, buffer) == buffer + 1);
  ok1(buffer[0] == 0x7f);

  ok1(UnicodeToUTF8(0xa2, buffer) == buffer + 2);
  ok1(buffer[0] == char(0xc2));
  ok1(buffer[1] == char(0xa2));

  ok1(UnicodeToUTF8(0x6fb3, buffer) == buffer + 3);
  ok1(buffer[0] == char(0xe6));
  ok1(buffer[1] == char(0xbe));
  ok1(buffer[2] == char(0xb3));

  ok1(UnicodeToUTF8(0xffff, buffer) == buffer + 3);
  ok1(buffer[0] == char(0xef));
  ok1(buffer[1] == char(0xbf));
  ok1(buffer[2] == char(0xbf));

  ok1(UnicodeToUTF8(0x10000, buffer) == buffer + 4);
  ok1(buffer[0] == char(0xf0));
  ok1(buffer[1] == char(0x90));
  ok1(buffer[2] == char(0x80));
  ok1(buffer[3] == char(0x80));

  ok1(UnicodeToUTF8(0x10ffff, buffer) == buffer + 4);
  ok1(buffer[0] == char(0xf4));
  ok1(buffer[1] == char(0x8f));
  ok1(buffer[2] == char(0xbf));
  ok1(buffer[3] == char(0xbf));

  return exit_status();
}