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.
2879 lines
100 KiB
2879 lines
100 KiB
/******************************Module*Header*******************************\
|
|
*
|
|
* Module Name: TEXTOUT.c
|
|
* Author: Martin Barber
|
|
* Date: Jun. 19, 1995
|
|
* Purpose: Handle calls to DrvTxtOut
|
|
*
|
|
* Copyright (c) 1995,1996 Cirrus Logic, Inc.
|
|
*
|
|
* $Log: X:/log/laguna/nt35/displays/cl546x/TEXTOUT.C $
|
|
*
|
|
* Rev 1.34 Mar 27 1998 14:47:14 frido
|
|
* PDR#11280. In the monospaced font loop there was a problem loading
|
|
* the pointer to the next glyph bits. It always got the pointer to the
|
|
* previous glyph.
|
|
*
|
|
* Rev 1.33 Mar 04 1998 15:38:46 frido
|
|
* Added new shadow macros.
|
|
*
|
|
* Rev 1.32 Dec 17 1997 16:42:14 frido
|
|
* PDR#10875: There was a GPF inside vMmClipGlyphExpansion and NT
|
|
* 3.51 does not handle this very well. It caused the hardware to wait for
|
|
* another DWORD which was never send.
|
|
*
|
|
* Rev 1.31 Dec 10 1997 13:32:20 frido
|
|
* Merged from 1.62 branch.
|
|
*
|
|
* Rev 1.30.1.1 Dec 03 1997 18:12:20 frido
|
|
* PDR#11039. Fixed allocation of font cache. In certain cases it would
|
|
* allocate too few cells and still use the unallocated cells causing
|
|
* corruption.
|
|
*
|
|
* Rev 1.30.1.0 Nov 18 1997 15:40:16 frido
|
|
* Changed a spelling error: RWQUIRE into REQUIRE.
|
|
*
|
|
* Rev 1.30 Nov 03 1997 10:17:36 frido
|
|
* Added REQUIRE and WRITE_STRING macros.
|
|
* Removed CHECK_QFREE macros.
|
|
*
|
|
* Rev 1.29 25 Aug 1997 16:07:24 FRIDO
|
|
*
|
|
* Fixed lockup in 8-bpp vMmClipGlyphExpansion SWAT7 code.
|
|
*
|
|
* Rev 1.28 08 Aug 1997 17:24:30 FRIDO
|
|
* Added support for new memory manager.
|
|
* Added SWAT7 switches for 8-bpp hardware bug.
|
|
*
|
|
* Rev 1.27 29 Apr 1997 16:28:50 noelv
|
|
*
|
|
* Merged in new SWAT code.
|
|
* SWAT:
|
|
* SWAT: Rev 1.7 24 Apr 1997 12:05:38 frido
|
|
* SWAT: Fixed a missing "}".
|
|
* SWAT:
|
|
* SWAT: Rev 1.6 24 Apr 1997 11:22:18 frido
|
|
* SWAT: NT140b09 merge.
|
|
* SWAT: Changed pfm into pCell for SWAT3 changes.
|
|
* SWAT:
|
|
* SWAT: Rev 1.5 19 Apr 1997 17:11:02 frido
|
|
* SWAT: Added SWAT.h include file.
|
|
* SWAT: Fixed a bug in DrvDestroyFont causing hangups in 2nd WB97 pass.
|
|
* SWAT:
|
|
* SWAT: Rev 1.4 18 Apr 1997 00:34:28 frido
|
|
* SWAT: Fixed a merge bug.
|
|
* SWAT:
|
|
* SWAT: Rev 1.3 18 Apr 1997 00:15:28 frido
|
|
* SWAT: NT140b07 merge.
|
|
* SWAT:
|
|
* SWAT: Rev 1.2 10 Apr 1997 16:02:06 frido
|
|
* SWAT: Oops, I allocated the font cache in the wrong size.
|
|
* SWAT:
|
|
* SWAT: Rev 1.1 09 Apr 1997 17:37:30 frido
|
|
* SWAT: New font cache allocation scheme. Allocate from a 'pool' of cells
|
|
* SWAT: instead of putting the font cache all over the place.
|
|
*
|
|
* Rev 1.26 08 Apr 1997 12:32:50 einkauf
|
|
*
|
|
* add SYNC_W_3D to coordinate MCD/2D hw access
|
|
*
|
|
* Rev 1.25 21 Mar 1997 13:37:06 noelv
|
|
* Added checkes for QFREE.
|
|
*
|
|
* Rev 1.24 06 Feb 1997 10:38:04 noelv
|
|
* Removed WAIT_FOR_IDLE
|
|
*
|
|
* Rev 1.23 04 Feb 1997 11:11:00 SueS
|
|
* Added support for hardware clipping for the 5465.
|
|
*
|
|
* Rev 1.22 17 Dec 1996 16:59:00 SueS
|
|
* Added test for writing to log file based on cursor at (0,0).
|
|
*
|
|
* Rev 1.21 26 Nov 1996 10:46:36 SueS
|
|
* Changed WriteLogFile parameters for buffering.
|
|
*
|
|
* Rev 1.20 13 Nov 1996 17:01:28 SueS
|
|
* Changed WriteFile calls to WriteLogFile.
|
|
*
|
|
* Rev 1.19 07 Nov 1996 16:10:16 bennyn
|
|
*
|
|
* Added no offscn mem allocation if DD enabled
|
|
*
|
|
* Rev 1.18 06 Sep 1996 15:16:44 noelv
|
|
* Updated NULL driver for 4.0
|
|
*
|
|
* Rev 1.17 20 Aug 1996 11:04:36 noelv
|
|
* Bugfix release from Frido 8-19-96
|
|
*
|
|
* Rev 1.3 16 Aug 1996 14:48:20 frido
|
|
* Fixed a small wanring error.
|
|
*
|
|
* Rev 1.2 15 Aug 1996 11:54:32 frido
|
|
* Fixed precompiled headers.
|
|
*
|
|
* Rev 1.1 15 Aug 1996 11:38:32 frido
|
|
* Added precompiled header.
|
|
*
|
|
* Rev 1.0 14 Aug 1996 17:16:32 frido
|
|
* Initial revision.
|
|
*
|
|
* Rev 1.16 25 Jul 1996 15:56:28 bennyn
|
|
*
|
|
* Modified to support DirectDraw
|
|
*
|
|
* Rev 1.15 28 May 1996 15:11:36 noelv
|
|
* Updated data logging.
|
|
*
|
|
* Rev 1.14 16 May 1996 15:06:18 bennyn
|
|
*
|
|
* Added PIXEL_ALIGN to allocoffscnmem()
|
|
*
|
|
* Rev 1.13 16 May 1996 14:54:32 noelv
|
|
* Added logging code.
|
|
*
|
|
* Rev 1.12 03 May 1996 15:09:42 noelv
|
|
*
|
|
* Added flag to turn caching on and off.
|
|
*
|
|
* Rev 1.11 01 May 1996 11:01:48 bennyn
|
|
*
|
|
* Modified for NT4.0
|
|
*
|
|
* Rev 1.10 12 Apr 1996 18:13:06 andys
|
|
* Fixed bug in combining 3 bytes into DWORD (<< | bug)
|
|
*
|
|
* Rev 1.9 11 Apr 1996 18:00:56 andys
|
|
* Added Code to the > 16 PEL case to guard against walking off the end of a b
|
|
*
|
|
* Rev 1.8 04 Apr 1996 13:20:32 noelv
|
|
* Frido release 26
|
|
*
|
|
* Rev 1.16 01 Apr 1996 15:29:22 frido
|
|
* Fixed bug in font cache when glyph cannot be cached.
|
|
*
|
|
* Rev 1.15 28 Mar 1996 23:37:34 frido
|
|
* Fixed drawing of partially left-clipped glyphs.
|
|
*
|
|
* Rev 1.14 27 Mar 1996 14:12:18 frido
|
|
* Commented changes.
|
|
*
|
|
* Rev 1.13 25 Mar 1996 11:58:38 frido
|
|
* Removed warning message.
|
|
*
|
|
* Rev 1.12 25 Mar 1996 11:50:42 frido
|
|
* Bellevue 102B03.
|
|
*
|
|
* Rev 1.5 18 Mar 1996 12:34:10 noelv
|
|
*
|
|
* Added data logging stuff
|
|
*
|
|
* Rev 1.4 07 Mar 1996 18:24:14 bennyn
|
|
*
|
|
* Removed read/modify/write on CONTROL reg
|
|
*
|
|
* Rev 1.3 05 Mar 1996 11:59:20 noelv
|
|
* Frido version 19
|
|
*
|
|
* Rev 1.11 04 Mar 1996 20:23:28 frido
|
|
* Cached grCONTROL register.
|
|
*
|
|
* Rev 1.10 29 Feb 1996 20:23:08 frido
|
|
* Changed some comments.
|
|
*
|
|
* Rev 1.9 28 Feb 1996 22:39:46 frido
|
|
* Added Optimize.h.
|
|
*
|
|
* Rev 1.8 27 Feb 1996 16:38:12 frido
|
|
* Added device bitmap store/restore.
|
|
*
|
|
* Rev 1.7 24 Feb 1996 01:23:16 frido
|
|
* Added device bitmaps.
|
|
*
|
|
* Rev 1.6 03 Feb 1996 13:57:24 frido
|
|
* Use the compile switch "-Dfrido=0" to disable my extensions.
|
|
*
|
|
* Rev 1.5 03 Feb 1996 12:17:58 frido
|
|
* Added text clipping.
|
|
*
|
|
* Rev 1.4 25 Jan 1996 12:45:56 frido
|
|
* Added reinitialization of font cache after mode switch.
|
|
*
|
|
* Rev 1.3 24 Jan 1996 23:10:16 frido
|
|
* Moved font cache and entry point to assembly for i386.
|
|
*
|
|
* Rev 1.2 23 Jan 1996 15:37:20 frido
|
|
* Added font cache.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include "font.h"
|
|
#include "SWAT.h" // SWAT optimizations
|
|
|
|
#define TEXT_DBG_LEVEL 1
|
|
#define TEXT_DBG_LEVEL1 1
|
|
#define RECORD_ON FALSE
|
|
#define BUFFER_EXPAND FALSE
|
|
|
|
|
|
/*
|
|
-------------------------------------------------------------------------------
|
|
Module Entry Points:
|
|
--------------------
|
|
DrvTextOut()
|
|
|
|
General Plan:
|
|
--------------------
|
|
*
|
|
* On every TextOut, GDI provides an array of 'GLYPHPOS' structures
|
|
* for every glyph to be drawn. Each GLYPHPOS structure contains a
|
|
* the glyph. (Note that unlike Windows 3.1, which provides a column-
|
|
* major glyph bitmap, Windows NT always provides a row-major glyph
|
|
* bitmap.) As such, there are three basic methods for drawing text
|
|
* with hardware acceleration:
|
|
*
|
|
* 1) Glyph caching -- Glyph bitmaps are cached by the accelerator
|
|
* (probably in off-screen memory), and text is drawn by
|
|
* referring the hardware to the cached glyph locations.
|
|
*
|
|
* 2) Glyph expansion -- Each individual glyph is colour-expanded
|
|
* directly to the screen from the monochrome glyph bitmap
|
|
* supplied by GDI.
|
|
*
|
|
* 3) Buffer expansion -- The CPU is used to draw all the glyphs into
|
|
* a 1bpp monochrome bitmap, and the hardware is then used
|
|
* to colour-expand the result.
|
|
*
|
|
* The fastest method depends on a number of variables, such as the
|
|
* colour expansion speed, bus speed, CPU speed, average glyph size,
|
|
* and average string length.
|
|
*
|
|
* Copyright (c) 1992-1994 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
//
|
|
// Data logging stuff.
|
|
// Gets compiled out in a free bulid.
|
|
//
|
|
#if LOG_CALLS
|
|
char BUF[256];
|
|
|
|
#if ENABLE_LOG_SWITCH
|
|
#define LogFile(x) \
|
|
do { \
|
|
if (pointer_switch == 1) \
|
|
{ \
|
|
int i = sprintf x ; \
|
|
WriteLogFile(ppdev->pmfile, BUF, i, ppdev->TxtBuff, &ppdev->TxtBuffIndex); \
|
|
} \
|
|
} while(0); \
|
|
|
|
#else
|
|
#define LogFile(x) \
|
|
do { \
|
|
int i = sprintf x ; \
|
|
WriteLogFile(ppdev->pmfile, BUF, i, ppdev->TxtBuff, &ppdev->TxtBuffIndex); \
|
|
} while(0); \
|
|
|
|
#endif
|
|
#else
|
|
#define BUF 0
|
|
#define LogFile(x)
|
|
#endif
|
|
|
|
|
|
|
|
POINTL gptlZero = { 0, 0 }; // Specifies that the origin of the
|
|
// temporary buffer given to the 1bpp
|
|
// transfer routine for fasttext is
|
|
// at (0, 0)
|
|
|
|
/******************************Public*Routine******************************\
|
|
* void AddToFontCacheChain
|
|
*
|
|
* Add the FONTCACHE to the Font cache chain
|
|
*
|
|
\**************************************************************************/
|
|
void AddToFontCacheChain(PDEV* ppdev,
|
|
FONTOBJ* pfo,
|
|
PFONTCACHE pfc)
|
|
{
|
|
DISPDBG((TEXT_DBG_LEVEL1," AddToFontCacheChain.\n"));
|
|
|
|
pfc->pfo = pfo;
|
|
|
|
#if !SWAT3 // We don't need this anymore. The cell grid has all the pointers.
|
|
// Hook the font cache into the chain.
|
|
if (ppdev->pfcChain != NULL)
|
|
{
|
|
ppdev->pfcChain->pfcPrev = pfc;
|
|
}
|
|
|
|
pfc->pfcPrev = NULL;
|
|
pfc->pfcNext = ppdev->pfcChain;
|
|
ppdev->pfcChain = pfc;
|
|
#endif
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bIntersect
|
|
*
|
|
* If 'prcl1' and 'prcl2' intersect, has a return value of TRUE and returns
|
|
* the intersection in 'prclResult'. If they don't intersect, has a return
|
|
* value of FALSE, and 'prclResult' is undefined.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bIntersect(
|
|
RECTL* prcl1,
|
|
RECTL* prcl2,
|
|
RECTL* prclResult)
|
|
{
|
|
DISPDBG((TEXT_DBG_LEVEL1," bIntersect.\n"));
|
|
|
|
prclResult->left = max(prcl1->left, prcl2->left);
|
|
prclResult->right = min(prcl1->right, prcl2->right);
|
|
|
|
if (prclResult->left < prclResult->right)
|
|
{
|
|
prclResult->top = max(prcl1->top, prcl2->top);
|
|
prclResult->bottom = min(prcl1->bottom, prcl2->bottom);
|
|
|
|
if (prclResult->top < prclResult->bottom)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* LONG cIntersect
|
|
*
|
|
* This routine takes a list of rectangles from 'prclIn' and clips them
|
|
* in-place to the rectangle 'prclClip'. The input rectangles don't
|
|
* have to intersect 'prclClip'; the return value will reflect the
|
|
* number of input rectangles that did intersect, and the intersecting
|
|
* rectangles will be densely packed.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
LONG cIntersect(
|
|
RECTL* prclClip,
|
|
RECTL* prclIn, // List of rectangles
|
|
LONG c) // Can be zero
|
|
{
|
|
LONG cIntersections;
|
|
RECTL* prclOut;
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL1," cIntersect.\n"));
|
|
cIntersections = 0;
|
|
prclOut = prclIn;
|
|
|
|
for ( ; c != 0; prclIn++, c--)
|
|
{
|
|
prclOut->left = max(prclIn->left, prclClip->left);
|
|
prclOut->right = min(prclIn->right, prclClip->right);
|
|
|
|
if (prclOut->left < prclOut->right)
|
|
{
|
|
prclOut->top = max(prclIn->top, prclClip->top);
|
|
prclOut->bottom = min(prclIn->bottom, prclClip->bottom);
|
|
|
|
if (prclOut->top < prclOut->bottom)
|
|
{
|
|
prclOut++;
|
|
cIntersections++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(cIntersections);
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vClipSolid
|
|
*
|
|
* Fills the specified rectangles with the specified colour, honouring
|
|
* the requested clipping. No more than four rectangles should be passed in.
|
|
* Intended for drawing the areas of the opaquing rectangle that extend
|
|
* beyond the text box. The rectangles must be in left to right, top to
|
|
* bottom order. Assumes there is at least one rectangle in the list.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vClipSolid(
|
|
PDEV* ppdev,
|
|
LONG crcl,
|
|
RECTL* prcl,
|
|
ULONG iColor,
|
|
CLIPOBJ* pco)
|
|
{
|
|
BOOL bMore; // Flag for clip enumeration
|
|
ENUMRECTS8 ce; // Clip enumeration object
|
|
ULONG i;
|
|
ULONG j;
|
|
#if !(DRIVER_5465 && HW_CLIPPING)
|
|
RECTL arclTmp[4];
|
|
ULONG crclTmp;
|
|
RECTL* prclTmp;
|
|
RECTL* prclClipTmp;
|
|
LONG iLastBottom;
|
|
#endif
|
|
RECTL* prclClip;
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL1,"vClipSolid: Entry.\n"));
|
|
ASSERTMSG( (crcl > 0) && (crcl <= 4), "Expected 1 to 4 rectangles");
|
|
ASSERTMSG( (pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
|
|
"Expected a non-null clip object");
|
|
|
|
// Do the loop invariant setup here
|
|
REQUIRE(2);
|
|
LL_DRAWBLTDEF(SOLID_COLOR_FILL, 2);
|
|
|
|
if (pco->iDComplexity == DC_RECT)
|
|
{
|
|
crcl = cIntersect(&pco->rclBounds, prcl, crcl);
|
|
while (crcl--)
|
|
{
|
|
REQUIRE(5);
|
|
LL_OP0(prcl->left + ppdev->ptlOffset.x,
|
|
prcl->top + ppdev->ptlOffset.y);
|
|
LL_BLTEXT((prcl->right - prcl->left), (prcl->bottom - prcl->top));
|
|
prcl++;
|
|
}
|
|
}
|
|
|
|
else // iDComplexity == DC_COMPLEX
|
|
{
|
|
// Initialize the clip rectangle enumeration to right-down so we can
|
|
// take advantage of the rectangle list being right-down:
|
|
|
|
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
|
|
|
|
#if DRIVER_5465 && HW_CLIPPING
|
|
// Set up the hardware clipping
|
|
REQUIRE(6);
|
|
LL_DRAWBLTDEF(SOLID_COLOR_FILL | DD_CLIPEN, 0);
|
|
i = max(0, prcl->left);
|
|
j = max(0, prcl->top);
|
|
LL_OP0(i + ppdev->ptlOffset.x, j + ppdev->ptlOffset.y);
|
|
LL_BLTEXT_EXT(prcl->right - i, prcl->bottom - j);
|
|
|
|
do
|
|
{
|
|
// Get a batch of region rectangles:
|
|
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (VOID*)&ce);
|
|
|
|
// Clip the rect list to each region rect:
|
|
for (j = ce.c, prclClip = ce.arcl; j-- > 0; prclClip++)
|
|
{
|
|
// Draw the clipped rects
|
|
REQUIRE(5);
|
|
LL_CLIPULE(prclClip->left + ppdev->ptlOffset.x,
|
|
prclClip->top + ppdev->ptlOffset.y);
|
|
LL_CLIPLOR_EX(prclClip->right + ppdev->ptlOffset.x,
|
|
prclClip->bottom + ppdev->ptlOffset.y);
|
|
|
|
} // End for each rectangle in the list.
|
|
|
|
} while (bMore); // End loop for each batch
|
|
#else
|
|
|
|
// Bottom of last rectangle to fill
|
|
iLastBottom = prcl[crcl - 1].bottom;
|
|
|
|
// Scan through all the clip rectangles, looking for intersects
|
|
// of fill areas with region rectangles:
|
|
|
|
do
|
|
{
|
|
// Get a batch of region rectangles:
|
|
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (VOID*)&ce);
|
|
|
|
// Clip the rect list to each region rect:
|
|
for (j = ce.c, prclClip = ce.arcl; j-- > 0; prclClip++)
|
|
{
|
|
// Since the rectangles and the region enumeration are both
|
|
// right-down, we can zip through the region until we reach
|
|
// the first fill rect, and are done when we've passed the
|
|
// last fill rect.
|
|
|
|
if (prclClip->top >= iLastBottom)
|
|
{
|
|
// Past last fill rectangle; nothing left to do:
|
|
return;
|
|
}
|
|
|
|
// Do intersection tests only if we've reached the top of
|
|
// the first rectangle to fill:
|
|
|
|
if (prclClip->bottom > prcl->top)
|
|
{
|
|
// We've reached the top Y scan of the first rect, so
|
|
// it's worth bothering checking for intersection.
|
|
|
|
// Generate a list of the rects clipped to this region
|
|
// rect:
|
|
|
|
prclTmp = prcl;
|
|
prclClipTmp = arclTmp;
|
|
|
|
for (i = crcl, crclTmp = 0; i-- != 0; prclTmp++)
|
|
{
|
|
// Intersect fill and clip rectangles
|
|
|
|
if (bIntersect(prclTmp, prclClip, prclClipTmp))
|
|
{
|
|
// Draw the clipped rects
|
|
REQUIRE(5);
|
|
LL_OP0(prclClipTmp->left + ppdev->ptlOffset.x,
|
|
prclClipTmp->top + ppdev->ptlOffset.y);
|
|
LL_BLTEXT ( (prclClipTmp->right - prclClipTmp->left) ,
|
|
(prclClipTmp->bottom - prclClipTmp->top) );
|
|
}
|
|
|
|
} // End for each rectangle in the batch.
|
|
|
|
} // End intersect test.
|
|
|
|
} // End for each rectangle in the list.
|
|
|
|
} while (bMore); // End loop for each batch
|
|
#endif // if !(DRIVER_5465 && HW_CLIPPING)
|
|
|
|
} // End DC_COMPLEX
|
|
|
|
}
|
|
|
|
#if SWAT7
|
|
/******************************Public*Routine******************************\
|
|
* VOID Xfer64Pixels
|
|
*
|
|
* Copy 64 pixels of font data to the Laguna memory.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID Xfer64Pixels(
|
|
PDEV* ppdev,
|
|
UINT x,
|
|
UINT y,
|
|
UINT bitOffset,
|
|
UINT height,
|
|
BYTE* pjGlyph,
|
|
UINT delta
|
|
)
|
|
{
|
|
delta = (delta + 7) >> 3;
|
|
|
|
REQUIRE(5);
|
|
LL_OP0(x + ppdev->ptlOffset.x, y + ppdev->ptlOffset.y);
|
|
LL_BLTEXT(64, height);
|
|
|
|
while (height--)
|
|
{
|
|
REQUIRE(3);
|
|
LL32(grHOSTDATA[0], *(ULONG*) &pjGlyph[0]);
|
|
LL32(grHOSTDATA[1], *(ULONG*) &pjGlyph[4]);
|
|
if (bitOffset > 0)
|
|
{
|
|
LL32(grHOSTDATA[2], pjGlyph[8]);
|
|
}
|
|
pjGlyph += delta;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vMmClipGlyphExpansion
|
|
*
|
|
* Handles any strings that need to be clipped, using the 'glyph
|
|
* expansion' method.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vMmClipGlyphExpansion(
|
|
PDEV* ppdev,
|
|
STROBJ* pstro,
|
|
CLIPOBJ* pco)
|
|
{
|
|
BOOL bMoreGlyphs;
|
|
ULONG cGlyphOriginal;
|
|
ULONG cGlyph;
|
|
GLYPHPOS* pgpOriginal;
|
|
GLYPHPOS* pgp;
|
|
GLYPHBITS* pgb;
|
|
POINTL ptlOrigin;
|
|
BOOL bMore;
|
|
ENUMRECTS8 ce;
|
|
RECTL* prclClip;
|
|
ULONG ulCharInc;
|
|
LONG cxGlyph;
|
|
LONG cyGlyph;
|
|
BYTE* pjGlyph;
|
|
BYTE* pTmp;
|
|
LONG cj;
|
|
LONG cw;
|
|
LONG xLeft;
|
|
LONG yTop;
|
|
LONG xRight;
|
|
LONG yBottom;
|
|
LONG xBias;
|
|
LONG lDelta;
|
|
LONG cx;
|
|
LONG cy;
|
|
#if SWAT7
|
|
UINT xOrigin;
|
|
#endif
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL1,"vMmClipGlyphExpansion: Entry.\n"));
|
|
|
|
ASSERTMSG(pco != NULL, "Don't expect NULL clip objects here");
|
|
|
|
do // Loop for each batch of glyphs to be done.
|
|
{
|
|
//
|
|
// Get a batch of glyphs.
|
|
//
|
|
|
|
if (pstro->pgp != NULL)
|
|
{
|
|
// There's only the one batch of glyphs, so save ourselves
|
|
// a call:
|
|
|
|
pgpOriginal = pstro->pgp;
|
|
cGlyphOriginal = pstro->cGlyphs;
|
|
bMoreGlyphs = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
|
|
}
|
|
|
|
//
|
|
// cGlyphOrigional is the number of glyphs in the batch before they
|
|
// are clipped.
|
|
// bMoreGlyphs is TRUE if there are more batches to be done after
|
|
// this one.
|
|
//
|
|
|
|
if (cGlyphOriginal > 0) // Were there any glyphs in the batch?
|
|
{
|
|
ulCharInc = pstro->ulCharInc;
|
|
|
|
if (pco->iDComplexity == DC_RECT)
|
|
{
|
|
//
|
|
// We could call 'cEnumStart' and 'bEnum' when the clipping is
|
|
// DC_RECT, but the last time I checked, those two calls took
|
|
// more than 150 instructions to go through GDI. Since
|
|
// 'rclBounds' already contains the DC_RECT clip rectangle,
|
|
// and since it's such a common case, we'll special case it:
|
|
//
|
|
|
|
bMore = FALSE; // No more clip lists to do.
|
|
prclClip = &pco->rclBounds;
|
|
ce.c = 1; // Only one rectangle in this list.
|
|
|
|
goto SingleRectangle;
|
|
}
|
|
|
|
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
|
|
|
|
do // For each list of rectangles.
|
|
{
|
|
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
|
|
|
|
// For each rectangle in the list.
|
|
for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
|
|
{
|
|
SingleRectangle:
|
|
|
|
pgp = pgpOriginal;
|
|
cGlyph = cGlyphOriginal;
|
|
pgb = pgp->pgdf->pgb;
|
|
|
|
ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
|
|
ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
|
|
|
|
// Loop through all the glyphs for this rectangle:
|
|
while (TRUE)
|
|
{
|
|
LogFile((BUF, "GC:M\r\n"));
|
|
|
|
cxGlyph = pgb->sizlBitmap.cx;
|
|
cyGlyph = pgb->sizlBitmap.cy;
|
|
|
|
pjGlyph = pgb->aj;
|
|
#if SWAT7
|
|
lDelta = (cxGlyph + 7) >> 3;
|
|
#endif
|
|
|
|
if ((prclClip->left <= ptlOrigin.x) &&
|
|
(prclClip->top <= ptlOrigin.y) &&
|
|
(prclClip->right >= ptlOrigin.x + cxGlyph) &&
|
|
(prclClip->bottom >= ptlOrigin.y + cyGlyph))
|
|
{
|
|
//-----------------------------------------------------
|
|
// Unclipped glyph
|
|
|
|
#if SWAT7
|
|
xOrigin = ptlOrigin.x;
|
|
#endif
|
|
|
|
#if SWAT7
|
|
//
|
|
// Test for 5465AD hardware bug in 8-bpp.
|
|
//
|
|
if ( (cxGlyph > 64) && (cxGlyph < 128)
|
|
&& (ppdev->iBytesPerPixel == 1)
|
|
)
|
|
{
|
|
Xfer64Pixels(ppdev, xOrigin, ptlOrigin.y, 0,
|
|
cyGlyph, pjGlyph, cxGlyph);
|
|
pjGlyph += 64 / 8;
|
|
xOrigin += 64;
|
|
cxGlyph -= 64;
|
|
}
|
|
REQUIRE(5);
|
|
LL_OP0(xOrigin + ppdev->ptlOffset.x,
|
|
ptlOrigin.y + ppdev->ptlOffset.y);
|
|
#else
|
|
REQUIRE(5);
|
|
LL_OP0(ptlOrigin.x + ppdev->ptlOffset.x,
|
|
ptlOrigin.y + ppdev->ptlOffset.y);
|
|
#endif
|
|
LL_BLTEXT(cxGlyph, cyGlyph);
|
|
|
|
if (cxGlyph <= 8)
|
|
{
|
|
//-----------------------------------------------------
|
|
// 1 to 8 pels in width
|
|
|
|
while ( cyGlyph-- )
|
|
{
|
|
REQUIRE(1);
|
|
#if SWAT7
|
|
LL32 (grHOSTDATA[0], *pjGlyph);
|
|
pjGlyph += lDelta;
|
|
#else
|
|
LL32 (grHOSTDATA[0], *pjGlyph++);
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
else if (cxGlyph <= 16)
|
|
{
|
|
//-----------------------------------------------------
|
|
// 9 to 16 pels in width
|
|
|
|
while ( cyGlyph-- )
|
|
{
|
|
REQUIRE(1);
|
|
#if SWAT7
|
|
LL32 (grHOSTDATA[0], *(USHORT*)pjGlyph);
|
|
pjGlyph += lDelta;
|
|
#else
|
|
LL32 (grHOSTDATA[0], *((USHORT*)pjGlyph)++);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
//-----------------------------------------------------
|
|
// More than 16 pels in width
|
|
|
|
#if SWAT7
|
|
cw = (cxGlyph + 31) >> 5;
|
|
#else
|
|
lDelta = (pgb->sizlBitmap.cx + 7) >> 3;
|
|
cw = (lDelta + 3) >> 2;
|
|
#endif
|
|
pTmp = pjGlyph + lDelta * pgb->sizlBitmap.cy;
|
|
|
|
for (;cyGlyph!=1; cyGlyph--)
|
|
{
|
|
WRITE_STRING(pjGlyph, cw);
|
|
pjGlyph += lDelta;
|
|
}
|
|
|
|
{
|
|
ULONG *pSrc = (ULONG*) pjGlyph + cw - 1;
|
|
WRITE_STRING(pjGlyph, cw - 1);
|
|
|
|
if ((BYTE *)pSrc+4<=pTmp)
|
|
{
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], *pSrc++ );
|
|
}
|
|
else
|
|
{
|
|
int Extra = (ULONG) pTmp - (ULONG) pSrc;
|
|
BYTE * pByte = (BYTE *)pSrc;
|
|
ULONG ulData;
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL1,
|
|
"Caught it %s %d %d %x %x\n", __FILE__, __LINE__, Extra, pTmp, pSrc));
|
|
|
|
if (Extra == 1)
|
|
ulData = (ULONG)(*pByte);
|
|
else if (Extra == 2)
|
|
ulData = (ULONG)(*(USHORT*)pByte);
|
|
else
|
|
ulData = (((ULONG)*(pByte+2) << 8) | (ULONG)*(pByte+1)) << 8 | *pByte;
|
|
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], ulData );
|
|
}
|
|
}
|
|
} // End 16 pels or wider.
|
|
} // End unclipped glyph.
|
|
|
|
else
|
|
{
|
|
//-----------------------------------------------------
|
|
// Clipped glyph
|
|
|
|
// Find the intersection of the glyph rectangle
|
|
// and the clip rectangle:
|
|
|
|
xLeft = max(prclClip->left, ptlOrigin.x);
|
|
yTop = max(prclClip->top, ptlOrigin.y);
|
|
xRight = min(prclClip->right, ptlOrigin.x + cxGlyph);
|
|
yBottom = min(prclClip->bottom, ptlOrigin.y + cyGlyph);
|
|
|
|
// Check for trivial rejection:
|
|
if (((cx = xRight - xLeft) > 0) &&
|
|
((cy = yBottom - yTop) > 0))
|
|
{
|
|
|
|
xBias = (xLeft - ptlOrigin.x) & 7;
|
|
|
|
// 'xBias' is the bit position in the monochrome glyph
|
|
// bitmap of the first pixel to be lit, relative to
|
|
// the start of the byte. That is, if 'xBias' is 2,
|
|
// then the first unclipped pixel is represented by bit
|
|
// 2 of the corresponding bitmap byte.
|
|
//
|
|
// Normally, the accelerator expects bit 0 to be the
|
|
// first lit byte. We set the host phase to discard the
|
|
// first 'xBias' bits.
|
|
//
|
|
|
|
if ( xBias )
|
|
{
|
|
REQUIRE(2);
|
|
LL_OP2_MONO (xBias,0);
|
|
}
|
|
|
|
#if !SWAT7
|
|
REQUIRE(5);
|
|
LL_OP0(xLeft + ppdev->ptlOffset.x,
|
|
yTop + ppdev->ptlOffset.y);
|
|
LL_BLTEXT (cx, cy);
|
|
#endif
|
|
|
|
lDelta = (cxGlyph + 7) >> 3;
|
|
|
|
// compute the end-of-glyph marker before
|
|
// clipping the glyph.
|
|
pTmp = pjGlyph + lDelta * cy;
|
|
|
|
pjGlyph += (yTop - ptlOrigin.y) * lDelta
|
|
+ ((xLeft - ptlOrigin.x) >> 3);
|
|
|
|
#if SWAT7
|
|
//
|
|
// Test for 5465AD hardware bug in 8-bpp.
|
|
//
|
|
if ( (cx > 64) && (cx < 128)
|
|
&& (ppdev->iBytesPerPixel == 1)
|
|
)
|
|
{
|
|
Xfer64Pixels(ppdev, xLeft, yTop, xBias, cy,
|
|
pjGlyph, cxGlyph);
|
|
pjGlyph += 64 / 8;
|
|
xLeft += 64;
|
|
cx -= 64;
|
|
}
|
|
|
|
REQUIRE(5);
|
|
LL_OP0(xLeft + ppdev->ptlOffset.x,
|
|
yTop + ppdev->ptlOffset.y);
|
|
LL_BLTEXT (cx, cy);
|
|
#endif
|
|
|
|
cj = (cx + xBias + 31) >> 5;
|
|
|
|
for (;cy!=1; cy--)
|
|
{
|
|
WRITE_STRING(pjGlyph, cj);
|
|
pjGlyph += lDelta;
|
|
}
|
|
|
|
{
|
|
ULONG *pSrc = (ULONG*) pjGlyph + cj - 1;
|
|
|
|
int Extra = (ULONG) pTmp - (ULONG) pSrc;
|
|
BYTE * pByte = (BYTE *)pSrc;
|
|
ULONG ulData;
|
|
|
|
WRITE_STRING(pjGlyph, cj - 1);
|
|
|
|
if (Extra == 1)
|
|
ulData = (ULONG)(*pByte);
|
|
else if (Extra == 2)
|
|
ulData = (ULONG)(*(USHORT*)pByte);
|
|
else if (Extra == 3)
|
|
ulData = (((ULONG)*(pByte+2) << 8) | (ULONG)*(pByte+1)) << 8 | *pByte;
|
|
else
|
|
ulData = *pSrc;
|
|
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], ulData );
|
|
}
|
|
|
|
if (xBias != 0)
|
|
{
|
|
REQUIRE(2);
|
|
LL_OP2_MONO(0,0);
|
|
}
|
|
|
|
} // if not trivially rejected.
|
|
|
|
} // End clipped glyph.
|
|
|
|
//
|
|
// If we're out of glyphs the get next batch.
|
|
if (--cGlyph == 0)
|
|
break;
|
|
|
|
// Get ready for next glyph:
|
|
pgp++;
|
|
pgb = pgp->pgdf->pgb;
|
|
|
|
//
|
|
// Calculate where to place the next glyph.
|
|
// If this is mono spaced text, we may need to
|
|
// skip over some pixels to make our characters
|
|
// line up.
|
|
//
|
|
if (ulCharInc == 0)
|
|
{
|
|
ptlOrigin.x = pgp->ptl.x + pgb->ptlOrigin.x;
|
|
ptlOrigin.y = pgp->ptl.y + pgb->ptlOrigin.y;
|
|
}
|
|
else
|
|
{
|
|
ptlOrigin.x += ulCharInc;
|
|
}
|
|
|
|
} // End loop for each glyph in the batch.
|
|
|
|
} // End for each rectangle in the list.
|
|
|
|
} while (bMore); // Loop for each batch of clipping rectangles.
|
|
|
|
} // If there were any glyphs in this batch.
|
|
|
|
} while (bMoreGlyphs); // Loop for each batch of glyphs.
|
|
|
|
} // End clipped glyph expansion.
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DrvTextOut
|
|
*
|
|
* If it's the fastest method, outputs text using the 'glyph expansion'
|
|
* method. Each individual glyph is colour-expanded directly to the
|
|
* screen from the monochrome glyph bitmap supplied by GDI.
|
|
*
|
|
* If it's not the fastest method, calls the routine that implements the
|
|
* 'buffer expansion' method.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#if (USE_ASM && defined(i386))
|
|
BOOL i386DrvTextOut(
|
|
#else
|
|
BOOL APIENTRY DrvTextOut(
|
|
#endif
|
|
SURFOBJ* pso,
|
|
STROBJ* pstro,
|
|
FONTOBJ* pfo,
|
|
CLIPOBJ* pco,
|
|
RECTL* prclExtra, // If we had set GCAPS_HORIZSTRIKE, we would have
|
|
// to fill these extra rectangles (it is used
|
|
// largely for underlines). It's not a big
|
|
// performance win (GDI will call our DrvBitBlt
|
|
// to draw the extra rectangles).
|
|
RECTL* prclOpaque,
|
|
BRUSHOBJ* pboFore,
|
|
BRUSHOBJ* pboOpaque,
|
|
POINTL* pptlBrush,
|
|
MIX mix)
|
|
{
|
|
PDEV* ppdev;
|
|
BOOL bTextPerfectFit;
|
|
ULONG cGlyph;
|
|
BOOL bMoreGlyphs;
|
|
GLYPHPOS* pgp;
|
|
GLYPHBITS* pgb;
|
|
BYTE* pjGlyph;
|
|
BYTE* pTmp;
|
|
#if SWAT7
|
|
LONG cxGlyph;
|
|
#endif
|
|
LONG cyGlyph;
|
|
POINTL ptlOrigin;
|
|
LONG ulCharInc;
|
|
BYTE iDComplexity;
|
|
LONG lDelta;
|
|
LONG cw;
|
|
ULONG iFGColor;
|
|
ULONG iBGColor;
|
|
ULONG bitCount;
|
|
#if SWAT7
|
|
UINT xOrigin;
|
|
#endif
|
|
|
|
#if NULL_TEXTOUT
|
|
{
|
|
if (pointer_switch) return TRUE;
|
|
}
|
|
#endif
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL,"DrvTextOut: Entry.\n"));
|
|
|
|
|
|
// The DDI spec says we'll only ever get foreground and background
|
|
// mixes of R2_COPYPEN:
|
|
|
|
ASSERTMSG(mix == 0x0d0d, "GDI should only give us a copy mix");
|
|
|
|
ppdev = (PDEV*) pso->dhpdev;
|
|
|
|
SYNC_W_3D(ppdev); // if 3D context(s) active, make sure 3D engine idle before continuing...
|
|
|
|
if (pso->iType == STYPE_DEVBITMAP)
|
|
{
|
|
PDSURF pdsurf = (PDSURF)pso->dhsurf;
|
|
LogFile((BUF, "DTO Id=%p ", pdsurf));
|
|
if (pdsurf->pso)
|
|
{
|
|
if ( !bCreateScreenFromDib(ppdev, pdsurf) )
|
|
{
|
|
LogFile((BUF, "DTO: D=DH (punted)\r\n"));
|
|
return(EngTextOut(pdsurf->pso, pstro, pfo, pco, prclExtra,
|
|
prclOpaque, pboFore, pboOpaque, pptlBrush, mix));
|
|
}
|
|
else
|
|
{
|
|
LogFile((BUF, "DTO: D=DF "));
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
LogFile((BUF, "DTO: D=D "));
|
|
}
|
|
ppdev->ptlOffset.x = pdsurf->ptl.x;
|
|
ppdev->ptlOffset.y = pdsurf->ptl.y;
|
|
}
|
|
else
|
|
{
|
|
LogFile((BUF, "DTO: D=S "));
|
|
ppdev->ptlOffset.x = ppdev->ptlOffset.y = 0;
|
|
}
|
|
|
|
//
|
|
// Dump information about the call to the log file.
|
|
//
|
|
LogFile((BUF, "FG=%X BG=%X ",
|
|
pboFore->iSolidColor, pboOpaque->iSolidColor));
|
|
LogFile((BUF, "C=%s ",
|
|
(pco == NULL) ? "N " :
|
|
((pco->iDComplexity == DC_TRIVIAL) ? "T" :
|
|
((pco->iDComplexity == DC_RECT) ? "R" : "C" ))
|
|
));
|
|
LogFile((BUF, "%s ", (prclOpaque != NULL) ? "O" : "T"));
|
|
LogFile((BUF, "%s ", (pstro->ulCharInc == 0) ? "P" : "M"));
|
|
|
|
|
|
#if !(USE_ASM && defined(i386))
|
|
// If we have a font that is cached but the screen has been reinitialized,
|
|
// we delete the font from memory and try again.
|
|
|
|
if (ppdev->UseFontCache == 0)
|
|
pfo->pvConsumer = (VOID*) -1;
|
|
|
|
if (pfo->pvConsumer != NULL && pfo->pvConsumer != (PVOID) -1)
|
|
{
|
|
if (((PFONTCACHE) pfo->pvConsumer)->ulFontCount != ppdev->ulFontCount)
|
|
{
|
|
LogFile((BUF, "FCD "));
|
|
DrvDestroyFont(pfo);
|
|
}
|
|
else
|
|
LogFile((BUF, "GC=2 "));
|
|
}
|
|
|
|
if (pfo->pvConsumer == (PVOID) -1)
|
|
{
|
|
LogFile((BUF, "GC=3"));
|
|
}
|
|
|
|
|
|
// If we have a font that has not yet been cached, try caching it.
|
|
if (pfo->pvConsumer == NULL)
|
|
{
|
|
// New font, check it out.
|
|
int height = pstro->rclBkGround.bottom - pstro->rclBkGround.top;
|
|
LogFile((BUF, "GC="));
|
|
|
|
#if SWAT3
|
|
if (height > FONTCELL_Y * 3 / 2)
|
|
#else
|
|
if (height > LINES_PER_TILE * 3 / 2)
|
|
#endif
|
|
{
|
|
// Font too big, mark is as uncacheable.
|
|
LogFile((BUF, "0size "));
|
|
pfo->pvConsumer = (PVOID) -1;
|
|
}
|
|
else
|
|
{
|
|
// Allocate memory for the font cache.
|
|
#ifdef WINNT_VER40
|
|
pfo->pvConsumer = MEM_ALLOC(FL_ZERO_MEMORY, sizeof(FONTCACHE), ALLOC_TAG);
|
|
#else
|
|
pfo->pvConsumer = MEM_ALLOC(LMEM_FIXED | LMEM_ZEROINIT, sizeof(FONTCACHE));
|
|
#endif
|
|
if (pfo->pvConsumer == NULL)
|
|
{
|
|
// Not enough memory, mark it as uncacheable.
|
|
LogFile((BUF, "0mem "));
|
|
pfo->pvConsumer = (PVOID) -1;
|
|
}
|
|
else
|
|
{
|
|
LogFile((BUF, "1 "));
|
|
|
|
AddToFontCacheChain(ppdev, pfo, pfo->pvConsumer);
|
|
|
|
// Store device this font belongs to.
|
|
((PFONTCACHE) pfo->pvConsumer)->ppdev = ppdev;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
// Set FG / BG colors at this level
|
|
|
|
iFGColor = pboFore->iSolidColor;
|
|
iBGColor = pboOpaque->iSolidColor;
|
|
|
|
switch (ppdev->iBitmapFormat)
|
|
{
|
|
case BMF_8BPP:
|
|
iFGColor |= iFGColor << 8;
|
|
iBGColor |= iBGColor << 8;
|
|
|
|
case BMF_16BPP:
|
|
iFGColor |= iFGColor << 16;
|
|
iBGColor |= iBGColor << 16;
|
|
break;
|
|
}
|
|
|
|
iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
|
|
|
|
#if !(USE_ASM && defined(i386))
|
|
// Can we use the font cache?
|
|
if ( (pfo->pvConsumer != (PVOID) -1) && (iDComplexity != DC_COMPLEX)
|
|
&& (((PFONTCACHE) pfo->pvConsumer)->ppdev == ppdev))
|
|
{
|
|
// Set color registers.
|
|
REQUIRE(4);
|
|
LL_BGCOLOR(iBGColor, 2);
|
|
LL_FGCOLOR(iFGColor, 2);
|
|
|
|
if (prclOpaque != NULL)
|
|
{
|
|
#if LOG_CALLS
|
|
#define FIT_FLAGS (SO_ZERO_BEARINGS | \
|
|
SO_FLAG_DEFAULT_PLACEMENT | \
|
|
SO_MAXEXT_EQUAL_BM_SIDE | \
|
|
SO_CHAR_INC_EQUAL_BM_BASE)
|
|
|
|
bTextPerfectFit =
|
|
(pstro->flAccel & FIT_FLAGS) == FIT_FLAGS;
|
|
|
|
if (!(bTextPerfectFit) ||
|
|
(pstro->rclBkGround.top > prclOpaque->top) ||
|
|
(pstro->rclBkGround.left > prclOpaque->left) ||
|
|
(pstro->rclBkGround.right < prclOpaque->right) ||
|
|
(pstro->rclBkGround.bottom < prclOpaque->bottom))
|
|
{
|
|
LogFile((BUF, "FIT=N "));
|
|
}
|
|
else
|
|
{
|
|
LogFile((BUF, "FIT=Y "));
|
|
}
|
|
#endif
|
|
|
|
|
|
// Draw opaqueing rectangle.
|
|
if (iDComplexity == DC_TRIVIAL)
|
|
{
|
|
REQUIRE(7);
|
|
LL_DRAWBLTDEF(SOLID_COLOR_FILL, 0);
|
|
LL_OP0(prclOpaque->left + ppdev->ptlOffset.x,
|
|
prclOpaque->top + ppdev->ptlOffset.y);
|
|
LL_BLTEXT(prclOpaque->right - prclOpaque->left,
|
|
prclOpaque->bottom - prclOpaque->top);
|
|
}
|
|
else
|
|
{
|
|
LONG x, y, cx, cy;
|
|
x = max(prclOpaque->left, pco->rclBounds.left);
|
|
y = max(prclOpaque->top, pco->rclBounds.top);
|
|
cx = min(prclOpaque->right, pco->rclBounds.right) - x;
|
|
cy = min(prclOpaque->bottom, pco->rclBounds.bottom) - y;
|
|
if ( (cx > 0) && (cy > 0) )
|
|
{
|
|
REQUIRE(7);
|
|
LL_DRAWBLTDEF(SOLID_COLOR_FILL, 0);
|
|
LL_OP0(x + ppdev->ptlOffset.x, y + ppdev->ptlOffset.y);
|
|
LL_BLTEXT(cx, cy);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Enable bit swizzling and set DRAWBLTDEF.
|
|
ppdev->grCONTROL |= SWIZ_CNTL;
|
|
LL16(grCONTROL, ppdev->grCONTROL);
|
|
REQUIRE(2);
|
|
LL_DRAWBLTDEF(CACHE_EXPAND_XPAR, 2);
|
|
LogFile((BUF, "UC"));
|
|
LogFile((BUF, "\r\n"));
|
|
|
|
// Call the font cache handler.
|
|
if (iDComplexity == DC_TRIVIAL)
|
|
{
|
|
FontCache((PFONTCACHE) pfo->pvConsumer, pstro);
|
|
}
|
|
else
|
|
{
|
|
ClipCache((PFONTCACHE) pfo->pvConsumer, pstro, pco->rclBounds);
|
|
}
|
|
|
|
// Disable bit swizzling.
|
|
ppdev->grCONTROL = ppdev->grCONTROL & ~SWIZ_CNTL;
|
|
LL16(grCONTROL, ppdev->grCONTROL);
|
|
return(TRUE);
|
|
}
|
|
#endif
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: Setting FG/BG Color.\n"));
|
|
REQUIRE(4);
|
|
LL_BGCOLOR(iBGColor, 2);
|
|
LL_FGCOLOR(iFGColor, 2);
|
|
|
|
ppdev->grCONTROL |= SWIZ_CNTL;
|
|
LL16(grCONTROL, ppdev->grCONTROL);
|
|
|
|
if (prclOpaque != NULL)
|
|
{
|
|
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: Setting Opaque.\n"));
|
|
////////////////////////////////////////////////////////////
|
|
// Opaque Initialization
|
|
////////////////////////////////////////////////////////////
|
|
//
|
|
// If we paint the glyphs in 'opaque' mode, we may not actually
|
|
// have to draw the opaquing rectangle up-front -- the process
|
|
// of laying down all the glyphs will automatically cover all
|
|
// of the pixels in the opaquing rectangle.
|
|
//
|
|
// The condition that must be satisfied is that the text must
|
|
// fit 'perfectly' such that the entire background rectangle is
|
|
// covered, and none of the glyphs overlap (if the glyphs
|
|
// overlap, such as for italics, they have to be drawn in
|
|
// transparent mode after the opaquing rectangle is cleared).
|
|
//
|
|
|
|
#define PERFECT_FIT_FLAGS (SO_ZERO_BEARINGS | \
|
|
SO_FLAG_DEFAULT_PLACEMENT | \
|
|
SO_MAXEXT_EQUAL_BM_SIDE | \
|
|
SO_CHAR_INC_EQUAL_BM_BASE)
|
|
|
|
bTextPerfectFit =
|
|
(pstro->flAccel & PERFECT_FIT_FLAGS) == PERFECT_FIT_FLAGS;
|
|
|
|
if (!(bTextPerfectFit) ||
|
|
(pstro->rclBkGround.top > prclOpaque->top) ||
|
|
(pstro->rclBkGround.left > prclOpaque->left) ||
|
|
(pstro->rclBkGround.right < prclOpaque->right)||
|
|
(pstro->rclBkGround.bottom < prclOpaque->bottom))
|
|
{
|
|
//
|
|
// Draw opaquing rectangle.
|
|
//
|
|
|
|
if (iDComplexity == DC_TRIVIAL)
|
|
{
|
|
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: Opaque DC_TRIVIAL.\n"));
|
|
REQUIRE(7);
|
|
LL_DRAWBLTDEF(SOLID_COLOR_FILL, 0);
|
|
LL_OP0(prclOpaque->left + ppdev->ptlOffset.x,
|
|
prclOpaque->top + ppdev->ptlOffset.y);
|
|
LL_BLTEXT ((prclOpaque->right - prclOpaque->left) ,
|
|
(prclOpaque->bottom - prclOpaque->top) );
|
|
}
|
|
else
|
|
{
|
|
vClipSolid(ppdev, 1, prclOpaque, pboOpaque->iSolidColor, pco);
|
|
}
|
|
|
|
LogFile((BUF, "FIT=N "));
|
|
// Opaquing rectangle has been drawn, now
|
|
// we do transparent text.
|
|
}
|
|
else
|
|
{
|
|
LogFile((BUF, "FIT=Y "));
|
|
// We don't have to draw the opaquing rectangle because
|
|
// the text is an exact fit.
|
|
goto TextInitOpaque;
|
|
}
|
|
|
|
} // End (prclOpaque != NULL)
|
|
|
|
LogFile((BUF, "\r\n"));
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Transparent Initialization
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
|
// Initialize the hardware for transparent text:
|
|
|
|
//
|
|
// Set the chip up to do transparent text.
|
|
//
|
|
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: Setting XPAR Text.\n"));
|
|
LL_DRAWBLTDEF(TEXT_EXPAND_XPAR, 2);
|
|
|
|
goto TextInitDone;
|
|
|
|
TextInitOpaque:
|
|
|
|
//
|
|
// Set the chip up to do opaque text.
|
|
// Any opaquing rectangle needed has been drawn by now.
|
|
//
|
|
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: Setting Opaque Text.\n"));
|
|
LL_DRAWBLTDEF(TEXT_EXPAND_OPAQUE, 2);
|
|
|
|
TextInitDone:
|
|
|
|
//
|
|
// We're all set up to do either opaque or transparent text.
|
|
// If necessary, any opaquing has been done by now.
|
|
// So let's draw some glyphs on the screen.
|
|
//
|
|
|
|
REQUIRE(2);
|
|
LL_OP2_MONO (0,0); // Set Zero phase for transfers
|
|
if (iDComplexity == DC_TRIVIAL)
|
|
{
|
|
do // Loop while there are glyphs to draw.
|
|
{
|
|
//
|
|
// Get a batch of glyphs to draw.
|
|
//
|
|
|
|
if (pstro->pgp != NULL)
|
|
{
|
|
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: One batch of Glyphs.\n"));
|
|
// There's only the one batch of glyphs, so save ourselves
|
|
// a call:
|
|
|
|
pgp = pstro->pgp;
|
|
cGlyph = pstro->cGlyphs;
|
|
bMoreGlyphs = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DISPDBG((TEXT_DBG_LEVEL1,
|
|
"DrvTextOut: Calling STROBJ_bEnum for Glyphs.\n"));
|
|
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
|
|
}
|
|
|
|
//
|
|
// cGlyph is the count of glyphs in this batch.
|
|
// bMorGlyphs is TRUE if there is another batch waiting for
|
|
// us after this one.
|
|
//
|
|
|
|
if (cGlyph > 0)
|
|
{
|
|
//
|
|
// Check the type of spacing.
|
|
//
|
|
|
|
if (pstro->ulCharInc == 0)
|
|
{
|
|
///////////////////////////////////////////////////////////
|
|
// Proportional Spacing
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL1,
|
|
"DrvTextOut: Proportional Spacing.\n"));
|
|
|
|
while (TRUE) // Loop once for each Glyph.
|
|
{
|
|
pgb = pgp->pgdf->pgb;
|
|
|
|
LogFile((BUF, "GC:M\r\n"));
|
|
|
|
#if !SWAT7
|
|
REQUIRE(5);
|
|
LL_OP0(pgp->ptl.x + pgb->ptlOrigin.x + ppdev->ptlOffset.x,
|
|
pgp->ptl.y + pgb->ptlOrigin.y + ppdev->ptlOffset.y);
|
|
LL_BLTEXT (pgb->sizlBitmap.cx, pgb->sizlBitmap.cy);
|
|
#endif
|
|
|
|
#if SWAT7
|
|
xOrigin = pgp->ptl.x + pgb->ptlOrigin.x;
|
|
cxGlyph = pgb->sizlBitmap.cx;
|
|
lDelta = (cxGlyph + 7) >> 3;
|
|
#endif
|
|
pjGlyph = pgb->aj;
|
|
cyGlyph = pgb->sizlBitmap.cy;
|
|
|
|
#if SWAT7
|
|
//
|
|
// Test for 5465AD hardware bug in 8-bpp.
|
|
//
|
|
if ( (cxGlyph > 64) && (cxGlyph < 128)
|
|
&& (ppdev->iBytesPerPixel == 1)
|
|
)
|
|
{
|
|
Xfer64Pixels(ppdev, xOrigin, pgp->ptl.y +
|
|
pgb->ptlOrigin.y, 0, cyGlyph, pjGlyph,
|
|
cxGlyph);
|
|
pjGlyph += 64 / 8;
|
|
xOrigin += 64;
|
|
cxGlyph -= 64;
|
|
}
|
|
|
|
REQUIRE(5);
|
|
LL_OP0(xOrigin + ppdev->ptlOffset.x, pgp->ptl.y +
|
|
pgb->ptlOrigin.y + ppdev->ptlOffset.y);
|
|
LL_BLTEXT (cxGlyph, cyGlyph);
|
|
#endif
|
|
|
|
// The monochrome bitmap describing the glyph is
|
|
// byte-aligned. This means that if the glyph is
|
|
// 1 to 8 pels in width, each row of the glyph is
|
|
// defined in consecutive bytes; if the glyph is 9
|
|
// to 16 pels in width, each row of the glyph is
|
|
// defined in consecutive words, etc.
|
|
//
|
|
|
|
#if SWAT7
|
|
if (cxGlyph <= 8)
|
|
#else
|
|
if (pgb->sizlBitmap.cx <= 8)
|
|
#endif
|
|
{
|
|
//--------------------------------------------------
|
|
// 1 to 8 pels in width
|
|
// 91% of all glyphs will go through this path.
|
|
|
|
while (cyGlyph--)
|
|
#if SWAT7
|
|
{
|
|
REQUIRE(1);
|
|
LL32(grHOSTDATA[0], *pjGlyph);
|
|
pjGlyph += lDelta;
|
|
}
|
|
#else
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], *pjGlyph++);
|
|
|
|
// We're a bit tricky here in order to avoid letting
|
|
// the compiler tail-merge this code (which would
|
|
// add an extra jump):
|
|
|
|
pgp++;
|
|
if (--cGlyph != 0)
|
|
continue; // Go do the next glyph.
|
|
|
|
break; // Done with all glyphs in this batch.
|
|
// breakout of Glyph Loop.
|
|
#endif
|
|
}
|
|
|
|
#if SWAT7
|
|
else if (cxGlyph <= 16)
|
|
#else
|
|
else if (pgb->sizlBitmap.cx <= 16)
|
|
#endif
|
|
{
|
|
//--------------------------------------------------
|
|
// 9 to 16 pels in width
|
|
// 5% of all glyphs will go through this path.
|
|
|
|
while ( cyGlyph-- )
|
|
#if SWAT7
|
|
{
|
|
REQUIRE(1);
|
|
LL32(grHOSTDATA[0], *(USHORT*)pjGlyph);
|
|
pjGlyph += lDelta;
|
|
}
|
|
#else
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], *((USHORT*)pjGlyph)++);
|
|
#endif
|
|
}
|
|
|
|
else
|
|
{
|
|
//--------------------------------------------------
|
|
// More than 16 pels in width
|
|
|
|
#if SWAT7
|
|
cw = (cxGlyph + 31) >> 5;
|
|
#else
|
|
lDelta = (pgb->sizlBitmap.cx + 7) >> 3;
|
|
cw = (lDelta + 3) >> 2;
|
|
#endif
|
|
|
|
pTmp = pjGlyph + lDelta * pgb->sizlBitmap.cy;
|
|
|
|
for (;cyGlyph!=1; cyGlyph--)
|
|
{
|
|
WRITE_STRING(pjGlyph, cw);
|
|
pjGlyph += lDelta;
|
|
}
|
|
|
|
{
|
|
ULONG *pSrc = (ULONG*) pjGlyph + cw - 1;
|
|
WRITE_STRING(pjGlyph, cw - 1);
|
|
|
|
if ((BYTE *)pSrc+4<=pTmp)
|
|
{
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], *pSrc++ );
|
|
}
|
|
else
|
|
{
|
|
int Extra = (ULONG) pTmp - (ULONG) pSrc;
|
|
BYTE * pByte = (BYTE *)pSrc;
|
|
ULONG ulData;
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL1,
|
|
"Caught it %s %d %d %x %x\n", __FILE__, __LINE__, Extra, pTmp, pSrc));
|
|
|
|
if (Extra == 1)
|
|
ulData = (ULONG)(*pByte);
|
|
else if (Extra == 2)
|
|
ulData = (ULONG)(*(USHORT*)pByte);
|
|
else
|
|
ulData = (((ULONG)*(pByte+2) << 8) | (ULONG)*(pByte+1)) << 8 | *pByte;
|
|
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], ulData );
|
|
}
|
|
}
|
|
|
|
} // END pel width test.
|
|
|
|
pgp++; // Next glyph
|
|
if (--cGlyph == 0)
|
|
break; // Done with this batch.
|
|
// Break out of the Glyph Loop.
|
|
|
|
} // End Glyph Loop.
|
|
|
|
} // End porportional characters.
|
|
|
|
else
|
|
{
|
|
////////////////////////////////////////////////////////////
|
|
// Mono Spacing
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: Mono Spacing.\n"));
|
|
|
|
ulCharInc = pstro->ulCharInc;
|
|
pgb = pgp->pgdf->pgb;
|
|
|
|
ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
|
|
ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
|
|
|
|
while (TRUE) // Loop once for each Glyph in the batch.
|
|
{
|
|
LogFile((BUF, "GC:M\r\n"));
|
|
pgb = pgp->pgdf->pgb;
|
|
|
|
#if !SWAT7
|
|
REQUIRE(5);
|
|
LL_OP0(ptlOrigin.x + ppdev->ptlOffset.x,
|
|
ptlOrigin.y + ppdev->ptlOffset.y);
|
|
|
|
ptlOrigin.x += ulCharInc;
|
|
|
|
LL_BLTEXT (pgb->sizlBitmap.cx, pgb->sizlBitmap.cy);
|
|
#endif
|
|
|
|
pjGlyph = pgb->aj;
|
|
cyGlyph = pgb->sizlBitmap.cy;
|
|
#if SWAT7
|
|
xOrigin = ptlOrigin.x;
|
|
cxGlyph = pgb->sizlBitmap.cx;
|
|
lDelta = (cxGlyph + 7) >> 3;
|
|
|
|
//
|
|
// Test for 5465AD hardware bug in 8-bpp.
|
|
//
|
|
if ( (cxGlyph > 64) && (cxGlyph < 128)
|
|
&& (ppdev->iBytesPerPixel == 1)
|
|
)
|
|
{
|
|
Xfer64Pixels(ppdev, xOrigin, ptlOrigin.y, 0,
|
|
cyGlyph, pjGlyph, cxGlyph);
|
|
pjGlyph += 64 / 8;
|
|
xOrigin += 64;
|
|
cxGlyph -= 64;
|
|
}
|
|
|
|
REQUIRE(5);
|
|
LL_OP0(xOrigin + ppdev->ptlOffset.x,
|
|
ptlOrigin.y + ppdev->ptlOffset.y);
|
|
|
|
ptlOrigin.x += ulCharInc;
|
|
|
|
LL_BLTEXT (cxGlyph, cyGlyph);
|
|
#endif
|
|
|
|
//
|
|
// Note: Mono spacing does not guarantee that all the
|
|
// glyphs are the same size -- that is, we cannot
|
|
// move the size check out of this inner loop,
|
|
// unless we key off some more of the STROBJ
|
|
// accelerator flags.
|
|
// We are not guarenteed the Glyphs are the same size,
|
|
// only that they are the same distance apart.
|
|
//
|
|
|
|
#if SWAT7
|
|
if (cxGlyph <= 8)
|
|
#else
|
|
if (pgb->sizlBitmap.cx <= 8)
|
|
#endif
|
|
{
|
|
//-----------------------------------------------------
|
|
// 1 to 8 pels in width
|
|
|
|
while ( cyGlyph-- )
|
|
#if SWAT7
|
|
{
|
|
REQUIRE(1);
|
|
LL32(grHOSTDATA[0], *pjGlyph);
|
|
pjGlyph += lDelta;
|
|
}
|
|
#else
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], *pjGlyph++);
|
|
#endif
|
|
|
|
}
|
|
#if SWAT7
|
|
else if (cxGlyph <= 16)
|
|
#else
|
|
else if (pgb->sizlBitmap.cx <= 16)
|
|
#endif
|
|
{
|
|
//-----------------------------------------------------
|
|
// 9 to 16 pels in width
|
|
|
|
|
|
while ( cyGlyph-- )
|
|
#if SWAT7
|
|
{
|
|
REQUIRE(1);
|
|
LL32(grHOSTDATA[0], *(USHORT*)pjGlyph);
|
|
pjGlyph += lDelta;
|
|
}
|
|
#else
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], *((USHORT*)pjGlyph)++);
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
//-----------------------------------------------------
|
|
// More than 16 pels in width
|
|
|
|
|
|
#if SWAT7
|
|
cw = (cxGlyph + 31) >> 5;
|
|
#else
|
|
lDelta = (pgb->sizlBitmap.cx + 7) >> 3;
|
|
cw = (lDelta + 3) >> 2;
|
|
#endif
|
|
|
|
pTmp = pjGlyph + lDelta * pgb->sizlBitmap.cy;
|
|
|
|
for (;cyGlyph!=1; cyGlyph--)
|
|
{
|
|
WRITE_STRING(pjGlyph, cw);
|
|
pjGlyph += lDelta;
|
|
}
|
|
|
|
{
|
|
ULONG *pSrc = (ULONG*) pjGlyph + cw - 1;
|
|
WRITE_STRING(pjGlyph, cw - 1);
|
|
|
|
if ((BYTE *)pSrc+4<=pTmp)
|
|
{
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], *pSrc++ );
|
|
}
|
|
else
|
|
{
|
|
int Extra = (ULONG) pTmp - (ULONG) pSrc;
|
|
BYTE * pByte = (BYTE *)pSrc;
|
|
ULONG ulData;
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL1,
|
|
"Caught it %s %d %d %x %x\n",
|
|
__FILE__, __LINE__, Extra, pTmp, pSrc));
|
|
|
|
if (Extra == 1)
|
|
ulData = (ULONG)(*pByte);
|
|
else if (Extra == 2)
|
|
ulData = (ULONG)(*(USHORT*)pByte);
|
|
else
|
|
ulData = (((ULONG)*(pByte+2) << 8) | (ULONG)*(pByte+1)) << 8 | *pByte;
|
|
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], ulData );
|
|
}
|
|
}
|
|
} // End more than 16 pels wide.
|
|
|
|
pgp++;
|
|
if (--cGlyph == 0) // We are done with this batch
|
|
break; // of glyphs. Break out of the glyph loop.
|
|
|
|
} // End Glyph Loop.
|
|
|
|
} // End Mono Spacing.
|
|
|
|
} // End if (cGlyph > 0)
|
|
|
|
//
|
|
// Done with this batch of Glyphs.
|
|
// Go get the next one.
|
|
//
|
|
|
|
} while (bMoreGlyphs);
|
|
|
|
} // End DC_TRIVIAL
|
|
else
|
|
{
|
|
// If there's clipping, call off to a function:
|
|
vMmClipGlyphExpansion(ppdev, pstro, pco);
|
|
}
|
|
|
|
ppdev->grCONTROL = ppdev->grCONTROL & ~SWIZ_CNTL;
|
|
LL16(grCONTROL, ppdev->grCONTROL);
|
|
|
|
return(TRUE);
|
|
|
|
} // End DrvTextOut.
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bEnableText
|
|
*
|
|
* Performs the necessary setup for the text drawing subcomponent.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bEnableText(
|
|
PDEV* ppdev)
|
|
{
|
|
// Our text algorithms require no initialization. If we were to
|
|
// do glyph caching, we would probably want to allocate off-screen
|
|
// memory and do a bunch of other stuff here.
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL,"bEnableText: Entry.\n"));
|
|
#if RECORD_ON
|
|
LL( RECORD, 1); // Switch on
|
|
LL( RECORD, 2); // Pause
|
|
DISPDBG((TEXT_DBG_LEVEL1,"xbEnableText: Recording Paused.\n"));
|
|
#endif
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDisableText
|
|
*
|
|
* Performs the necessary clean-up for the text drawing subcomponent.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vDisableText(PDEV* ppdev)
|
|
{
|
|
// Here we free any stuff allocated in 'bEnableText'.
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL,"vDisableText: Entry.\n"));
|
|
}
|
|
|
|
#if !SWAT3
|
|
#pragma optimize("", off) // Microsoft doesn't know how to do compile...
|
|
#endif
|
|
/******************************Public*Routine******************************\
|
|
* VOID vAssertModeText
|
|
*
|
|
* Disables or re-enables the text drawing subcomponent in preparation for
|
|
* full-screen entry/exit.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vAssertModeText(
|
|
PDEV* ppdev,
|
|
BOOL bEnable)
|
|
{
|
|
#if SWAT3
|
|
SIZEL sizl;
|
|
POINTL pos;
|
|
int i;
|
|
|
|
if (bEnable)
|
|
{
|
|
// We are enabling the screen again, so allocate the font cache if it
|
|
// is not yet allocated.
|
|
if (ppdev->pofmFontCache == NULL)
|
|
{
|
|
#if MEMMGR
|
|
sizl.cx = ppdev->lDeltaScreen / FONTCELL_X;
|
|
#else
|
|
//sizl.cx = ppdev->cxMemory;
|
|
sizl.cx = ppdev->lDeltaScreen / ppdev->iBytesPerPixel / FONTCELL_X;
|
|
#endif
|
|
sizl.cy = (FONTCELL_COUNT + sizl.cx - 1) / sizl.cx;
|
|
sizl.cx *= FONTCELL_X;
|
|
sizl.cy *= FONTCELL_Y;
|
|
|
|
ppdev->pofmFontCache = AllocOffScnMem(ppdev, &sizl, 0, NULL);
|
|
//ppdev->pofmFontCache = AllocOffScnMem(ppdev, &sizl,
|
|
// PIXEL_AlIGN, NULL);
|
|
}
|
|
|
|
if (ppdev->pofmFontCache != NULL)
|
|
{
|
|
// Clear the entire font cell array.
|
|
pos.x = pos.y = 0;
|
|
for (i = 0; i < FONTCELL_COUNT; i++)
|
|
{
|
|
if (pos.y >= sizl.cy)
|
|
{
|
|
ppdev->fcGrid[i].x = 0;
|
|
ppdev->fcGrid[i].y = 0;
|
|
ppdev->fcGrid[i].pfc = (PFONTCACHE) -1;
|
|
}
|
|
else
|
|
{
|
|
ppdev->fcGrid[i].x = ppdev->pofmFontCache->x + pos.x;
|
|
ppdev->fcGrid[i].y = ppdev->pofmFontCache->y + pos.y;
|
|
ppdev->fcGrid[i].pfc = NULL;
|
|
ppdev->fcGrid[i].ulLastX = 0;
|
|
ppdev->fcGrid[i].pNext = NULL;
|
|
|
|
pos.x += FONTCELL_X;
|
|
if (pos.x >= (LONG) ppdev->cxMemory)
|
|
{
|
|
pos.x = 0;
|
|
pos.y += FONTCELL_Y;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We are disabling the screen so destroy all cached fonts.
|
|
if (ppdev->pofmFontCache != NULL)
|
|
{
|
|
for (i = 0; i < FONTCELL_COUNT; i++)
|
|
{
|
|
if ( (ppdev->fcGrid[i].pfc != NULL)
|
|
&& (ppdev->fcGrid[i].pfc != (PFONTCACHE) -1)
|
|
)
|
|
{
|
|
DrvDestroyFont(ppdev->fcGrid[i].pfc->pfo);
|
|
}
|
|
}
|
|
|
|
// Free the font cache cells.
|
|
FreeOffScnMem(ppdev, ppdev->pofmFontCache);
|
|
ppdev->pofmFontCache = NULL;
|
|
}
|
|
}
|
|
#elif !SWAT3
|
|
if (!bEnable)
|
|
{
|
|
// Remove all chained fonts.
|
|
PFONTCACHE p = ppdev->pfcChain;
|
|
while (p != NULL)
|
|
{
|
|
DrvDestroyFont(p->pfo);
|
|
p = ppdev->pfcChain;
|
|
}
|
|
}
|
|
#endif // SWAT3
|
|
|
|
}
|
|
#if !SWAT3
|
|
#pragma optimize("", on)
|
|
#endif
|
|
|
|
#if SWAT3
|
|
/******************************************************************************\
|
|
* PFONTCELL fcAllocCell(PFONTCACGE pfc)
|
|
*
|
|
* Allocate a font cell for the given font cache. Returns NULL if there are no
|
|
* more empty font cells.
|
|
\******************************************************************************/
|
|
PFONTCELL fcAllocCell(PFONTCACHE pfc)
|
|
{
|
|
int i;
|
|
PPDEV ppdev = pfc->ppdev;
|
|
PFONTCELL p = ppdev->fcGrid;
|
|
|
|
if (ppdev->pofmFontCache == NULL)
|
|
{
|
|
// Font cache is disabled, return NULL.
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < FONTCELL_COUNT; i++, p++)
|
|
{
|
|
if (p->pfc == NULL)
|
|
{
|
|
p->pfc = pfc;
|
|
return p;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/******************************************************************************\
|
|
* void fcFreeCell(PFONTCELL pCell)
|
|
*
|
|
* Mark the given font cell as free.
|
|
\******************************************************************************/
|
|
void fcFreeCell(PFONTCELL pCell)
|
|
{
|
|
pCell->pfc = NULL;
|
|
pCell->ulLastX = 0;
|
|
pCell->pNext = NULL;
|
|
}
|
|
#endif // SWAT3
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DrvDestroyFont
|
|
*
|
|
* We're being notified that the given font is being deallocated; clean up
|
|
* anything we've stashed in the 'pvConsumer' field of the 'pfo'.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID DrvDestroyFont(FONTOBJ *pfo)
|
|
{
|
|
DISPDBG((TEXT_DBG_LEVEL, "DrvDestroyFont Entry\n"));
|
|
|
|
if (pfo->pvConsumer != NULL && pfo->pvConsumer != (PVOID) -1)
|
|
{
|
|
PFONTCACHE pfc = (PFONTCACHE) pfo->pvConsumer;
|
|
#if SWAT3
|
|
PFONTCELL pCell, pCellNext;
|
|
#else
|
|
PFONTMEMORY pfm, pfmNext;
|
|
#endif
|
|
PPDEV ppdev;
|
|
|
|
ppdev = pfc->ppdev;
|
|
|
|
LogFile((BUF, "DrvDestroyFont: "));
|
|
|
|
#if SWAT3
|
|
for (pCell = pfc->pFontCell; pCell != NULL; pCell = pCellNext)
|
|
{
|
|
pCellNext = pCell->pNext;
|
|
fcFreeCell(pCell);
|
|
}
|
|
LogFile((BUF, "\r\n"));
|
|
#else
|
|
for (pfm = pfc->pFontMemory; pfm != NULL; pfm = pfmNext)
|
|
{
|
|
pfmNext = pfm->pNext;
|
|
if (pfm->pTile != NULL)
|
|
{
|
|
FreeOffScnMem(pfc->ppdev, pfm->pTile);
|
|
}
|
|
MEMORY_FREE(pfm);
|
|
}
|
|
|
|
// Unhook the font cache from the chain.
|
|
if (pfc->pfcPrev != NULL)
|
|
{
|
|
pfc->pfcPrev->pfcNext = pfc->pfcNext;
|
|
}
|
|
else
|
|
{
|
|
ppdev->pfcChain = pfc->pfcNext;
|
|
}
|
|
|
|
if (pfc->pfcNext != NULL)
|
|
{
|
|
pfc->pfcNext->pfcPrev = pfc->pfcPrev;
|
|
}
|
|
#endif
|
|
|
|
LogFile((BUF, "\r\n"));
|
|
MEMORY_FREE(pfc);
|
|
}
|
|
|
|
pfo->pvConsumer = NULL;
|
|
DISPDBG((TEXT_DBG_LEVEL, "DrvDestroyFont Exit\n"));
|
|
}
|
|
|
|
/*
|
|
* GetGlyphSize
|
|
*
|
|
* Get the size (in pixels) of the requested glyph. Return the width of the
|
|
* glyph in bytes or 0 if the glyph is too big to cache.
|
|
*
|
|
*/
|
|
long GetGlyphSize(
|
|
GLYPHBITS* pgb, // Pointer to glyph.
|
|
POINTL* pptlOrigin, // Pointer to return origin in.
|
|
DWORD* pcSize // Pointer to return size in.
|
|
)
|
|
{
|
|
long x, y, height = 0;
|
|
BYTE* pByte = pgb->aj;
|
|
int i;
|
|
|
|
x = (pgb->sizlBitmap.cx + 7) >> 3; // get width in bytes
|
|
if (x > 0)
|
|
{
|
|
// find first line in glyph that contains data
|
|
for (y = 0; y < pgb->sizlBitmap.cy; y++, pByte += x)
|
|
{
|
|
// walk trough every byte on a line
|
|
for (i = 0; i < x; i++)
|
|
{
|
|
if (pByte[i]) // we have data, so we are at the first line
|
|
{
|
|
// find the last line in te glyph that contains data
|
|
height = pgb->sizlBitmap.cy - y;
|
|
for (pByte += (height - 1) * x; height > 0; height--)
|
|
{
|
|
// walk trough every byte on a line
|
|
for (i = 0; i < x; i++)
|
|
{
|
|
if (pByte[i])
|
|
{
|
|
// test height of glyph
|
|
#if SWAT3
|
|
if (height > FONTCELL_Y)
|
|
#else
|
|
if (height > LINES_PER_TILE)
|
|
#endif
|
|
{
|
|
// glyph too big, mark it as uncacheable
|
|
*pcSize = (DWORD) -1;
|
|
return(0);
|
|
}
|
|
// fill return parameters
|
|
pptlOrigin->y = y;
|
|
*pcSize = PACK_XY(pgb->sizlBitmap.cx, height);
|
|
return(x);
|
|
}
|
|
}
|
|
pByte -= x;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// glyph is empty
|
|
*pcSize = 0;
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* AllocFontCache
|
|
*
|
|
* Allocate the requsted memory in off-screen memory. Return TRUE and the x,y
|
|
* coordinates of the upper left corner of this region, or FALSE if there is
|
|
* not enough memory.
|
|
*
|
|
*/
|
|
BOOL AllocFontCache(
|
|
PFONTCACHE pfc, // Pointer to font cache.
|
|
long cWidth, // Width (in bytes) to allocate.
|
|
long cHeight, // Height to allocate.
|
|
POINTL* ppnt // Point to return cooridinate in.
|
|
)
|
|
{
|
|
#if SWAT3
|
|
PFONTCELL pCell;
|
|
#else
|
|
SIZEL sizl;
|
|
PFONTMEMORY pfm;
|
|
#endif
|
|
long x;
|
|
PPDEV ppdev = pfc->ppdev;
|
|
|
|
#if !SWAT3
|
|
if (ppdev->iBytesPerPixel == 3)
|
|
{
|
|
sizl.cx = (128 + 2) / 3;
|
|
}
|
|
else
|
|
{
|
|
sizl.cx = 128 / ppdev->iBytesPerPixel;
|
|
}
|
|
sizl.cy = 16;
|
|
#endif
|
|
|
|
#if SWAT3
|
|
if (pfc->pFontCell == NULL)
|
|
{
|
|
pfc->pFontCell = fcAllocCell(pfc);
|
|
}
|
|
#else
|
|
if (pfc->pFontMemory == NULL)
|
|
{
|
|
pfc->pFontMemory = (PFONTMEMORY)
|
|
#ifdef WINNT_VER40
|
|
MEM_ALLOC(FL_ZERO_MEMORY, sizeof(FONTMEMORY), ALLOC_TAG);
|
|
#else
|
|
MEM_ALLOC(LMEM_FIXED | LMEM_ZEROINIT, sizeof(FONTMEMORY));
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if SWAT3
|
|
for (pCell = pfc->pFontCell; pCell != NULL; pCell = pCell->pNext)
|
|
{
|
|
x = pCell->ulLastX;
|
|
if (x + cWidth <= FONTCELL_X)
|
|
{
|
|
pCell->ulLastX += cWidth;
|
|
ppnt->x = pCell->x + x;
|
|
ppnt->y = pCell->y;
|
|
return TRUE;
|
|
}
|
|
|
|
if (pCell->pNext == NULL)
|
|
{
|
|
pCell->pNext = fcAllocCell(pfc);
|
|
}
|
|
}
|
|
#else
|
|
for (pfm = pfc->pFontMemory; pfm; pfm = pfm->pNext)
|
|
{
|
|
if (pfm->pTile == NULL)
|
|
{
|
|
#ifdef ALLOC_IN_CREATESURFACE
|
|
if (!ppdev->bDirectDrawInUse)
|
|
#endif
|
|
pfm->pTile = AllocOffScnMem(ppdev, &sizl, PIXEL_AlIGN, NULL);
|
|
if (pfm->pTile == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ppnt->x = pfm->pTile->x;
|
|
ppnt->y = pfm->pTile->y;
|
|
pfm->ulLastX = cWidth;
|
|
return TRUE;
|
|
}
|
|
|
|
x = pfm->ulLastX;
|
|
if (x + cWidth <= BYTES_PER_TILE)
|
|
{
|
|
pfm->ulLastX += cWidth;
|
|
ppnt->x = pfm->pTile->x + x;
|
|
ppnt->y = pfm->pTile->y;
|
|
return TRUE;
|
|
}
|
|
|
|
if (pfm->pNext == NULL)
|
|
{
|
|
pfm->pNext = (PFONTMEMORY)
|
|
#ifdef WINNT_VER40
|
|
MEM_ALLOC(FL_ZERO_MEMORY, sizeof(FONTMEMORY), ALLOC_TAG);
|
|
#else
|
|
MEM_ALLOC(LMEM_FIXED | LMEM_ZEROINIT, sizeof(FONTMEMORY));
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* AllocGlyph
|
|
*
|
|
* Allocate memory for the requested glyph and copy the glyph into off-screen
|
|
* memory. If there is not enough off-screen memory left, or the glyph is too
|
|
* large to glyph, return FALSE, otherwise return TRUE.
|
|
*
|
|
*/
|
|
VOID AllocGlyph(
|
|
PFONTCACHE pfc, // pointer to font cache
|
|
GLYPHBITS* pgb, // pointer to glyph to cache
|
|
GLYPHCACHE* pgc // pointer to glyph cache structure
|
|
)
|
|
{
|
|
long cBytes;
|
|
BYTE *pOffScreen, *pSrc;
|
|
long y;
|
|
PDEV *ppdev;
|
|
POINTL pointl;
|
|
|
|
ppdev = pfc->ppdev;
|
|
cBytes = GetGlyphSize(pgb, &pgc->ptlOrigin, &pgc->cSize);
|
|
if (cBytes == 0)
|
|
{
|
|
pgc->xyPos = (DWORD) -1;
|
|
LogFile((BUF, "GC:F\r\n"));
|
|
return;
|
|
}
|
|
|
|
if (AllocFontCache(pfc, cBytes, pgc->cSize >> 16, &pointl) == FALSE)
|
|
{
|
|
pgc->cSize = (DWORD) -1;
|
|
LogFile((BUF, "GC:F\r\n"));
|
|
return;
|
|
}
|
|
|
|
pOffScreen = ppdev->pjScreen + pointl.x + pointl.y * ppdev->lDeltaScreen;
|
|
pSrc = &pgb->aj[pgc->ptlOrigin.y * cBytes];
|
|
y = (long) (pgc->cSize >> 16);
|
|
if (cBytes == sizeof(BYTE))
|
|
{
|
|
while (y-- > 0)
|
|
{
|
|
*pOffScreen = Swiz[*pSrc];
|
|
pOffScreen += ppdev->lDeltaScreen;
|
|
pSrc += sizeof(BYTE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (y-- > 0)
|
|
{
|
|
long lDelta = ppdev->lDeltaScreen - cBytes;
|
|
long i;
|
|
|
|
for (i = cBytes; i > 0; i--)
|
|
{
|
|
*pOffScreen++ = Swiz[*pSrc++];
|
|
}
|
|
pOffScreen += lDelta;
|
|
}
|
|
}
|
|
pgc->xyPos = PACK_XY(pointl.x * 8, pointl.y);
|
|
pgc->ptlOrigin.x = pgb->ptlOrigin.x;
|
|
pgc->ptlOrigin.y += pgb->ptlOrigin.y;
|
|
LogFile((BUF, "GC:S\r\n"));
|
|
}
|
|
|
|
|
|
#if !(USE_ASM && defined(i386))
|
|
|
|
/*
|
|
* FontCache
|
|
*
|
|
* Draw glyphs using the off-screen font cache.
|
|
*
|
|
*/
|
|
VOID FontCache(
|
|
PFONTCACHE pfc, // Pointer to font cache.
|
|
STROBJ* pstro // Pointer to glyphs.
|
|
)
|
|
{
|
|
PDEV* ppdev;
|
|
BOOL bMoreGlyphs = TRUE;
|
|
ULONG cGlyph;
|
|
GLYPHPOS* pgp;
|
|
POINTL ptlOrigin;
|
|
PGLYPHCACHE pgc;
|
|
ULONG ulCharInc;
|
|
|
|
// set pointer to physical device
|
|
ppdev = pfc->ppdev;
|
|
|
|
// loop until there are no more glyphs to process
|
|
while (bMoreGlyphs)
|
|
{
|
|
if (pstro->pgp != NULL)
|
|
{
|
|
// we have just one set of glyphs
|
|
pgp = pstro->pgp;
|
|
cGlyph = pstro->cGlyphs;
|
|
bMoreGlyphs = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// enumerate a set of glyphs
|
|
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
|
|
}
|
|
|
|
if (pstro->ulCharInc)
|
|
{
|
|
// fixed fonts... get x and y coordinates of first glyph
|
|
ptlOrigin.x = pgp->ptl.x;
|
|
ptlOrigin.y = pgp->ptl.y;
|
|
// get glyph increment
|
|
ulCharInc = pstro->ulCharInc;
|
|
|
|
// walk through all glyphs
|
|
while (cGlyph-- > 0)
|
|
{
|
|
if (pgp->hg < MAX_GLYPHS)
|
|
{
|
|
// this glyph index is cacheable
|
|
pgc = &pfc->aGlyphs[pgp->hg];
|
|
if (pgc->xyPos == 0)
|
|
{
|
|
// cache the glyph
|
|
AllocGlyph(pfc, pgp->pgdf->pgb, pgc);
|
|
}
|
|
if ((long) pgc->cSize > 0)
|
|
{
|
|
LogFile((BUF, "GC:H\r\n"));
|
|
// the glyph is cached, blit it on the screen
|
|
REQUIRE(7);
|
|
LL_OP0(ptlOrigin.x + pgc->ptlOrigin.x + ppdev->ptlOffset.x,
|
|
ptlOrigin.y + pgc->ptlOrigin.y + ppdev->ptlOffset.y);
|
|
LL32 (grOP2_opMRDRAM, pgc->xyPos);
|
|
LL32 (grBLTEXT_EX.dw, pgc->cSize);
|
|
}
|
|
else if ((long) pgc->cSize == -1)
|
|
{
|
|
// the glyph is uncacheable, draw it directly
|
|
DrawGlyph(ppdev, pgp->pgdf->pgb, ptlOrigin);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the glyph index is out of range, draw it directly
|
|
DrawGlyph(ppdev, pgp->pgdf->pgb, ptlOrigin);
|
|
}
|
|
// increment glyph x coordinate
|
|
ptlOrigin.x += ulCharInc;
|
|
// next glyph
|
|
pgp++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// variable width fonts, walk trough all glyphs
|
|
while (cGlyph-- > 0)
|
|
{
|
|
if (pgp->hg < MAX_GLYPHS)
|
|
{
|
|
// this glyph index is cacheable
|
|
pgc = &pfc->aGlyphs[pgp->hg];
|
|
if (pgc->xyPos == 0)
|
|
{
|
|
// cache the glyph
|
|
AllocGlyph(pfc, pgp->pgdf->pgb, pgc);
|
|
}
|
|
if ((long) pgc->cSize > 0)
|
|
{
|
|
LogFile((BUF, "GC:H\r\n"));
|
|
// the glyph is cached, blit it on the screen
|
|
REQUIRE(7);
|
|
LL_OP0(pgp->ptl.x + pgc->ptlOrigin.x + ppdev->ptlOffset.x,
|
|
pgp->ptl.y + pgc->ptlOrigin.y + ppdev->ptlOffset.y);
|
|
LL32 (grOP2_opMRDRAM, pgc->xyPos);
|
|
LL32 (grBLTEXT_EX.dw, pgc->cSize);
|
|
}
|
|
else if ((long) pgc->cSize == -1)
|
|
{
|
|
// the glyph is uncacheable, draw it directly
|
|
DrawGlyph(ppdev, pgp->pgdf->pgb, pgp->ptl);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the glyph index is out of range, draw it directly
|
|
DrawGlyph(ppdev, pgp->pgdf->pgb, pgp->ptl);
|
|
}
|
|
// next glyph
|
|
pgp++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* DrawGlyph
|
|
*
|
|
* Draw glyphs directly on the screen.
|
|
*
|
|
*/
|
|
VOID DrawGlyph(
|
|
PDEV* ppdev, // Pointer to physical device.
|
|
GLYPHBITS* pgb, // Pointer to glyph to draw.
|
|
POINTL ptl // Location of glyph.
|
|
)
|
|
{
|
|
BYTE* pjGlyph;
|
|
ULONG cyGlyph;
|
|
#if SWAT7
|
|
ULONG cxGlyph;
|
|
ULONG xOrigin;
|
|
LONG lDelta;
|
|
#endif
|
|
|
|
LogFile((BUF, "GC:M\r\n"));
|
|
|
|
#if SWAT7
|
|
xOrigin = ptl.x + pgb->ptlOrigin.x;
|
|
cxGlyph = pgb->sizlBitmap.cx;
|
|
cyGlyph = pgb->sizlBitmap.cy;
|
|
pjGlyph = pgb->aj;
|
|
lDelta = (cxGlyph + 7) >> 3;
|
|
#endif
|
|
|
|
// start the blit
|
|
REQUIRE(4);
|
|
LL_DRAWBLTDEF(TEXT_EXPAND_XPAR, 0);
|
|
LL_OP2_MONO(0, 0);
|
|
#if !SWAT7
|
|
REQUIRE(5);
|
|
LL_OP0(ptl.x + pgb->ptlOrigin.x + ppdev->ptlOffset.x,
|
|
ptl.y + pgb->ptlOrigin.y + ppdev->ptlOffset.y);
|
|
LL_BLTEXT(pgb->sizlBitmap.cx, pgb->sizlBitmap.cy);
|
|
|
|
pjGlyph = pgb->aj;
|
|
cyGlyph = pgb->sizlBitmap.cy;
|
|
#endif
|
|
|
|
#if SWAT7
|
|
//
|
|
// Test for 5465AD hardware bug in 8-bpp.
|
|
//
|
|
if ( (cxGlyph > 64) && (cxGlyph < 128)
|
|
&& (ppdev->iBytesPerPixel == 1)
|
|
)
|
|
{
|
|
Xfer64Pixels(ppdev, xOrigin, ptl.y + pgb->ptlOrigin.y, 0, cyGlyph,
|
|
pjGlyph, cxGlyph);
|
|
pjGlyph += 64 / 8;
|
|
xOrigin += 64;
|
|
cxGlyph -= 64;
|
|
}
|
|
|
|
REQUIRE(5);
|
|
LL_OP0(xOrigin + ppdev->ptlOffset.x,
|
|
ptl.y + pgb->ptlOrigin.y + ppdev->ptlOffset.y);
|
|
LL_BLTEXT(cxGlyph, cyGlyph);
|
|
#endif
|
|
|
|
#if SWAT7
|
|
if (cxGlyph <= 8)
|
|
#else
|
|
if (pgb->sizlBitmap.cx <= 8)
|
|
#endif
|
|
{
|
|
// just one byte per line
|
|
while (cyGlyph--)
|
|
{
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], *pjGlyph);
|
|
#if SWAT7
|
|
pjGlyph += lDelta;
|
|
#else
|
|
pjGlyph++;
|
|
#endif
|
|
}
|
|
}
|
|
#if SWAT7
|
|
else if (cxGlyph <= 16)
|
|
#else
|
|
else if (pgb->sizlBitmap.cx <= 16)
|
|
#endif
|
|
{
|
|
// just two bytes per line
|
|
while (cyGlyph--)
|
|
{
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], *(WORD *) pjGlyph);
|
|
#if SWAT7
|
|
pjGlyph += lDelta;
|
|
#else
|
|
pjGlyph += 2;
|
|
#endif
|
|
}
|
|
}
|
|
#if SWAT7
|
|
else if (cxGlyph <= 24)
|
|
#else
|
|
else if (pgb->sizlBitmap.cx <= 24)
|
|
#endif
|
|
{
|
|
// just three bytes per line
|
|
while (cyGlyph--)
|
|
{
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], *(DWORD *) pjGlyph);
|
|
#if SWAT7
|
|
pjGlyph += lDelta;
|
|
#else
|
|
pjGlyph += 3;
|
|
#endif
|
|
}
|
|
}
|
|
#if SWAT7
|
|
else if (cxGlyph <= 32)
|
|
#else
|
|
else if (pgb->sizlBitmap.cx <= 32)
|
|
#endif
|
|
{
|
|
// just four bytes per line
|
|
while (cyGlyph--)
|
|
{
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], *(DWORD *) pjGlyph);
|
|
#if SWAT7
|
|
pjGlyph += lDelta;
|
|
#else
|
|
pjGlyph += 4;
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// any number of bytes per line
|
|
#if SWAT7
|
|
int cw = (cxGlyph + 31) >> 5;
|
|
#else
|
|
long lDelta = (pgb->sizlBitmap.cx + 7) >> 3;
|
|
int cw = (lDelta + 3) >> 2;
|
|
#endif
|
|
|
|
BYTE * pTmp = pjGlyph + lDelta * pgb->sizlBitmap.cy;
|
|
|
|
for (;cyGlyph!=1; cyGlyph--)
|
|
{
|
|
WRITE_STRING(pjGlyph, cw);
|
|
pjGlyph += lDelta;
|
|
}
|
|
|
|
{
|
|
ULONG *pSrc = (ULONG*) pjGlyph + cw - 1;
|
|
WRITE_STRING(pjGlyph, cw - 1);
|
|
|
|
if ((BYTE *)pSrc+4<=pTmp)
|
|
{
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], *pSrc++ );
|
|
}
|
|
else
|
|
{
|
|
int Extra = (ULONG) pTmp - (ULONG) pSrc;
|
|
BYTE * pByte = (BYTE *)pSrc;
|
|
ULONG ulData;
|
|
|
|
DISPDBG((TEXT_DBG_LEVEL1,
|
|
"Caught it %s %d %d %x %x\n",
|
|
__FILE__, __LINE__, Extra, pTmp, pSrc));
|
|
|
|
if (Extra == 1)
|
|
ulData = (ULONG)(*pByte);
|
|
else if (Extra == 2)
|
|
ulData = (ULONG)(*(USHORT*)pByte);
|
|
else
|
|
ulData = (((ULONG)*(pByte+2) << 8) | (ULONG)*(pByte+1)) << 8 | *pByte;
|
|
|
|
REQUIRE(1);
|
|
LL32 (grHOSTDATA[0], ulData );
|
|
}
|
|
}
|
|
}
|
|
|
|
// reset to transparent cache expansion
|
|
LL_DRAWBLTDEF(CACHE_EXPAND_XPAR, 2);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID ClipCache(
|
|
PFONTCACHE pfc, // Pointer to font cache.
|
|
STROBJ* pstro, // Pointer to glyphs.
|
|
RECTL rclBounds // Clipping rectangle.
|
|
)
|
|
{
|
|
PDEV* ppdev;
|
|
BOOL bMoreGlyphs = TRUE;
|
|
ULONG cGlyph;
|
|
GLYPHPOS* pgp;
|
|
POINTL ptlOrigin;
|
|
PGLYPHCACHE pgc;
|
|
ULONG ulCharInc;
|
|
|
|
// set pointer to physical device
|
|
ppdev = pfc->ppdev;
|
|
|
|
// loop until there are no more glyphs to process
|
|
while (bMoreGlyphs)
|
|
{
|
|
if (pstro->pgp != NULL)
|
|
{
|
|
// we have just one set of glyphs
|
|
pgp = pstro->pgp;
|
|
cGlyph = pstro->cGlyphs;
|
|
bMoreGlyphs = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// enumerate a set of glyphs
|
|
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
|
|
}
|
|
|
|
// get x and y coordinates of first glyph
|
|
ptlOrigin.x = pgp->ptl.x;
|
|
ptlOrigin.y = pgp->ptl.y;
|
|
// get glyph increment
|
|
ulCharInc = pstro->ulCharInc;
|
|
|
|
// walk through all glyphs
|
|
while (cGlyph-- > 0)
|
|
{
|
|
if (pgp->hg < MAX_GLYPHS)
|
|
{
|
|
// this glyph index is cacheable
|
|
pgc = &pfc->aGlyphs[pgp->hg];
|
|
if (pgc->xyPos == 0)
|
|
{
|
|
// cache the glyph
|
|
AllocGlyph(pfc, pgp->pgdf->pgb, pgc);
|
|
}
|
|
if ((long) pgc->cSize > 0)
|
|
{
|
|
RECTL rcl;
|
|
LONG i, cx, cy;
|
|
ULONG xyPos;
|
|
|
|
|
|
// the glyph is cached, ckeck clipping
|
|
rcl.left = ptlOrigin.x + pgc->ptlOrigin.x;
|
|
rcl.top = ptlOrigin.y + pgc->ptlOrigin.y;
|
|
rcl.right = rcl.left + (pgc->cSize & 0x0000FFFF);
|
|
rcl.bottom = rcl.top + (pgc->cSize >> 16);
|
|
xyPos = pgc->xyPos;
|
|
|
|
i = rclBounds.left - rcl.left;
|
|
if (i > 0)
|
|
{
|
|
// the glyph is partially clipped on the left, draw it
|
|
// directly
|
|
ClipGlyph(ppdev, pgp->pgdf->pgb, ptlOrigin, rclBounds);
|
|
}
|
|
else
|
|
{
|
|
LogFile((BUF, "GC:H\r\n"));
|
|
cx = min(rcl.right, rclBounds.right) - rcl.left;
|
|
if (cx > 0)
|
|
{
|
|
i = rclBounds.top - rcl.top;
|
|
if (i > 0)
|
|
{
|
|
rcl.top += i;
|
|
xyPos += i << 16;
|
|
}
|
|
cy = min(rcl.bottom, rclBounds.bottom) - rcl.top;
|
|
if (cy > 0)
|
|
{
|
|
REQUIRE(7);
|
|
LL_OP0(rcl.left + ppdev->ptlOffset.x,
|
|
rcl.top + ppdev->ptlOffset.y);
|
|
LL32(grOP2_opMRDRAM, xyPos);
|
|
LL_BLTEXT(cx, cy);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ((long) pgc->cSize == -1)
|
|
{
|
|
// the glyph is uncacheable, draw it directly
|
|
ClipGlyph(ppdev, pgp->pgdf->pgb, ptlOrigin, rclBounds);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the glyph index is out of range, draw it directly
|
|
ClipGlyph(ppdev, pgp->pgdf->pgb, ptlOrigin, rclBounds);
|
|
}
|
|
// next glyph
|
|
pgp++;
|
|
if (ulCharInc == 0)
|
|
{
|
|
ptlOrigin.x = pgp->ptl.x;
|
|
ptlOrigin.y = pgp->ptl.y;
|
|
}
|
|
else
|
|
{
|
|
// increment glyph x coordinate
|
|
ptlOrigin.x += ulCharInc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID ClipGlyph(
|
|
PDEV* ppdev, // Pointer to physical device.
|
|
GLYPHBITS* pgb, // Pointer to glyph to draw.
|
|
POINTL ptl, // Location of glyph.
|
|
RECTL rclBounds // Clipping rectangle.
|
|
)
|
|
{
|
|
BYTE* pjGlyph;
|
|
LONG cx, cy, lDelta, i;
|
|
RECTL rcl;
|
|
ULONG xBit;
|
|
|
|
LogFile((BUF, "GC:M\r\n"));
|
|
|
|
rcl.left = ptl.x + pgb->ptlOrigin.x;
|
|
rcl.top = ptl.y + pgb->ptlOrigin.y;
|
|
rcl.right = rcl.left + pgb->sizlBitmap.cx;
|
|
rcl.bottom = rcl.top + pgb->sizlBitmap.cy;
|
|
xBit = 0;
|
|
pjGlyph = pgb->aj;
|
|
lDelta = (pgb->sizlBitmap.cx + 7) >> 3;
|
|
|
|
i = rclBounds.left - rcl.left;
|
|
if (i > 0)
|
|
{
|
|
pjGlyph += i >> 3;
|
|
xBit = i & 7;
|
|
rcl.left += i;
|
|
}
|
|
cx = min(rcl.right, rclBounds.right) - rcl.left;
|
|
if (cx > 0)
|
|
{
|
|
i = rclBounds.top - rcl.top;
|
|
if (i > 0)
|
|
{
|
|
pjGlyph += i * lDelta;
|
|
rcl.top += i;
|
|
}
|
|
cy = min(rcl.bottom, rclBounds.bottom) - rcl.top;
|
|
if (cy > 0)
|
|
{
|
|
// start the blit
|
|
REQUIRE(4);
|
|
LL_DRAWBLTDEF(TEXT_EXPAND_XPAR, 0);
|
|
LL_OP2(xBit, 0);
|
|
|
|
#if SWAT7
|
|
//
|
|
// Test for 5465AD hardware bug in 8-bpp.
|
|
//
|
|
if ((cx > 64) && (cx < 128) && (ppdev->iBytesPerPixel == 1))
|
|
{
|
|
Xfer64Pixels(ppdev, rcl.left, rcl.top, xBit, cy, pjGlyph,
|
|
pgb->sizlBitmap.cx);
|
|
pjGlyph += 64 / 8;
|
|
rcl.left += 64;
|
|
cx -= 64;
|
|
}
|
|
#endif
|
|
|
|
REQUIRE(5);
|
|
LL_OP0(rcl.left + ppdev->ptlOffset.x,
|
|
rcl.top + ppdev->ptlOffset.y);
|
|
LL_BLTEXT(cx, cy);
|
|
|
|
cx = (xBit + cx + 7) >> 3;
|
|
switch (cx)
|
|
{
|
|
case 1:
|
|
while (cy--)
|
|
{
|
|
REQUIRE(1);
|
|
LL32(grHOSTDATA[0], *(BYTE *) pjGlyph);
|
|
pjGlyph += lDelta;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
while (cy--)
|
|
{
|
|
REQUIRE(1);
|
|
LL32(grHOSTDATA[0], *(WORD *) pjGlyph);
|
|
pjGlyph += lDelta;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
case 4:
|
|
while (cy--)
|
|
{
|
|
REQUIRE(1);
|
|
LL32(grHOSTDATA[0], *(DWORD *) pjGlyph);
|
|
pjGlyph += lDelta;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
while (cy--)
|
|
{
|
|
WRITE_STRING(pjGlyph, (cx + 3) / 4);
|
|
pjGlyph += lDelta;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// reset to transparent cache expansion
|
|
REQUIRE(2);
|
|
LL_DRAWBLTDEF(CACHE_EXPAND_XPAR, 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // !(USE_ASM && defined(i386))
|