Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// character_manager.cpp: implementation of the TFont class.
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//////////////////////////////////////////////////////////////////////
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tpixelgr.h"
Toshihiro Shimizu 890ddd
#include "tfont.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
//#include "tcurves.h"
Toshihiro Shimizu 890ddd
#include "traster.h"
Toshihiro Shimizu 890ddd
#include <vector></vector>
Toshihiro Shimizu 890ddd
#include <iostream></iostream>
Toshihiro Shimizu 890ddd
#include <string></string>
Toshihiro Shimizu 890ddd
//#include <tstring.h></tstring.h>
Toshihiro Shimizu 890ddd
#include <tmathutil.h></tmathutil.h>
Toshihiro Shimizu 890ddd
//#include <tdebugmessage.h></tdebugmessage.h>
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
using namespace std;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef map<wstring, logfontw=""> WindowsFontTable;</wstring,>
Toshihiro Shimizu 890ddd
typedef map<pair<unsigned short="" short,="" unsigned="">, int> KerningPairs;</pair<unsigned>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct TFont::Impl {
Shinya Kitaoka 120a6e
  bool m_hasKerning;
Shinya Kitaoka 120a6e
  bool m_hasVertical;
Shinya Kitaoka 120a6e
  HFONT m_font;
Shinya Kitaoka 120a6e
  HDC m_hdc;
Shinya Kitaoka 120a6e
  TEXTMETRICW m_metrics;
Shinya Kitaoka 120a6e
  KerningPairs m_kerningPairs;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Impl(const LOGFONTW &font, HDC hdc);
Shinya Kitaoka 120a6e
  ~Impl();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFont::TFont(const LOGFONTW &font, HDC hdc) { m_pimpl = new Impl(font, hdc); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFont::~TFont() { delete m_pimpl; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFont::Impl::Impl(const LOGFONTW &logfont, HDC hdc) : m_hdc(hdc) {
Shinya Kitaoka 120a6e
  m_font = CreateFontIndirectW(&logfont);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_font) throw TFontCreationError();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  HGDIOBJ hObj = SelectObject(hdc, m_font);
Shinya Kitaoka 120a6e
  if (!hObj || hObj == HGDI_ERROR) throw TFontCreationError();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!GetTextMetricsW(hdc, &m_metrics)) throw TFontCreationError();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  DWORD pairsCount = GetKerningPairsW(hdc, 0, 0);
Shinya Kitaoka 120a6e
  if (pairsCount) {
Shinya Kitaoka 120a6e
    m_hasKerning = true;
Shinya Kitaoka 120a6e
    std::unique_ptr<kerningpair[]> tempKernPairs(new KERNINGPAIR[pairsCount]);</kerningpair[]>
Shinya Kitaoka 120a6e
    GetKerningPairsW(hdc, pairsCount, tempKernPairs.get());
Shinya Kitaoka 120a6e
    for (UINT i = 0; i < pairsCount; i++) {
Shinya Kitaoka 120a6e
      pair<unsigned short="" short,="" unsigned=""> key =</unsigned>
Shinya Kitaoka 120a6e
          make_pair(tempKernPairs[i].wFirst, tempKernPairs[i].wSecond);
Shinya Kitaoka 120a6e
      m_kerningPairs[key] = tempKernPairs[i].iKernAmount;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    m_hasKerning = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_hasVertical = (logfont.lfFaceName)[0] == '@';
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFont::Impl::~Impl() {
Shinya Kitaoka 120a6e
  // delete m_advances;
Shinya Kitaoka 120a6e
  DeleteObject(m_font);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
inline TThickPoint toThickPoint(POINTFX point) {
Shinya Kitaoka 120a6e
  double app1 = point.x.value +
Shinya Kitaoka 120a6e
                ((double)point.x.fract) / (std::numeric_limits<word>::max)();</word>
Shinya Kitaoka 120a6e
  double app2 = point.y.value +
Shinya Kitaoka 120a6e
                ((double)point.y.fract) / (std::numeric_limits<word>::max)();</word>
Shinya Kitaoka 120a6e
  return TThickPoint(app1, app2, 0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPoint TFont::drawChar(TVectorImageP &image, wchar_t charcode,
Shinya Kitaoka 120a6e
                       wchar_t nextCharCode) const
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
  GLYPHMETRICS gm;
Shinya Kitaoka 120a6e
  MAT2 mat2;
Shinya Kitaoka 120a6e
  mat2.eM11.fract = 0;
Shinya Kitaoka 120a6e
  mat2.eM12.fract = 0;
Shinya Kitaoka 120a6e
  mat2.eM21.fract = 0;
Shinya Kitaoka 120a6e
  mat2.eM22.fract = 0;
Shinya Kitaoka 120a6e
  mat2.eM11.value = 1;
Shinya Kitaoka 120a6e
  mat2.eM12.value = 0;
Shinya Kitaoka 120a6e
  mat2.eM21.value = 0;
Shinya Kitaoka 120a6e
  mat2.eM22.value = 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  vector<tthickpoint> points;</tthickpoint>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  UINT j = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  DWORD charMemorySize =
Shinya Kitaoka 120a6e
      GetGlyphOutlineW(m_pimpl->m_hdc, charcode, GGO_NATIVE, &gm, 0, 0, &mat2);
Shinya Kitaoka 120a6e
  if (charMemorySize == GDI_ERROR) {
Shinya Kitaoka 120a6e
    assert(0);
Shinya Kitaoka 120a6e
    return TPoint();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::unique_ptr<char[]> lpvBuffer(new char[charMemorySize]);</char[]>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  charMemorySize = GetGlyphOutlineW(m_pimpl->m_hdc, charcode, GGO_NATIVE, &gm,
Shinya Kitaoka 120a6e
                                    charMemorySize, lpvBuffer.get(), &mat2);
Shinya Kitaoka 120a6e
  if (charMemorySize == GDI_ERROR) {
Shinya Kitaoka 120a6e
    assert(0);
Shinya Kitaoka 120a6e
    return TPoint();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)lpvBuffer.get();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while ((char *)header < (char *)lpvBuffer.get() + charMemorySize) {
Shinya Kitaoka 120a6e
    points.clear();
Shinya Kitaoka 120a6e
    TThickPoint startPoint = toThickPoint(header->pfxStart);
Shinya Kitaoka 120a6e
    points.push_back(startPoint);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (header->dwType != TT_POLYGON_TYPE) {
Shinya Kitaoka 120a6e
      assert(0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    int memorySize = header->cb;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    while ((char *)curve < (char *)header + memorySize) {
Shinya Kitaoka 120a6e
      switch (curve->wType) {
Shinya Kitaoka 120a6e
      case TT_PRIM_LINE:
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        for (j = 0; j < curve->cpfx; j++) {
Shinya Kitaoka 120a6e
          TThickPoint p0 = points.back();
Shinya Kitaoka 120a6e
          TThickPoint p1 = toThickPoint(((*curve).apfx[j]));
Shinya Kitaoka 120a6e
          points.push_back((p0 + p1) * 0.5);
Shinya Kitaoka 120a6e
          points.push_back(p1);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      case TT_PRIM_QSPLINE:
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        for (j = 0; (int)j + 2 < curve->cpfx; j++) {
Shinya Kitaoka 120a6e
          TThickPoint p1 = toThickPoint(((*curve).apfx[j]));
Shinya Kitaoka 120a6e
          TThickPoint p2 = toThickPoint(((*curve).apfx[j + 1]));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          points.push_back(p1);
Shinya Kitaoka 120a6e
          points.push_back((p1 + p2) * 0.5);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        points.push_back(toThickPoint(((*curve).apfx[j++])));
Shinya Kitaoka 120a6e
        points.push_back(toThickPoint(((*curve).apfx[j++])));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case TT_PRIM_CSPLINE:
Shinya Kitaoka 120a6e
        assert(0);
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      default:
Shinya Kitaoka 120a6e
        assert(0);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      curve = (TTPOLYCURVE *)(&(curve->apfx)[j]);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TThickPoint p0 = points.back();
Shinya Kitaoka 120a6e
    if (!isAlmostZero(p0.x - startPoint.x) ||
Shinya Kitaoka 120a6e
        !isAlmostZero(p0.y - startPoint.y)) {
Shinya Kitaoka 120a6e
      points.push_back((p0 + startPoint) * 0.5);
Shinya Kitaoka 120a6e
      points.push_back(startPoint);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TStroke *stroke = new TStroke();
Shinya Kitaoka 120a6e
    stroke->reshape(&(points[0]), points.size());
Shinya Kitaoka 120a6e
    stroke->setSelfLoop(true);
Shinya Kitaoka 120a6e
    image->addStroke(stroke);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    header = (TTPOLYGONHEADER *)curve;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  image->group(0, image->getStrokeCount());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return getDistance(charcode, nextCharCode);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPoint appDrawChar(TRasterGR8P &outImage, HDC hdc, wchar_t charcode) {
Shinya Kitaoka 120a6e
  GLYPHMETRICS gm;
Shinya Kitaoka 120a6e
  MAT2 mat2;
Shinya Kitaoka 120a6e
  mat2.eM11.fract = 0;
Shinya Kitaoka 120a6e
  mat2.eM12.fract = 0;
Shinya Kitaoka 120a6e
  mat2.eM21.fract = 0;
Shinya Kitaoka 120a6e
  mat2.eM22.fract = 0;
Shinya Kitaoka 120a6e
  mat2.eM11.value = 1;
Shinya Kitaoka 120a6e
  mat2.eM12.value = 0;
Shinya Kitaoka 120a6e
  mat2.eM21.value = 0;
Shinya Kitaoka 120a6e
  mat2.eM22.value = 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  DWORD charMemorySize =
Shinya Kitaoka 120a6e
      GetGlyphOutlineW(hdc, charcode, GGO_GRAY8_BITMAP, &gm, 0, 0, &mat2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (charMemorySize == GDI_ERROR) {
Shinya Kitaoka 120a6e
    assert(0);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int lx = gm.gmBlackBoxX;
Shinya Kitaoka 120a6e
  int ly = gm.gmBlackBoxY;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int wrap = ((lx + 3) >> 2) << 2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterGR8P appImage = TRasterGR8P(wrap, ly);
Shinya Kitaoka 120a6e
  appImage->clear();
Shinya Kitaoka 120a6e
  outImage = appImage->extract(0, 0, lx - 1, ly - 1);
Shinya Kitaoka 120a6e
  outImage->lock();
Shinya Kitaoka 120a6e
  GetGlyphOutlineW(hdc, charcode, GGO_GRAY8_BITMAP, &gm, wrap * ly,
Shinya Kitaoka 120a6e
                   outImage->getRawData(), &mat2);
Shinya Kitaoka 120a6e
  outImage->unlock();
Shinya Kitaoka 120a6e
  TPoint glyphOrig;
Shinya Kitaoka 120a6e
  glyphOrig.x = gm.gmptGlyphOrigin.x;
Shinya Kitaoka 120a6e
  glyphOrig.y = gm.gmptGlyphOrigin.y;
Shinya Kitaoka 120a6e
  return glyphOrig;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
// valori compresi tra 0 e 64 (si si, proprio 64 e non 63: sono 65 valori)
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
TPoint TFont::drawChar(TRasterGR8P &outImage, TPoint &glyphOrigin,
Shinya Kitaoka 120a6e
                       wchar_t charcode, wchar_t nextCharCode) const {
Shinya Kitaoka 120a6e
  TRasterGR8P grayAppImage;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPoint glyphOrig = appDrawChar(grayAppImage, m_pimpl->m_hdc, charcode);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (glyphOrig.x < 0) {
Shinya Kitaoka 120a6e
    glyphOrigin.x = glyphOrig.x;
Shinya Kitaoka 120a6e
    glyphOrig.x   = 0;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    glyphOrigin.x = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (glyphOrig.y < 0) {
Shinya Kitaoka 120a6e
    glyphOrigin.y = glyphOrig.y;
Shinya Kitaoka 120a6e
    glyphOrig.y   = 0;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    glyphOrigin.y = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int srcLx = grayAppImage->getLx();
Shinya Kitaoka 120a6e
  int srcLy = grayAppImage->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int dstLx = srcLx + glyphOrig.x;
Shinya Kitaoka 120a6e
  int dstLy = getMaxHeight();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  outImage = TRasterGR8P(dstLx, dstLy);
Shinya Kitaoka 120a6e
  outImage->clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int ty = m_pimpl->m_metrics.tmDescent - 1 + glyphOrig.y;
Shinya Kitaoka 120a6e
  assert(ty < dstLy);
Shinya Kitaoka 120a6e
  assert(ty >= srcLy - 1);
Shinya Kitaoka 120a6e
  grayAppImage->lock();
Shinya Kitaoka 120a6e
  outImage->lock();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int sy = 0; sy < srcLy; ++sy, --ty) {
Shinya Kitaoka 120a6e
    TPixelGR8 *srcPix = grayAppImage->pixels(sy);
Shinya Kitaoka 120a6e
    TPixelGR8 *tarPix = outImage->pixels(ty) + glyphOrig.x;
Shinya Kitaoka 120a6e
    for (int x = 0; x < srcLx; ++x) {
Shinya Kitaoka 120a6e
      assert(srcPix->value < 65);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      switch (srcPix->value) {
Shinya Kitaoka 120a6e
      case 0:
Shinya Kitaoka 120a6e
        tarPix->value = 0;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      default:
Shinya Kitaoka 120a6e
        tarPix->value = (srcPix->value << 2) - 1;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      ++srcPix;
Shinya Kitaoka 120a6e
      ++tarPix;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  grayAppImage->unlock();
Shinya Kitaoka 120a6e
  outImage->unlock();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return getDistance(charcode, nextCharCode);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPoint TFont::drawChar(TRasterCM32P &outImage, TPoint &glyphOrigin, int inkId,
Shinya Kitaoka 120a6e
                       wchar_t charcode, wchar_t nextCharCode) const {
Shinya Kitaoka 120a6e
  TRasterGR8P grayAppImage;
Shinya Kitaoka 120a6e
  TPoint glyphOrig = appDrawChar(grayAppImage, m_pimpl->m_hdc, charcode);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (glyphOrig.x < 0) {
Shinya Kitaoka 120a6e
    glyphOrigin.x = glyphOrig.x;
Shinya Kitaoka 120a6e
    glyphOrig.x   = 0;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    glyphOrigin.x = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (glyphOrig.y < 0) {
Shinya Kitaoka 120a6e
    glyphOrigin.y = glyphOrig.y;
Shinya Kitaoka 120a6e
    glyphOrig.y   = 0;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    glyphOrigin.y = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int srcLx = grayAppImage->getLx();
Shinya Kitaoka 120a6e
  int srcLy = grayAppImage->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int dstLx = srcLx + glyphOrig.x;
Shinya Kitaoka 120a6e
  int dstLy = getMaxHeight();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  outImage = TRasterCM32P(dstLx, dstLy);
Shinya Kitaoka 120a6e
  outImage->clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(TPixelCM32::getMaxTone() == 255);
Shinya Kitaoka 120a6e
  // TPixelCM32
Shinya Kitaoka 120a6e
  // bgColor(BackgroundStyle,BackgroundStyle,TPixelCM32::getMaxTone());
Shinya Kitaoka 120a6e
  TPixelCM32 bgColor;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int ty = m_pimpl->m_metrics.tmDescent - 1 + glyphOrig.y;
Shinya Kitaoka 120a6e
  assert(ty < dstLy);
Shinya Kitaoka 120a6e
  assert(ty >= srcLy - 1);
Shinya Kitaoka 120a6e
  grayAppImage->lock();
Shinya Kitaoka 120a6e
  outImage->lock();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int sy = 0; sy < srcLy; ++sy, --ty) {
Shinya Kitaoka 120a6e
    TPixelGR8 *srcPix  = grayAppImage->pixels(sy);
Shinya Kitaoka 120a6e
    TPixelCM32 *tarPix = outImage->pixels(ty) + glyphOrig.x;
Shinya Kitaoka 120a6e
    for (int x = 0; x < srcLx; ++x) {
Shinya Kitaoka 120a6e
      int tone = 256 - (srcPix->value << 2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // grayScale  ToonzImage tone   Meaning
Shinya Kitaoka 120a6e
      //         0  255               Bg = PurePaint
Shinya Kitaoka 120a6e
      //         1  252
Shinya Kitaoka 120a6e
      //                 ...
Shinya Kitaoka 120a6e
      //        63    4
Shinya Kitaoka 120a6e
      //        64    0               Fg = Pure Ink
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (tone < 0) tone = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (tone >= 255)
Shinya Kitaoka 120a6e
        *tarPix = bgColor;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        *tarPix = TPixelCM32(inkId, 0, tone);  // BackgroundStyle,tone);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      ++srcPix;
Shinya Kitaoka 120a6e
      ++tarPix;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  grayAppImage->unlock();
Shinya Kitaoka 120a6e
  outImage->unlock();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return getDistance(charcode, nextCharCode);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPoint TFont::getDistance(wchar_t firstChar, wchar_t secondChar) const {
Shinya Kitaoka 120a6e
  int advance;
Shinya Kitaoka 120a6e
  BOOL result = GetCharWidth32W(m_pimpl->m_hdc, firstChar, firstChar, &advance);
Shinya Kitaoka 120a6e
  assert(result);
Shinya Kitaoka 120a6e
  if (m_pimpl->m_hasKerning && secondChar) {
Shinya Kitaoka 120a6e
    KerningPairs::iterator it =
Shinya Kitaoka 120a6e
        m_pimpl->m_kerningPairs.find(make_pair(firstChar, secondChar));
Shinya Kitaoka 120a6e
    if (it != m_pimpl->m_kerningPairs.end()) {
Shinya Kitaoka 120a6e
      advance += it->second;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return TPoint(advance, 0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TFont::getMaxHeight() const { return m_pimpl->m_metrics.tmHeight; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TFont::getMaxWidth() const { return m_pimpl->m_metrics.tmMaxCharWidth; }
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TFont::getLineAscender() const { return m_pimpl->m_metrics.tmAscent; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TFont::getLineDescender() const { return -m_pimpl->m_metrics.tmDescent; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TFont::hasKerning() const { return m_pimpl->m_hasKerning; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TFont::hasVertical() const { return m_pimpl->m_hasVertical; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
//====================      TFontManager  =====================================
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct TFontManager::Impl {
Shinya Kitaoka 120a6e
  WindowsFontTable m_families;
Shinya Kitaoka 120a6e
  bool m_loaded;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  LOGFONTW m_currentLogFont;
Shinya Kitaoka 120a6e
  TFont *m_currentFont;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // this option is set by library user when he wants to write vertically.
Shinya Kitaoka 120a6e
  // In this implementation, if m_vertical is true and the font
Shinya Kitaoka 120a6e
  // has the @-version, the library use it.
Shinya Kitaoka 120a6e
  bool m_vertical;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFontManager::Impl() : m_loaded(false), m_currentFont(0), m_vertical(false) {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFontManager::TFontManager() { m_pimpl = new TFontManager::Impl(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFontManager::~TFontManager() { delete m_pimpl; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFontManager *TFontManager::instance() {
Shinya Kitaoka 120a6e
  static TFontManager theManager;
Shinya Kitaoka 120a6e
  return &theManager;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
BOOL CALLBACK EnumFamCallBack(CONST LOGFONTW *lplf, CONST TEXTMETRICW *,
Shinya Kitaoka 120a6e
                              DWORD FontType, LPARAM data) {
Shinya Kitaoka 120a6e
  if (FontType & TRUETYPE_FONTTYPE) {
Shinya Kitaoka 120a6e
    LOGFONTW newLplf        = *lplf;
Shinya Kitaoka 120a6e
    newLplf.lfHeight        = 200;
Shinya Kitaoka 120a6e
    newLplf.lfWidth         = 0;
Shinya Kitaoka 120a6e
    WindowsFontTable &table = *(WindowsFontTable *)data;
Shinya Kitaoka 120a6e
    table[lplf->lfFaceName] = newLplf;
Shinya Kitaoka 120a6e
    return TRUE;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return TRUE;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFontManager::loadFontNames() {
Shinya Kitaoka 120a6e
  if (m_pimpl->m_loaded) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  HDC hdc = CreateCompatibleDC(NULL);
Shinya Kitaoka 120a6e
  if (!hdc) throw TFontLibraryLoadingError();
Shinya Kitaoka 120a6e
  EnumFontFamiliesW(hdc, (LPCWSTR)NULL, (FONTENUMPROCW)EnumFamCallBack,
Shinya Kitaoka 120a6e
                    (LPARAM) & (m_pimpl->m_families));
Shinya Kitaoka 120a6e
  DeleteDC(hdc);
Shinya Kitaoka 120a6e
  hdc = 0;
Shinya Kitaoka 120a6e
  if (m_pimpl->m_families.empty()) throw TFontLibraryLoadingError();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_pimpl->m_loaded = true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFontManager::setFamily(const wstring family) {
Shinya Kitaoka 120a6e
  wstring userFamilyName =
Shinya Kitaoka 120a6e
      ((family.c_str())[0] == L'@') ? wstring(family.c_str() + 1) : family;
Shinya Kitaoka 120a6e
  wstring realFamilyName = (m_pimpl->m_vertical && (family.c_str())[0] != L'@')
Shinya Kitaoka 120a6e
                               ? L"@" + family
Shinya Kitaoka 120a6e
                               : family;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  wstring currentFamilyName = wstring(m_pimpl->m_currentLogFont.lfFaceName);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (currentFamilyName == realFamilyName) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  LOGFONTW logfont;
Shinya Kitaoka 120a6e
  if (m_pimpl->m_vertical) {
Shinya Kitaoka 120a6e
    WindowsFontTable::iterator it = m_pimpl->m_families.find(realFamilyName);
Shinya Kitaoka 120a6e
    if (it != m_pimpl->m_families.end())
Shinya Kitaoka 120a6e
      logfont = it->second;
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      it = m_pimpl->m_families.find(userFamilyName);
Shinya Kitaoka 120a6e
      assert(it != m_pimpl->m_families.end());
Shinya Kitaoka 120a6e
      if (it != m_pimpl->m_families.end())
Shinya Kitaoka 120a6e
        logfont = it->second;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        throw TFontCreationError();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    WindowsFontTable::iterator it = m_pimpl->m_families.find(userFamilyName);
Shinya Kitaoka 120a6e
    assert(it != m_pimpl->m_families.end());
Shinya Kitaoka 120a6e
    if (it != m_pimpl->m_families.end())
Shinya Kitaoka 120a6e
      logfont = it->second;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      throw TFontCreationError();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_pimpl->m_currentFont) {
Shinya Kitaoka 120a6e
    logfont.lfHeight = m_pimpl->m_currentLogFont.lfHeight;
Shinya Kitaoka 120a6e
    logfont.lfItalic = m_pimpl->m_currentLogFont.lfItalic;
Shinya Kitaoka 120a6e
    logfont.lfWeight = m_pimpl->m_currentLogFont.lfWeight;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    logfont.lfHeight = 200;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    HDC hdc        = CreateCompatibleDC(NULL);
Shinya Kitaoka 120a6e
    TFont *newfont = new TFont(logfont, hdc);
Shinya Kitaoka 120a6e
    delete m_pimpl->m_currentFont;
Shinya Kitaoka 120a6e
    m_pimpl->m_currentFont    = newfont;
Shinya Kitaoka 120a6e
    m_pimpl->m_currentLogFont = logfont;
Shinya Kitaoka 120a6e
  } catch (TException &) {
Shinya Kitaoka 120a6e
    throw TFontCreationError();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFontManager::setTypeface(const wstring typeface) {
Shinya Kitaoka 120a6e
  LOGFONTW logfont = m_pimpl->m_currentLogFont;
Shinya Kitaoka 120a6e
  logfont.lfItalic =
Shinya Kitaoka 120a6e
      (typeface == L"Italic" || typeface == L"Bold Italic") ? TRUE : FALSE;
Shinya Kitaoka 120a6e
  logfont.lfWeight =
Shinya Kitaoka 120a6e
      (typeface == L"Bold" || typeface == L"Bold Italic") ? 700 : 400;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    HDC hdc        = CreateCompatibleDC(NULL);
Shinya Kitaoka 120a6e
    TFont *newfont = new TFont(logfont, hdc);
Shinya Kitaoka 120a6e
    delete m_pimpl->m_currentFont;
Shinya Kitaoka 120a6e
    m_pimpl->m_currentFont    = newfont;
Shinya Kitaoka 120a6e
    m_pimpl->m_currentLogFont = logfont;
Shinya Kitaoka 120a6e
  } catch (TException &) {
Shinya Kitaoka 120a6e
    throw TFontCreationError();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFontManager::setSize(int size) {
Shinya Kitaoka 120a6e
  LOGFONTW logfont = m_pimpl->m_currentLogFont;
Shinya Kitaoka 120a6e
  logfont.lfHeight = size;
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    HDC hdc        = CreateCompatibleDC(NULL);
Shinya Kitaoka 120a6e
    TFont *newfont = new TFont(logfont, hdc);
Shinya Kitaoka 120a6e
    delete m_pimpl->m_currentFont;
Shinya Kitaoka 120a6e
    m_pimpl->m_currentFont    = newfont;
Shinya Kitaoka 120a6e
    m_pimpl->m_currentLogFont = logfont;
Shinya Kitaoka 120a6e
  } catch (TException &) {
Shinya Kitaoka 120a6e
    throw TFontCreationError();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
wstring TFontManager::getCurrentFamily() const {
Shinya Kitaoka 120a6e
  wstring currentFamilyName =
Shinya Kitaoka 120a6e
      (m_pimpl->m_currentLogFont.lfFaceName[0] == L'@')
Shinya Kitaoka 120a6e
          ? wstring(m_pimpl->m_currentLogFont.lfFaceName + 1)
Shinya Kitaoka 120a6e
          : wstring(m_pimpl->m_currentLogFont.lfFaceName);
Shinya Kitaoka 120a6e
  return currentFamilyName;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
wstring TFontManager::getCurrentTypeface() const {
Shinya Kitaoka 120a6e
  if (m_pimpl->m_currentLogFont.lfItalic) {
Shinya Kitaoka 120a6e
    if (m_pimpl->m_currentLogFont.lfWeight == 700)
Shinya Kitaoka 120a6e
      return L"Bold Italic";
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return L"Italic";
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    if (m_pimpl->m_currentLogFont.lfWeight == 700)
Shinya Kitaoka 120a6e
      return L"Bold";
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return L"Regular";
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFont *TFontManager::getCurrentFont() {
Shinya Kitaoka 120a6e
  if (m_pimpl->m_currentFont) return m_pimpl->m_currentFont;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!m_pimpl->m_currentFont) loadFontNames();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(!m_pimpl->m_families.empty());
Shinya Kitaoka 120a6e
  setFamily(m_pimpl->m_families.begin()->first);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return m_pimpl->m_currentFont;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFontManager::getAllFamilies(vector<wstring> &families) const {</wstring>
Shinya Kitaoka 120a6e
  families.clear();
Shinya Kitaoka 120a6e
  families.reserve(m_pimpl->m_families.size());
Shinya Kitaoka 120a6e
  WindowsFontTable::iterator it = m_pimpl->m_families.begin();
Shinya Kitaoka 120a6e
  for (; it != m_pimpl->m_families.end(); ++it) {
Shinya Kitaoka 120a6e
    if ((it->first)[0] != L'@') families.push_back(it->first);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFontManager::getAllTypefaces(vector<wstring> &typefaces) const {</wstring>
Shinya Kitaoka 120a6e
  typefaces.resize(4);
Shinya Kitaoka 120a6e
  typefaces[0] = L"Regular";
Shinya Kitaoka 120a6e
  typefaces[1] = L"Italic";
Shinya Kitaoka 120a6e
  typefaces[2] = L"Bold";
Shinya Kitaoka 120a6e
  typefaces[3] = L"Bold Italic";
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TFontManager::setVertical(bool vertical) {
Shinya Kitaoka 120a6e
  if (m_pimpl->m_vertical == vertical) return;
Shinya Kitaoka 120a6e
  m_pimpl->m_vertical = vertical;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  wstring currentFamilyName =
Shinya Kitaoka 120a6e
      (m_pimpl->m_currentLogFont.lfFaceName[0] == L'@')
Shinya Kitaoka 120a6e
          ? wstring(m_pimpl->m_currentLogFont.lfFaceName + 1)
Shinya Kitaoka 120a6e
          : wstring(m_pimpl->m_currentLogFont.lfFaceName);
Shinya Kitaoka 120a6e
  if (vertical) currentFamilyName = L'@' + currentFamilyName;
Shinya Kitaoka 120a6e
  setFamily(currentFamilyName);
Toshihiro Shimizu 890ddd
}