text: 
  /*
   * Copyright 2011 Google Inc.
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  #include "SkScalerContext.h"
  #include "SkBitmap.h"
  #include "SkCanvas.h"
  #include "SkDescriptor.h"
  #include "SkFDot6.h"
  #include "SkFontHost.h"
  #include "SkMask.h"
  #include "SkStream.h"
  #include "SkString.h"
  #include "SkThread.h"
  #include "SkTemplates.h"
  
  #include <acaapi.h>
  
  //////////////////////////////////////////////////////////////////////////
  
  #include "SkMMapStream.h"
  
  class SkScalerContext_Ascender : public SkScalerContext {
  public:
      SkScalerContext_Ascender(const SkDescriptor* desc);
      virtual ~SkScalerContext_Ascender();
  
  protected:
      virtual unsigned generateGlyphCount();
      virtual uint16_t generateCharToGlyph(SkUnichar uni);
      virtual void generateMetrics(SkGlyph* glyph);
      virtual void generateImage(const SkGlyph& glyph);
      virtual void generatePath(const SkGlyph& glyph, SkPath* path);
      virtual void generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my);
  
  private:
      aca_FontHandle  fHandle;
      void*   fWorkspace;
      void*   fGlyphWorkspace;
      SkStream*   fFontStream;
      SkStream*   fHintStream;
  };
  
  ///////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////
  
  SkScalerContext_Ascender::SkScalerContext_Ascender(const SkDescriptor* desc)
      : SkScalerContext(desc)
  {
      int size = aca_Get_FontHandleRec_Size();
      fHandle = (aca_FontHandle)sk_malloc_throw(size);
  
      // get the pointer to the font
  
      fFontStream = new SkMMAPStream("/UcsGB2312-Hei-H.FDL");
      fHintStream = new SkMMAPStream("/genv6-23.bin");
  
      void* hints = sk_malloc_throw(fHintStream->getLength());
      memcpy(hints, fHintStream->getMemoryBase(), fHintStream->getLength());
  
      aca_Create_Font_Handle(fHandle,
                             (void*)fFontStream->getMemoryBase(), fFontStream->getLength(),
                             "fred",
                             hints, fHintStream->getLength());
  
      // compute our factors from the record
  
      SkMatrix    m;
  
      fRec.getSingleMatrix(&m);
  
      //  now compute our scale factors
      SkScalar    sx = m.getScaleX();
      SkScalar    sy = m.getScaleY();
  
      int ppemX = SkScalarRound(sx);
      int ppemY = SkScalarRound(sy);
  
      size = aca_Find_Font_Memory_Required(fHandle, ppemX, ppemY);
      size *= 8;  // Jeff suggests this :)
      fWorkspace = sk_malloc_throw(size);
      aca_Set_Font_Memory(fHandle, (uint8_t*)fWorkspace, size);
  
      aca_GlyphAttribsRec rec;
  
      memset(&rec, 0, sizeof(rec));
      rec.xSize = ppemX;
      rec.ySize = ppemY;
      rec.doAdjust = true;
      rec.doExceptions = true;
      rec.doGlyphHints = true;
      rec.doInterpolate = true;
      rec.grayMode = 2;
      aca_Set_Font_Attributes(fHandle, &rec, &size);
  
      fGlyphWorkspace = sk_malloc_throw(size);
      aca_Set_Glyph_Memory(fHandle, fGlyphWorkspace);
  }
  
  SkScalerContext_Ascender::~SkScalerContext_Ascender()
  {
      delete fHintStream;
      delete fFontStream;
      sk_free(fGlyphWorkspace);
      sk_free(fWorkspace);
      sk_free(fHandle);
  }
  
  unsigned SkScalerContext_Ascender::generateGlyphCount()
  {
      return 1000;
  }
  
  uint16_t SkScalerContext_Ascender::generateCharToGlyph(SkUnichar uni)
  {
      return (uint16_t)(uni & 0xFFFF);
  }
  
  void SkScalerContext_Ascender::generateMetrics(SkGlyph* glyph)
  {
      glyph->fRsbDelta = 0;
      glyph->fLsbDelta = 0;
  
      aca_GlyphImageRec   rec;
      aca_Vector          topLeft;
  
      int adv = aca_Get_Adv_Width(fHandle, glyph->getGlyphID());
      if (aca_GLYPH_NOT_PRESENT == adv)
          goto ERROR;
  
      aca_Rasterize(glyph->getGlyphID(), fHandle, &rec, &topLeft);
  
      if (false)  // error
      {
  ERROR:
          glyph->fWidth   = 0;
          glyph->fHeight  = 0;
          glyph->fTop     = 0;
          glyph->fLeft    = 0;
          glyph->fAdvanceX = 0;
          glyph->fAdvanceY = 0;
          return;
      }
  
      glyph->fWidth = rec.width;
      glyph->fHeight = rec.rows;
      glyph->fRowBytes = rec.width;
      glyph->fTop = -topLeft.y;
      glyph->fLeft = topLeft.x;
      glyph->fAdvanceX = SkIntToFixed(adv);
      glyph->fAdvanceY = SkIntToFixed(0);
  }
  
  void SkScalerContext_Ascender::generateImage(const SkGlyph& glyph)
  {
      aca_GlyphImageRec   rec;
      aca_Vector          topLeft;
  
      aca_Rasterize(glyph.getGlyphID(), fHandle, &rec, &topLeft);
  
      const uint8_t* src = (const uint8_t*)rec.buffer;
      uint8_t* dst = (uint8_t*)glyph.fImage;
      int height = glyph.fHeight;
  
      src += rec.y0 * rec.pitch + rec.x0;
      while (--height >= 0)
      {
          memcpy(dst, src, glyph.fWidth);
          src += rec.pitch;
          dst += glyph.fRowBytes;
      }
  }
  
  ///////////////////////////////////////////////////////////////////////////////////////////
  
  void SkScalerContext_Ascender::generatePath(const SkGlyph& glyph, SkPath* path)
  {
      SkRect r;
  
      r.set(0, 0, SkIntToScalar(4), SkIntToScalar(4));
      path->reset();
      path->addRect(r);
  }
  
  void SkScalerContext_Ascender::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my)
  {
      if (NULL == mx && NULL == my)
          return;
  
      if (mx)
      {
          mx->fTop = SkIntToScalar(-16);
          mx->fAscent = SkIntToScalar(-16);
          mx->fDescent = SkIntToScalar(4);
          mx->fBottom = SkIntToScalar(4);
          mx->fLeading = 0;
  
          // FIXME:
          mx->fAvgCharWidth = 0;
          mx->fXMin = 0;
          mx->fXMax = 0;
          mx->fXHeight = 0;
      }
      if (my)
      {
          my->fTop = SkIntToScalar(-16);
          my->fAscent = SkIntToScalar(-16);
          my->fDescent = SkIntToScalar(4);
          my->fBottom = SkIntToScalar(4);
          my->fLeading = 0;
  
          // FIXME:
          my->fAvgCharWidth = 0;
          my->fXMin = 0;
          my->fXMax = 0;
          my->fXHeight = 0;
      }
  }
  
  ////////////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////////////
  
  SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc)
  {
      return SkNEW_ARGS(SkScalerContext_Ascender, (desc));
  }
  