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, #307 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))) #308 { #309 error = FT_Load_Glyph(face,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, #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,&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, #368 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))) #369 { #370 error = FT_Load_Glyph(face,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,&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); #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} (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |