reactos操作系统实现(184)

GreExtTextOutW函数实现一串字符串输出到指定区域,当然是从字符串变成图片输出。这些都调用FreeType库来实现的,具体实现代码如下:

#001  BOOL

#002  APIENTRY

#003  GreExtTextOutW(

#004      IN HDC hDC,

#005      IN INT XStart,

#006      IN INT YStart,

#007      IN UINT fuOptions,

#008      IN OPTIONAL LPRECT lprc,

#009      IN LPWSTR String,

#010      IN INT Count,

#011      IN OPTIONAL LPINT Dx,

#012      IN DWORD dwCodePage)

#013  {

#014      /*

#015       * FIXME:

#016       * Call EngTextOut, which does the real work (calling DrvTextOut where

#017       * appropriate)

#018       */

#019 

#020      DC *dc;

#021      PDC_ATTR Dc_Attr;

#022      SURFOBJ *SurfObj;

#023      SURFACE *psurf = NULL;

#024      int error, glyph_index, n, i;

#025      FT_Face face;

#026      FT_GlyphSlot glyph;

#027      FT_Glyph realglyph;

#028      FT_BitmapGlyph realglyph2;

#029      LONGLONG TextLeft, RealXStart;

#030      ULONG TextTop, previous, BackgroundLeft;

#031      FT_Bool use_kerning;

#032      RECTL DestRect, MaskRect;

#033      POINTL SourcePoint, BrushOrigin;

#034      HBRUSH hBrushFg = NULL;

#035      PGDIBRUSHOBJ BrushFg = NULL;

#036      GDIBRUSHINST BrushFgInst;

#037      HBRUSH hBrushBg = NULL;

#038      PGDIBRUSHOBJ BrushBg = NULL;

#039      GDIBRUSHINST BrushBgInst;

#040      HBITMAP HSourceGlyph;

#041      SURFOBJ *SourceGlyphSurf;

#042      SIZEL bitSize;

#043      FT_CharMap found = 0, charmap;

#044      INT yoff;

#045      FONTOBJ *FontObj;

#046      PFONTGDI FontGDI;

#047      PTEXTOBJ TextObj = NULL;

#048      PPALGDI PalDestGDI;

#049      XLATEOBJ *XlateObj=NULL, *XlateObj2=NULL;

#050      ULONG Mode;

#051      FT_Render_Mode RenderMode;

#052      BOOLEAN Render;

#053      POINT Start;

#054      BOOL DoBreak = FALSE;

#055      HPALETTE hDestPalette;

#056      USHORT DxShift;

#057 

#058      // TODO: Write test-cases to exactly match real Windows in different

#059      // bad parameters (e.g. does Windows check the DC or the RECT first?).

 

锁住输出设备。

#060      dc = DC_LockDc(hDC);

#061      if (!dc)

#062      {

#063          SetLastWin32Error(ERROR_INVALID_HANDLE);

#064          return FALSE;

#065      }

#066      if (dc->DC_Type == DC_TYPE_INFO)

#067      {

#068          DC_UnlockDc(dc);

#069          /* Yes, Windows really returns TRUE in this case */

#070          return TRUE;

#071      }

#072 

 

获取设备的属性。

#073      Dc_Attr = dc->pDc_Attr;

#074      if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;

#075 

 

检查输出字符串是否有效,如果无效就直接返回。

#076      /* Check if String is valid */

#077      if ((Count > 0xFFFF) || (Count > 0 && String == NULL))

#078      {

#079          SetLastWin32Error(ERROR_INVALID_PARAMETER);

#080          goto fail;

#081      }

#082 

#083      DxShift = fuOptions & ETO_PDY ? 1 : 0;

#084 

 

获取输出路径。

#085      if (PATH_IsPathOpen(dc->DcLevel))

#086      {

#087          if (!PATH_ExtTextOut( dc,

#088                                XStart,

#089                                YStart,

#090                                fuOptions,

#091                                (const RECT *)lprc,

#092                                String,

#093                                Count,

#094                                (const INT *)Dx)) goto fail;

#095          goto good;

#096      }

#097 

 

转换逻辑坐标为设备坐标。

#098      if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))

#099      {

#100          IntLPtoDP(dc, (POINT *)lprc, 2);

#101      }

#102 

 

获取设备输出的表面层缓冲区。

#103      psurf = SURFACE_LockSurface(dc->w.hBitmap);

#104      if (!psurf)

#105      {

#106          goto fail;

#107      }

#108      SurfObj = &psurf->SurfObj;

#109      ASSERT(SurfObj);

#110 

#111      Start.x = XStart;

#112      Start.y = YStart;

#113      IntLPtoDP(dc, &Start, 1);

#114 

#115      RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;

#116      YStart = Start.y + dc->ptlDCOrig.y;

#117 

 

创建输出字符串的调色板。

#118      /* Create the brushes */

#119      hDestPalette = psurf->hDIBPalette;

#120      if (!hDestPalette) hDestPalette = pPrimarySurface->DevInfo.hpalDefault;

#121      PalDestGDI = PALETTE_LockPalette(hDestPalette);

#122      if ( !PalDestGDI )

#123          Mode = PAL_RGB;

#124      else

#125      {

#126          Mode = PalDestGDI->Mode;

#127          PALETTE_UnlockPalette(PalDestGDI);

#128      }

#129      XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, hDestPalette, NULL);

#130      if ( !XlateObj )

#131      {

#132          goto fail;

#133      }

 

创建输出字体的画刷。

#134      hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, Dc_Attr->crForegroundClr), 0);

#135      if ( !hBrushFg )

#136      {

#137          goto fail;

#138      }

#139      BrushFg = BRUSHOBJ_LockBrush(hBrushFg);

#140      if ( !BrushFg )

#141      {

#142          goto fail;

#143      }

#144      IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);

#145      if ((fuOptions & ETO_OPAQUE) || Dc_Attr->jBkMode == OPAQUE)

#146      {

#147          hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, Dc_Attr->crBackgroundClr), 0);

#148          if ( !hBrushBg )

#149          {

#150              goto fail;

#151          }

#152          BrushBg = BRUSHOBJ_LockBrush(hBrushBg);

#153          if ( !BrushBg )

#154          {

#155              goto fail;

#156          }

#157          IntGdiInitBrushInstance(&BrushBgInst, BrushBg, NULL);

#158      }

#159      XlateObj2 = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, Mode, NULL, hDestPalette);

#160      if ( !XlateObj2 )

#161      {

#162          goto fail;

#163      }

#164 

#165      SourcePoint.x = 0;

#166      SourcePoint.y = 0;

#167      MaskRect.left = 0;

#168      MaskRect.top = 0;

#169      BrushOrigin.x = 0;

#170      BrushOrigin.y = 0;

#171 

 

在输出文本字符串前之前,用当前背景色更新输出区域。

#172      if ((fuOptions & ETO_OPAQUE) && lprc)

#173      {

#174          DestRect.left   = lprc->left   + dc->ptlDCOrig.x;

#175          DestRect.top    = lprc->top    + dc->ptlDCOrig.y;

#176          DestRect.right  = lprc->right  + dc->ptlDCOrig.x;

#177          DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;

#178          IntLPtoDP(dc, (LPPOINT)&DestRect, 2);

#179          IntEngBitBlt(

#180              &psurf->SurfObj,

#181              NULL,

#182              NULL,

#183              dc->CombinedClip,

#184              NULL,

#185              &DestRect,

#186              &SourcePoint,

#187              &SourcePoint,

#188              &BrushBgInst.BrushObject,

#189              &BrushOrigin,

#190              ROP3_TO_ROP4(PATCOPY));

#191          fuOptions &= ~ETO_OPAQUE;

#192      }

#193      else

#194      {

#195          if (Dc_Attr->jBkMode == OPAQUE)

#196          {

#197              fuOptions |= ETO_OPAQUE;

#198          }

#199      }

#200 

 

初始化字符串输出的字体。

#201      TextObj = RealizeFontInit(Dc_Attr->hlfntNew);

#202      if (TextObj == NULL)

#203      {

#204          goto fail;

#205      }

#206 

#207      FontObj = TextObj->Font;

#208      ASSERT(FontObj);

#209      FontGDI = ObjToGDI(FontObj, FONT);

#210      ASSERT(FontGDI);

#211 

 

使用FREETYPE库来查找相应字符编码表。

#212      IntLockFreeType;

#213      face = FontGDI->face;

#214      if (face->charmap == NULL)

#215      {

#216          DPRINT("WARNING: No charmap selected!/n");

#217          DPRINT("This font face has %d charmaps/n", face->num_charmaps);

#218 

#219          for (n = 0; n < face->num_charmaps; n++)

#220          {

#221              charmap = face->charmaps[n];

#222              DPRINT("found charmap encoding: %u/n", charmap->encoding);

#223              if (charmap->encoding != 0)

#224              {

#225                  found = charmap;

#226                  break;

#227              }

#228          }

#229          if (!found)

#230          {

#231              DPRINT1("WARNING: Could not find desired charmap!/n");

#232          }

#233          error = FT_Set_Charmap(face, found);

#234          if (error)

#235          {

#236              DPRINT1("WARNING: Could not set the charmap!/n");

#237          }

#238      }

#239 

 

判断是单色字符显示,还是彩色图片显示。

#240      Render = IntIsFontRenderingEnabled();

#241      if (Render)

#242          RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);

#243      else

#244          RenderMode = FT_RENDER_MODE_MONO;

#245 

 

设置字体需像素点大小。

#246      error = FT_Set_Pixel_Sizes(

#247                  face,

#248                  TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,

#249                  /* FIXME should set character height if neg */

#250                  (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?

#251                   - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :

#252                   TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));

#253      if (error)

#254      {

#255          DPRINT1("Error in setting pixel sizes: %u/n", error);

#256          IntUnLockFreeType;

#257          goto fail;

#258      }

#259 

#260      /*

#261       * Process the vertical alignment and determine the yoff.

#262       */

#263 

 

处理每行字体的高度。

#264      if (Dc_Attr->lTextAlign & TA_BASELINE)

#265          yoff = 0;

#266      else if (Dc_Attr->lTextAlign & TA_BOTTOM)

#267          yoff = -face->size->metrics.descender >> 6;

#268      else /* TA_TOP */

#269          yoff = face->size->metrics.ascender >> 6;

#270 

#271      use_kerning = FT_HAS_KERNING(face);

#272      previous = 0;

#273 

#274      /*

#275       * Process the horizontal alignment and modify XStart accordingly.

#276       */

#277 

 

处理字体宽度。

#278      if (Dc_Attr->lTextAlign & (TA_RIGHT | TA_CENTER))

#279      {

#280          ULONGLONG TextWidth = 0;

#281          LPCWSTR TempText = String;

#282          int Start;

#283 

#284          /*

#285           * Calculate width of the text.

#286           */

#287 

#288          if (NULL != Dx)

#289          {

#290              Start = Count < 2 ? 0 : Count - 2;

#291              TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);

#292          }

#293          else

#294          {

#295              Start = 0;

#296          }

#297          TempText = String + Start;

#298  

#299          for (i = Start; i < Count; i++)

#300          {

#301              if (fuOptions & ETO_GLYPH_INDEX)

#302                  glyph_index = *TempText;

#303              else

#304                  glyph_index = FT_Get_Char_Index(face, *TempText);

#305 

#306              if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,

#307                                                   TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))

#308              {

#309                  error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);

#310                  if (error)

#311                  {

#312                      DPRINT1("WARNING: Failed to load and render glyph! [index: %u]/n", glyph_index);

#313                  }

#314 

#315                  glyph = face->glyph;

#316                  realglyph = ftGdiGlyphCacheSet(face, glyph_index,

#317                                                 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);

#318                  if (!realglyph)

#319                  {

#320                      DPRINT1("Failed to render glyph! [index: %u]/n", glyph_index);

#321                      IntUnLockFreeType;

#322                      goto fail;

#323                  }

#324 

#325              }

#326              /* retrieve kerning distance */

#327              if (use_kerning && previous && glyph_index)

#328              {

#329                  FT_Vector delta;

#330                  FT_Get_Kerning(face, previous, glyph_index, 0, &delta);

#331                  TextWidth += delta.x;

#332              }

#333 

#334              TextWidth += realglyph->advance.x >> 10;

#335 

#336              previous = glyph_index;

#337              TempText++;

#338          }

#339 

#340          previous = 0;

#341 

#342          if (Dc_Attr->lTextAlign & TA_RIGHT)

#343          {

#344              RealXStart -= TextWidth;

#345          }

#346          else

#347          {

#348              RealXStart -= TextWidth / 2;

#349          }

#350      }

#351 

#352      TextLeft = RealXStart;

#353      TextTop = YStart;

#354      BackgroundLeft = (RealXStart + 32) >> 6;

#355 

#356      /*

#357       * The main rendering loop.

#358       */

#359 

 

这里循环处理显示每一个字符,主要的过程就是读取一个字符的编码,然后根据编码到码表里找到字符的笔画,然后生成一个字符的BMP位图,再把每个字符位图输出,就可以显示相应的字符串了。

#360      for (i = 0; i < Count; i++)

#361      {

#362          if (fuOptions & ETO_GLYPH_INDEX)

#363              glyph_index = *String;

#364          else

#365              glyph_index = FT_Get_Char_Index(face, *String);

#366 

#367          if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,

#368                                               TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))

#369          {

#370              error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);

#371              if (error)

#372              {

#373                  DPRINT1("Failed to load and render glyph! [index: %u]/n", glyph_index);

#374                  IntUnLockFreeType;

#375                  goto fail;

#376              }

#377              glyph = face->glyph;

#378              realglyph = ftGdiGlyphCacheSet(face,

#379                                             glyph_index,

#380                                             TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,

#381                                             glyph,

#382                                             RenderMode);

#383              if (!realglyph)

#384              {

#385                  DPRINT1("Failed to render glyph! [index: %u]/n", glyph_index);

#386                  IntUnLockFreeType;

#387                  goto fail;

#388              }

#389          }

#390  //      DbgPrint("realglyph: %x/n", realglyph);

#391  //      DbgPrint("TextLeft: %d/n", TextLeft);

#392 

#393          /* retrieve kerning distance and move pen position */

#394          if (use_kerning && previous && glyph_index && NULL == Dx)

#395          {

#396              FT_Vector delta;

#397              FT_Get_Kerning(face, previous, glyph_index, 0, &delta);

#398              TextLeft += delta.x;

#399          }

#400  //      DPRINT1("TextLeft: %d/n", TextLeft);

#401  //      DPRINT1("TextTop: %d/n", TextTop);

#402 

#403          if (realglyph->format == ft_glyph_format_outline)

#404          {

#405              DbgPrint("Should already be done/n");

#406  //         error = FT_Render_Glyph(glyph, RenderMode);

#407              error = FT_Glyph_To_Bitmap(&realglyph, RenderMode, 0, 0);

#408              if (error)

#409              {

#410                  DPRINT1("WARNING: Failed to render glyph!/n");

#411                  goto fail;

#412              }

#413          }

#414          realglyph2 = (FT_BitmapGlyph)realglyph;

#415 

#416  //      DPRINT1("Pitch: %d/n", pitch);

#417  //      DPRINT1("Advance: %d/n", realglyph->advance.x);

#418 

#419          if (fuOptions & ETO_OPAQUE)

#420          {

#421              DestRect.left = BackgroundLeft;

#422              DestRect.right = (TextLeft + (realglyph->advance.x >> 10) + 32) >> 6;

#423              DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6);

#424              DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6);

#425              IntEngBitBlt(

#426                  &psurf->SurfObj,

#427                  NULL,

#428                  NULL,

#429                  dc->CombinedClip,

#430                  NULL,

#431                  &DestRect,

#432                  &SourcePoint,

#433                  &SourcePoint,

#434                  &BrushBgInst.BrushObject,

#435                  &BrushOrigin,

#436                  ROP3_TO_ROP4(PATCOPY));

#437              BackgroundLeft = DestRect.right;

#438          }

#439 

#440          DestRect.left = ((TextLeft + 32) >> 6) + realglyph2->left;

#441          DestRect.right = DestRect.left + realglyph2->bitmap.width;

#442          DestRect.top = TextTop + yoff - realglyph2->top;

#443          DestRect.bottom = DestRect.top + realglyph2->bitmap.rows;

#444 

#445          bitSize.cx = realglyph2->bitmap.width;

#446          bitSize.cy = realglyph2->bitmap.rows;

#447          MaskRect.right = realglyph2->bitmap.width;

#448          MaskRect.bottom = realglyph2->bitmap.rows;

#449 

#450          /*

#451           * We should create the bitmap out of the loop at the biggest possible

#452           * glyph size. Then use memset with 0 to clear it and sourcerect to

#453           * limit the work of the transbitblt.

#454           *

#455           * FIXME: DIB bitmaps should have an lDelta which is a multiple of 4.

#456           * Here we pass in the pitch from the FreeType bitmap, which is not

#457           * guaranteed to be a multiple of 4. If it's not, we should expand

#458           * the FreeType bitmap to a temporary bitmap.

#459           */

#460 

#461          HSourceGlyph = EngCreateBitmap(bitSize, realglyph2->bitmap.pitch,

#462                                         (realglyph2->bitmap.pixel_mode == ft_pixel_mode_grays) ?

#463                                         BMF_8BPP : BMF_1BPP, BMF_TOPDOWN,

#464                                         realglyph2->bitmap.buffer);

#465          if ( !HSourceGlyph )

#466          {

#467              DPRINT1("WARNING: EngLockSurface() failed!/n");

#468              // FT_Done_Glyph(realglyph);

#469              IntUnLockFreeType;

#470              goto fail;

#471          }

#472          SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);

#473          if ( !SourceGlyphSurf )

#474          {

#475              EngDeleteSurface((HSURF)HSourceGlyph);

#476              DPRINT1("WARNING: EngLockSurface() failed!/n");

#477              IntUnLockFreeType;

#478              goto fail;

#479          }

#480 

#481          /*

#482           * Use the font data as a mask to paint onto the DCs surface using a

#483           * brush.

#484           */

#485 

#486          if (lprc &&

#487                  (fuOptions & ETO_CLIPPED) &&

#488                  DestRect.right >= lprc->right + dc->ptlDCOrig.x)

#489          {

#490              // We do the check '>=' instead of '>' to possibly save an iteration

#491              // through this loop, since it's breaking after the drawing is done,

#492              // and x is always incremented.

#493              DestRect.right = lprc->right + dc->ptlDCOrig.x;

#494              DoBreak = TRUE;

#495          }

#496 

#497          IntEngMaskBlt(

#498              SurfObj,

#499              SourceGlyphSurf,

#500              dc->CombinedClip,

#501              XlateObj,

#502              XlateObj2,

#503              &DestRect,

#504              &SourcePoint,

#505              (PPOINTL)&MaskRect,

#506              &BrushFgInst.BrushObject,

#507              &BrushOrigin);

#508 

#509          EngUnlockSurface(SourceGlyphSurf);

#510          EngDeleteSurface((HSURF)HSourceGlyph);

#511 

#512          if (DoBreak)

#513          {

#514              break;

#515          }

#516 

#517          if (NULL == Dx)

#518          {

#519              TextLeft += realglyph->advance.x >> 10;

#520  //         DbgPrint("new TextLeft: %d/n", TextLeft);

#521          }

#522          else

#523          {

#524              TextLeft += Dx[i<<DxShift] << 6;

#525  //         DbgPrint("new TextLeft2: %d/n", TextLeft);

#526          }

#527 

#528          if (DxShift)

#529          {

#530              TextTop -= Dx[2 * i + 1] << 6;

#531          }

#532 

#533          previous = glyph_index;

#534 

#535          String++;

#536      }

#537 

 

后面就是删除分配的资源。

#538      IntUnLockFreeType;

#539 

#540      EngDeleteXlate(XlateObj);

#541      EngDeleteXlate(XlateObj2);

#542      SURFACE_UnlockSurface(psurf);

#543      if (TextObj != NULL)

#544          TEXTOBJ_UnlockText(TextObj);

#545      if (hBrushBg != NULL)

#546      {

#547          BRUSHOBJ_UnlockBrush(BrushBg);

#548          NtGdiDeleteObject(hBrushBg);

#549      }

#550      BRUSHOBJ_UnlockBrush(BrushFg);

#551      NtGdiDeleteObject(hBrushFg);

#552  good:

#553      DC_UnlockDc( dc );

#554 

#555      return TRUE;

#556 

#557  fail:

#558      if ( XlateObj2 != NULL )

#559          EngDeleteXlate(XlateObj2);

#560      if ( XlateObj != NULL )

#561          EngDeleteXlate(XlateObj);

#562      if (TextObj != NULL)

#563          TEXTOBJ_UnlockText(TextObj);

#564      if (psurf != NULL)

#565          SURFACE_UnlockSurface(psurf);

#566      if (hBrushBg != NULL)

#567      {

#568          BRUSHOBJ_UnlockBrush(BrushBg);

#569          NtGdiDeleteObject(hBrushBg);

#570      }

#571      if (hBrushFg != NULL)

#572      {

#573          BRUSHOBJ_UnlockBrush(BrushFg);

#574          NtGdiDeleteObject(hBrushFg);

#575      }

#576      DC_UnlockDc(dc);

#577 

#578      return FALSE;

#579  }

 

posted @ 2010-01-21 21:26  ajuanabc  阅读(234)  评论(0编辑  收藏  举报