/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: rtwin.cpp,v 1.1.2.1 2004/07/09 01:50:45 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

/////////////////////////////////////////////////////////////////////////////
//
// RTWIN.CPP
//
// Function:
//  BOOL OnPaint(TextWindow* pTextWindow, void* pDC, void* pPaintstruct,
//	    ULONG32 ulTimeOfCurrentDraw,
//	    BOOL SomeonesBeginOrEndTimeWasCrossedOverSinceLastDraw,
//	    INT16 xScrollWindowAmt, INT16 yScrollWindowAmt);
// Purpose:
//  This function does the actual rendering of text by doing a TextOut() of
//  all text in all TextContainers in the TextContainerList of pTextWindow
//  whose text is visible in the rectangle to be updated
//  This Function is called from WM_PAINT and hdc and ps are from
//  BeginPaint(); ps holds the invalid rectangle to be updated: 
// Returns:
//  Returns FALSE on error, TRUE otherwise. 
//
//
// Function:
//  BOOL PaintBackground(TextWindow* pTextWindow, void* pPaintstruct)
// Purpose:
//  This function paints the background of the window at the given rectangle
//  of pPaintstruct.
//  This Function is called from WM_PAINT, and pPaintstruct is (in Windows)
//  from  BeginPaint(); pPaintstruct holds the invalid rectangle to be
//  painted.
// Returns:
//  Returns FALSE on error, TRUE otherwise. 
//
//

#include "hxtypes.h" /*Must be included before windows.h for VC6 compiler*/

#if defined(_WINDOWS)
#include <windows.h>
#endif

#include "hxassert.h"

#include "hxstack.h"
#include "hxslist.h"

#include "rt_types.h" //for _CHAR, RED_GREEN_OR_BLUE, COLORTYPE

#include "fontdefs.h"
#include "txtattrb.h"
#include "txtcntnr.h"
#include "textline.h"
#include "atocolor.h"
#include "fontinfo.h" //for GetCharacterWidth().
#include "atotime.h" //for live time comparison: IsTimeAMoreRecentThanTimeB()

#include "chxxtype.h"
#include "txtwindw.h" //for class TextWindow.
#include "hxcom.h"
#include "hxvsurf.h"
#include "textprsr.h" /* for REAL_TEXT_TRANSPARENT_BGCOLOR_MAJOR_VERSION + ... */

// /#define USE_FREETYPE_DIRECTLY

#if defined (USE_FREETYPE_DIRECTLY)
#if defined(_WINDOWS)
#include "../textsvcs.h"
#elif defined(_MACINTOSH)
#include "textsvcs.h"
#endif
#endif /* END: USE_FREETYPE_DIRECTLY. */


#if defined(_WINDOWS)
#include "../rtwin.h"
#elif defined(_MACINTOSH)
#include "rtwin.h"
#endif

#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE		
static char HX_THIS_FILE[] = __FILE__;
#endif

#if defined(_DEBUG)
// /#define XXXEH_TESTING_DATAURLPLAINTEXT_HANDLING2
#endif


COLORREF convertCOLORTYPEtoWinBGRColor(
	COLORTYPE RGBVal)
{
    COLORREF winColor = 0L;
    RED_GREEN_OR_BLUE red, green, blue;
    red = (RED_GREEN_OR_BLUE)(RGBVal>>16); //red is bytes 4,5
    green = (RED_GREEN_OR_BLUE)(RGBVal>>8); //green is 2,3
    blue = (RED_GREEN_OR_BLUE)RGBVal; //and blue is bytes 0,1
    winColor = (COLORREF)red | (COLORREF(green)<<8) | 
	    (COLORREF(blue)<<16); 
    return winColor;
}


/////////////////////////////////////////////////////////////////////////////
// Function:
//  BOOL
//  OnPaint
//  (
//	TextWindow* pTextWindow,
//	void* pDC,
//	void* pPaintstruct,
//	ULONG32 ulTimeOfCurrentDraw
//  )
//
// Purpose:
//  This function does the actual rendering of text by doing a TextOut() of
//  all text in all TextContainers in the TextContainerList of pTextWindow
//  whose text is visible in the rectangle to be updated
//  This Function is called from WM_PAINT and hdc and ps are from
//  BeginPaint(); ps holds the invalid rectangle to be updated: 
//
// Returns:
//  Returns FALSE on error, TRUE otherwise. 
//
BOOL OnPaint(TextWindow* pTextWindow, void* pVoid, void* pPaintstruct,
	ULONG32 ulTimeOfCurrentDraw,
	BOOL SomeonesBeginOrEndTimeWasCrossedOverSinceLastDraw,
	INT16 xScrollWindowAmt, INT16 yScrollWindowAmt)
{
    HX_ASSERT_VALID_PTR(pTextWindow);
    HX_ASSERT(pVoid);
    HX_ASSERT_VALID_PTR(pPaintstruct);
    if(!pTextWindow  ||  !pVoid  ||  !pPaintstruct
	    ||  !pTextWindow->m_hBitmap)
    {
	return FALSE;
    }

    // Initialize chromaKey flag. If the background
    // color is the same as the chroma key, then we 
    // know we are applying the chroma key. Also, when
    // we draw text of a certain color later down in
    // this method, we may be setting this flag, depending
    // on the text color.
    BOOL bChromaKeyWasApplied = FALSE;
    if (pTextWindow->isChromaKeySet())
    {
        if (DoesChromaKeyMatch(pTextWindow->getBackgroundColor(),
                               pTextWindow->getChromaKey(),
                               pTextWindow->getChromaKeyTolerance()))
        {
            if (pTextWindow->getChromaKeyOpacity() < 255)
            {
                bChromaKeyWasApplied = TRUE;
            }
        }
    }

    LONG32 lWindowWidth = pTextWindow->getWindowWidth();
    LONG32 lWindowHeight = pTextWindow->getWindowHeight();

    
    PAINTSTRUCT ps = *((PAINTSTRUCT*)pPaintstruct);
#if !defined(USE_DIB_SECTION)
    HBITMAP hbmpOld;
#endif
    BOOL b_FunctionSucceeded = TRUE;
    RECT updateRect = ps.rcPaint;
    //Due to window-offset-in-layout problem,
    // we need to translate the rect by the upperleftX,Y of pTextWindow:
    updateRect.left -= pTextWindow->getUpperLeftX();
    updateRect.top -= pTextWindow->getUpperLeftY();

    ULONG32 listSize = pTextWindow->textCntnrListSize();
    
    if(!pTextWindow->m_pDeviceContextMemory)
    {
	return FALSE;	
    }

    HDC	hDC = (HDC)pTextWindow->m_pDeviceContextMemory;

#if !defined(USE_DIB_SECTION)
    hbmpOld = (HBITMAP)SelectObject(hDC,
	    (HBITMAP)pTextWindow->m_pBmpCompat);
    if(!hbmpOld)
    {
	return FALSE;
    }
#endif

    BOOL bDoingScrollOfRect = FALSE;
    if(!SomeonesBeginOrEndTimeWasCrossedOverSinceLastDraw  &&
	    (xScrollWindowAmt>0  ||  yScrollWindowAmt>0)
	    //XXXEH- no CPU-friendly diagonal motion, yet, due to
	    // strange behavior in drawing in rtwin with lImageOffset
	    // not being calculated to take into account the extra
	    // width bytes:
	    &&  !(xScrollWindowAmt>0  &&  yScrollWindowAmt>0))
    {
#if defined(SCROLLINGVERSION_SCROLLDC)
	RECT rectScroll;
	RECT rectClip;
	rectScroll.left = 0;
	rectScroll.top = 0;
	rectScroll.right = lWindowWidth +
		(xScrollWindowAmt>0? lWindowWidth/2 : 0);
	//FONT_SIZE_PLUS4 is max height of new char, so no
	// need to scroll beyond since nothing will have been
	// drawn beyond yet:
	rectScroll.bottom = lWindowHeight + FONT_SIZE_PLUS4;
	rectClip.left = 0;
	rectClip.top = 0;
	rectClip.right = lWindowWidth +
		(xScrollWindowAmt>0? lWindowWidth/2 : 0);
	rectClip.bottom = lWindowHeight + FONT_SIZE_PLUS4;
	ScrollDC(hDC,
		-xScrollWindowAmt, -yScrollWindowAmt,
		&rectScroll, &rectClip, NULL, NULL);
#endif
	bDoingScrollOfRect = TRUE;
    }

#if defined(XXXEH_TESTING_DATAURLPLAINTEXT_HANDLING2)
FILE* f1 = ::fopen("c:\\LogDataURLhandling.txt", "a+");
::fprintf(f1, "Draw(), just before PaintBackground (listsize=%lu)\n", listSize);
::fclose(f1);
#endif

    if(!bDoingScrollOfRect  &&
	    !PaintBackground(pTextWindow, pPaintstruct))
    {
#if !defined(USE_DIB_SECTION)
	SelectObject(hDC, hbmpOld);
#endif
	return FALSE;
    }
    

#if defined (USE_FREETYPE_DIRECTLY)
/* XXXEH- moved the following block (up to "END XXXEH-0") for cross-plat use
 *  vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv *

    // /Moved this code up from under the below while loop so we can pass pBits
    // to ApplyTextOpacity() instead of doing the same code over and over
    // inside ApplyTextOpacity(); that'll make ApplyTextOpacity() be cross-
    // platform, as well (and it can be moved out so all plats can use it):
#if !defined(USE_DIB_SECTION)
    // retreive the bitmap handler
    HBITMAP hBM = (HBITMAP)SelectObject(hDC, hbmpOld);
#endif /* !USE_DIB_SECTION. */

    UCHAR*  pBits = NULL;
    LPBITMAPINFOHEADER pHeader = NULL;

    CHXxRect* pDestRect = (CHXxRect*)((HXxEvent*)pVoid)->param2;

    CHXxRect srcRect(0, 0, lWindowWidth, lWindowHeight);
    CHXxRect destRect;
    
    LONG32 lImageOffset = 0L;

    LONG32 lSavedHeaderHeight = -1;


#if !defined(USE_DIB_SECTION)
    // convert HBITMAP to DIB:
    if (pTextWindow->m_hDIB &&
	HXR_OK == pTextWindow->m_hDIB->GetDIBits(hDC, hBM, pBits, pHeader))
    {				    
#else //USE_DIB_SECTION:
    //we already have a DIB, so use it:
    if(pTextWindow->m_pBits)
    {
	pBits = (UCHAR*)(pTextWindow->m_pBits);
	pHeader = &(pTextWindow->m_BITMAPINFOHEADER);
#endif /* USE_ else !USE_ DIB_SECTION. */

#if defined(SCROLLINGVERSION_SCROLL_BY_MOVING_WINDOW)
	if(bDoingScrollOfRect)
	{
	    if(xScrollWindowAmt>0)
	    {
		srcRect.left += xScrollWindowAmt;
		srcRect.right += xScrollWindowAmt;
	    }
	    if(yScrollWindowAmt>0)
	    {
		//Note: we have to subtract, not add, because DIB's origin is
		// bottom left, not top left:
		srcRect.top += yScrollWindowAmt;
		srcRect.bottom += yScrollWindowAmt;
	    }
	}

	//Keep the offscreen height so we can reset it after doing the Blt():
	lSavedHeaderHeight = pHeader->biHeight;
	//If we're just using part of a larger offscreen area, then we need to
	// send an offset into the buffer that accounts for the extra vertical
	// lines of data (which, in Windows, byte 0 of the data is the first
	// byte of the LAST scan line, i.e., starts line # pBitmapInfo->biHeight):
	if(pHeader->biHeight != srcRect.Height())
	{
	    lImageOffset =
		    (pHeader->biHeight - srcRect.Height() - srcRect.top) *
		    (pHeader->biBitCount / 8) * pHeader->biWidth;
	    if(lImageOffset > 0L)
	    {
		if(srcRect.top != 0)
		    srcRect.bottom -= srcRect.top;
		srcRect.top = 0;
		pHeader->biHeight = srcRect.Height();
		pHeader->biSizeImage = WIDTHBYTES((pHeader->biWidth * 
			pHeader->biBitCount) * pHeader->biHeight);
	    }
	    else
	    {
		lImageOffset = 0L;
	    }
	}
#endif /* SCROLLINGVERSION_SCROLL_BY_MOVING_WINDOW. */

	if (pDestRect)
	{
	    destRect.SetRect(pDestRect->left, 
			     pDestRect->top, 
			     pDestRect->right,
			     pDestRect->bottom);
	}
	else
	{
	    destRect.SetRect(0,
			     0,
			     lWindowWidth, 
			     lWindowHeight);
	}

/* END XXXEH-0. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
#endif /* USE_FREETYPE_DIRECTLY. */




    if(!bDoingScrollOfRect  &&  listSize  &&
	    (TIME_INVALID != ulTimeOfCurrentDraw) )
    {

	LISTPOSITION pos = pTextWindow->GetStartPosition();

#if defined(XXXEH_TESTING_DATAURLPLAINTEXT_HANDLING2)
FILE* f1 = ::fopen("c:\\LogDataURLhandling.txt", "a+");
::fprintf(f1, "\tDraw(): about to draw %lu TextContainers; pos=%p\n", listSize, pos);
::fclose(f1);
#endif

	//We must adjust for where the virtual window location is due to
	// looping:
	LONG32 currentXOffsetDueToLooping = 0L;
	LONG32 currentYOffsetDueToLooping = 0L;
	if(pTextWindow->isLooping())
	{
	    currentXOffsetDueToLooping =
		    pTextWindow->getCurrentXOffsetDueToLooping();
	    currentYOffsetDueToLooping =
		    pTextWindow->getCurrentYOffsetDueToLooping();
	}

	BOOL bWindowHeightIsNotTheOriginalValue = 
		lWindowHeight != pTextWindow->getHeight();
	BOOL bWindowWidthIsNotTheOriginalValue =
		lWindowWidth != pTextWindow->getWidth();

	//We must adjust for where the virtual window location is due to
	// "teleprompter" adjustment so that the last line of text is visible
	// at the bottom edge of the window:
	LONG32 currentYOffsetForTeleprompter = 0L;
	if(TYPE_TELEPROMPTER == pTextWindow->getType())
	{
	    currentYOffsetForTeleprompter =
		    pTextWindow->getCurrentYOffsetForTeleprompter();
	}

	int bkModeOld;
	bkModeOld = SetBkMode(hDC, TRANSPARENT);

#if defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
	CTextServices crossPlatTextSvcs;
#endif /* END USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

	while(pos)
	{
	    TextContainer* curTextContainerPtr =
			    /*  Note: effectively does GetAt(pos++):  */
			    (TextContainer*)pTextWindow->GetNext(pos);

	    ///Added call to the new function 
	    ///	"::textShouldBeDrawn()" because textHasChanged..() was
	    ///	not enough -- repaint of background was overwriting
	    /// non-moved text:

	    if(curTextContainerPtr->textHasChangedSinceLastDraw()  ||
		    curTextContainerPtr->textShouldBeDrawn())
	    {
		LONG32 lUpperLeftXWithOffsets =
			currentXOffsetDueToLooping +
			curTextContainerPtr->getXUpperLeftCorner();
		LONG32 lLowerRightXWithOffsets =
			currentXOffsetDueToLooping +
			curTextContainerPtr->getXLowerRightCorner();
		LONG32 lUpperLeftYWithOffsets =
			currentYOffsetDueToLooping +
			currentYOffsetForTeleprompter +
			curTextContainerPtr->getYUpperLeftCorner();
		LONG32 lLowerRightYWithOffsets =
			currentYOffsetDueToLooping +
			currentYOffsetForTeleprompter +
			curTextContainerPtr->getYLowerRightCorner();

		LONG32 xScaled  = lUpperLeftXWithOffsets;

		LONG32 yScaled = lUpperLeftYWithOffsets;

		LONG32 lScaledUpperLeftXWithOffsets =
			lUpperLeftXWithOffsets;
		LONG32 lScaledLowerRightXWithOffsets =
			lLowerRightXWithOffsets;
		LONG32 lScaledUpperLeftYWithOffsets =
			lUpperLeftYWithOffsets;
		LONG32 lScaledLowerRightYWithOffsets =
			lLowerRightYWithOffsets;

		if (bWindowWidthIsNotTheOriginalValue)
		{
		    xScaled  = MulDiv(xScaled,  
				    lWindowWidth,  
				    pTextWindow->getWidth());
		    lScaledUpperLeftXWithOffsets = MulDiv(
				    lUpperLeftXWithOffsets,
				    lWindowWidth,  
				    pTextWindow->getWidth());
		    lScaledLowerRightXWithOffsets = MulDiv(
				    lLowerRightXWithOffsets,
				    lWindowWidth,  
				    pTextWindow->getWidth());
		}
		if (bWindowHeightIsNotTheOriginalValue)
		{
		    yScaled = MulDiv(yScaled, 
				    lWindowHeight, 
				    pTextWindow->getHeight());
		    lScaledUpperLeftYWithOffsets = MulDiv(
				    lUpperLeftYWithOffsets,
				    lWindowHeight,  
				    pTextWindow->getHeight());
		    lScaledLowerRightYWithOffsets = MulDiv(
				    lLowerRightYWithOffsets,
				    lWindowHeight,  
				    pTextWindow->getHeight());
		}

		///Make sure curTextContainerPtr's text is located in the
		///window before we go to the trouble of doing a TextOut:
		if(	    (lScaledUpperLeftXWithOffsets
			    > updateRect.right) 
			||  (lScaledLowerRightXWithOffsets
			    < updateRect.left)
			||  (lScaledUpperLeftYWithOffsets
			    > updateRect.bottom) 
			||  (lScaledLowerRightYWithOffsets
			    < updateRect.top) )
		{
		    continue; //text doesn't overlap the window.
		}
		//If updateRect is in stretched coordinates, then the above
		// check won't find everyone who is outside the window, so
		// let's make sure we do here:
		if (bWindowHeightIsNotTheOriginalValue)
		{
		    if(yScaled > updateRect.bottom)
			continue; //It's outside the window
		}
		if (bWindowWidthIsNotTheOriginalValue)
		{
		    if(xScaled > updateRect.right)
			continue; //It's outside the window
		}

		//Since OnTimeSync()/OnTimeSynch() may not yet have been
		//called, we need to time-bounds check:
		//XXXEH- revisit this; don't do this every time for every T.C.,
		// but instead just keep track of whether or not OnTimeSynch()
		// has been called yet or not (...???):
		//First, if we're live, we need to compare times keeping
		// ULONG32-wrap-around in mind:
		BOOL bBeginTimeIsMoreRecentThanCurTime =
			IsTimeAMoreRecentThanTimeB(
			curTextContainerPtr->getBeginTime(),
			ulTimeOfCurrentDraw,
			pTextWindow->isLiveSource());
		BOOL bCurTimeIsMoreRecentThanEndTime =
			IsTimeAMoreRecentThanTimeB(
			ulTimeOfCurrentDraw,
			curTextContainerPtr->getEndTime(),
			pTextWindow->isLiveSource());
		//Sanity check:
		if(TIME_INVALID == curTextContainerPtr->getEndTime())
		{
		    HX_ASSERT(!bCurTimeIsMoreRecentThanEndTime);
		}
		if(bBeginTimeIsMoreRecentThanCurTime  ||
			bCurTimeIsMoreRecentThanEndTime)
		{
		    continue;
		}
		
		
#if defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
		/* encoding.  Pre-defined values are:
		* ft_encoding_symbol, ft_encoding_unicode,
		* ft_encoding_latin_2, ft_encoding_sjis,
		* ft_encoding_gb2312, ft_encoding_big5,
		* ft_encoding_wansung (Hangeul(?) A.K.A. ksc5601),
		* ft_encoding_johab, ft_encoding_apple_roman
		*/
		FT_Encoding ftCharsetEncoding = ft_encoding_none;
#endif /* USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

#if !defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
		HFONT hfont, hfontOld;
#endif /* !USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

		DWORD fdwCharset = ANSI_CHARSET;
		ULONG32 ulCharset = curTextContainerPtr->getFontCharset();
		if(ulCharset & HX_WEST_EUROPE_CHARSET)
		{
		    fdwCharset = ANSI_CHARSET;
#if defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
		    ftCharsetEncoding = ft_encoding_none;
#endif /* !USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
		}
		else if(ulCharset & HX_JAPANESE_CHARSET)
		{
		    fdwCharset = SHIFTJIS_CHARSET;
#if defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
		    ftCharsetEncoding = ft_encoding_sjis;
#endif /* !USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
		}
		else if(ulCharset & HX_KOREAN_CHARSET)
		{
		    fdwCharset = HANGEUL_CHARSET;
#if defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
		    ftCharsetEncoding = ft_encoding_wansung; // /==Hangeul=ksc5601?
#endif /* !USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
		}
		else if(ulCharset & HX_CHINESE_CHARSET)
		{
		    //Note: there are two charsets for 2312, namely
		    // CHARSET__gb_2312 and CHARSET__gb_2312_80, but Windows
		    // doesn't know about the _80 one, so treat them both as
		    // GB2312_CHARSET.
		    fdwCharset = GB2312_CHARSET; 
#if defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
		    ftCharsetEncoding = ft_encoding_gb2312;
#endif /* !USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
		    if(ulCharset == CHARSET__big5)
		    {
			fdwCharset = CHINESEBIG5_CHARSET;
#if defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
			ftCharsetEncoding = ft_encoding_big5;
#endif /* !USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
		    }
		} 
		/* XXXXXEH- don't do this yet; there's no point in defaulting
		 * to the default charset for this computer because RT requires
		 * you to specify a font face otherwise it uses "times"
		else
		{
		    fdwCharset = OEM_CHARSET;
		}
		*/

		ULONG32 ulFontFaceIndex =
			curTextContainerPtr->getFontFace();
		ULONG32 ulFontPointSize =
			curTextContainerPtr->getFontPointSize();
		BOOL bIsBold =
			curTextContainerPtr->isBold();
		BOOL bIsItalicized =
			curTextContainerPtr->isItalicized();

		//Create the appropriate font for this block of text:

		// XXXBHG -  Support for font scaling in 2x and FS mode
		LONG32 ulScaledHeight = ulFontPointSize;
		LONG32 ulScaledWidth  = 0;

		_CHAR* pCurFontFaceString =
			(_CHAR*)curTextContainerPtr->getFontFaceString(
			pTextWindow->getMajorContentVersion(),
			pTextWindow->getMinorContentVersion());

#if !defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
		// if we're not at 1x mode, then create a temporary 1x font
		// to determine it's average width, we'll use this to ask
		// for the right average width in 2x and FS modes
		if (bWindowHeightIsNotTheOriginalValue)
		{
		    HFONT htempfont = CreateFont(
			    ulFontPointSize, //logical ht 
			    0, // logical average character width 
			    0, // angle of escapement 
			    0, //base-line orientation angle (==escapement Win95)
			    (bIsBold?FW_BOLD:FW_NORMAL),
			    bIsItalicized,//italic flag
			    //Do underlining manually now (due to
			    // possible gaps if alternate font has to be
			    // used and forced spacing is not quite as os
			    // calculates it:
			    FALSE,
			    curTextContainerPtr->isStruckOut(),//strikeout flag
			    fdwCharset,
			    OUT_DEFAULT_PRECIS,	// output precision 
			    CLIP_DEFAULT_PRECIS,// clipping precision 
			    DEFAULT_QUALITY,// output quality 
			    DEFAULT_PITCH|FF_DONTCARE,// pitch and family
			    (char*)pCurFontFaceString
			    );

		    LOGFONT logfont;
		    GetObject(htempfont,sizeof(logfont),&logfont);
		    DeleteObject(htempfont);

		    ulScaledHeight = MulDiv(logfont.lfHeight, lWindowHeight,
			    pTextWindow->getHeight());
		    ulScaledWidth  = MulDiv(logfont.lfWidth,  lWindowWidth,
			    pTextWindow->getWidth() );
		}

		hfont = CreateFont(
			(INT32)ulScaledHeight, //logical ht 
			(INT32)ulScaledWidth, // logical average character width 
			0, // angle of escapement 
			0, //base-line orientation angle (==escapement Win95)
			(bIsBold?FW_BOLD:FW_NORMAL),
			bIsItalicized,//italic flag
			//Do underlining manually now (due to
			// possible gaps if alternate font has to be
			// used and forced spacing is not quite as os
			// calculates it:
			FALSE,
			//Do strike-through manually now (due to
			// possible gaps if alternate font has to be
			// used and forced spacing is not quite as os
			// calculates it:
			FALSE, //curTextContainerPtr->isStruckOut(),
			fdwCharset,
			OUT_DEFAULT_PRECIS,	// output precision 
			CLIP_DEFAULT_PRECIS,// clipping precision 
			DEFAULT_QUALITY,// output quality 
			DEFAULT_PITCH|FF_DONTCARE,// pitch and family
			(char*)pCurFontFaceString
			);



		if(!hfont)
		{
#if !defined(USE_DIB_SECTION)
		    SelectObject(hDC, hbmpOld);
#endif
		    return FALSE;
		}

		hfontOld = (HFONT)SelectObject(hDC, hfont);
		if(!hfontOld)
		{
#if !defined(USE_DIB_SECTION)
		    SelectObject(hDC, hbmpOld);
#endif
		    DeleteObject(hfont);
		    return FALSE;
		}
#endif /* !USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

		COLORTYPE textColor, textColorOld;
		COLORTYPE bgTextColor;
		textColor = curTextContainerPtr->getTextColor();
		if(TYPE_TICKERTAPE == pTextWindow->getType())
		{
		    textColor =curTextContainerPtr->getTickertapeTextColor();
		}
		textColorOld = SetTextColor(
			hDC, convertCOLORTYPEtoWinBGRColor(textColor) );
		if(CLR_INVALID == textColorOld)
		{
#if !defined(USE_DIB_SECTION)
		    SelectObject(hDC, hbmpOld);
#endif
#if !defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
		    DeleteObject(hfont);
#endif /* USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
		    return FALSE;
		}

		bgTextColor = curTextContainerPtr->getTextBackgroundColor();

		_CHAR* pTextbuffer = curTextContainerPtr->getBuffer();
		ULONG32 ulTextLengthPlusOneOfCurTC =
			curTextContainerPtr->getTextLengthPlus1();

		char tmpString[4]; /* Flawfinder: ignore */  //[0] holds char to be drawn (or [0] and
				    // [1] do if DBCS), and [1] (or [2] if 
				    // 2-byte char) holds '\0';
		tmpString[1] = tmpString[2] = tmpString[3] = '\0';
		INT16 tmpStringLen = 0;

#if defined(XXXEH_TESTING_DATAURLPLAINTEXT_HANDLING2)
FILE* f1 = ::fopen("c:\\LogDataURLhandling.txt", "a+");
::fprintf(f1, "\tDraw(): pTextBuffer={{{%s}}}\n", pTextbuffer);
::fclose(f1);
#endif

		if(pTextbuffer  &&  ulTextLengthPlusOneOfCurTC > 1)
		{
#if 0
UINT prevAlignment = 
	SetTextAlign(hDC, VTA_BASELINE);
#endif

		    //if bgcolor is not transparent, and/or if isUnderlined
		    // is TRUE, draw a rect (or line for underline) manually
		    // behind the entire text rather than letting textout do
		    // it for each letter (which is slower and sometimes leaves
		    // gaps if the letter spacing is slightly different than
		    // the os would natively space it:
		    if((BAD_RGB_COLOR != bgTextColor  &&
			    TRANSPARENT_COLOR != bgTextColor)  ||
			    curTextContainerPtr->isUnderlined()  ||
			    curTextContainerPtr->isStruckOut())
		    {
			LONG32 yLowerRightScaled =
				lScaledLowerRightYWithOffsets;

			RECT updateRect;
			updateRect.left = xScaled;
			//Fix for bug 6527; when double sized, we want to
			// double the padding on the right edge.  This
			// "padding" (which used to be +1 always) is
			// necessary when drawing a rect in Windows because
			// PaintRectangle draws up to, but not including,
			// the right edge:
			LONG32 additionalWidth = 1;
			if(lLowerRightYWithOffsets != 0) //avoid div by 0.
			{
			    additionalWidth =
				yLowerRightScaled /
				lLowerRightYWithOffsets;
			}
			if(additionalWidth < 1)
			{
			    additionalWidth=1;
			}
			updateRect.right =
				lScaledLowerRightXWithOffsets + additionalWidth;
			if(BAD_RGB_COLOR != bgTextColor  &&
				TRANSPARENT_COLOR != bgTextColor)
			{
			    updateRect.top = yScaled;
			    updateRect.bottom = yLowerRightScaled+1;
			    PaintRectangle(pTextWindow, updateRect,
				    (COLORREF)bgTextColor,
                                    pTextWindow->getMediaOpacity());
			}
			//Do underlining manually now (due to
			// possible gaps if alternate font has to be
			// used and forced spacing is not quite as os
			// calculates it):
			if(curTextContainerPtr->isUnderlined())
			{
			    INT32 thickness =
				    (yLowerRightScaled - yScaled) / 12;
			    if(thickness < 1)
			    {
				thickness = 1;
			    }
			    if(bIsBold)
			    {
				thickness += (thickness/2);
			    }
			    updateRect.top = yLowerRightScaled-thickness+1;
			    updateRect.bottom = yLowerRightScaled+1;
			    //Draw the underline:
			    PaintRectangle(pTextWindow, updateRect,
				    (COLORREF)textColor,
                                    pTextWindow->getMediaOpacity());
			}
			//Do strike-through manually now (due to
			// possible gaps if alternate font has to be
			// used and forced spacing is not quite as os
			// calculates it):
			if(curTextContainerPtr->isStruckOut())
			{
			    INT32 thickness =
				    (yLowerRightScaled - yScaled) / 18;
			    if(thickness < 1)
			    {
				thickness = 1;
			    }
			    updateRect.top =
				    yScaled +
				    ((yLowerRightScaled - yScaled) / 2) + 1;
			    updateRect.bottom = updateRect.top + thickness;
			    //Draw the underline:
			    PaintRectangle(pTextWindow, updateRect,
				    (COLORREF)textColor,
                                    pTextWindow->getMediaOpacity());
			}
		    }


		    LONG32 ulXTotalCharsOffset = 0L;
		    BOOL bUseSameFontAsForLastChar = FALSE;
		    do //draw each character @ offset in x from the first:
		    {
			_CHAR ch = *pTextbuffer;
			UINT16 usCh = ch;
			tmpString[0] = ch;
			tmpStringLen = 1;
			if (HX_DBCS_CHARSET & ulCharset  ||
				HX_UNICODE_CHARSET & ulCharset)
			{
			    if (HX_UNICODE_CHARSET & ulCharset  ||
				    (UCHAR)ch >= DBCS_MIN_LEAD_BYTE_VAL)
			    {   //then ch is lead byte of a 2-byte char.
				pTextbuffer++;
				ch = *pTextbuffer;
				tmpString[tmpStringLen] = ch; //==trail byte.
				tmpStringLen++; //is a 2-byte char.
#if defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(_MACINTOSH)
// /XXXEH- need to look at possible big-VS-little-endian problem with this:
#endif
#endif /* USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
				usCh <<= 8; //move lead byte into high byte.
				usCh |= ch; //put trail byte into low byte.
			    }
			}
			//XXXEH- test this DBCS stuff^^!!!

			//Now move in x by the amount that the
			// cross-platform (uniform) table says is the
			// width of this char:
			ULONG32 ulLookupCharWidth =
				GetCharacterWidth(usCh, ulFontFaceIndex,
				ulFontPointSize, bIsBold, bIsItalicized,
				ulCharset);
			if(bWindowWidthIsNotTheOriginalValue)
			{
			    ulLookupCharWidth = MulDiv(ulLookupCharWidth,  
					    lWindowWidth,  
					    pTextWindow->getWidth());
			}

			//However, we want to horizontally center the
			// character inside its bounding box in case its
			// native width is noticably different from its
			// cross-platform-table-assigned width:
			LONG32 lXPlatWidth = (LONG32)ulLookupCharWidth;
			SIZE charsize;
			BOOL bGtepSucceeded =
#if defined(_WIN16)
				//Docs say this has an off-by-one error,
				// but that shouldn't be a big deal
				// (especially if we never release a Win16
				// client ;-)
				GetTextExtentPoint(
#else
				GetTextExtentPoint32(
#endif
				    hDC, tmpString, tmpStringLen, &charsize);

			LONG32 lCrossPlatVsNativeWidthOffset = 0L;
			LONG32 lNativeWidth = charsize.cx;
			if(bGtepSucceeded  &&
				lXPlatWidth != lNativeWidth)
			{
			    //Note: we should not adjust lNativeWidth if
			    // bWindowWidthIsNotTheOriginalValue because
			    // that's already been accounted for in hDC's
			    // font point size.

			    //Note: this can be negative!:
			    lCrossPlatVsNativeWidthOffset =
				    (lXPlatWidth-lNativeWidth)/2;
			}

                        INT32 lXStart = xScaled +
					lCrossPlatVsNativeWidthOffset +
					ulXTotalCharsOffset;
                        INT32 lYStart = yScaled;

#if defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/

			// /XXXEH- add this option to RT-file's header (or
			// maybe user's player pref?):
			BOOL bDoAntialias = TRUE;

			tmpString[tmpStringLen] = '\0'; // /Ensure NULL terminated.
			LONG32 lOffscreenDepth = pHeader->biBitCount; // /XXXEH- check this!
#define XXXEH_FUDGE_SCALE_FACTOR .9  /* FreeType renders at about .9x what Windows does. */
#define XXXEH_ENABLE_X_INDEPENDENT_SCALING
			// /Fixes CROSSPLAT-TEXT-BUG-0005; offscreen bitmap's width is
			// always divisible by 4:
			INT32 lRectWidthAdjustedToDivBy4 = srcRect.Width();
			lRectWidthAdjustedToDivBy4 +=
				(4 - (lRectWidthAdjustedToDivBy4 & 0x3)) & 0x3;
			HX_RESULT hxrRndrText = HXR_OK;

			if (!bUseSameFontAsForLastChar) // /Load new font:
			{
			    hxrRndrText =
				    crossPlatTextSvcs.renderText((const char*)tmpString,
				    pBits,
				    lRectWidthAdjustedToDivBy4, srcRect.Height(),
				    lOffscreenDepth,
				    lXStart, lYStart,
				    bDoAntialias,
				    ftCharsetEncoding,
				    (char*)pCurFontFaceString,
				    bIsBold,
				    bIsItalicized,				
#if defined(XXXEH_ENABLE_X_INDEPENDENT_SCALING)
				    // /XXXEH- indep. X-scaling = new functionality
				    // that wasn't possible in prior RealText due
				    // to OS-API drawing of chars.  This should be
				    // tested more than just by me, and should
				    // happen only with higher-versioned RT(?):
				    ulScaledWidth * XXXEH_FUDGE_SCALE_FACTOR, // logical average character width
#else
				    0,
#endif
				    ulScaledHeight * XXXEH_FUDGE_SCALE_FACTOR, //logical ht in pixels
				    textColor);
			}
			else // /Re-use same font face and bold ital attribs:
			{
			    hxrRndrText =
				    crossPlatTextSvcs.renderTextSameFontFace((const char*)tmpString,
				    pBits,
				    lRectWidthAdjustedToDivBy4, srcRect.Height(),
				    lOffscreenDepth,
				    lXStart, lYStart,
				    bDoAntialias,
				    ftCharsetEncoding,
#if defined(XXXEH_ENABLE_X_INDEPENDENT_SCALING)
				    // /XXXEH- indep. X-scaling = new functionality
				    ulScaledWidth * XXXEH_FUDGE_SCALE_FACTOR, // logical average character width
#else
				    0,
#endif
				    ulScaledHeight * XXXEH_FUDGE_SCALE_FACTOR, //logical ht in pixels
				    textColor);
			}
#else
			TextOut(hDC,
                                lXStart,
                                lYStart,
				tmpString,
				tmpStringLen); //only draw this 1-2 byte char

#if defined(XXXEH_TESTING_DATAURLPLAINTEXT_HANDLING2)
FILE* f1 = ::fopen("c:\\LogDataURLhandling.txt", "a+");
::fprintf(f1, "Draw(): just did TextOut(x=%ld, y=%ld, %c)", lXStart, lYStart, *tmpString);
::fclose(f1);
#endif

#endif /* USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

                        // The following code handles both media opacity
                        // and chroma key
                        BOOL bChromaMatch = FALSE;
                        if (pTextWindow->isChromaKeySet())
                        {
                            bChromaMatch = DoesChromaKeyMatch(textColor,
                                                              pTextWindow->getChromaKey(),
                                                              pTextWindow->getChromaKeyTolerance());
                        }
                        if (pTextWindow->getMediaOpacity() < 255 ||
                            (bChromaMatch && pTextWindow->getChromaKeyOpacity() < 255))
                        {
                            UINT32 ulOpacity = pTextWindow->getMediaOpacity();
                            if (bChromaMatch)
                            {
                                ulOpacity            = pTextWindow->getChromaKeyOpacity();
                                bChromaKeyWasApplied = TRUE;
                            }
                            ApplyTextOpacity(pTextWindow,
                                              lXStart, lYStart, charsize.cx, charsize.cy, TRUE,
                                              textColor, ulOpacity);
                        }

			ulXTotalCharsOffset += ulLookupCharWidth;

#if defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
			// /If rendering failed, try again with next char,
			// otherwise re-use same font:
			bUseSameFontAsForLastChar = (HXR_OK == hxrRndrText);
#endif /* USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
			
		    } while(*(++pTextbuffer));

#if 0
if(GDI_ERROR != prevAlignment)
{
    SetTextAlign(hDC, prevAlignment);
}
#endif
		}

#if !defined(USE_FREETYPE_DIRECTLY) /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
		/*  Restore the previous font:  */
		SelectObject(hDC, hfontOld);
		DeleteObject(hfont);
#endif /* USE_FREETYPE_DIRECTLY. */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

		/*  Restore the previous colors:  */
		SetTextColor(hDC, textColorOld);
/* XXXXXEH> no need to do this: (right?)
		SetBkColor(hDC, textColorOld); 
<XXXXXEH. */
		curTextContainerPtr->textHasChangedSinceLastDraw(FALSE);
	    } //end "if(curTextContainerPtr->textHasChangedSinceLastDraw())".
	} //end "while(pos)".

	SetBkMode(hDC, bkModeOld);
    } //end "if (!bDoing... listSize ...)".

#if !defined (USE_FREETYPE_DIRECTLY)
// / *  XXXEH-1 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv *
#if !defined(USE_DIB_SECTION)
    // retreive the bitmap handler
    HBITMAP hBM = (HBITMAP)SelectObject(hDC, hbmpOld);
#endif

    UCHAR*  pBits = NULL;
    LPBITMAPINFOHEADER pHeader = NULL;

#if !defined(USE_DIB_SECTION)
    // convert HBITMAP to DIB:
    if (pTextWindow->m_hDIB &&
	HXR_OK == pTextWindow->m_hDIB->GetDIBits(hDC, hBM, pBits, pHeader))
    {				    
#else //USE_DIB_SECTION:
    //we already have a DIB, so use it:
    if(pTextWindow->m_pBits)
    {
	pBits = (UCHAR*)(pTextWindow->m_pBits);
	pHeader = &(pTextWindow->m_BITMAPINFOHEADER);
#endif
	CHXxRect* pDestRect = (CHXxRect*)((HXxEvent*)pVoid)->param2;

	CHXxRect srcRect(0, 0, lWindowWidth, lWindowHeight);
	
	LONG32 lImageOffset = 0L;

#if defined(SCROLLINGVERSION_SCROLL_BY_MOVING_WINDOW)
	if(bDoingScrollOfRect)
	{
	    if(xScrollWindowAmt>0)
	    {
		srcRect.left += xScrollWindowAmt;
		srcRect.right += xScrollWindowAmt;
	    }
	    if(yScrollWindowAmt>0)
	    {
		//Note: we have to subtract, not add, because DIB's origin is
		// bottom left, not top left:
		srcRect.top += yScrollWindowAmt;
		srcRect.bottom += yScrollWindowAmt;
	    }
	}

	//Keep the offscreen height so we can reset it after doing the Blt():
	LONG32 lSavedHeaderHeight = pHeader->biHeight;
	//If we're just using part of a larger offscreen area, then we need to
	// send an offset into the buffer that accounts for the extra vertical
	// lines of data (which, in Windows, byte 0 of the data is the first
	// byte of the LAST scan line, i.e., starts line # pBitmapInfo->biHeight):
	if(pHeader->biHeight != srcRect.Height())
	{
	    lImageOffset =
		    (pHeader->biHeight - srcRect.Height() - srcRect.top) *
		    (pHeader->biBitCount / 8) * pHeader->biWidth;
	    if(lImageOffset > 0L)
	    {
		if(srcRect.top != 0)
		    srcRect.bottom -= srcRect.top;
		srcRect.top = 0;
		pHeader->biHeight = srcRect.Height();
		pHeader->biSizeImage = WIDTHBYTES((pHeader->biWidth * 
			pHeader->biBitCount) * pHeader->biHeight);
	    }
	    else
	    {
		lImageOffset = 0L;
	    }
	}
#endif

	CHXxRect destRect;

	if (pDestRect)
	{
	    destRect.SetRect(pDestRect->left, 
			     pDestRect->top, 
			     pDestRect->right,
			     pDestRect->bottom);
	}
	else
	{
	    destRect.SetRect(0,
			     0,
			     lWindowWidth, 
			     lWindowHeight);
	}

// /END XXXEH-1. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
#endif /* !(USE_FREETYPE_DIRECTLY). */

	IHXVideoSurface* pVideoSurface = (IHXVideoSurface*)((HXxEvent*)pVoid)->param1;
	pVideoSurface->AddRef();
	if(!pTextWindow->m_bHandlingWindowResizing
		&&  pTextWindow->m_hBitmap)//avoid race condition
				      // when re-allocating offscreen bitmap:
	{
#if defined(XXXMEH_BACKGROUND_NO_GDI) && defined(HANDLE_TRANSPARENT_WINDOW_BACKGROUND)
            DWORD oldComp = pHeader->biCompression;
            if (pTextWindow->getBackgroundOpacity() < 255 ||
                pTextWindow->getMediaOpacity() < 255 ||
                bChromaKeyWasApplied)
            {
                pHeader->biCompression = HX_ARGB;
            }
#endif
	    ((HXxEvent*)pVoid)->result = pVideoSurface->Blt(
		    pBits + lImageOffset,
		    (HXBitmapInfoHeader*)pHeader,
		    destRect, 
		    srcRect);
#if defined(XXXMEH_BACKGROUND_NO_GDI) && defined(HANDLE_TRANSPARENT_WINDOW_BACKGROUND)
            pHeader->biCompression = oldComp;
#endif
	}

#if defined(SCROLLINGVERSION_SCROLL_BY_MOVING_WINDOW)
	if (lSavedHeaderHeight > 0)
	{
	    pHeader->biHeight = lSavedHeaderHeight; //Restore it for the next time.
	}
#endif

	HX_RELEASE(pVideoSurface);
    }
    else
    {
	b_FunctionSucceeded = FALSE;
    }
    
    return b_FunctionSucceeded;
}



/////////////////////////////////////////////////////////////////////////////
// Function:
//  BOOL
//  PaintBackground
//  (
//  	TextWindow* pTextWindow,
//  	void* pPaintstruct
//  )
//
// Purpose:
//  This function paints the background of the window at the given rectangle
//  of pPaintstruct.
//  This Function is called from WM_PAINT, and pPaintstruct is (in Windows)
//  from  BeginPaint(); pPaintstruct holds the invalid rectangle to be
//  updated.
//
// Returns:
//  Returns FALSE on error, TRUE otherwise. 
//
BOOL PaintBackground(TextWindow* pTextWindow, void* pPaintstruct)
{
    HX_ASSERT_VALID_PTR(pTextWindow);
    HX_ASSERT_VALID_PTR(pPaintstruct);
    if(!pTextWindow  ||  !pPaintstruct)
    {
	return FALSE;
    }

    RECT updateRect = ((PAINTSTRUCT*)pPaintstruct)->rcPaint;

    // If backgroundOpacity is specified, then we will use it.
    // If backgroundOpacity is not specified, then we will
    // see if the chromaKey is specified. If it is, then
    // we will check if the background color is the same
    // as the chromakey. If it is, then we will use the
    // chromakey opacity for the background.
    UINT32 ulOpacity = pTextWindow->getBackgroundOpacity();
    if (pTextWindow->isChromaKeySet())
    {
        if (DoesChromaKeyMatch(pTextWindow->getBackgroundColor(),
                               pTextWindow->getChromaKey(),
                               pTextWindow->getChromaKeyTolerance()))
        {
            ulOpacity = pTextWindow->getChromaKeyOpacity();
        }
    }

    BOOL bIsPaintBackgroundCall = TRUE;
    return PaintRectangle(pTextWindow, updateRect,
	    (COLORREF)pTextWindow->getBackgroundColor(),
            ulOpacity, bIsPaintBackgroundCall);
}


BOOL PaintRectangle(TextWindow* pTextWindow, RECT& updateRect,
		    COLORREF rectColor, UINT32 ulOpacity,
		    BOOL bIsPaintBackgroundCall)
{
    HX_ASSERT_VALID_PTR(pTextWindow);
    if(!pTextWindow)
    {
	return FALSE;
    }

#if defined(XXXMEH_BACKGROUND_NO_GDI)
// The following code only works for 32bpp
#if defined(USE_16_BIT_COLOR_DEPTH)
#error Cannot define both XXXMEH_BACKGROUND_NO_GDI and USE_16_BIT_COLOR_DEPTH
#endif
    UCHAR*             pBits   = NULL;
    LPBITMAPINFOHEADER pHeader = NULL;
#if !defined(USE_DIB_SECTION)
    // convert HBITMAP to DIB:
    pTextWindow->m_hDIB->GetDIBits(hDC, hBM, pBits, pHeader);
#else
    //we already have a DIB, so use it:
    pBits   = (UCHAR*)(pTextWindow->m_pBits);
    pHeader = &(pTextWindow->m_BITMAPINFOHEADER);
#endif
    // Compute the color to copy
    UINT32* pulBits   = (UINT32*) pBits;
    UINT32  ulColor   = rectColor; // /Use rectColor! fixes PR 56578.
    if (ulOpacity > 255) ulOpacity = 255;
    UINT32  ulAlpha   = 255 - ulOpacity;
    UINT32  ulColorA  = (ulColor & 0x00FFFFFF) |
                        (ulAlpha << 24);

    RECT updateRectAdjustedForTopDown;
    updateRectAdjustedForTopDown.left = updateRect.left;
    updateRectAdjustedForTopDown.right = updateRect.right;

    // /Fixes PR 62883: if left is less than 0 (as can happen with underlined
    // text in a crawling (horizontally-scrolling) window, then clip it at 0
    // so we don't try to draw beyond the bounds of the offscreen bitmap:
    if (updateRectAdjustedForTopDown.left < 0)
    {
	updateRectAdjustedForTopDown.left = 0;
    }
    // /If right is less than left, then there's nothing to draw:
    if (updateRectAdjustedForTopDown.right < updateRectAdjustedForTopDown.left)
    {
	return FALSE;
    }

    // /Inverting these fixes PR 56577.  In Windows, the bitmap is inverted
    // so we need to draw top-down instead of bottom up otherwise underlines,
    // strike-throughs, and font bgcolor rects will get drawn inverted in y.
    // The bonus side-effect of this fix is that it also fixes PR 54635,
    // where the entire window's background was not drawing at lines 0 to n
    // if 0<n<4 and where n is the difference between the actual 4-pixel-aligned
    // width of the DIB and the calculated window width and height.
    updateRectAdjustedForTopDown.bottom =
	    (UINT32)pHeader->biHeight - updateRect.top;
    updateRectAdjustedForTopDown.top =
	    (UINT32)pHeader->biHeight - updateRect.bottom;

    // /Fixes PR 56145: if updateRect.right is out of bounds (beyond the
    // pHeader's biWidth), then don't count on that being clipped by the
    // OS.  Just reduce it to pHeader->biWidth here to prevent accessing
    // beyond the buffer.  (The old GDI call used to clip the rect which
    // is why RT didn't used to crash when the text string bounding box
    // extended beyond the width of the offscreen area):
    if ((UINT32)updateRectAdjustedForTopDown.right > (UINT32)pHeader->biWidth)
    {
	updateRectAdjustedForTopDown.right = pHeader->biWidth;
    }
    // /Do same fix for vertical:
    if ((UINT32)updateRectAdjustedForTopDown.bottom > (UINT32)pHeader->biHeight)
    {
	updateRectAdjustedForTopDown.bottom = pHeader->biHeight;
    }

    // /Fixes part 2 of PR 54635: if this is a paintBackground rect call,
    // then we need to paint into the 0 to 3 extra 4-byte-aligned pixels
    // width-wise.  (Part 1 of PR 54635 is a height-only problem):
    if (bIsPaintBackgroundCall)
    {
	INT32 lDiff = pHeader->biWidth - updateRectAdjustedForTopDown.right;
	if (0 < lDiff  &&  lDiff < 4)
	{
	    updateRectAdjustedForTopDown.right = pHeader->biWidth;
	}
    }
    
    // Copy the color 32bits at a time
    UINT32  ulWidth = (UINT32) pHeader->biWidth;
    UINT32  ulX     = (UINT32) updateRectAdjustedForTopDown.left;
    UINT32  ulNumX  = (UINT32) updateRectAdjustedForTopDown.right -
	    updateRectAdjustedForTopDown.left;
    for (UINT32 ulY = (UINT32) updateRectAdjustedForTopDown.top;
	    ulY < (UINT32) updateRectAdjustedForTopDown.bottom;
	    ulY++)
    {
        UINT32* pPix  = pulBits + ulY * ulWidth + ulX;
        UINT32  ulNum = ulNumX;
        while (ulNum--)
        {
            *pPix++ = ulColorA;
        }
    }
#else
    HBRUSH hBrush, hBrushOld;
    LOGBRUSH logBrush;

#if defined (HANDLE_TRANSPARENT_WINDOW_BACKGROUND)
    ULONG32 ulAlpha = 0xFF000000 & rectColor;
    if (BAD_RGB_COLOR == rectColor)
    {
	ulAlpha = 0;
    }
#endif

    logBrush.lbStyle = BS_SOLID;
    logBrush.lbColor = convertCOLORTYPEtoWinBGRColor(rectColor);

#if defined (HANDLE_TRANSPARENT_WINDOW_BACKGROUND)
    logBrush.lbColor |= ulAlpha;
#endif

    hBrush = CreateBrushIndirect(&logBrush);
    if(!hBrush)
    {
	return FALSE;
    }

    hBrushOld = (HBRUSH)SelectObject(
	    (HDC)pTextWindow->m_pDeviceContextMemory,
	    hBrush);
    if(!hBrushOld)
    {
	DeleteObject(hBrush);
	return FALSE;
    }

    //Added this so black edge is not drawn around window:
    HPEN hPen, hPenOld;
    LOGPEN logPen;
    logPen.lopnStyle = PS_NULL;
    hPen = CreatePenIndirect(&logPen);
    if(!hPen)
    {
	return FALSE;
    }

    hPenOld = (HPEN)SelectObject(
	    (HDC)pTextWindow->m_pDeviceContextMemory,
	    hPen);
    if(!hPenOld)
    {
	DeleteObject(hPen);
	return FALSE;
    }

    Rectangle((HDC)pTextWindow->m_pDeviceContextMemory, 
	    updateRect.left,updateRect.top,
	    updateRect.right+1, updateRect.bottom+1);

    SelectObject((HDC)pTextWindow->m_pDeviceContextMemory,
	    hBrushOld);

    DeleteObject(hBrush);

    SelectObject((HDC)pTextWindow->m_pDeviceContextMemory,
	    hPenOld);
    DeleteObject(hPen);
#endif

    return TRUE;
}

BOOL ApplyTextOpacity(TextWindow* pTextWindow,
                      INT32       lX,
                      INT32       lY,
                      INT32       lW,
                      INT32       lH,
                      BOOL        bRowsInverted,
                      UINT32      ulColor,
                      UINT32      ulOpacity)
{
    BOOL bRet = TRUE;

#if defined(XXXMEH_BACKGROUND_NO_GDI)
#if defined(USE_16_BIT_COLOR_DEPTH)
#error Cannot define both XXXMEH_BACKGROUND_NO_GDI and USE_16_BIT_COLOR_DEPTH
#endif
    UCHAR*             pBits   = NULL;
    LPBITMAPINFOHEADER pHeader = NULL;
#if !defined(USE_DIB_SECTION)
    // convert HBITMAP to DIB:
    pTextWindow->m_hDIB->GetDIBits(hDC, hBM, pBits, pHeader);
#else
    //we already have a DIB, so use it:
    pBits   = (UCHAR*)(pTextWindow->m_pBits);
    pHeader = &(pTextWindow->m_BITMAPINFOHEADER);
#endif
    // Make sure the color to match doesn't already
    // have an alpha value
    UINT32 ulColorNoAlpha = ulColor & 0x00FFFFFF;
    // Compute the alpha to set
    if (ulOpacity > 255) ulOpacity = 255;
    UINT32  ulAlphaShifted = (255 - ulOpacity) << 24;
    // Run through the rectangle
    UINT32* pulBits  = (UINT32*) pBits;

    // /Use of lMaxRows in the for loop, below, fixes PR 66089: crash when
    // resizing semi-opaque plain text.  Don't exceed the bitmap boundaries:
    LONG32 lMaxRows = pHeader->biHeight;
    LONG32 lWBoundsChecked = lW < pHeader->biWidth? lW : pHeader->biWidth-1;

    for (INT32 lRow = lY; lRow < lY + lH  &&  lRow < lMaxRows; lRow++)
    {
        UINT32* pPix  = pulBits +
                        (bRowsInverted ? pHeader->biHeight - 1 - lRow : lRow) *
                         pHeader->biWidth + lX;
        UINT32  ulNum = (UINT32) lWBoundsChecked; // /For PR 66089.
        while (ulNum--)
        {
            // Is this one of the colors that we are looking for?
            UINT32 ulPixNoAlpha = *pPix & 0x00FFFFFF;
            if (ulPixNoAlpha == ulColorNoAlpha)
            {
                *pPix = ulPixNoAlpha | ulAlphaShifted;
            }
            pPix++;
        }
    }
#endif

    return bRet;
}

BOOL DoesChromaKeyChannelMatch(UINT32 ulColor,
                               UINT32 ulChromaKey,
                               UINT32 ulChromaKeyTol)
{
    BOOL bRet = FALSE;

    INT32 lDiff = ((INT32) ulColor) - ((INT32) ulChromaKey);
    if (lDiff < 0)
    {
        lDiff = -lDiff;
    }
    if (lDiff <= (INT32) ulChromaKeyTol)
    {
        bRet = TRUE;
    }

    return bRet;
}

#define ARGB32_RED(a)   (((a) & 0x00FF0000) >> 16)
#define ARGB32_GREEN(a) (((a) & 0x0000FF00) >>  8)
#define ARGB32_BLUE(a)   ((a) & 0x000000FF)

BOOL DoesChromaKeyMatch(UINT32 ulColor,
                        UINT32 ulChromaKey,
                        UINT32 ulChromaKeyTol)
{
    BOOL bRet = FALSE;

    if (DoesChromaKeyChannelMatch(ARGB32_RED(ulColor),
                                  ARGB32_RED(ulChromaKey),
                                  ARGB32_RED(ulChromaKeyTol)) &&
        DoesChromaKeyChannelMatch(ARGB32_GREEN(ulColor),
                                  ARGB32_GREEN(ulChromaKey),
                                  ARGB32_GREEN(ulChromaKeyTol)) &&
        DoesChromaKeyChannelMatch(ARGB32_BLUE(ulColor),
                                  ARGB32_BLUE(ulChromaKey),
                                  ARGB32_BLUE(ulChromaKeyTol)))
    {
        bRet = TRUE;
    }

    return bRet;
}

