/******************************Module*Header*******************************\ * Module Name: TextOut.c * * Text * * Copyright (c) 1992 Microsoft Corporation * \**************************************************************************/ #include "driver.h" BOOL vFastText(PDEV *, GLYPHPOS *, ULONG, PBYTE, ULONG, ULONG, RECTL *, RECTL *, INT, INT, ULONG); VOID lclFillRect(CLIPOBJ *, ULONG, PRECTL, PPDEV, INT); #define FIFTEEN_BITS ((1 << 15)-1) #define TAKING_ALLOC_STATS 0 #if TAKING_ALLOC_STATS ULONG BufferHitInText = 0; ULONG BufferMissInText = 0; #endif /**************************************************************************** * DrvTextOut ***************************************************************************/ BOOL DrvTextOut( SURFOBJ* pso, STROBJ* pstro, FONTOBJ* pfo, CLIPOBJ* pco, RECTL* prclExtra, RECTL* prclOpaque, BRUSHOBJ* pboFore, BRUSHOBJ* pboOpaque, POINTL* pptlOrg, MIX mix) { BOOL b; PPDEV ppdev; INT iClip; // clip object's complexity ULONG iSolidForeColor; // Solid foreground color ULONG iSolidBkColor; // Solid background color RECTL arclTmp[4]; // Temp storage for portions of opaquing rect ULONG culRcl; // Temp rectangle count PVOID pvBuf; // pointer to buffer we'll use ULONG ulBufferWidthInBytes; ULONG ulBufferHeight; ULONG ulBufferBytes; BOOL bTextPerfectFit; ULONG fDrawFlags; ppdev = (PPDEV) pso->dhpdev; //--------------------------------------------------------------------- // Get information about clip object. //--------------------------------------------------------------------- iClip = DC_TRIVIAL; if (pco != NULL) { iClip = pco->iDComplexity; } //--------------------------------------------------------------------- // Get text color. //--------------------------------------------------------------------- iSolidForeColor = pboFore->iSolidColor; //--------------------------------------------------------------------- // See if this is text we can handle faster with special-case code. //--------------------------------------------------------------------- if (((ppdev->fl & DRIVER_PLANAR_CAPABLE) || (prclOpaque == (PRECTL) NULL)) && // opaque only if planar for now // LATER implement fast non-planar // opaque (iClip == DC_TRIVIAL) && // no clipping for now ((pstro->rclBkGround.right & ~0x03) > ((pstro->rclBkGround.left + 3) & ~0x03)) && // not if no full nibbles spanned // for now @@@ (pstro->pgp != NULL) && // no glyph enumeration for now (prclExtra == NULL) && // no extra rects for now ((pstro->flAccel & (SO_HORIZONTAL | SO_VERTICAL | SO_REVERSED)) == SO_HORIZONTAL)) { // only left-to-right text for now // It's the type of text we can special-case; see if the temp buffer is // big enough for the text. ulBufferWidthInBytes = ((((pstro->rclBkGround.right + 7) & ~0x07) - (pstro->rclBkGround.left & ~0x07)) >> 3); ulBufferHeight = pstro->rclBkGround.bottom - pstro->rclBkGround.top; ulBufferBytes = ulBufferWidthInBytes * ulBufferHeight; if ((ulBufferWidthInBytes > FIFTEEN_BITS) || (ulBufferHeight > FIFTEEN_BITS)) { // the math will have overflowed return(FALSE); } if (ulBufferBytes <= GLOBAL_BUFFER_SIZE) { #if TAKING_ALLOC_STATS BufferHitInText++; #endif pvBuf = ppdev->pvTmpBuf; } else { #if TAKING_ALLOC_STATS BufferMissInText++; #endif pvBuf = EngAllocUserMem(ulBufferBytes, ALLOC_TAG); if (!pvBuf) { goto no_special_case; } } // It's big enough; set up for the accelerator // Set fixed pitch, overlap, and top & bottom Y alignment flags fDrawFlags = ((pstro->ulCharInc != 0) ? 0x01 : 0) | (((pstro->flAccel & (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT)) != (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT)) ? 0x02 : 0) | (((pstro->flAccel & (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE)) == (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE)) ? 0x04 : 0); // If there's an opaque rectangle, we'll do as much opaquing as // possible as we do the text. If the opaque rectangle is larger // than the text rectangle, then we'll do the fringe areas right // now, and the text and associated background areas together, // later. if (prclOpaque != (PRECTL) NULL) { // This driver only handles solid brushes iSolidBkColor = pboOpaque->iSolidColor; // See if we have fringe areas to do. If so, build a list of // rectangles to fill, in rightdown order culRcl = 0; // Top fragment if (pstro->rclBkGround.top > prclOpaque->top) { arclTmp[culRcl].top = prclOpaque->top; arclTmp[culRcl].left = prclOpaque->left; arclTmp[culRcl].right = prclOpaque->right; arclTmp[culRcl++].bottom = pstro->rclBkGround.top; } // Left fragment if (pstro->rclBkGround.left > prclOpaque->left) { arclTmp[culRcl].top = pstro->rclBkGround.top; arclTmp[culRcl].left = prclOpaque->left; arclTmp[culRcl].right = pstro->rclBkGround.left; arclTmp[culRcl++].bottom = pstro->rclBkGround.bottom; } // Right fragment if (pstro->rclBkGround.right < prclOpaque->right) { arclTmp[culRcl].top = pstro->rclBkGround.top; arclTmp[culRcl].right = prclOpaque->right; arclTmp[culRcl].left = pstro->rclBkGround.right; arclTmp[culRcl++].bottom = pstro->rclBkGround.bottom; } // Bottom fragment if (pstro->rclBkGround.bottom < prclOpaque->bottom) { arclTmp[culRcl].bottom = prclOpaque->bottom; arclTmp[culRcl].left = prclOpaque->left; arclTmp[culRcl].right = prclOpaque->right; arclTmp[culRcl++].top = pstro->rclBkGround.bottom; } if (culRcl != 0) { if (iClip == DC_TRIVIAL) { vTrgBlt(ppdev, culRcl, arclTmp, R2_COPYPEN, *((RBRUSH_COLOR*) &iSolidBkColor), NULL); } else { lclFillRect(pco, culRcl, arclTmp, ppdev, iSolidBkColor); } } } // We're done with separate opaquing; any further opaquing will // happen as part of the text drawing // Clear the buffer if the text isn't going to set every bit bTextPerfectFit = (pstro->flAccel & (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE | SO_CHAR_INC_EQUAL_BM_BASE)) == (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE | SO_CHAR_INC_EQUAL_BM_BASE); if (!bTextPerfectFit) { vClearMemDword(pvBuf, (ulBufferBytes + 3) >> 2); } // Draw the text into the temp buffer, and thence to the screen vFastText(ppdev, pstro->pgp, pstro->cGlyphs, pvBuf, ulBufferWidthInBytes, pstro->ulCharInc, &pstro->rclBkGround, prclOpaque, iSolidForeColor, iSolidBkColor, fDrawFlags); // free any memory that was allocated if (ulBufferBytes > GLOBAL_BUFFER_SIZE) { // we had to have allocated memory EngFreeUserMem (pvBuf); } return(TRUE); } no_special_case: // Can't special-case; let the engine draw the text pso = ppdev->pSurfObj; // It may be that the opaquing rectangle is larger than the text rectangle, // so we'll want to use that to tell the bank manager which banks to // enumerate: pco = pcoBankStart(ppdev, (prclOpaque != NULL) ? prclOpaque : &pstro->rclBkGround, pso, pco); do { b = EngTextOut(pso, pstro, pfo, pco, prclExtra, prclOpaque, pboFore, pboOpaque, pptlOrg, mix); } while (b && bBankEnum(ppdev, pso, pco)); return(b); } //-------------------------------------------------------------------------- // Fills the specified rectangles on the specified surface with the // specified color, honoring the requested clipping. No more than four // rectangles should be passed in. Intended for drawing the areas of the // opaquing rectangle that extended 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 lclFillRect( CLIPOBJ *pco, ULONG culRcl, PRECTL prcl, PPDEV ppdev, INT iColor) { BOOL bMore; // Flag for clip enumeration TEXTENUM txen; // Clip enumeration object ULONG i, j; RECTL arclTmp[4]; ULONG culRclTmp; RECTL *prclTmp, *prclClipTmp; INT iLastBottom; RECTL *pClipRcl; INT iClip; iClip = DC_TRIVIAL; if (pco != NULL) { iClip = pco->iDComplexity; } switch ( iClip ) { case DC_TRIVIAL: vTrgBlt(ppdev, culRcl, prcl, R2_COPYPEN, *((RBRUSH_COLOR*) &iColor), NULL); break; case DC_RECT: prclTmp = &pco->rclBounds; // Generate a list of clipped rects for (culRclTmp=0, i=0; i 0; pClipRcl++) { // Since the rectangles and the region enumeration are both // rightdown, 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 (pClipRcl->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 (pClipRcl->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 = culRcl, culRclTmp=0; i-- > 0; prclTmp++) { // Intersect fill and clip rectangles if (bIntersectRect(prclClipTmp, prclTmp, pClipRcl)) { // Add to list if anything's left to draw culRclTmp++; prclClipTmp++; } } // Draw the clipped rects if (culRclTmp != 0) { vTrgBlt(ppdev, culRclTmp, arclTmp, R2_COPYPEN, *((RBRUSH_COLOR*) &iColor), NULL); } } } } while (bMore); break; } }