/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: txtattrb.cpp,v 1.1.2.1 2004/07/09 01:50:20 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 ***** */

/////////////////////////////////////////////////////////////////////////////
//
//  TXTATTRB.CPP
//
//  TextAttributes class implementation.
//
//	A class TextAttributes object holds the text to	be rendered's
//	attributes like font color, weight, size, italicized or not,
//	...etc.
//
//  TextAttribStack class implementaion:
//
//	A class TextAttribStack[BOOL|ULONG32] object is a stack of type
//	[BOOL|ULONG32] that always maintains its default value on the bottom
//	of the stack; if a pop() is done when there is only this default
//	value on the stack, the stack top is not reduced and the default
//	value is returned.  For example, "<B>text</B>text2</B>text3" would
//	push the first bold tag so that "text1" is bold, would then pop
//	the bold tag so that "text2" is not bold (default is not bold,
//	on bottom of stack) and then would try to pop again but this would
//	have no effect, leaving the default on the bottom of the stack.
//
//  TextAttributeStacks class implementaion:
//
//	A class TextAttributeStacks object is an array of TextAttrbStack
//	objects that keep track of changes in attributes so that when the
//	scope of a change ends (and that change is "popped" from the stack),
//	the previous value for that attribute can be obtained and used for
//	the next block of text.
//


#include <memory.h> //for memcpy().
#include <stdlib.h>
#include <string.h>

#include <limits.h> //for ULONG_MAX.

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

#include "rt_string.h"
#include "atotime.h"

#include "parsing.h" //For convertToUpperCase().

#include "fontdefs.h"  //(broke defs out of txtattrb.h)

#include "hxstack.h"

#include "hxslist.h" //for base class CHXSimpleList.

#include "txtattrb.h" //for base class TextAttributes.
#include "txtcntnr.h"
#include "textprsr.h" /*for ..._CONTENT_VERSION_... defines */

#ifdef _WINDOWS
#ifdef _WIN16
#include <windows.h>
#endif /* _WIN16 */
#endif /* _WINDOWS */

#include "hxslist.h"
#include "textline.h"
#include "txtwindw.h"

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


#ifdef _CARBON
#pragma old_argmatch on
#endif

void TextAttributes::init()
{
    /*resets to default vals, sets dynamically-allocated buffers to NULL*/
    m_textColor = DEFAULT_TEXT_COLOR;
    m_textBackgroundColor = DEFAULT_TEXT_BGCOLOR;
    m_tickerUpperColor = DEFAULT_TICKER_UPPERCOLOR;
    m_tickerLowerColor = DEFAULT_TICKER_LOWERCOLOR;
    m_fontFaceIndex = DEFAULT_FONT_FACE_INDX;
    //Added this line to handle charsets:
    m_fontCharset = CHARSET__default;
    m_fontPointSize = DEFAULT_FONT_PTSIZE;
    m_isBold = m_isItalicized = m_isUnderlined = m_isStruckOut = FALSE;
    m_isCentered = m_bIsPreFormatted = FALSE;
    m_numNewlinesAtStart = 0L;
    m_isFakeNewLine = FALSE;//new var for crawlrate "lines"
    m_isWordWrapNewLine = FALSE;//new var.
    m_breakSpacingX = m_breakSpacingY = 0L;
    m_isTickerUpperText = TRUE;
    m_blinkRate = DEFAULT_BLINKRATE;
    m_isLit = TRUE;
    m_pHrefBuf = NULL;
    m_hrefBufLen = 0L;
    m_ulTargetOfURL = URL_TARGET_INVALID;

    m_beginTime = m_endTime = m_lastKnownTime = TIME_INVALID;
    m_ulMostRecentTimeTagEndTime = (ULONG32)ULONG_MAX;
    m_lastKnownX = m_lastKnownY = 0L;
    m_xAtTimeZeroUpperLeftCorner = m_yAtTimeZeroUpperLeftCorner = 0L;
    m_xUpperLeftCorner = m_yUpperLeftCorner = m_xExtent = m_yExtent = 0L;
    //added this for indenting text in lists and as requested:
    m_lineIndentAmtInPixels = 0;

    //This is needed for knowing which to put first in the packet header,
    // the <font color=...> tag or the <a...> tag:
    m_ulNumLinkColorOverrides = 0L;
}
	

void TextAttributes::clear_URL()
{
    if(m_pHrefBuf)
    {
	delete [] m_pHrefBuf;
	m_pHrefBuf = NULL;
    }
    m_hrefBufLen=0L;

    m_ulTargetOfURL = URL_TARGET_INVALID;
}



void TextAttributes::setFontFace(ULONG32 ulFntFcIndx)	
{
    m_fontFaceIndex = ulFntFcIndx;
}
void TextAttributes::setFontFace(_CHAR* pFntFc, ULONG32 len,
	ULONG32 ulMajorContentVersion, ULONG32 ulMinorContentVersion)	
{
    m_fontFaceIndex = getFontFaceIndexFromString(pFntFc, len,
	    ulMajorContentVersion, ulMinorContentVersion);
}

//added this function which converts a predefined 
// string into a font index (returning default index if string unrecognized):
ULONG32 getFontFaceIndexFromString(_CHAR* pFntFc, ULONG32 len,
	ULONG32 ulMajorContentVersion, ULONG32 ulMinorContentVersion)
{
    if(!pFntFc  ||  !len)
    {
	return DEFAULT_FONT_FACE_INDX;
    }

    BOOL bActiveContentVersionIncludesKorean = FALSE;
    //XXXEH: docs need updating: version="1.4" or higher must
    // be set in the <window> tag of the rt file in order for
    // Korean to be rendered:
    if(ulMajorContentVersion >
	REAL_TEXT_KOREAN_FONT_HANDLING_CONTENT_MAJOR_VERSION
	||
	(ulMajorContentVersion ==
	REAL_TEXT_KOREAN_FONT_HANDLING_CONTENT_MAJOR_VERSION
	&&
	ulMinorContentVersion >=
	REAL_TEXT_KOREAN_FONT_HANDLING_CONTENT_MINOR_VERSION)
	)
    {
	bActiveContentVersionIncludesKorean = TRUE;
    }

    convertToUpperCase(pFntFc, len);
    if(!stringCompare(
	    TIMES_FONT_FACE_STR, TIMES_FONT_FACE_STRLEN,
	    pFntFc, len)  ||
	    !stringCompare(
	    TIMES_FONT_FACE_STR2, TIMES_FONT_FACE_STR2LEN,
	    pFntFc, len)  )
    {
	return(TIMES_FONT_FACE_INDX);
    }
    else if(!stringCompare(
	    COURIERTT_FONT_FACE_STR, COURIERTT_FONT_FACE_STRLEN,
	    pFntFc, len)  ||
	    !stringCompare(
	    COURIERTT_FONT_FACE_STR2, COURIERTT_FONT_FACE_STR2LEN,
	    pFntFc, len)  )
    {
	return(COURIERTT_FONT_FACE_INDX);
    }
    else if(!stringCompare(
	    SYSTEM_FONT_FACE_STR, SYSTEM_FONT_FACE_STRLEN,
	    pFntFc, len)  ||
	    !stringCompare(
	    GENEVA_FONT_FACE_STR, GENEVA_FONT_FACE_STRLEN,
	    pFntFc, len)  )
    {
	return(SYSTEM_FONT_FACE_INDX);
    }
    else if(!stringCompare(
	    ARIAL_FONT_FACE_STR, ARIAL_FONT_FACE_STRLEN,
	    pFntFc, len)  )
    {
	return(ARIAL_FONT_FACE_INDX);
    }
    else if(!stringCompare(
	    HELVETICA_FONT_FACE_STR, HELVETICA_FONT_FACE_STRLEN,
	    pFntFc, len)  )
    {
	return(HELVETICA_FONT_FACE_INDX);
    }
    else if(!stringCompare(
	    ARIAL_BLACK_FONT_FACE_STR, ARIAL_BLACK_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(ARIAL_BLACK_FONT_FACE_INDX);
    }
    else if(!stringCompare(
	    ARIAL_NARROW_FONT_FACE_STR, ARIAL_NARROW_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(ARIAL_NARROW_FONT_FACE_INDX);
    }
    else if(!stringCompare(
	    ARIAL_ROUNDED_MT_BOLD_FONT_FACE_STR,
	    ARIAL_ROUNDED_MT_BOLD_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(ARIAL_ROUNDED_MT_BOLD_FONT_FACE_INDX);
    }

    else if(!stringCompare(
	    ALGERIAN_FONT_FACE_STR,
	    ALGERIAN_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return ALGERIAN_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    BOOK_ANTIQUA_FONT_FACE_STR,
	    BOOK_ANTIQUA_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return BOOK_ANTIQUA_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    BOOKMAN_OLD_STYLE_FONT_FACE_STR,
	    BOOKMAN_OLD_STYLE_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return BOOKMAN_OLD_STYLE_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    BRAGGADOCIO_FONT_FACE_STR,
	    BRAGGADOCIO_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return BRAGGADOCIO_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    BRITANNIC_BOLD_FONT_FACE_STR,
	    BRITANNIC_BOLD_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return BRITANNIC_BOLD_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    BRUSH_SCRIPT_FONT_FACE_STR,
	    BRUSH_SCRIPT_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return BRUSH_SCRIPT_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    CENTURY_GOTHIC_FONT_FACE_STR,
	    CENTURY_GOTHIC_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return CENTURY_GOTHIC_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    CENTURY_SCHOOLBOOK_FONT_FACE_STR,
	    CENTURY_SCHOOLBOOK_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return CENTURY_SCHOOLBOOK_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    COLONNA_MT_FONT_FACE_STR,
	    COLONNA_MT_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return COLONNA_MT_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    COMIC_SANS_MS_FONT_FACE_STR,
	    COMIC_SANS_MS_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return COMIC_SANS_MS_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    DESDEMONA_FONT_FACE_STR,
	    DESDEMONA_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return DESDEMONA_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    FOOTLIGHT_MT_LIGHT_FONT_FACE_STR,
	    FOOTLIGHT_MT_LIGHT_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return FOOTLIGHT_MT_LIGHT_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    GARAMOND_FONT_FACE_STR,
	    GARAMOND_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return GARAMOND_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    HAETTENSCHWEILER_FONT_FACE_STR,
	    HAETTENSCHWEILER_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return HAETTENSCHWEILER_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    IMPACT_FONT_FACE_STR,
	    IMPACT_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return IMPACT_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    KINO_MT_FONT_FACE_STR,
	    KINO_MT_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return KINO_MT_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    MATURA_MT_SCRIPT_CAPITALS_FONT_FACE_STR,
	    MATURA_MT_SCRIPT_CAPITALS_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return MATURA_MT_SCRIPT_CAPITALS_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    MODERN_FONT_FACE_STR,
	    MODERN_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return MODERN_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    MS_DIALOG_FONT_FACE_STR,
	    MS_DIALOG_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return MS_DIALOG_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    MS_DIALOG_LIGHT_FONT_FACE_STR,
	    MS_DIALOG_LIGHT_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return MS_DIALOG_LIGHT_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    MS_LINEDRAW_FONT_FACE_STR,
	    MS_LINEDRAW_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return MS_LINEDRAW_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    MS_SANS_SERIF_FONT_FACE_STR,
	    MS_SANS_SERIF_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return MS_SANS_SERIF_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    MS_SERIF_FONT_FACE_STR,
	    MS_SERIF_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return MS_SERIF_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    MS_SYSTEMEX_FONT_FACE_STR,
	    MS_SYSTEMEX_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return MS_SYSTEMEX_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    PLAYBILL_FONT_FACE_STR,
	    PLAYBILL_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return PLAYBILL_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    SMALL_FONTS_FONT_FACE_STR,
	    SMALL_FONTS_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return SMALL_FONTS_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    VERDANA_FONT_FACE_STR,
	    VERDANA_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return VERDANA_FONT_FACE_INDX;
    }
    else if(!stringCompare(
	    WIDE_LATIN_FONT_FACE_STR,
	    WIDE_LATIN_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return WIDE_LATIN_FONT_FACE_INDX;
    }

    //DBCS and UNICODE fonts:
    else if(!stringCompare(
	    OSAKA_FONT_FACE_STR, OSAKA_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(OSAKA_FONT_FACE_INDX);
    }
    else if(!stringCompare(
	    SIMPLECHINESE_FONT_FACE_STR, SIMPLECHINESE_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(SIMPLECHINESE_FONT_FACE_INDX);
    }
    else if(!stringCompare(
	    TRADITIONALCHINESE_FONT_FACE_STR, TRADITIONALCHINESE_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(TRADITIONALCHINESE_FONT_FACE_INDX);
    }
    //KOREAN!
    else if(!stringCompare(
	    SEOUL_FONT_FACE_STR, SEOUL_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(bActiveContentVersionIncludesKorean?
		SEOUL_FONT_FACE_INDX : DEFAULT_FONT_FACE_INDX);
    }
    //KOREAN!
    else if(!stringCompare(
	    BATANG_FONT_FACE_STR, BATANG_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(bActiveContentVersionIncludesKorean?
		BATANG_FONT_FACE_INDX : DEFAULT_FONT_FACE_INDX);
    }
    //KOREAN!
    else if(!stringCompare(
	    BATANGCHE_FONT_FACE_STR, BATANGCHE_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(bActiveContentVersionIncludesKorean?
		BATANGCHE_FONT_FACE_INDX : DEFAULT_FONT_FACE_INDX);
    }
    //KOREAN!
    else if(!stringCompare(
	    GULIM_FONT_FACE_STR, GULIM_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(bActiveContentVersionIncludesKorean?
		GULIM_FONT_FACE_INDX : DEFAULT_FONT_FACE_INDX);
    }
    //KOREAN!
    else if(!stringCompare(
	    GULIMCHE_FONT_FACE_STR, GULIMCHE_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(bActiveContentVersionIncludesKorean?
		GULIMCHE_FONT_FACE_INDX : DEFAULT_FONT_FACE_INDX);
    }
    //KOREAN!
    else if(!stringCompare(
	    GOTHIC_FONT_FACE_STR, GOTHIC_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(bActiveContentVersionIncludesKorean?
		GOTHIC_FONT_FACE_INDX : DEFAULT_FONT_FACE_INDX);
    }
    //KOREAN!
    else if(!stringCompare(
	    APPLEGOTHIC_FONT_FACE_STR, APPLEGOTHIC_FONT_FACE_STRLEN,
	    pFntFc, len) )
    {
	return(bActiveContentVersionIncludesKorean?
		APPLEGOTHIC_FONT_FACE_INDX : DEFAULT_FONT_FACE_INDX);
    }
    else
    {
	return(DEFAULT_FONT_FACE_INDX);
    }
}

//added this function which looks at the current
// value of the font index and returns the predefined string for that val:
const _CHAR* TextAttributes::getFontFaceString(
	ULONG32 ulMajorContentVersion, ULONG32 ulMinorContentVersion)
{
    BOOL bActiveContentVersionIncludesKorean = FALSE;
    //XXXEH: docs need updating: version="1.4" or higher must
    // be set in the <window> tag of the rt file in order for
    // Korean to be rendered:
    if(ulMajorContentVersion >
	    REAL_TEXT_KOREAN_FONT_HANDLING_CONTENT_MAJOR_VERSION
	    ||
	    (ulMajorContentVersion ==
	    REAL_TEXT_KOREAN_FONT_HANDLING_CONTENT_MAJOR_VERSION
	    &&
	    ulMinorContentVersion >=
	    REAL_TEXT_KOREAN_FONT_HANDLING_CONTENT_MINOR_VERSION)
	    )
    {
	bActiveContentVersionIncludesKorean = TRUE;
    }

    switch(m_fontFaceIndex)
    {
	case TIMES_FONT_FACE_INDX:
	{
	    return TIMES_FONT_FACE_STR;
	}
	case COURIERTT_FONT_FACE_INDX:
	{
	    return COURIERTT_FONT_FACE_STR2;
	}
	case SYSTEM_FONT_FACE_INDX:
	{
	    return SYSTEM_FONT_FACE_STR;
	}
	case ARIAL_FONT_FACE_INDX:
	{
	    return ARIAL_FONT_FACE_STR;
	}
	case ARIAL_BLACK_FONT_FACE_INDX:
	{
	    return ARIAL_BLACK_FONT_FACE_STR;
	}
	case ARIAL_NARROW_FONT_FACE_INDX:
	{
	    return ARIAL_NARROW_FONT_FACE_STR;
	}
	case ARIAL_ROUNDED_MT_BOLD_FONT_FACE_INDX:
	{
	    return ARIAL_ROUNDED_MT_BOLD_FONT_FACE_STR;
	}
	case ALGERIAN_FONT_FACE_INDX:
	{
	    return ALGERIAN_FONT_FACE_STR;
	}
	case BOOK_ANTIQUA_FONT_FACE_INDX:
	{
	    return BOOK_ANTIQUA_FONT_FACE_STR;
	}
	case BOOKMAN_OLD_STYLE_FONT_FACE_INDX:
	{
	    return BOOKMAN_OLD_STYLE_FONT_FACE_STR;
	}
	case BRAGGADOCIO_FONT_FACE_INDX:
	{
	    return BRAGGADOCIO_FONT_FACE_STR;
	}
	case BRITANNIC_BOLD_FONT_FACE_INDX:
	{
	    return BRITANNIC_BOLD_FONT_FACE_STR;
	}
	case BRUSH_SCRIPT_FONT_FACE_INDX:
	{
	    return BRUSH_SCRIPT_FONT_FACE_STR;
	}
	case CENTURY_GOTHIC_FONT_FACE_INDX:
	{
	    return CENTURY_GOTHIC_FONT_FACE_STR;
	}
	case CENTURY_SCHOOLBOOK_FONT_FACE_INDX:
	{
	    return CENTURY_SCHOOLBOOK_FONT_FACE_STR;
	}
	case COLONNA_MT_FONT_FACE_INDX:
	{
	    return COLONNA_MT_FONT_FACE_STR;
	}
	case COMIC_SANS_MS_FONT_FACE_INDX:
	{
	    return COMIC_SANS_MS_FONT_FACE_STR;
	}
	case DESDEMONA_FONT_FACE_INDX:
	{
	    return DESDEMONA_FONT_FACE_STR;
	}
	case FOOTLIGHT_MT_LIGHT_FONT_FACE_INDX:
	{
	    return FOOTLIGHT_MT_LIGHT_FONT_FACE_STR;
	}
	case GARAMOND_FONT_FACE_INDX:
	{
	    return GARAMOND_FONT_FACE_STR;
	}
	case HAETTENSCHWEILER_FONT_FACE_INDX:
	{
	    return HAETTENSCHWEILER_FONT_FACE_STR;
	}
	case HELVETICA_FONT_FACE_INDX:
	{
	    return HELVETICA_FONT_FACE_STR;
	}
	case IMPACT_FONT_FACE_INDX:
	{
	    return IMPACT_FONT_FACE_STR;
	}
	case KINO_MT_FONT_FACE_INDX:
	{
	    return KINO_MT_FONT_FACE_STR;
	}
	case MATURA_MT_SCRIPT_CAPITALS_FONT_FACE_INDX:
	{
	    return MATURA_MT_SCRIPT_CAPITALS_FONT_FACE_STR;
	}
	case MODERN_FONT_FACE_INDX:
	{
	    return MODERN_FONT_FACE_STR;
	}
	case MS_DIALOG_FONT_FACE_INDX:
	{
	    return MS_DIALOG_FONT_FACE_STR;
	}
	case MS_DIALOG_LIGHT_FONT_FACE_INDX:
	{
	    return MS_DIALOG_LIGHT_FONT_FACE_STR;
	}
	case MS_LINEDRAW_FONT_FACE_INDX:
	{
	    return MS_LINEDRAW_FONT_FACE_STR;
	}
	case MS_SANS_SERIF_FONT_FACE_INDX:
	{
	    return MS_SANS_SERIF_FONT_FACE_STR;
	}
	case MS_SERIF_FONT_FACE_INDX:
	{
	    return MS_SERIF_FONT_FACE_STR;
	}
	case MS_SYSTEMEX_FONT_FACE_INDX:
	{
	    return MS_SYSTEMEX_FONT_FACE_STR;
	}
	case PLAYBILL_FONT_FACE_INDX:
	{
	    return PLAYBILL_FONT_FACE_STR;
	}
	case SMALL_FONTS_FONT_FACE_INDX:
	{
	    return SMALL_FONTS_FONT_FACE_STR;
	}
	case VERDANA_FONT_FACE_INDX:
	{
	    return VERDANA_FONT_FACE_STR;
	}
	case WIDE_LATIN_FONT_FACE_INDX:
	{
	    return WIDE_LATIN_FONT_FACE_STR;
	}

	//DBCS and UNICODE fonts:
	case OSAKA_FONT_FACE_INDX:
	{
	    return OSAKA_FONT_FACE_STR;
	}
	case SIMPLECHINESE_FONT_FACE_INDX:
	{
	    return SIMPLECHINESE_FONT_FACE_STR;
	}
	case TRADITIONALCHINESE_FONT_FACE_INDX:
	{
	    return TRADITIONALCHINESE_FONT_FACE_STR;
	}

	//KOREAN!
	case SEOUL_FONT_FACE_INDX:
	{
	    return (_CHAR*)(bActiveContentVersionIncludesKorean?
		    SEOUL_FONT_FACE_STR : DEFAULT_FONT_STR);
	}
	//KOREAN!
	case BATANG_FONT_FACE_INDX:
	{
	    return (_CHAR*)(bActiveContentVersionIncludesKorean?
		    BATANG_FONT_FACE_STR : DEFAULT_FONT_STR);
	}
	//KOREAN!
	case BATANGCHE_FONT_FACE_INDX:
	{
	    return (_CHAR*)(bActiveContentVersionIncludesKorean?
		    BATANGCHE_FONT_FACE_STR : DEFAULT_FONT_STR);
	}
	//KOREAN!
	case GULIM_FONT_FACE_INDX:
	{
	    return (_CHAR*)(bActiveContentVersionIncludesKorean?
		    GULIM_FONT_FACE_STR : DEFAULT_FONT_STR);
	}
	//KOREAN!
	case GULIMCHE_FONT_FACE_INDX:
	{
	    return (_CHAR*)(bActiveContentVersionIncludesKorean?
		    GULIMCHE_FONT_FACE_STR : DEFAULT_FONT_STR);
	}
	//KOREAN!
	case GOTHIC_FONT_FACE_INDX:
	{
	    return (_CHAR*)(bActiveContentVersionIncludesKorean?
		    GOTHIC_FONT_FACE_STR : DEFAULT_FONT_STR);
	}
	//KOREAN!
	case APPLEGOTHIC_FONT_FACE_INDX:
	{
	    return (_CHAR*)(bActiveContentVersionIncludesKorean?
		    APPLEGOTHIC_FONT_FACE_STR : DEFAULT_FONT_STR);
	}
    }
    return DEFAULT_FONT_STR;
}


//NOTE: returns FALSE if alloc fails:
BOOL TextAttributes::copyIntoHrefBuf(_CHAR* pHref, ULONG32 len,
				     ULONG32 ulTargetOfURL) 
{
    if(m_pHrefBuf)
    {
	delete [] m_pHrefBuf;
	m_pHrefBuf = 0;
    }
    m_pHrefBuf = new _CHAR[len+1];
    HX_ASSERT(m_pHrefBuf);
    if(!m_pHrefBuf)   //Couldn't get the memory needed, so return FALSE:
    {
	m_hrefBufLen=0L;
	return FALSE;
    }

    stringCopy(m_pHrefBuf, pHref, len);

    m_hrefBufLen = len;

    m_ulTargetOfURL = ulTargetOfURL;

    return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
//
//  This gets called in response to a <CLEAR> tag being
//  encountered at time ulNewEndTime; if(m_startTime < ulNewEndTime),
//  this function resets m_endTime to min(m_endTime, ulNewEndTime);
//  returns TRUE if change is made to m_endTime, else FALSE:
//
BOOL TextAttributes::MarkForClear(ULONG32 ulNewEndTime,
				  BOOL bIsLiveSource)
{
    if(IsTimeASameOrMoreRecentThanTimeB(
		ulNewEndTime,
		m_beginTime,
		bIsLiveSource) )
    {
	if(IsTimeASameOrMoreRecentThanTimeB(
		m_endTime,
		ulNewEndTime,
		bIsLiveSource) )
	{
	    //add -1 to fix 1-millisec overlap problem: if cur time is t
	    // and this object's end time is t, then this object won't
	    // go away right at t because (t<t) evaluates to FALSE, so
	    // we reduce the end time by 1 millisec to ensure that it
	    // goes away at t:
	    m_endTime = (ulNewEndTime>0L? ulNewEndTime-1L:0L);
	    if(bIsLiveSource)
	    {
		// Also, if it ends up being 0, set it to TIME_INFINITY
		// (which is 0xfffffffe).  Also, if ulNewEndTime is
		// TIME_INVALID, then m_endTime will be set to
		// TIME_INVALID-1 which is TIME_INFINITY:
		m_endTime =
		    (ulNewEndTime>1L? ulNewEndTime-1L:TIME_INFINITY);
	    }
	    return TRUE;
	}
	return FALSE;
    }
    return FALSE;
}


/////////////////////////////////////////////////////////////////////////////
//
//  This gets called in OnTimeSynch() to compute where the text should be
//  dislayed based on the current time:
//
LONG32 TextAttributes::ComputeCrawlDelta(
	ULONG32 ulCurTime, LONG32 crawlrate)
{
    ULONG32 retVal =  
	    //Avoid overflow by casting to double and then back:
	    //NOTE: the casting to double here is ONLY to avoid
	    // overflow and does not need special floating-point
	    // consideration for fixed-point code conversion,
	    // i.e., precision does not need to be maintainted:
	    ULONG32((double(crawlrate) * double(ulCurTime)) / 1000.0);
    return retVal;
}

/////////////////////////////////////////////////////////////////////////////
//
//  This gets called in OnTimeSynch() to compute where the text should be
//  dislayed based on the current time:
//
LONG32 TextAttributes::ComputeScrollDelta(
	ULONG32 ulCurTime, LONG32 scrollrate)
{
    ULONG32 retVal =  
	    //Avoid overflow by casting to double and then back:
	    //NOTE: the casting to double here is ONLY to avoid
	    // overflow and does not need special floating-point
	    // consideration for fixed-point code conversion,
	    // i.e., precision does not need to be maintainted:
	    ULONG32((double(scrollrate) * double(ulCurTime)) / 1000.0);
    return retVal;
}



/////////////////////////////////////////////////////////////////////////////
//
// //Changes the start and end times of *this if refTA's
// start or end time is earlier or later, respectively, than this's; this
// is used by TextList which updates for each TextContainer (each of which
// inherit TextAttributes):
//
// returns FALSE if pTA is somehow invalid.
//
BOOL TextAttributes::updateStartAndEndTimes(TextAttributes* pTA,
					    BOOL bIsLiveSource)
{
    if(!pTA)
    {
	return FALSE;
    }

    if(IsTimeAMoreRecentThanTimeB(
	    getStartTime(),
	    pTA->getStartTime(),
	    bIsLiveSource) )
    {
	setStartTime(pTA->getStartTime());
    }


    if(IsTimeAMoreRecentThanTimeB(
	    pTA->getEndTime(),
	    getEndTime(),
	    bIsLiveSource) )
    {
	setEndTime(pTA->getEndTime());
    }

    return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
//
// //Changes the start and end times of *this as
// calculated by "appearance" of the text in the window, i.e.,
// if there is a scrollrate or crawlrate, this calculates when it first
// becomes visible in the window and then when it moves back out.
//
// returns FALSE if pTW is somehow invalid.
//
BOOL TextAttributes::adjustStartAndEndTimes(TextWindow* pTW)
{
    if(!pTW)
    {
	return FALSE;
    }

    LONG32 windowWidth = pTW->getWidth();
    LONG32 windowHeight = pTW->getHeight();

    LONG32 scrollRate = pTW->getScrollRate();
    LONG32 crawlRate = pTW->getCrawlRate();

    if(!scrollRate  &&  !crawlRate)
    {
	return TRUE; //nothing more to do!
    }

    ULONG32 ulTimeItScrollsIntoWindow = 0L;
    ULONG32 ulTimeItScrollsOutOfWindow = 0L;
    ULONG32 ulTimeItCrawlsIntoWindow = 0L;
    ULONG32 ulTimeItCrawlsOutOfWindow = 0L;

/*
    ULONG32 ulTimeDiff;
*/
    BOOL bFirstIsMoreRecent;
    BOOL bIsLiveSource = pTW->isLiveSource();

    if(scrollRate)
    {
	//Now, calculate what time it will be when the text of *this
	// is just entering the window due to scrolling:
	if(m_yAtTimeZeroUpperLeftCorner - windowHeight > 0L)//pos vals only!!
	{
	    ulTimeItScrollsIntoWindow =
		    //Changed the order to fix missing-live-text bug (and
		    // on-demand bug, too, if duration is very high);
		    // this should be 21199150 at t=4239830seconds
		    // with scrollrate=5, not 4019286 as it used to be
		    // due to the order of multiplication causing an
		    // overflow at high values (4019286 = 21199150
		    // modulo [0xFFFFFFFF/1000] )
		    //NOTE: the casting to double here is ONLY to avoid
		    // overflow and does not need special floating-point
		    // consideration for fixed-point code conversion,
		    // i.e., precision does not need to be maintainted:
		    ULONG32(1000.0 * //(converts to milliseconds)
		    (((double)m_yAtTimeZeroUpperLeftCorner-
		    (double)windowHeight)/ (double)scrollRate) );

	    if(IsTimeAMoreRecentThanTimeB(
			ulTimeItScrollsIntoWindow,
			getStartTime(),
			bIsLiveSource) )
	    {
		setStartTime(ulTimeItScrollsIntoWindow);
	    }
	}

	//Now, calculate what time it will be when the text of *this
	// is just leaving the window due to scrolling:
	if(m_yAtTimeZeroUpperLeftCorner + m_yExtent > 0L)//pos vals only!!
	{
	    ulTimeItScrollsOutOfWindow =
		    ULONG32(1000.0 * //(converts to milliseconds)
		    //NOTE: the casting to double here is ONLY to avoid
		    // overflow and does not need special floating-point
		    // consideration for fixed-point code conversion,
		    // i.e., precision does not need to be maintainted:
		    (((double)m_yAtTimeZeroUpperLeftCorner +
		    (double)m_yExtent) / (double)scrollRate) );

	    bFirstIsMoreRecent =
		    IsTimeAMoreRecentThanTimeB(
		    getEndTime(),
		    ulTimeItScrollsOutOfWindow,
		    bIsLiveSource);
	    if(bFirstIsMoreRecent
		    //Note: for live, this will work becuase endTime (and
		    // other times) will never be set to 0:
		    ||  getEndTime()==0) //added this in case endtime init->0
	    {
		bFirstIsMoreRecent = IsTimeAMoreRecentThanTimeB(
			ulTimeItScrollsOutOfWindow,
			m_beginTime,
			bIsLiveSource);

		setEndTime(bFirstIsMoreRecent?
			ulTimeItScrollsOutOfWindow:m_beginTime);
	    }
	}
    }

    if(crawlRate)
    {
	//Now, calculate what time it will be when the text of *this
	// is just entering the window due to crawling:
	if(m_xAtTimeZeroUpperLeftCorner - windowWidth > 0L)//pos vals only!!
	{
	    ulTimeItCrawlsIntoWindow =
		    ULONG32(1000.0 * //(converts to milliseconds)
		    //NOTE: the casting to double here is ONLY to avoid
		    // overflow and does not need special floating-point
		    // consideration for fixed-point code conversion,
		    // i.e., precision does not need to be maintainted:
		    (((double)m_xAtTimeZeroUpperLeftCorner -
		    (double)windowWidth)/ (double)crawlRate) );

	    if(IsTimeAMoreRecentThanTimeB(
		    ulTimeItCrawlsIntoWindow,
		    getStartTime(),
		    bIsLiveSource) )
	    {
		setStartTime(ulTimeItCrawlsIntoWindow);
	    }
	}

	//Now, calculate what time it will be when the text of *this
	// is just leaving the window due to crawling:
	if(m_xAtTimeZeroUpperLeftCorner + m_xExtent > 0L)//pos vals only!!
	{
	    ulTimeItCrawlsOutOfWindow =
		    ULONG32(1000.0 * //(converts to milliseconds)
		    //NOTE: the casting to double here is ONLY to avoid
		    // overflow and does not need special floating-point
		    // consideration for fixed-point code conversion,
		    // i.e., precision does not need to be maintainted:
		    (((double)m_xAtTimeZeroUpperLeftCorner +
		    (double)m_xExtent) / (double)crawlRate) );

	    bFirstIsMoreRecent =
		    IsTimeAMoreRecentThanTimeB(
		    getEndTime(),
		    ulTimeItCrawlsOutOfWindow,
		    bIsLiveSource);

	    if(bFirstIsMoreRecent
		    //tXXXXXEH: handle this for live (not sure how...):
		    ||  getEndTime()==0) //added this in case endtime init->0
	    {
		bFirstIsMoreRecent = 
			IsTimeAMoreRecentThanTimeB(
			ulTimeItCrawlsOutOfWindow,
			m_beginTime,
			bIsLiveSource);

		setEndTime(bFirstIsMoreRecent?
			ulTimeItCrawlsOutOfWindow:m_beginTime);
	    }
	}
    }

    return TRUE;
}
    




/////////////////////////////////////////////////////////////////////////////
//
//	TextAttribStack methods:
//
/* [are inside the header file]
*/



/////////////////////////////////////////////////////////////////////////////
//
//	TextAttributeStacks methods:
//

/////////////////////////////////////////////////////////////////////////////
//
//	TextAttributeStacks constructor:
//
TextAttributeStacks::TextAttributeStacks() :
	m_ulRequiredTagCount(0L),
	m_ulPreTagCount(0L)
	, m_bIsTickerUpperText(TRUE)
{
    flush();

    m_fontStack.init(DEFAULT_TEXT_COLOR);
    m_fontFaceStack.init(DEFAULT_FONT_FACE_INDX);
    m_textColorStack.init(DEFAULT_TEXT_COLOR);
    m_textBackgroundColorStack.init(DEFAULT_TEXT_BGCOLOR); 
    m_fontCharsetStack.init(CHARSET__default);
    m_fontPointSizeStack.init(DEFAULT_FONT_PTSIZE);

    m_tickerUpperColorStack.init(DEFAULT_TICKER_UPPERCOLOR); 
    m_tickerLowerColorStack.init(DEFAULT_TICKER_LOWERCOLOR); 
    
    m_isBoldStack.init(FALSE);
    m_isItalicizedStack.init(FALSE);
    m_isUnderlinedStack.init(FALSE);
    m_isStruckOutStack.init(FALSE);
    m_blinkRateStack.init(DEFAULT_BLINKRATE);
    m_isCenteredStack.init(FALSE);

    //added this for indenting text in lists & as requested:
    m_lineIndentAmtInPixelsStack.init(0);

    m_fontTagStartByteInFileStack.init(0);
}


/////////////////////////////////////////////////////////////////////////////
//
//  TextAttributeStacks flush() which clears the stack except for the default
//  value, which is left at the bottom of the stack:
//
void TextAttributeStacks::flush()
{
    flushFontStacks();
    flushTickerStacks();
    flushBIUSandBlinkStacks();
    flushIndentAmtStack();
}

/////////////////////////////////////////////////////////////////////////////
//
void TextAttributeStacks::flushFontStacks()
{
    m_fontStack.removeAll();
    m_fontFaceStack.removeAll();
    m_textColorStack.removeAll();
    m_textBackgroundColorStack.removeAll();
    m_fontCharsetStack.removeAll();
    m_fontPointSizeStack.removeAll();
}
/////////////////////////////////////////////////////////////////////////////
//
void TextAttributeStacks::flushTickerStacks()
{
    m_tickerUpperColorStack.removeAll();
    m_tickerLowerColorStack.removeAll();
    m_bIsTickerUpperText = TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
void TextAttributeStacks::flushBIUSandBlinkStacks()
{
    m_isBoldStack.removeAll();
    m_isItalicizedStack.removeAll();
    m_isUnderlinedStack.removeAll();
    m_isStruckOutStack.removeAll();
    m_blinkRateStack.removeAll();
    m_isCenteredStack.removeAll();
    m_ulPreTagCount = 0L;
    m_ulRequiredTagCount = 0L;
}
/////////////////////////////////////////////////////////////////////////////
//
void TextAttributeStacks::flushIndentAmtStack()
{
    m_lineIndentAmtInPixelsStack.removeAll();
}


/////////////////////////////////////////////////////////////////////////////
//
//	TextAttributeStacks function that sets a TextAttributes object's values
//		to match those on the current top of the stack:
//
void TextAttributeStacks::setTextAttributesToTopsOfStacksVals(
		TextAttributes& ta)
{
    ta.setTextColor(m_textColorStack.peek());
    ta.setTextBackgroundColor(m_textBackgroundColorStack.peek());
    ta.setTickerUpperColor(m_tickerUpperColorStack.peek());
    ta.setTickerLowerColor(m_tickerLowerColorStack.peek());
    ta.isTickerUpperText(m_bIsTickerUpperText);
    ta.setFontFace(m_fontFaceStack.peek()); 
    //Added this line to handle charsets:
    ta.setFontCharset(m_fontCharsetStack.peek());
    ta.setFontPointSize(m_fontPointSizeStack.peek()); 
    ta.isBold((BOOL)m_isBoldStack.peek()); 
    ta.isItalicized((BOOL)m_isItalicizedStack.peek()); 
    ta.isUnderlined((BOOL)m_isUnderlinedStack.peek());
    ta.isStruckOut((BOOL)m_isStruckOutStack.peek());
    ta.setBlinkRate(m_blinkRateStack.peek());
    ta.isCentered((BOOL)m_isCenteredStack.peek());
    ta.isPreFormatted(peekAtIsPreStack());
    ta.isRequired(m_ulRequiredTagCount);
    //added this for indenting text in lists and as requested:
    ta.setLineIndentAmtInPixels((UINT16)m_lineIndentAmtInPixelsStack.peek());

}



/////////////////////////////////////////////////////////////////////////////
//
//	TextAttributeStacks function that manages the contents of the 
//		FontFace stack:
//
void TextAttributeStacks::pushFontFaceStack(ULONG32 fontFaceIndex)
{
    ULONG32 ulCopy = fontFaceIndex;
    m_fontFaceStack.push(ulCopy);
}

#ifdef _CARBON
#pragma old_argmatch reset
#endif


