You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
938 lines
28 KiB
938 lines
28 KiB
/*++
|
|
|
|
Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
foncache.c
|
|
|
|
Abstract:
|
|
|
|
This file is EUDC font cache
|
|
|
|
Author:
|
|
|
|
Kazuhiko Matsubara 21-June-1994
|
|
|
|
Revision History:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#if defined(FE_SB)
|
|
|
|
|
|
VOID
|
|
RebaseFontImageList(
|
|
IN PFONT_IMAGE NewFontImage,
|
|
IN PBYTE OldFontImage
|
|
)
|
|
{
|
|
PLIST_ENTRY ImageList;
|
|
PBYTE BaseImage = (PBYTE)NewFontImage;
|
|
|
|
do {
|
|
ImageList = &NewFontImage->ImageList;
|
|
if (ImageList->Blink)
|
|
ImageList->Blink = (PLIST_ENTRY)((PBYTE)ImageList->Blink - OldFontImage + BaseImage);
|
|
if (ImageList->Flink)
|
|
ImageList->Flink = (PLIST_ENTRY)((PBYTE)ImageList->Flink - OldFontImage + BaseImage);
|
|
} while (NewFontImage = (PFONT_IMAGE)ImageList->Flink);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ULONG
|
|
CreateFontCache(
|
|
OUT PFONT_CACHE_INFORMATION *FontCache
|
|
)
|
|
{
|
|
//
|
|
// allocate font cache data
|
|
//
|
|
|
|
*FontCache = ConsoleHeapAlloc(HEAP_ZERO_MEMORY,sizeof(FONT_CACHE_INFORMATION));
|
|
if (*FontCache == NULL) {
|
|
return (ULONG)STATUS_NO_MEMORY;
|
|
}
|
|
|
|
return (ULONG)(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
ULONG
|
|
DestroyFontCache(
|
|
IN PFONT_CACHE_INFORMATION FontCache
|
|
)
|
|
{
|
|
if (FontCache != NULL)
|
|
{
|
|
PFONT_HIGHLOW_OFFSET FontOffsetHighLow;
|
|
PFONT_LOW_OFFSET FontOffsetLow;
|
|
PFONT_IMAGE FontImage;
|
|
UINT i, j, k;
|
|
|
|
for (i=0;
|
|
i < sizeof(FontCache->FontTable.FontOffsetHighHigh)/sizeof(PFONT_HIGHLOW_OFFSET);
|
|
i++)
|
|
{
|
|
if (FontOffsetHighLow = FontCache->FontTable.FontOffsetHighHigh[i])
|
|
{
|
|
for (j=0;
|
|
j < sizeof(FontOffsetHighLow->FontOffsetHighLow)/sizeof(PFONT_LOW_OFFSET);
|
|
j++)
|
|
{
|
|
if (FontOffsetLow = FontOffsetHighLow->FontOffsetHighLow[j])
|
|
{
|
|
for (k=0;
|
|
k < sizeof(FontOffsetLow->FontOffsetLow)/sizeof(PFONT_IMAGE);
|
|
k++)
|
|
{
|
|
if (FontImage = FontOffsetLow->FontOffsetLow[k])
|
|
{
|
|
ConsoleHeapFree(FontImage);
|
|
}
|
|
}
|
|
ConsoleHeapFree(FontOffsetLow);
|
|
}
|
|
}
|
|
ConsoleHeapFree(FontOffsetHighLow);
|
|
}
|
|
}
|
|
if (FontCache->BaseImageBits) {
|
|
ConsoleHeapFree(FontCache->BaseImageBits);
|
|
}
|
|
ConsoleHeapFree(FontCache);
|
|
}
|
|
return (ULONG)(STATUS_SUCCESS);
|
|
}
|
|
|
|
ULONG
|
|
RebaseFontCache(
|
|
IN PFONT_CACHE_INFORMATION FontCache,
|
|
IN PBYTE OldBaseImage
|
|
)
|
|
{
|
|
if (FontCache != NULL)
|
|
{
|
|
PFONT_HIGHLOW_OFFSET FontOffsetHighLow;
|
|
PFONT_LOW_OFFSET FontOffsetLow;
|
|
PFONT_IMAGE FontImage;
|
|
UINT i, j, k;
|
|
|
|
for (i=0;
|
|
i < sizeof(FontCache->FontTable.FontOffsetHighHigh)/sizeof(PFONT_HIGHLOW_OFFSET);
|
|
i++)
|
|
{
|
|
if (FontOffsetHighLow = FontCache->FontTable.FontOffsetHighHigh[i])
|
|
{
|
|
for (j=0;
|
|
j < sizeof(FontOffsetHighLow->FontOffsetHighLow)/sizeof(PFONT_LOW_OFFSET);
|
|
j++)
|
|
{
|
|
if (FontOffsetLow = FontOffsetHighLow->FontOffsetHighLow[j])
|
|
{
|
|
for (k=0;
|
|
k < sizeof(FontOffsetLow->FontOffsetLow)/sizeof(PFONT_IMAGE);
|
|
k++)
|
|
{
|
|
if (FontImage = FontOffsetLow->FontOffsetLow[k])
|
|
{
|
|
LIST_ENTRY ImageList;
|
|
|
|
do {
|
|
ImageList = FontImage->ImageList;
|
|
if (FontImage->ImageBits) {
|
|
FontImage->ImageBits = FontImage->ImageBits - OldBaseImage
|
|
+ FontCache->BaseImageBits;
|
|
}
|
|
} while (FontImage = (PFONT_IMAGE)ImageList.Flink);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (ULONG)(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
#define CALC_BITMAP_BITS_FOR_X( FontSizeX, dwAlign ) \
|
|
( ( ( FontSizeX * BITMAP_BITS_PIXEL + (dwAlign-1) ) & ~(dwAlign-1)) >> BITMAP_ARRAY_BYTE )
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
CalcBitmapBufferSize(
|
|
IN COORD FontSize,
|
|
IN DWORD dwAlign
|
|
)
|
|
{
|
|
DWORD uiCount;
|
|
|
|
uiCount = CALC_BITMAP_BITS_FOR_X(FontSize.X,
|
|
(dwAlign==BYTE_ALIGN ? BITMAP_BITS_BYTE_ALIGN : BITMAP_BITS_WORD_ALIGN));
|
|
uiCount = uiCount * BITMAP_PLANES * FontSize.Y;
|
|
return uiCount;
|
|
}
|
|
|
|
VOID
|
|
AlignCopyMemory(
|
|
OUT PBYTE pDestBits,
|
|
IN DWORD dwDestAlign,
|
|
IN PBYTE pSrcBits,
|
|
IN DWORD dwSrcAlign,
|
|
IN COORD FontSize
|
|
)
|
|
{
|
|
DWORD dwDestBufferSize;
|
|
COORD coord;
|
|
|
|
if (dwDestAlign == dwSrcAlign) {
|
|
dwDestBufferSize = CalcBitmapBufferSize(FontSize, dwDestAlign);
|
|
RtlCopyMemory(pDestBits, pSrcBits, dwDestBufferSize);
|
|
return;
|
|
}
|
|
|
|
switch (dwDestAlign) {
|
|
default:
|
|
case WORD_ALIGN:
|
|
switch (dwSrcAlign) {
|
|
default:
|
|
//
|
|
// pDest = WORD, pSrc = WORD
|
|
//
|
|
case WORD_ALIGN:
|
|
dwDestBufferSize = CalcBitmapBufferSize(FontSize, dwDestAlign);
|
|
RtlCopyMemory(pDestBits, pSrcBits, dwDestBufferSize);
|
|
break;
|
|
//
|
|
// pDest = WORD, pSrc = BYTE
|
|
//
|
|
case BYTE_ALIGN:
|
|
dwDestBufferSize = CalcBitmapBufferSize(FontSize, dwDestAlign);
|
|
if (((FontSize.X % BITMAP_BITS_BYTE_ALIGN) == 0) &&
|
|
((FontSize.X % BITMAP_BITS_WORD_ALIGN) == 0) ) {
|
|
RtlCopyMemory(pDestBits, pSrcBits, dwDestBufferSize);
|
|
}
|
|
else {
|
|
RtlZeroMemory(pDestBits, dwDestBufferSize);
|
|
for (coord.Y=0; coord.Y < FontSize.Y; coord.Y++) {
|
|
for (coord.X=0;
|
|
coord.X < CALC_BITMAP_BITS_FOR_X(FontSize.X, BITMAP_BITS_BYTE_ALIGN);
|
|
coord.X++) {
|
|
*pDestBits++ = *pSrcBits++;
|
|
}
|
|
if (CALC_BITMAP_BITS_FOR_X(FontSize.X, BITMAP_BITS_BYTE_ALIGN) & 1)
|
|
pDestBits++;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case BYTE_ALIGN:
|
|
switch (dwSrcAlign) {
|
|
//
|
|
// pDest = BYTE, pSrc = BYTE
|
|
//
|
|
case BYTE_ALIGN:
|
|
dwDestBufferSize = CalcBitmapBufferSize(FontSize, dwDestAlign);
|
|
RtlCopyMemory(pDestBits, pSrcBits, dwDestBufferSize);
|
|
break;
|
|
default:
|
|
//
|
|
// pDest = BYTE, pSrc = WORD
|
|
//
|
|
case WORD_ALIGN:
|
|
dwDestBufferSize = CalcBitmapBufferSize(FontSize, dwDestAlign);
|
|
if (((FontSize.X % BITMAP_BITS_BYTE_ALIGN) == 0) &&
|
|
((FontSize.X % BITMAP_BITS_WORD_ALIGN) == 0) ) {
|
|
RtlCopyMemory(pDestBits, pSrcBits, dwDestBufferSize);
|
|
}
|
|
else {
|
|
RtlZeroMemory(pDestBits, dwDestBufferSize);
|
|
for (coord.Y=0; coord.Y < FontSize.Y; coord.Y++) {
|
|
for (coord.X=0;
|
|
coord.X < CALC_BITMAP_BITS_FOR_X(FontSize.X, BITMAP_BITS_BYTE_ALIGN);
|
|
coord.X++) {
|
|
*pDestBits++ = *pSrcBits++;
|
|
}
|
|
if (CALC_BITMAP_BITS_FOR_X(FontSize.X, BITMAP_BITS_BYTE_ALIGN) & 1)
|
|
pSrcBits++;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GetStretchImage(
|
|
IN COORD FontSize,
|
|
IN PFONT_IMAGE FontImage,
|
|
OUT PFONT_IMAGE *pFontImage
|
|
)
|
|
{
|
|
PFONT_IMAGE NearFont;
|
|
DWORD Find;
|
|
COORD FontDelta;
|
|
HDC hDC;
|
|
HDC hSrcMemDC, hDestMemDC;
|
|
HBITMAP hSrcBmp, hDestBmp;
|
|
DWORD BufferSize;
|
|
NTSTATUS Status = STATUS_NO_MEMORY;
|
|
|
|
Find = (DWORD)-1;
|
|
NearFont = NULL;
|
|
do {
|
|
FontDelta.X = (SHORT) abs(FontSize.X - FontImage->FontSize.X);
|
|
FontDelta.Y = (SHORT) abs(FontSize.Y - FontImage->FontSize.Y);
|
|
if (Find > (DWORD)(FontDelta.X + FontDelta.Y))
|
|
{
|
|
Find = (DWORD)(FontDelta.X + FontDelta.Y);
|
|
NearFont = FontImage;
|
|
}
|
|
}
|
|
while (FontImage = (PFONT_IMAGE)FontImage->ImageList.Flink);
|
|
|
|
if (NearFont == NULL)
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
if ((hDC = CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL)) != NULL) {
|
|
hSrcMemDC = CreateCompatibleDC(hDC);
|
|
hDestMemDC = CreateCompatibleDC(hDC);
|
|
|
|
hSrcBmp = CreateBitmap(NearFont->FontSize.X,
|
|
NearFont->FontSize.Y,
|
|
BITMAP_PLANES, BITMAP_BITS_PIXEL,
|
|
NearFont->ImageBits);
|
|
hDestBmp = CreateBitmap(FontSize.X,
|
|
FontSize.Y,
|
|
BITMAP_PLANES, BITMAP_BITS_PIXEL,
|
|
NULL);
|
|
if (hSrcMemDC && hSrcBmp && hDestMemDC && hDestBmp) {
|
|
SelectObject(hSrcMemDC, hSrcBmp);
|
|
SelectObject(hDestMemDC, hDestBmp);
|
|
|
|
if (! StretchBlt(hDestMemDC, 0, 0, FontSize.X, FontSize.Y,
|
|
hSrcMemDC, 0, 0, NearFont->FontSize.X, NearFont->FontSize.Y,
|
|
SRCCOPY)) {
|
|
Status = GetLastError();
|
|
} else {
|
|
BufferSize = CalcBitmapBufferSize(FontSize, WORD_ALIGN);
|
|
GetBitmapBits(hDestBmp, BufferSize, (*pFontImage)->ImageBits);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (hSrcMemDC) {
|
|
DeleteDC(hSrcMemDC);
|
|
}
|
|
if (hDestMemDC) {
|
|
DeleteDC(hDestMemDC);
|
|
}
|
|
if (hSrcBmp) {
|
|
DeleteObject(hSrcBmp);
|
|
}
|
|
if (hDestBmp) {
|
|
DeleteObject(hDestBmp);
|
|
}
|
|
DeleteDC(hDC);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GetFontImageInternal(
|
|
IN PFONT_CACHE_INFORMATION FontCache,
|
|
IN WCHAR wChar,
|
|
IN COORD FontSize,
|
|
OUT PFONT_IMAGE *pFontImage,
|
|
IN DWORD GetFlag
|
|
)
|
|
{
|
|
PFONT_HIGHLOW_OFFSET FontOffsetHighLow;
|
|
PFONT_LOW_OFFSET FontOffsetLow;
|
|
PFONT_IMAGE FontImage;
|
|
WORD HighHighIndex, HighLowIndex;
|
|
WORD LowIndex;
|
|
DWORD Flag;
|
|
|
|
HighHighIndex = (HIBYTE(wChar)) >> 4;
|
|
HighLowIndex = (HIBYTE(wChar)) & 0x0f;
|
|
LowIndex = LOBYTE(wChar);
|
|
|
|
FontOffsetHighLow = FontCache->FontTable.FontOffsetHighHigh[HighHighIndex];
|
|
if (FontOffsetHighLow == NULL)
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
FontOffsetLow = FontOffsetHighLow->FontOffsetHighLow[HighLowIndex];
|
|
if (FontOffsetLow == NULL)
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
FontImage = FontOffsetLow->FontOffsetLow[LowIndex];
|
|
if (FontImage == NULL)
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
|
|
Flag = ADD_IMAGE;
|
|
do {
|
|
if (FontImage->FontSize.X == FontSize.X &&
|
|
FontImage->FontSize.Y == FontSize.Y ) {
|
|
//
|
|
// Replace font image
|
|
//
|
|
Flag = REPLACE_IMAGE;
|
|
break;
|
|
}
|
|
}
|
|
while (FontImage = (PFONT_IMAGE)FontImage->ImageList.Flink);
|
|
|
|
switch (GetFlag)
|
|
{
|
|
//
|
|
// Get matched size font.
|
|
//
|
|
case FONT_MATCHED:
|
|
if (Flag != REPLACE_IMAGE)
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
*pFontImage = FontImage;
|
|
break;
|
|
|
|
//
|
|
// Get stretched size font.
|
|
//
|
|
case FONT_STRETCHED:
|
|
if (Flag == REPLACE_IMAGE &&
|
|
FontImage->ImageBits != NULL) {
|
|
|
|
*pFontImage = FontImage;
|
|
|
|
}
|
|
else {
|
|
GetStretchImage(FontSize,
|
|
FontOffsetLow->FontOffsetLow[LowIndex],
|
|
pFontImage
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// See Raid #362907, stress failure
|
|
//
|
|
|
|
VOID UnlinkAndShrinkFontImagesByOne(
|
|
PFONT_IMAGE* ppFontImage,
|
|
PFONT_IMAGE pFontImageRemove)
|
|
{
|
|
PFONT_IMAGE OldFontImage = *ppFontImage;
|
|
SIZE_T OldFontSize = ConsoleHeapSize(OldFontImage);
|
|
PFONT_IMAGE NewFontImage;
|
|
|
|
RIPMSG0(RIP_WARNING, "UnlinkAndShrinkFontImagesByOne entered.");
|
|
|
|
if (OldFontImage== NULL) {
|
|
RIPMSG0(RIP_ERROR, "UnlinkAndShrinkFontImagesByOne: *ppFontImage is NULL.");
|
|
//
|
|
// There's nothing to shrink.
|
|
//
|
|
return;
|
|
}
|
|
|
|
if (OldFontImage == pFontImageRemove) {
|
|
RIPMSG0(RIP_WARNING, "UnlinkAndShrinkFontImagesByOne: unshrinking just one element.");
|
|
//
|
|
// There's just one entry. Let's free it and set
|
|
// ppFontImage as NULL, and bail out.
|
|
//
|
|
UserAssert(OldFontSize < sizeof(FONT_IMAGE) * 2);
|
|
|
|
*ppFontImage = NULL;
|
|
ConsoleHeapFree(OldFontImage);
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
//
|
|
// Double check the integrity of the linked list.
|
|
//
|
|
{
|
|
PFONT_IMAGE FontImageTmp;
|
|
|
|
//
|
|
// Search the tail element
|
|
//
|
|
for (FontImageTmp = OldFontImage; FontImageTmp->ImageList.Flink; FontImageTmp = (PFONT_IMAGE)FontImageTmp->ImageList.Flink)
|
|
;
|
|
|
|
UserAssert(FontImageTmp == pFontImageRemove);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Remove the tail element
|
|
//
|
|
pFontImageRemove->ImageList.Blink->Flink = NULL;
|
|
|
|
//
|
|
// Shrink the contiguous memory chunk
|
|
//
|
|
// Note: this code assumes sizeof(FONT_IMAGE) is larger than
|
|
// HEAP_GRANULARITY. If not, the heap block actually does not
|
|
// shrink, and the assert below will hit.
|
|
//
|
|
NewFontImage = ConsoleHeapReAlloc(HEAP_ZERO_MEMORY,
|
|
OldFontImage,
|
|
OldFontSize - sizeof(FONT_IMAGE));
|
|
if (NewFontImage == NULL) {
|
|
//
|
|
// Win32HeapRealloc firstly allocates a new memory and then
|
|
// copies the content. If the allocation fails, it leaves the
|
|
// original heap as is.
|
|
//
|
|
// Even though the realloc fails, the last element (pFontImageRemove) is
|
|
// already removed from the linked list. The next time SetImageFontInternal
|
|
// is called, a new FontImage might be added to this memory chunk, but the
|
|
// the code always links the newly extended memory.
|
|
// This leaves the sizeof(FONT_IMAGE) memory unused, but it's safe. Assuming
|
|
// sizeof(FONT_IMAGE) is small, memory waste should be minimum.
|
|
//
|
|
// It's OK for us to just bail out here.
|
|
//
|
|
RIPMSG0(RIP_WARNING, "UnlinkAndShrinkFontImagesByOne: failed to shrink ppFontImage.");
|
|
return;
|
|
}
|
|
UserAssert(ConsoleHeapSize(NewFontImage) != OldFontSize);
|
|
|
|
if (NewFontImage != OldFontImage) {
|
|
//
|
|
// Rebase Font Image Linked List
|
|
//
|
|
RebaseFontImageList(NewFontImage, (PBYTE)OldFontImage);
|
|
*ppFontImage = NewFontImage;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SetFontImageInternal(
|
|
IN PFONT_CACHE_INFORMATION FontCache,
|
|
IN WCHAR wChar,
|
|
IN COORD FontSize,
|
|
IN DWORD dwAlign,
|
|
IN CONST VOID *ImageBits
|
|
)
|
|
{
|
|
PFONT_HIGHLOW_OFFSET FontOffsetHighLow;
|
|
PFONT_LOW_OFFSET FontOffsetLow;
|
|
PFONT_IMAGE FontImage;
|
|
PFONT_IMAGE FontImageTmp;
|
|
WORD HighHighIndex, HighLowIndex;
|
|
WORD LowIndex;
|
|
DWORD Flag;
|
|
DWORD BufferSize;
|
|
|
|
HighHighIndex = (HIBYTE(wChar)) >> 4;
|
|
HighLowIndex = (HIBYTE(wChar)) & 0x0f;
|
|
LowIndex = LOBYTE(wChar);
|
|
|
|
/*
|
|
* When Console is being destroyed, all font cache information
|
|
* will be freed (see DestroyFontCache), so no memory leak
|
|
* is expected on those, even if we cleanup everything on
|
|
* error return...
|
|
*/
|
|
|
|
FontOffsetHighLow = FontCache->FontTable.FontOffsetHighHigh[HighHighIndex];
|
|
if (FontOffsetHighLow == NULL) {
|
|
FontOffsetHighLow = ConsoleHeapAlloc( HEAP_ZERO_MEMORY, sizeof(FONT_HIGHLOW_OFFSET));
|
|
if (FontOffsetHighLow == NULL) {
|
|
RIPMSG1(RIP_WARNING, "SetFontImageInternal: cannot allocate memory (%d bytes)",
|
|
sizeof(FONT_HIGHLOW_OFFSET));
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
FontCache->FontTable.FontOffsetHighHigh[HighHighIndex] = FontOffsetHighLow;
|
|
}
|
|
|
|
FontOffsetLow = FontOffsetHighLow->FontOffsetHighLow[HighLowIndex];
|
|
if (FontOffsetLow == NULL) {
|
|
FontOffsetLow = ConsoleHeapAlloc( HEAP_ZERO_MEMORY, sizeof(FONT_LOW_OFFSET));
|
|
if (FontOffsetLow == NULL) {
|
|
RIPMSG0(RIP_WARNING, "SetFontImageInternal: failed to allocate FontOffsetLow.");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
FontOffsetHighLow->FontOffsetHighLow[HighLowIndex] = FontOffsetLow;
|
|
}
|
|
|
|
FontImage = FontOffsetLow->FontOffsetLow[LowIndex];
|
|
if (FontImage == NULL) {
|
|
FontImage = ConsoleHeapAlloc( HEAP_ZERO_MEMORY, sizeof(FONT_IMAGE));
|
|
if (FontImage == NULL) {
|
|
RIPMSG0(RIP_WARNING, "SetFontImageInternal: failed to allocate FontImage");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (FontSize.X == 0 &&
|
|
FontSize.Y == 0 ) {
|
|
//
|
|
// Reset registered font
|
|
//
|
|
if (FontImage != NULL)
|
|
{
|
|
ConsoleHeapFree(FontImage);
|
|
FontOffsetLow->FontOffsetLow[LowIndex] = NULL;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
Flag = ADD_IMAGE;
|
|
FontImageTmp = FontImage;
|
|
do {
|
|
if (FontImageTmp->FontSize.X == FontSize.X &&
|
|
FontImageTmp->FontSize.Y == FontSize.Y ) {
|
|
//
|
|
// Replace font image
|
|
//
|
|
Flag = REPLACE_IMAGE;
|
|
FontImage = FontImageTmp;
|
|
break;
|
|
}
|
|
}
|
|
while (FontImageTmp = (PFONT_IMAGE)FontImageTmp->ImageList.Flink);
|
|
|
|
switch (Flag) {
|
|
case ADD_IMAGE:
|
|
if (FontOffsetLow->FontOffsetLow[LowIndex] != NULL)
|
|
{
|
|
PFONT_IMAGE OldFontImage = FontOffsetLow->FontOffsetLow[LowIndex];
|
|
SIZE_T OldFontSize = ConsoleHeapSize(OldFontImage);
|
|
PFONT_IMAGE NewFontImage;
|
|
|
|
NewFontImage = ConsoleHeapReAlloc(HEAP_ZERO_MEMORY,
|
|
OldFontImage,
|
|
OldFontSize + sizeof(FONT_IMAGE));
|
|
if (NewFontImage == NULL) {
|
|
RIPMSG0(RIP_WARNING, "SetFontImageInternal: failed to allocate NewFontImage");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
FontOffsetLow->FontOffsetLow[LowIndex] = NewFontImage;
|
|
|
|
// Rebase Font Image List
|
|
RebaseFontImageList(NewFontImage, (PBYTE)OldFontImage);
|
|
|
|
NewFontImage = (PFONT_IMAGE)((PBYTE)NewFontImage + OldFontSize);
|
|
|
|
NewFontImage->FontSize = FontSize;
|
|
|
|
//
|
|
// Connect link list.
|
|
//
|
|
(NewFontImage-1)->ImageList.Flink = (PLIST_ENTRY)NewFontImage;
|
|
NewFontImage->ImageList.Blink = (PLIST_ENTRY)(NewFontImage-1);
|
|
|
|
FontImage = NewFontImage;
|
|
}
|
|
else
|
|
{
|
|
FontImage->FontSize = FontSize;
|
|
FontOffsetLow->FontOffsetLow[LowIndex] = FontImage;
|
|
}
|
|
|
|
//
|
|
// Allocate Image Buffer
|
|
//
|
|
BufferSize = CalcBitmapBufferSize(FontSize,WORD_ALIGN);
|
|
|
|
if (FontCache->BaseImageBits == NULL)
|
|
{
|
|
FontCache->BaseImageBits = ConsoleHeapAlloc( HEAP_ZERO_MEMORY, BufferSize);
|
|
if (FontCache->BaseImageBits == NULL) {
|
|
RIPMSG0(RIP_WARNING, "SetFontImageInternal: failed to allocate FontCache->BaseImageBits");
|
|
UnlinkAndShrinkFontImagesByOne(&FontOffsetLow->FontOffsetLow[LowIndex], FontImage);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
FontImage->ImageBits = FontCache->BaseImageBits;
|
|
}
|
|
else
|
|
{
|
|
PBYTE OldBaseImage = FontCache->BaseImageBits;
|
|
SIZE_T OldImageSize = ConsoleHeapSize(OldBaseImage);
|
|
FontCache->BaseImageBits = ConsoleHeapReAlloc(HEAP_ZERO_MEMORY,
|
|
OldBaseImage,
|
|
OldImageSize + BufferSize);
|
|
if (FontCache->BaseImageBits == NULL) {
|
|
RIPMSG0(RIP_WARNING, "SetFontImageInternal: failed to reallocate FontCache->BaseImageBits");
|
|
//
|
|
// When reallocation fails, we preserve the old baseImageBits
|
|
// so that other FontImage->ImageBits can be still valid.
|
|
//
|
|
FontCache->BaseImageBits = OldBaseImage;
|
|
//
|
|
// Remove the tail element that we failed to add image.
|
|
//
|
|
UnlinkAndShrinkFontImagesByOne(&FontOffsetLow->FontOffsetLow[LowIndex], FontImage);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
// Rebase font image pointer
|
|
RebaseFontCache(FontCache, OldBaseImage);
|
|
|
|
FontImage->ImageBits = FontCache->BaseImageBits + OldImageSize;
|
|
}
|
|
|
|
AlignCopyMemory(FontImage->ImageBits,// pDestBits
|
|
WORD_ALIGN, // dwDestAlign
|
|
(PVOID)ImageBits, // pSrcBits
|
|
dwAlign, // dwSrcAlign
|
|
FontSize);
|
|
|
|
break;
|
|
|
|
case REPLACE_IMAGE:
|
|
if (FontImage->ImageBits == NULL) {
|
|
RIPMSG0(RIP_WARNING, "SetFontImageInternal: FontImage->ImageBits is NULL.");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
AlignCopyMemory(FontImage->ImageBits,// pDestBits
|
|
WORD_ALIGN, // dwDestAlign
|
|
(PVOID)ImageBits, // pSrcBits
|
|
dwAlign, // dwSrcAlign
|
|
FontSize);
|
|
|
|
break;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ULONG
|
|
GetFontImage(
|
|
IN PFONT_CACHE_INFORMATION FontCache,
|
|
IN WCHAR wChar,
|
|
IN COORD FontSize,
|
|
IN DWORD dwAlign,
|
|
OUT VOID *ImageBits
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PFONT_IMAGE FontImage;
|
|
|
|
if (FontSize.X == 0 &&
|
|
FontSize.Y == 0 ) {
|
|
return (ULONG)(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
Status = GetFontImageInternal(FontCache,wChar,FontSize,&FontImage,FONT_MATCHED);
|
|
if (! NT_SUCCESS(Status) )
|
|
return (ULONG)Status;
|
|
|
|
if (FontImage->ImageBits == NULL ||
|
|
ImageBits == NULL)
|
|
return STATUS_SUCCESS;
|
|
|
|
AlignCopyMemory((PVOID)ImageBits, // pDestBits
|
|
dwAlign, // dwDestAlign
|
|
FontImage->ImageBits,// pSrcBits
|
|
WORD_ALIGN, // dwSrcAlign
|
|
FontSize);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
GetStretchedFontImage(
|
|
IN PFONT_CACHE_INFORMATION FontCache,
|
|
IN WCHAR wChar,
|
|
IN COORD FontSize,
|
|
IN DWORD dwAlign,
|
|
OUT VOID *ImageBits
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PFONT_IMAGE FontImage;
|
|
FONT_IMAGE FontBuff;
|
|
DWORD BufferSize;
|
|
|
|
if (FontSize.X == 0 &&
|
|
FontSize.Y == 0 ) {
|
|
return (ULONG)(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
FontImage = &FontBuff;
|
|
|
|
BufferSize = CalcBitmapBufferSize(FontSize,WORD_ALIGN);
|
|
FontImage->ImageBits = ConsoleHeapAlloc( HEAP_ZERO_MEMORY, BufferSize);
|
|
if (FontImage->ImageBits == NULL) {
|
|
RIPMSG0(RIP_WARNING, "GetStretchedFontImage: failed to allocate FontImage->ImageBits");
|
|
return (ULONG)STATUS_NO_MEMORY;
|
|
}
|
|
|
|
Status = GetFontImageInternal(FontCache,wChar,FontSize,&FontImage,FONT_STRETCHED);
|
|
if (! NT_SUCCESS(Status) )
|
|
{
|
|
ConsoleHeapFree(FontBuff.ImageBits);
|
|
return (ULONG)Status;
|
|
}
|
|
|
|
if (FontImage->ImageBits == NULL)
|
|
{
|
|
ConsoleHeapFree(FontBuff.ImageBits);
|
|
return (ULONG)STATUS_SUCCESS;
|
|
}
|
|
|
|
AlignCopyMemory((PVOID)ImageBits, // pDestBits
|
|
dwAlign, // dwDestAlign
|
|
FontImage->ImageBits,// pSrcBits
|
|
WORD_ALIGN, // dwSrcAlign
|
|
FontSize);
|
|
|
|
ConsoleHeapFree(FontBuff.ImageBits);
|
|
|
|
return (ULONG)STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
GetFontImagePointer(
|
|
IN PFONT_CACHE_INFORMATION FontCache,
|
|
IN WCHAR wChar,
|
|
IN COORD FontSize,
|
|
OUT PFONT_IMAGE *FontImage
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if (FontSize.X == 0 &&
|
|
FontSize.Y == 0 ) {
|
|
return (ULONG)(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
Status = GetFontImageInternal(FontCache,wChar,FontSize,(PFONT_IMAGE*)FontImage,FONT_MATCHED);
|
|
if (! NT_SUCCESS(Status) )
|
|
return (ULONG)Status;
|
|
|
|
if ((*FontImage)->ImageBits == NULL)
|
|
return (ULONG)STATUS_ACCESS_DENIED;
|
|
|
|
return Status;
|
|
}
|
|
|
|
ULONG
|
|
SetFontImage(
|
|
IN PFONT_CACHE_INFORMATION FontCache,
|
|
IN WCHAR wChar,
|
|
IN COORD FontSize,
|
|
IN DWORD dwAlign,
|
|
IN CONST VOID *ImageBits
|
|
)
|
|
{
|
|
return SetFontImageInternal(FontCache,wChar,FontSize,dwAlign,ImageBits);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetExpandImage(
|
|
COORD InputFontSize,
|
|
PWORD InputFontImage,
|
|
COORD OutputFontSize,
|
|
PWORD OutputFontImage
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
DWORD InputRow = CALC_BITMAP_BITS_FOR_X(InputFontSize.X, BITMAP_BITS_WORD_ALIGN);
|
|
DWORD OutputRow = CALC_BITMAP_BITS_FOR_X(OutputFontSize.X, BITMAP_BITS_WORD_ALIGN);
|
|
DWORD InputBufferSize = CalcBitmapBufferSize(InputFontSize,WORD_ALIGN);
|
|
DWORD OutputBufferSize = CalcBitmapBufferSize(OutputFontSize,WORD_ALIGN);
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
|
|
RtlZeroMemory(OutputFontImage,OutputBufferSize);
|
|
|
|
ASSERT(InputRow==OutputRow);
|
|
|
|
if (InputFontSize.Y < OutputFontSize.Y)
|
|
RtlCopyMemory(OutputFontImage, InputFontImage, InputBufferSize);
|
|
else
|
|
RtlCopyMemory(OutputFontImage, InputFontImage, OutputBufferSize);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetExpandFontImage(
|
|
PFONT_CACHE_INFORMATION FontCache,
|
|
WCHAR wChar,
|
|
COORD InputFontSize,
|
|
COORD OutputFontSize,
|
|
PWORD OutputFontImage
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
DWORD InputBufferSize;
|
|
PWORD InputFontImage;
|
|
|
|
if (InputFontSize.X == 0 &&
|
|
InputFontSize.Y == 0 ) {
|
|
return (ULONG)(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (OutputFontSize.X == 0 &&
|
|
OutputFontSize.Y == 0 ) {
|
|
return (ULONG)(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
InputBufferSize = CalcBitmapBufferSize(InputFontSize,WORD_ALIGN);
|
|
InputFontImage = ConsoleHeapAlloc( HEAP_ZERO_MEMORY, InputBufferSize);
|
|
if (InputFontImage==NULL)
|
|
return STATUS_NO_MEMORY;
|
|
|
|
|
|
Status = GetFontImage(FontCache,
|
|
wChar,
|
|
InputFontSize,
|
|
WORD_ALIGN,
|
|
InputFontImage);
|
|
if (! NT_SUCCESS(Status) )
|
|
{
|
|
ConsoleHeapFree(InputFontImage);
|
|
return Status;
|
|
}
|
|
|
|
Status = GetExpandImage(InputFontSize,
|
|
InputFontImage,
|
|
OutputFontSize,
|
|
OutputFontImage);
|
|
|
|
ConsoleHeapFree(InputFontImage);
|
|
|
|
return Status;
|
|
}
|
|
#endif
|