//
// Copyright 2010 The Android Open Source Project
//
// The Display dispatcher.
//

//#define LOG_NDEBUG 0
#define LOG_TAG "subtitleNativeDisplay"
#include "log.h"
#include "cdx_config.h"

#include <stddef.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <utils/Errors.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <ui/Region.h>
#include <ui/Rect.h>
#include <ui/PixelFormat.h>
#include <EGL/egl.h>
#include <SkCanvas.h>
#include <SkBitmap.h>
#include <SkImageEncoder.h>
#include <SkXfermode.h>
#include <SkRegion.h>
#include <SkTypeface.h>
#include <SkGlyphCache.h>
#include <SkUtils.h>
#include <SkAutoKern.h>
#include <cutils/properties.h>
#ifdef __cplusplus
extern "C"
{
#endif
#include "unicode/ucnv.h"
#include "unicode/ustring.h"
#ifdef __cplusplus
}
#endif
#include "subtitleNativeDisplay.h"
#include "ui/DisplayInfo.h"
#include "native_window.h"
#include "SkDevice.h"
#include "sdecoder.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define  BASELAYER                  8  //5, 3, higher number layer is on topper.
#define  TOPBASELAYER				8  //5, 3
#define  BOTTOMBASELAYER			8
#define  LAYER_MULTIPLIER			10000
#define  LAYER_OFFSET				1000
#define  TRANSPARENT_COLOR			0x00050107
#define  MAX_TEXTLINE				3
#define  MAX_FONTHEIGHT				36
#define  SUB_DISPLAY				0
#define  FONT_SIZE_UNIT			16
#define  DEFAULT_TEXT_SIZE          24

#define  SUB_SHOW_NEW_VALID         1
#define  SUB_SHOW_OLD_VALID         2
#define  SUB_SHOW_INVALID           0
#define  SUB_HAS_NONE_COLOR         0
#define  SUB_HAS_DEFINED_COLOR      1
#define  SUB_HAS_DEFINED_FONTSIZE   1
#define  SUB_HAS_NONE_FONTSIZE      0
#define  SUB_HAS_DEFINED_STYLE      1
#define  SUB_HAS_NONE_STYLE         0
#define  SUB_INIT_SET_FONT_INFO     1
#define  SUB_USER_SET_FONT_INFO     2

#define PROP_SUBTITLE_MAXFONTSIZE_KEY  "media.stagefright.maxsubfont"
#define SAVE_BITMAP_TO_PNG 0

#if SAVE_BITMAP_TO_PNG
static bool save(const char filename[], SkBitmap &bitmap)
{
	//remove(filename);

	if(!SkImageEncoder::EncodeFile(filename, bitmap, SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality))
	{
		printf("save png %s failed \n",filename);
	}
		printf("%s saved ok\n",filename);
	return true;
}
#endif

namespace android
{
	static SkBitmap::Config convertPixelFormat(PixelFormat ePixelFormat)
	{
	    switch (ePixelFormat)
	    {

		    case PIXEL_FORMAT_RGBX_8888:
            {
                 return SkBitmap::kARGB_8888_Config;
            }
		    case PIXEL_FORMAT_RGBA_8888:
            {
                 return SkBitmap::kARGB_8888_Config;
		    }
		    case PIXEL_FORMAT_RGBA_4444:
            {
                 return SkBitmap::kARGB_4444_Config;
            }
		    case PIXEL_FORMAT_RGB_565:
            {
                 return SkBitmap::kRGB_565_Config;
		    }
		    //case PIXEL_FORMAT_A_8:          return SkBitmap::kA8_Config;
		    default:
            {
                 return SkBitmap::kNo_Config;
		    }
	    }
	}

	static inline int is_ws_(int ch)
	{
	    return !((ch - 1) >> 5);
	}

	static inline int is_break(int c1,int c2)
	{
		if(c1 == 0x0D && c2 == 0x0A)
		{
			return true;
		}

		return false;
	}

	static size_t subLineBreak(const char cText[], const char cStop[], const SkPaint& paint, SkScalar margin,size_t *drawCount, int specialEffectFlag, SkScalar* lineWidth)
	{
	    const char*			pStart =NULL;
        #if(CONFIG_OS_VERSION == OPTION_OS_VERSION_ANDROID_4_2)
	    SkAutoGlyphCache    ac(paint, NULL);
        #else
        SkAutoGlyphCache    ac(paint, NULL, NULL);
        #endif
	    SkGlyphCache*       cache = NULL;
	    SkFixed             w = 0;
	    SkFixed             limit=0;
	    SkAutoKern          autokern;
	    size_t				count = 0;
	    const char* pWord_start = NULL;
	    int         prevWS		= true;
	    int			isbreak		= false;
        int         forbidBreakFlag = 0;
        const char* pPrevText    = NULL;
        const char* breaktext   = NULL;
        SkUnichar   uni;
        int         currWS;

        SkUnichar   nextuni;

        pStart = cText;
        cache = ac.getCache();
        limit = SkScalarToFixed(margin);
        pWord_start = cText;

        forbidBreakFlag = ((specialEffectFlag==SUB_RENDER_EFFECT_BANNER_LTOR)||
                           (specialEffectFlag==SUB_RENDER_EFFECT_BANNER_RTOL)||
                           (specialEffectFlag==SUB_RENDER_EFFECT_KARAOKE));

	    while (cText < cStop)
	    {
	        pPrevText	= cText;
	        uni		= SkUTF8_NextUnichar(&cText);
	        currWS		= is_ws_(uni);
	        const SkGlyph&  mGlyph = cache->getUnicharMetrics(uni);

            if (!currWS && prevWS)
	        {
	            pWord_start = pPrevText;
	        }

	        prevWS = currWS;

	        if(uni == 0x0D)
	        {
			breaktext			= cText;
			nextuni = SkUTF8_NextUnichar(&breaktext);
			if(nextuni == 0x0A)
			{
				isbreak = true;
			}
			else
			{
                    count += SkUTF8_CountUTF8Bytes(pPrevText);
			}
	        }
	        else
	        {
			count += SkUTF8_CountUTF8Bytes(pPrevText);
	        }


	        w += autokern.adjust(mGlyph) + mGlyph.fAdvanceX;

	        //if ((w > limit) || isbreak)
	        if(isbreak ||((w>limit)&&(forbidBreakFlag==0)))
	        {
	            if (currWS) // eat the rest of the whitespace
	            {
			*drawCount = count;
	                while (cText < cStop && is_ws_(SkUTF8_ToUnichar(cText)))
	                {
	                    cText += SkUTF8_CountUTF8Bytes(cText);
	                }
	            }
	            else    // backup until a whitespace (or 1 char)
	            {
	                if (pWord_start == pStart)
	                {
	                    if (pPrevText > pStart)
	                    {
	                        cText = pPrevText;
	                    }
	                }
	                else
	                {
	                    cText = pWord_start;
	                }

	                *drawCount = cText - pStart;
	            }

	            break;
	        }
	    }

        *lineWidth = (w>limit)? ((SkScalar)(limit>>16)): ((SkScalar)(w>>16));

	    if(cText >= cStop)
	    {
		*drawCount = count;
	    }
		return cText - pStart;
	}

	int CedarXSubTextBox::countLines(const char* pText, size_t len, const SkPaint& paint, SkScalar mWidth, SkScalar* subTextWidth, int specialEffectFlag)
	{
	    const char* stop = pText + len;
	    int         nCount = 0;
	    size_t	    charCount;
	    SkScalar    lineWidth = 0;

        *subTextWidth = 0;

	    if (mWidth > 0)
	    {
	        do
	        {
	            nCount += 1;
	            pText += subLineBreak(pText, stop, paint, mWidth, &charCount, specialEffectFlag, &lineWidth);
                if(*subTextWidth < lineWidth)
                {
                    *subTextWidth = lineWidth;
                }
	        } while (pText < stop);
	    }
	    return nCount;
	}

	//////////////////////////////////////////////////////////////////////////////

	CedarXSubTextBox::CedarXSubTextBox()
	{
	    mFBox.setEmpty();
	    mFSpacingMul = SK_Scalar1;
	    mFSpacingAdd = 0;
	    fMode = CedarXSubTextBoxLineBreak_Mode;
	    fSpacingAlign = CedarXSubTextBoxEnd_SpacingAlign;
        mLastDispXPos = -1;
        mLastDispYPos = -1;
	}

	void CedarXSubTextBox::setMode(CedarXSubTextBoxMode mode)
	{
	    fMode = SkToU8(mode);
	}

	void CedarXSubTextBox::setSpacingAlign(CedarXSubTextBoxSpacingAlign align)
	{
	    fSpacingAlign = SkToU8(align);
	}

	void CedarXSubTextBox::subGetBox(SkRect* box) const
	{
	    if (box)
	    {
	        *box = mFBox;
	    }
	}

	void CedarXSubTextBox::subSetBox(const SkRect& box)
	{
	    mFBox = box;
	}

	void CedarXSubTextBox::subSetBox(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom)
	{
	    mFBox.set(left, top, right, bottom);
	}

	void CedarXSubTextBox::subGetSpacing(SkScalar* mul, SkScalar* add) const
	{
	    if (mul)
	    {
	        *mul = mFSpacingMul;
	    }
	    if (add)
	    {
	        *add = mFSpacingAdd;
	    }
	}

	void CedarXSubTextBox::subSetSpacing(SkScalar mul, SkScalar add)
	{
	    mFSpacingMul = mul;
	    mFSpacingAdd = add;
	}

    int CedarXSubTextBox::getLastXPos()
	{
	    return mLastDispXPos;
	}

    int CedarXSubTextBox::getLastYPos()
	{
	    return mLastDispYPos;
	}

	/////////////////////////////////////////////////////////////////////////////////////////////

	int CedarXSub::Show()
	{
		if(mShow == false)
		{
			mSurfaceControl->show();
			mShow	= true;
		}

		return  NO_ERROR;
	}

	int CedarXSub::Hide()
	{
		if(mShow == true)
		{
			mSurfaceControl->hide();
			mShow	= false;
		}

		return  NO_ERROR;
	}

	int CedarXSub::setZorderBottom()
	{
		mSurfaceControl->setLayer(mBottomBaseLayer);

		return  NO_ERROR;
	}

	int CedarXSub::setZorderTop()
	{
		mSurfaceControl->setLayer(mTopBaseLayer);

		return  NO_ERROR;
	}

	int	CedarXSub::setLayer(int layer)
	{
		if(mShow == true)
		{
			SurfaceComposerClient::openGlobalTransaction();

			mSurfaceControl->setLayer(layer);

			SurfaceComposerClient::closeGlobalTransaction();
		}

		mLayer	= layer;

		return  NO_ERROR;
	}

	int	CedarXSub::getLayer()
	{
		return mLayer;
	}

	int CedarXSub::setBackColor(int color)
	{
		if(mBackColor != color)
		{
			mBackColor = color;

            if(mShow == true)
			{
                startRender();
			    render();
			    endRender();
            }
		}

		return NO_ERROR;
	}

	int CedarXSub::getBackColor()
	{
		return mBackColor;
	}

	int	CedarXSub::getBitmapFormat()
	{
		int   format;

		//format = (int)get_bitmap_format();

		return PIXEL_FORMAT_RGBA_8888;
	}

	int CedarXSub::mapDecToRender(int deccharset)
	{
		switch(deccharset)
		{
			case SUB_ENCODING_UTF8:
				return   SUB_CHARSET_UTF_8;

			case SUB_ENCODING_UTF16LE:
				return   SUB_CHARSET_UTF_16LE;

			case SUB_ENCODING_UTF32LE:
				return   SUB_CHARSET_UTF_32LE;

			case SUB_ENCODING_UTF32BE:
				return   SUB_CHARSET_UTF_32BE;

			case SUB_ENCODING_BIG5:
				return   SUB_CHARSET_BIG5;

			case SUB_ENCODING_GBK:
				return   SUB_CHARSET_GBK;

			case SUB_ENCODING_UTF16BE:
				return   SUB_CHARSET_UTF_16BE;

			default:
				return   SUB_CHARSET_UNKNOWN;
		}
	}

	int CedarXSub::convertUniCode(sub_item_inf *sub_info)
	{
		int			charset;
		const char* enc = NULL;

		//logd("******************CedarXSub::convertUniCode sub_info->encodingType = %d mCharset=%d",sub_info->encodingType,mCharset);
		charset	= sub_info->encodingType; //mapDecToRender(sub_info->encodingType);
		if(charset == SUBTITLE_TEXT_FORMAT_UNKNOWN)
		{
			charset = mCharset;
		}

        #if 0
		logd("((((((((((((((((((((((((((((((((((((((((((((( CedarXSub::convertUniCode charset = %d",charset);
		logd("CedarXSub::convertUniCode!sub_info->subTextBuf = %s",sub_info->subTextBuf);

		char fname[128];
		sprintf(fname, "/data/camera/fuqiang.txt");
		FILE *fp = fopen(fname, "w");
		fwrite((void *)sub_info->subTextBuf, sub_info->subTextLen, 1, fp);
		fflush(fp);
		fclose(fp);
        #endif

        switch(charset)
	    {
	        case SUBTITLE_TEXT_FORMAT_UTF8:
	             enc = "UTF-8";
	             break;

	        case SUBTITLE_TEXT_FORMAT_GB2312:
	             enc = "HZ-GB-2312" ;
	             break;

	        case SUBTITLE_TEXT_FORMAT_UTF16LE:
	             enc = "UTF-16LE";
	             break;

	        case SUBTITLE_TEXT_FORMAT_UTF16BE:
	             enc = "UTF-16BE";
	             break;

	        case SUBTITLE_TEXT_FORMAT_UTF32LE:
	             enc = "UTF-32LE";
	             break;

	        case SUBTITLE_TEXT_FORMAT_UTF32BE:
	             enc = "UTF-32BE";
	             break;

	        case SUBTITLE_TEXT_FORMAT_BIG5:
	             enc = "Big5";
	             break;

	        case SUBTITLE_TEXT_FORMAT_GBK:
	             enc = "GBK";
	             break;

	        case SUBTITLE_TEXT_FORMAT_ANSI:  //can not match,set to "UTF-8"
	             enc = "UTF-8";
	             break;

	        default:
	             enc = "UTF-8";
	             break;
	    }

	    if (enc)
	    {

	        UErrorCode status = U_ZERO_ERROR;

	        UConverter *conv = ucnv_open(enc, &status);
	        if (U_FAILURE(status))
	        {
	            logw("could not create UConverter for %s\n", enc);

	            return -1;
	        }

	        UConverter *utf8Conv = ucnv_open("UTF-8", &status);
	        if (U_FAILURE(status))
	        {
	            logw("could not create UConverter for UTF-8\n");

	            ucnv_close(conv);
	            return -1;
	        }

            // first we need to untangle the utf8 and convert it back to the original bytes
            // since we are reducing the length of the string, we can do this in place
            const char* src = (const char*)sub_info->subTextBuf;
            int len = sub_info->subTextLen;
            // now convert from native encoding to UTF-8
            int targetLength = len * 3 + 1;
            memset(mText,0,MAX_SUBLENGTH);
            char* target = &mText[0];
            ucnv_convertEx(utf8Conv, conv, &target, (const char*)target + targetLength,&src, (const char*)src + len, NULL, NULL, NULL, NULL, true, true, &status);
            if (U_FAILURE(status))
            {
                logw("ucnv_convertEx failed: %d\n", status);

                memset(mText,0,MAX_SUBLENGTH);
            }

            logv("CedarXSub::convertUniCode src = %s, mText: %s\n",sub_info->subTextBuf, mText);

	        ucnv_close(conv);
	        ucnv_close(utf8Conv);
	    }
	    return NO_ERROR;
	}


//*************************************************************************************************//
//*************************************************************************************************//
    int CedarXSub::setPosition(int posX,int posY)
	{
		if(true)
		{
			size_t		count;
			int			posx;
			int			posy;

			mPosX	= posX;
			mPosY	= posY;
			if(mPosX + mMaxWidth > mScreenWidth)
			{
				//mPosX = mScreenWidth - mMaxWidth;
                mMaxWidth = mScreenWidth - mPosX;
			}

			if(mPosY + mMaxHeight > mScreenHeight)
			{
				//mPosY = mScreenHeight - mMaxHeight;
				mMaxHeight  = mScreenHeight - mPosY;
			}

			SurfaceComposerClient::openGlobalTransaction();
			mSurfaceControl->setPosition(mPosX,mPosY);

			SurfaceComposerClient::closeGlobalTransaction();
		}

		return  NO_ERROR;
	}

	int CedarXSub::setPositionYPercent(int percent)
	{
           int maxYPos = 0;


		   if(mSubMode & PIC_SUBTITLE)
		   {
				mPosY   = (mScreenHeight - mMaxHeight)* (100 - percent) / 100;
				if(mPosY + mMaxHeight > mScreenHeight)
				{
					mPosY = mScreenHeight - mMaxHeight;
				}
				logd("2@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ %d %d", mPosX, mPosY);
				mSurfaceControl->setPosition(mPosX,mPosY);
            }
            else if((mShow == true) && (mSubMode & TEXT_SUBTITLE))
            {
                maxYPos = mScreenHeight*(100-percent)/100;
                if(mEndy > maxYPos)
                {
                    mEndy = maxYPos;
                }
                if((mEndy-mStarty)<mTextHeight)
                {
                    mStarty = mEndy-mTextHeight;
                }
                if(mStarty < 0)
                {
                    mStarty = 0;
                }
                setPosition(mStartx,mStarty);
	            mTextBox->subSetBox(0,0,SkIntToScalar(mEndx-mStartx),SkIntToScalar(mEndy-mStarty));
            }

		return  NO_ERROR;
	}

	int CedarXSub::getPositionX()
	{
		return mPosX;
	}

	int CedarXSub::getPositionY()
	{
		return mPosY;
	}

	int CedarXSub::getWidth()
	{
		return mWidth;
	}

	int CedarXSub::getHeight()
	{
		return mHeight;
	}

	int CedarXSub::setFontSize(int fontsize)
	{
		int		len;
        SkScalar textBoxHeight;

        if(mSubMode & PIC_SUBTITLE)
        {
            return NO_ERROR;
        }
		if(fontsize != mFontSize)
		{
			mFontSize = fontsize;
			mPaint.setTextSize(fontsize * mFontScaleRatio / FONT_SIZE_UNIT);
			if(mShow == true)
			{
                len	= strlen((char*)mText);
                mTextBox->getTextVerInf(mText,len,mPaint,&mTextHeight,&mTextWidth, &textBoxHeight, mStartx, mEndx, mStarty, mEndy, mDispSubInfo->subEffectFlag);
                needModifyBoxInf(textBoxHeight);
                setPosition(mStartx,mStarty);
	            mTextBox->subSetBox(0,0,SkIntToScalar(mEndx-mStartx),SkIntToScalar(mEndy-mStarty));
                startRender();
			    render();
			    endRender();
			}
		}

		return NO_ERROR;
	}

	int CedarXSub::getFontSize()
	{
		return mFontSize;
	}
	int CedarXSub::setTextColor(int color)
	{
        if(mTextColor != (unsigned int)color)
		{
			mTextColor = (unsigned int)color;

			mPaint.setColor(mTextColor);
			if(mShow == true)
			{
                startRender();
			    render();
			    endRender();
			}
		}

		return NO_ERROR;
	}

	int CedarXSub::getTextColor()
	{
		return mTextColor;
	}

	int CedarXSub::setCharset(int Charset)
	{
		mCharset = Charset;

		return NO_ERROR;
	}

	int CedarXSub::getCharset()
	{
		return mCharset;
	}

	int CedarXSub::setTextAlign(int align)
	{
		if(mTextAlign != align)
		{
			mTextAlign = align;

			if((align & SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_LEFT)
			{
				mPaint.setTextAlign(SkPaint::kLeft_Align);
			}
			else if((align & SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_CENTER)
			{
				mPaint.setTextAlign(SkPaint::kCenter_Align);
			}
			else if((align & SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_RIGHT)
			{
				mPaint.setTextAlign(SkPaint::kRight_Align);
			}
			else
			{
				mPaint.setTextAlign(SkPaint::kLeft_Align);
			}

			if((align & SUN_RENDER_VALIGN_MASK) == SUB_RENDER_VALIGN_TOP)
			{
				if(mTextBox != NULL)
				{
					mTextBox->setSpacingAlign(CedarXSubTextBox::CedarXSubTextBoxStart_SpacingAlign);
				}
			}
			else if((align & SUN_RENDER_VALIGN_MASK) == SUB_RENDER_VALIGN_CENTER)
			{
				if(mTextBox != NULL)
				{
					mTextBox->setSpacingAlign(CedarXSubTextBox::CedarXSubTextBoxCenter_SpacingAlign);

				}
			}
			else if((align & SUN_RENDER_VALIGN_MASK) == SUB_RENDER_VALIGN_BOTTOM)
			{
				if(mTextBox != NULL)
				{
					mTextBox->setSpacingAlign(CedarXSubTextBox::CedarXSubTextBoxEnd_SpacingAlign);
				}
			}
			else
			{
				if(mTextBox != NULL)
				{
					mTextBox->setSpacingAlign(CedarXSubTextBox::CedarXSubTextBoxStart_SpacingAlign);
				}
			}
            if(mShow == true)
            {
                startRender();
			    render();
			    endRender();
            }
		}

		return NO_ERROR;
	}

	int CedarXSub::getTextAlign()
	{
		return mTextAlign;
	}

	int CedarXSub::setFontStyle(int style)
	{
		if(mFontStyle != style)
		{
			mFontStyle = style;

			if((style & SUB_RENDER_STYLE_BOLD) == SUB_RENDER_STYLE_BOLD)
			{
				mPaint.setFakeBoldText(true);
			}
			else
			{
				mPaint.setFakeBoldText(false);
			}

			if((style & SUB_RENDER_STYLE_ITALIC) == SUB_RENDER_STYLE_ITALIC)
			{
				mPaint.setLinearText(true);
			}
			else
			{
				mPaint.setLinearText(false);
			}

			if((style & SUB_RENDER_STYLE_UNDERLINE) == SUB_RENDER_STYLE_UNDERLINE)
			{
				mPaint.setUnderlineText(true);
			}
			else
			{
				mPaint.setUnderlineText(false);
			}
            if((style & SUB_RENDER_STYLE_STRIKETHROUGH) == SUB_RENDER_STYLE_STRIKETHROUGH)
			{
				mPaint.setStrikeThruText(true);
			}
			else
			{
				mPaint.setStrikeThruText(false);
			}

            if(mShow == true)
			{
                startRender();

			    render();

			    endRender();
            }
		}

		return NO_ERROR;
	}

	int CedarXSub::getFontStyle()
	{
		return mFontStyle;
	}

//************************************************************************************************//
//*************************************************************************************************//
	CedarXSubRender::CedarXSubRender()
	{
		sp<CedarXSub>	  cedarXSub;

		logd("CedarXSubRender::CedarXSubRender xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1");
        mUserSetFontColor = 0;
        mUserSetFontSize  = 20;
        mUserSetFontStyle = 0;
        mUserSetYPercent  = 10;
        sub_pre           = NULL;
        mInitSetFontColor = 0;
        mInitSetFontSize  = 0;
        mInitSetFontStyle = 0;
        mDisplay          = 0;
        mPid              = 0;
		mBaseLayer        = 0;

		cedarXSub = new CedarXSub(0, mUserSetFontColor, mUserSetFontSize, mUserSetFontStyle, mUserSetYPercent);
		logd("CedarXSubRender::CedarXSubRender xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2");

		/*create main cedarXSub*/
		mCedarXSubs.add(cedarXSub);
	}

	CedarXSubRender::~CedarXSubRender()
	{
		logd("CedarXSubRender::~CedarXSubRender!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
	}

	int CedarXSubRender::cedarxSubShow()
	{
		size_t		count;
		logv("CedarXSubRender::cedarxSubShow!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
		count	= mCedarXSubs.size();

		SurfaceComposerClient::openGlobalTransaction();

		for(size_t i = 0;i < count;i++)
		{
            if(mCedarXSubs[i]->getSubShowFlag() == SUB_SHOW_NEW_VALID)
			{
                mCedarXSubs[i]->Show();
            }
		}

		SurfaceComposerClient::closeGlobalTransaction();

		return NO_ERROR;
	}

	int CedarXSubRender::cedarxSubHide(unsigned int systemTime, unsigned int* hasSubShowFlag)
	{
		size_t		count;
		unsigned  int remainSubShowFlag;
        logv("CedarXSubRender::cedarxSubHide!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
		count	= mCedarXSubs.size();

		SurfaceComposerClient::openGlobalTransaction();
        remainSubShowFlag = 0;

        if(systemTime == 0xFFFFFFFF)
		{
            for(size_t i = 0;i < count;i++)
		    {
                mCedarXSubs[i]->setSubShowFlag(SUB_SHOW_INVALID);
			    mCedarXSubs[i]->Hide();
		    }
        }
        else
        {

            for(size_t i = 0;i < count;i++)
		    {
			   if(mCedarXSubs[i]->getSubShowFlag()!=SUB_SHOW_INVALID)
			   {
                    if((mCedarXSubs[i]->getSubShowEndTime())<=systemTime)
                    {
                        mCedarXSubs[i]->setSubShowFlag(SUB_SHOW_INVALID);
                        mCedarXSubs[i]->Hide();
                    }
                    else
                    {
                        remainSubShowFlag = 1;
                        mCedarXSubs[i]->setSubShowFlag(SUB_SHOW_OLD_VALID);

                    }
               }
		    }
        }

        if(hasSubShowFlag != NULL)
        {
            *hasSubShowFlag = remainSubShowFlag;
        }
		SurfaceComposerClient::closeGlobalTransaction();

        if(remainSubShowFlag == 1)
        {
            for(size_t i = 0;i < count;i++)
		    {
			   if(mCedarXSubs[i]->getSubShowFlag()!=SUB_SHOW_INVALID)
			   {
                  mCedarXSubs[i]->processSpecialEffect(systemTime);
               }
		    }
        }
		return  NO_ERROR;
	}

	int CedarXSubRender::cedarxSubSetZorderTop()
	{
		size_t		count;
		logd("CedarXSubRender::cedarxSubSetZorderTop!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
		count	= mCedarXSubs.size();

		SurfaceComposerClient::openGlobalTransaction();

		for(size_t i = 0;i < count;i++)
		{
			mCedarXSubs[i]->setZorderTop();
		}

		SurfaceComposerClient::closeGlobalTransaction();

		return  NO_ERROR;
	}

	int CedarXSubRender::cedarxSubSetZorderBottom()
	{
		size_t		count;
		logd("CedarXSubRender::cedarxSubSetZorderBottom!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
		count	= mCedarXSubs.size();

		SurfaceComposerClient::openGlobalTransaction();

		for(size_t i = 0;i < count;i++)
		{
			mCedarXSubs[i]->setZorderBottom();
		}

		SurfaceComposerClient::closeGlobalTransaction();

		return  NO_ERROR;
	}


	int CedarXSubRender::cedarxSubSetPosition(int index,int positionx,int positiony)
	{
		size_t			count;

		count = mCedarXSubs.size();

		if(index > (int)count)
		{
			logw("Invalid index value!\n");

			return -1;
		}
		logd("???????????????????1");
		return  mCedarXSubs[index]->setPosition(positionx,positiony);
	}

	int CedarXSubRender::cedarxSubSetYPercent(int index,int percent)
	{
		size_t			count;
		int			i;

		count = mCedarXSubs.size();
		if(index > (int)count)
		{
			logw("Invalid index value!\n");

			return -1;
		}

		SurfaceComposerClient::openGlobalTransaction();
        #if 0
		if(index == -1)
		{
			for(index=0; index<(int)count; index++)
			{
				mCedarXSubs[index]->setPositionYPercent(percent);
			}
		}
		else
		{
			mCedarXSubs[index]->setPositionYPercent(percent);
		}
        #endif
        /*
        if(count == 1)
        {
            if(index==-1)
            {
                mCedarXSubs[0]->setPositionYPercent(percent);
            }
            else
            {
                mCedarXSubs[index]->setPositionYPercent(percent);
            }
        }
        */
		mUserSetYPercent  = percent;
        if(mCedarXSubs[0]->mShow == true)
        {
            cedarxSubHide(0xFFFFFFFF,NULL);
            if(sub_pre!=NULL)
                updateSubPara(sub_pre);
            cedarxSubShow();
        }
		SurfaceComposerClient::closeGlobalTransaction();

		return  0;
	}

	int CedarXSubRender::cedarxSubGetPositionX(int index)
	{
		size_t			count;

		count = mCedarXSubs.size();

		if(index > (int)count)
		{
			logw("Invalid index value!\n");

			return -1;
		}

		return  mCedarXSubs[index]->getPositionX();
	}

	int CedarXSubRender::cedarxSubGetPositionY(int index)
	{
		size_t			count;

		count = mCedarXSubs.size();

		if(index > (int)count)
		{
			logw("Invalid index value!\n");

			return -1;
		}

		return  mCedarXSubs[index]->getPositionY();
	}


	int CedarXSubRender::cedarxSubGetHeight(int index)
	{
		size_t			count;

		count = mCedarXSubs.size();

		if(index > (int)count)
		{
			logw("Invalid index value!\n");

			return -1;
		}

		return  mCedarXSubs[index]->getHeight();
	}

	int CedarXSubRender::cedarxSubGetWidth(int index)
	{
		size_t			count;

		count = mCedarXSubs.size();

		if(index > (int)count)
		{
			logw("Invalid index value!\n");

			return -1;
		}

		return  mCedarXSubs[index]->getWidth();
	}

    int CedarXSubRender::cedarxSubSetFontColor(int color)
	{
		size_t		count;

		count	= mCedarXSubs.size();

		for(size_t i = 0;i < count;i++)
		{
#if 0
            if(mCedarXSubs[i]->getTextColorFlag() == SUB_HAS_NONE_COLOR)
			{
                mCedarXSubs[i]->setTextColor(color);
            }
#else
            mCedarXSubs[i]->setTextColor(color);
#endif
		}

        mInitSetFontColor = (mUserSetFontColor ==0)? SUB_INIT_SET_FONT_INFO : SUB_USER_SET_FONT_INFO;
		mUserSetFontColor = color;
		return NO_ERROR;
	}

	int CedarXSubRender::cedarxSubGetFontColor()
	{
		return mCedarXSubs[0]->getTextColor();
	}

	int CedarXSubRender::cedarxSubSetFontSize(int size)
	{
		size_t		count;

		count	= mCedarXSubs.size();

		for(size_t i = 0;i < count;i++)
		{
#if 0
            if(mCedarXSubs[i]->getTextFontSizeFlag() == SUB_HAS_NONE_FONTSIZE)
			{
                mCedarXSubs[i]->setFontSize(size);
            }
#else
             mInitSetFontSize = (mUserSetFontSize ==0)? SUB_INIT_SET_FONT_INFO : SUB_USER_SET_FONT_INFO;
             mCedarXSubs[i]->setFontSize(size);
#endif
		}
        mUserSetFontSize = size;
		return NO_ERROR;
	}

	int CedarXSubRender::cedarxSubGetFontSize()
	{
		return mCedarXSubs[0]->getFontSize();
	}

	int CedarXSubRender::cedarxSubSetCharset(int charset)
	{
		size_t		count;

		count	= mCedarXSubs.size();

		for(size_t i = 0;i < count;i++)
		{
			mCedarXSubs[i]->setCharset(charset);
		}

		return NO_ERROR;
	}

	int CedarXSubRender::cedarxSubGetCharset()
	{
		return mCedarXSubs[0]->getCharset();
	}

	int CedarXSubRender::cedarxSubSetBackColor(int color)
	{
		size_t		count;

		count	= mCedarXSubs.size();

		for(size_t	i = 0;i < count;i++)
		{
			mCedarXSubs[i]->setBackColor(color);
		}

		return  NO_ERROR;
	}

	int CedarXSubRender::cedarxSubGetBackColor()
	{
		return mCedarXSubs[0]->getBackColor();
	}

	int CedarXSubRender::cedarxSubSetAlign(int align)
	{
		size_t		count;

		count	= mCedarXSubs.size();

		for(size_t	i = 0;i < count;i++)
		{
			mCedarXSubs[i]->setTextAlign(align);
		}
		return  NO_ERROR;
	}

	int CedarXSubRender::cedarxSubGetAlign()
	{
		return mCedarXSubs[0]->getTextAlign();
	}

 //**********************************************************************************************************//
 //**********************************************************************************************************//
    int CedarXSubRender::cedarxSubSetFontStyle(int style)
	{
		size_t		count;

		count	= mCedarXSubs.size();

		for(size_t	i = 0;i < count;i++)
		{
#if 0
            if(mCedarXSubs[i]->getTextFontStyleFlag() == SUB_HAS_NONE_STYLE)
			{
                mCedarXSubs[i]->setFontStyle(style);
            }
#else
            mInitSetFontStyle = (mUserSetFontStyle ==0)? SUB_INIT_SET_FONT_INFO : SUB_USER_SET_FONT_INFO;
            mCedarXSubs[i]->setFontStyle(style);
#endif
		}
        mUserSetFontStyle = style;
		return  NO_ERROR;
	}

	int CedarXSubRender::cedarxSubGetFontStyle()
	{
		return mCedarXSubs[0]->getFontStyle();
	}

//**********************************************************************************************************//
//**********************************************************************************************************//
    int CedarXSub::setSubInf(sub_item_inf *sub_info,int startx, int starty, int endx, int endy, int lastDispx, int lastDispy, int newShowSubFlag, int yPercent)
    {
        mSubShowFlag       = SUB_SHOW_NEW_VALID;
        mDispSubInfo       = sub_info;
        logv("setSubInf start");
        if(sub_info->subMode != 0)
        {
            return 0;
        }
        setTextBox(sub_info, startx, starty, endx, endy, lastDispx, lastDispy, newShowSubFlag, yPercent);

        switch(sub_info->subEffectFlag)
        {
            case SUB_RENDER_EFFECT_NONE:
            {
                break;
            }
            case SUB_RENDER_EFFECT_SCROLL_UP:
            {
                mAlignment &= SUN_RENDER_HALIGN_MASK;
                mAlignment |= SUB_RENDER_VALIGN_TOP;
                mEndy   = mDispSubInfo->effectEndyPos;
                mStarty = mEndy - mMaxHeight;
                if(mStarty < 0)
                {
                    mStarty = 0;
                }
                break;
            }
            case SUB_RENDER_EFFECT_SCROLL_DOWN:
            {
                mAlignment &= SUN_RENDER_HALIGN_MASK;
                mAlignment |= SUB_RENDER_VALIGN_BOTTOM;
                mStarty   = mDispSubInfo->effectStartyPos;
                mEndy   = mStarty + mMaxHeight;
                if(mEndy > mScreenHeight)
                {
                    mEndy = mScreenHeight;
                }
                break;
            }
            case SUB_RENDER_EFFECT_BANNER_LTOR:
            {
                mAlignment &= SUN_RENDER_VALIGN_MASK;
                mAlignment |= SUB_RENDER_HALIGN_RIGHT;
                mStartx = 0;
                mEndx   = mScreenWidth;
                break;
            }
            case SUB_RENDER_EFFECT_BANNER_RTOL:
            {
                mAlignment &= SUN_RENDER_VALIGN_MASK;
                mAlignment |= SUB_RENDER_HALIGN_LEFT;
                mStartx = 0;
                mEndx   = mScreenWidth;
                break;
            }
            case SUB_RENDER_EFFECT_MOVE:
            {
                mAlignment &= SUN_RENDER_HALIGN_MASK;
                mAlignment &= SUN_RENDER_VALIGN_MASK;
                mAlignment |= SUB_RENDER_VALIGN_TOP;
                mAlignment |= SUB_RENDER_HALIGN_LEFT;
                mStartx = 0;
                mEndx   = mScreenWidth;
                mEndy   = mScreenHeight;
                mStarty = mScreenHeight -mMaxHeight;
                break;
            }
            case SUB_RENDER_EFFECT_KARAOKE:
            {
                break;
            }
        }
		logv("setSubInf finish");
        return NO_ERROR;
    }

   int CedarXSub::setSubShowFlag(int subShowFlag)
   {
        mSubShowFlag = subShowFlag;
        return NO_ERROR;
   }
   int CedarXSub::getSubShowFlag()
   {
        return mSubShowFlag;
   }

   unsigned int CedarXSub::getSubShowEndTime()
   {
        return mDispSubInfo->endTime;
   }

   int  CedarXSub::getTextColorFlag()
   {
        if(mDispSubInfo == NULL)
        {
            return SUB_HAS_NONE_COLOR;
        }
        return (mDispSubInfo->primaryColor>0)? SUB_HAS_DEFINED_COLOR: SUB_HAS_NONE_COLOR;
   }
   int  CedarXSub::getTextFontSizeFlag()
   {
        if(mDispSubInfo == NULL)
        {
            return SUB_HAS_NONE_STYLE;
        }
        return (mDispSubInfo->fontSize>0)? SUB_HAS_DEFINED_FONTSIZE: SUB_HAS_NONE_FONTSIZE;
   }

   int  CedarXSub::getTextFontStyleFlag()
   {
        if(mDispSubInfo == NULL)
        {
            return SUB_HAS_NONE_STYLE;
        }
        return (mDispSubInfo->subStyle==SUB_RENDER_STYLE_NONE)? SUB_HAS_NONE_STYLE:SUB_HAS_DEFINED_STYLE;
   }

  //**************************************************************************************//
  //***************************************************************************************//

   int CedarXSub::processSpecialEffect(unsigned int systemTime)
   {
        int xPos = 0;
        int yPos = 0;
        int startx = 0;
        int endx = 0;
        int curSubSectionIdx = 0;
        int newAlignment = 0;

        if((mSubShowFlag==SUB_SHOW_INVALID) ||(mDispSubInfo->subEffectFlag==SUB_RENDER_EFFECT_NONE))
        {
            return NO_ERROR;
        }

        switch(mDispSubInfo->subEffectFlag)
        {
            case SUB_RENDER_EFFECT_SCROLL_UP:
            {
                xPos = getPositionX();
                yPos = mDispSubInfo->effectEndyPos - (systemTime-mDispSubInfo->startTime)/mDispSubInfo->effectTimeDelay;
                setPosition(xPos, yPos);
                break;
            }
            case SUB_RENDER_EFFECT_SCROLL_DOWN:
            {
                xPos = getPositionX();
                yPos = mDispSubInfo->effectStartyPos+(systemTime-mDispSubInfo->startTime)/mDispSubInfo->effectTimeDelay;
                setPosition(xPos, yPos);
                break;
            }
            case SUB_RENDER_EFFECT_BANNER_LTOR:
            {
                xPos = mDispSubInfo->effectStartxPos+(systemTime-mDispSubInfo->startTime)/mDispSubInfo->effectTimeDelay;
                mTextBox->subSetBox(0,0,SkIntToScalar(xPos),SkIntToScalar(mEndy-mStarty));
                break;
            }
            case SUB_RENDER_EFFECT_BANNER_RTOL:
            {
                xPos = mDispSubInfo->effectEndxPos-(systemTime-mDispSubInfo->startTime)/mDispSubInfo->effectTimeDelay;
                mTextBox->subSetBox(xPos,0,SkIntToScalar(mEndx-mStartx),SkIntToScalar(mEndy-mStarty));
                break;
            }
            case SUB_RENDER_EFFECT_MOVE:
            {
                if(mDispSubInfo->effectStartyPos < mDispSubInfo->effectEndyPos)
                {
                    yPos = mDispSubInfo->effectStartyPos +
                          ((mDispSubInfo->effectEndyPos-mDispSubInfo->effectStartyPos)*(systemTime-mDispSubInfo->startTime))/(mDispSubInfo->endTime-mDispSubInfo->startTime);
                }
                else
                {
                    yPos = mDispSubInfo->effectStartyPos -
                           ((mDispSubInfo->effectStartyPos-mDispSubInfo->effectEndyPos)*(systemTime-mDispSubInfo->startTime))/(mDispSubInfo->endTime-mDispSubInfo->startTime);
                }
                if(mDispSubInfo->effectStartxPos < mDispSubInfo->effectEndxPos)
                {
                    xPos = mDispSubInfo->effectStartxPos +
                          ((mDispSubInfo->effectEndxPos-mDispSubInfo->effectStartxPos)*(systemTime-mDispSubInfo->startTime))/(mDispSubInfo->endTime-mDispSubInfo->startTime);
                }
                else
                {
                    xPos = mDispSubInfo->effectStartxPos -
                           ((mDispSubInfo->effectStartxPos-mDispSubInfo->effectEndxPos)*(systemTime-mDispSubInfo->startTime))/(mDispSubInfo->endTime-mDispSubInfo->startTime);
                }
                setPosition(xPos, yPos);
                break;
            }
            #if 0
            case SUB_RENDER_EFFECT_KARAOKE:
            {
                 if((systemTime-mDispSubInfo->startTime)> mDispSubInfo->effectTimeDelay)
                 {
                    return NO_ERROR;
                 }
                 if((mAlignment&SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_LEFT)
                 {
                    startx = mStartx;
                 }
                 else if((mAlignment&SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_CENTER)
                 {
                    startx = mStartx+(mEndx-mStartx-(int)mTextWidth)/2;
                 }
                 else if((mAlignment&SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_RIGHT)
                 {
                    startx = mEndx-(int)mTextWidth;
                 }
                 endx = startx+mTextWidth*(systemTime-mDispSubInfo->startTime)/mDispSubInfo->effectTimeDelay;

                 setPosition(startx, mStarty);

                 mTextBox->subSetBox(0,0,SkIntToScalar(endx-startx),SkIntToScalar(mEndy-mStarty));
                 newAlignment = mAlignment;
                 newAlignment &= SUN_RENDER_VALIGN_MASK;
                 newAlignment |= SUB_RENDER_HALIGN_LEFT;

                 setTextAlign(newAlignment);
                 SurfaceComposerClient::openGlobalTransaction();

                 if(mTextColor != mDispSubInfo->primaryColor)
                 {
                    mTextColor = mDispSubInfo->primaryColor;
			        mPaint.setColor(mTextColor);
                 }
                 startRenderRegion(startx, mStarty, endx, mEndy);
                 render(0);
                 endRender();
                 SurfaceComposerClient::closeGlobalTransaction();
                 return NO_ERROR;
            }
            #endif
           #if 0
            case SUB_RENDER_EFFECT_KARAOKE:
            {
                 if((systemTime-mDispSubInfo->startTime)> mDispSubInfo->effectTimeDelay)
                 {
                    return NO_ERROR;
                 }
                 mDispSubInfo->subKarakoEffectInf->karaKoSectionLen[0] = 0;
                 mDispSubInfo->subKarakoEffectInf->karaKoSectionLen[68] = 0;
                 mDispSubInfo->subKarakoEffectInf->karaKoSectionLen[126] = 0;

                 for(curSubSectionIdx=0; curSubSectionIdx<mDispSubInfo->subKarakoEffectInf->karakoSectionNum; curSubSectionIdx++)
                 {
                     baseTime1 = mDispSubInfo->subKarakoEffectInf->karaKoSectionStartTime[curSubSectionIdx];
                     baseTime2 = mDispSubInfo->subKarakoEffectInf->karaKoSectionStartTime[curSubSectionIdx+1];
                     logd("***********baseTime1=%d, baseTime2=%d, diffTime=%d\n", baseTime1, baseTime2, (systemTime-mDispSubInfo->startTime));
                    if(((systemTime-mDispSubInfo->startTime)>=baseTime1)&&
                        ((systemTime-mDispSubInfo->startTime)<baseTime2))
                    {
                        break;
                    }
                }
                 if((mAlignment&SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_LEFT)
                 {
                    startx = mStartx;
                 }
                 else if((mAlignment&SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_CENTER)
                 {
                    startx = mStartx+(mEndx-mStartx-(int)mTextWidth)/2;
                 }
                 else if((mAlignment&SUN_RENDER_HALIGN_MASK) == SUB_RENDER_HALIGN_RIGHT)
                 {
                    startx = mEndx-(int)mTextWidth;
                 }


                 len1      = mDispSubInfo->subKarakoEffectInf->karaKoSectionLen[curSubSectionIdx];
                 len2      = mDispSubInfo->subKarakoEffectInf->karaKoSectionLen[curSubSectionIdx+1];

                 logd("***********len1=%d, len2=%d, curSubSectionIdx=%d\n", len1, len2, curSubSectionIdx);

                 startx += len1;

                 endx  = startx +(systemTime-mDispSubInfo->startTime-baseTime1)*(len2-len1)/(baseTime2-baseTime1);

                 //endx = startx+mTextWidth*(systemTime-mDispSubInfo->startTime)/mDispSubInfo->effectTimeDelay;

                 setPosition(startx, mStarty);

                 mTextBox->subSetBox(0,0,SkIntToScalar(endx-startx),SkIntToScalar(mEndy-mStarty));
                 newAlignment = mAlignment;
                 newAlignment &= SUN_RENDER_VALIGN_MASK;
                 newAlignment |= SUB_RENDER_HALIGN_LEFT;

                 setTextAlign(newAlignment);
                 SurfaceComposerClient::openGlobalTransaction();

                 if(mTextColor != mDispSubInfo->primaryColor)
                 {
                    mTextColor = mDispSubInfo->primaryColor;
			        mPaint.setColor(mTextColor);
                 }
                 startRenderRegion(startx, mStarty, endx, mEndy);
                 render(0);
                 endRender();
                 SurfaceComposerClient::closeGlobalTransaction();
                 return NO_ERROR;

            }
            #endif
            default:
            {
                return NO_ERROR;
            }
        }

        SurfaceComposerClient::openGlobalTransaction();
        startRender();
        render();
        endRender();
        SurfaceComposerClient::closeGlobalTransaction();
        return NO_ERROR;
    }

 //************************************************************************************************************//
 //*********************************************************************************************************** //
    int CedarXSub::getTextBox(int* startx, int *starty, int* endx, int* endy, int *lastDispx, int *lastDispy)
    {
        *startx     = mStartx;
        *starty     = mStarty;
        *endx       = mEndx;
        *endy       = mEndy;
        *lastDispx  = mStartDispx;
        *lastDispy  = mStartDispy;
        return NO_ERROR;
    }
 //************************************************************************************************************//
 //*********************************************************************************************************** //

    int  CedarXSub::setTextBox(sub_item_inf *sub_info,int startx, int starty, int endx, int endy, int lastDispx, int lastDispy, int newShowSubFlag, int yPercent)
    {
        int align = 0;
        int newStartx = 0;
        int newStarty = 0;
        int newEndx = 0;
        int newEndy = 0;
        int maxYPos = 0;

        mStartx     = startx;
        mStarty     = starty;
        mEndx       = endx;
        mEndy       = endy;
        mStartDispx = lastDispx;
        mStartDispy = lastDispy;

        mMaxWidth		= mScreenWidth;
        //mMaxHeight      = mMaxTextLine*mMaxFontHeight;
        mMaxHeight = mScreenHeight;
        mPosX = 0;
        mPosY = 0;

        maxYPos = mScreenHeight*(100-yPercent)/100;

        switch(sub_info->subDispPos)
        {
            case SUB_DISPPOS_TOP_LEFT:
                 align |= SUB_RENDER_HALIGN_LEFT;
                 align |= SUB_RENDER_VALIGN_TOP;
                 newStartx  = sub_info->startx;
                 newStarty  = sub_info->starty;
                 newEndx    = mScreenWidth;
                 newEndy    = newStarty+mMaxHeight;
                 if(newEndy > maxYPos)
                 {
                    newEndy = maxYPos;
                 }
                 break;
            case SUB_DISPPOS_TOP_MID:
                 align |= SUB_RENDER_HALIGN_CENTER;
                 align |= SUB_RENDER_VALIGN_TOP;

                 newStartx  = 0;
                 newStarty  = sub_info->starty;
                 newEndx    = mScreenWidth;
                 newEndy    = newStarty+mMaxHeight;
                 if(newEndy > maxYPos)
                 {
                    newEndy = maxYPos;
                 }
                 break;
            case SUB_DISPPOS_TOP_RIGHT:
                 align |= SUB_RENDER_HALIGN_RIGHT;
                 align |= SUB_RENDER_VALIGN_TOP;
                 newStartx  = 0;
                 newStarty  = sub_info->starty;
                 newEndx    = sub_info->endx;
                 newEndy    = newStarty+mMaxHeight;
                 if(newEndy > maxYPos)
                 {
                    newEndy = maxYPos;
                 }
                 break;
            case SUB_DISPPOS_MID_LEFT:
                 align |= SUB_RENDER_HALIGN_LEFT;
                 align |= SUB_RENDER_VALIGN_CENTER;
                 newStartx  = sub_info->startx;
                 newStarty  = (mScreenHeight-mMaxHeight)>>1;
                 newEndx    = mScreenWidth;
                 newEndy    = newStarty+mMaxHeight;
                 if(newEndy > maxYPos)
                 {
                    newEndy = maxYPos;
                 }
                 break;
            case SUB_DISPPOS_MID_MID:
                 align |= SUB_RENDER_HALIGN_CENTER;
                 align |= SUB_RENDER_VALIGN_CENTER;
                 newStartx  = 0;
                 newStarty  = (mScreenHeight-mMaxHeight)>>1;
                 newEndx    = mScreenWidth;
                 newEndy    = newStarty+mMaxHeight;
                 if(newEndy > maxYPos)
                 {
                    newEndy = maxYPos;
                 }
                 break;
            case SUB_DISPPOS_MID_RIGHT:
                 align |= SUB_RENDER_HALIGN_RIGHT;
                 align |= SUB_RENDER_VALIGN_CENTER;
                 newStartx  = 0;
                 newStarty  = (mScreenHeight-mMaxHeight)>>1;
                 newEndx    = sub_info->endx;
                 newEndy    = newStarty+mMaxHeight;
                 if(newEndy > maxYPos)
                 {
                    newEndy = maxYPos;
                 }
                 break;
            case SUB_DISPPOS_BOT_LEFT:
                 align |= SUB_RENDER_HALIGN_LEFT;
                 align |= SUB_RENDER_VALIGN_BOTTOM;
                 newStartx  = sub_info->startx;
                 newEndy    = sub_info->endy;
                 if(newEndy > maxYPos)
                 {
                    newEndy = maxYPos;
                 }
                 newEndx    = mScreenWidth;
                 newStarty  = newEndy-mMaxHeight;
                 if(newStarty < 0)
                 {
                    newStarty = 0;
                 }
                 break;
            case SUB_DISPPOS_BOT_MID:
                 align |= SUB_RENDER_HALIGN_CENTER;
                 align |= SUB_RENDER_VALIGN_BOTTOM;
                 newStartx  = 0;
                 newEndx    = mScreenWidth;
                 newEndy    = sub_info->endy;
                 if((newEndy+10) > maxYPos)
                 {
                    newEndy = maxYPos;
                 }
                 newStarty  = newEndy-mMaxHeight;
                 if(newStarty < 0)
                 {
                    newStarty = 0;
                 }
                 break;
            case SUB_DISPPOS_BOT_RIGHT:
                 align |= SUB_RENDER_HALIGN_RIGHT;
                 align |= SUB_RENDER_VALIGN_BOTTOM;
                 newStartx  = 0;
                 newEndx    = sub_info->endx;
                 newEndy    = sub_info->endy;
                 if(newEndy > maxYPos)
                 {
                    newEndy = maxYPos;
                 }
                 newStarty  = newEndy-mMaxHeight;
                 if(newStarty < 0)
                 {
                    newStarty = 0;
                 }
                 break;
            default:
                 align |= SUB_RENDER_HALIGN_CENTER;
                 align |= SUB_RENDER_VALIGN_BOTTOM;
                 newStartx  = mPosX;
                 newEndx    = mPosX+mWidth;
                 newEndy    = maxYPos;
                 newStarty  = newEndy - mMaxHeight;
                 if(newStarty < 0)
                 {
                    newStarty = 0;
                 }
                 break;
          }
         if((newShowSubFlag==0)&&(newStartx==mStartx)&&(newStarty==mStarty)&&(newEndx==mEndx)&&(newEndy==mEndy))
         {
            mStartx = newStartx;
            mEndx   = newEndx;
            mEndy   = mStartDispy+mStarty;
            mStarty = mEndy-mMaxHeight;
            if(mStarty <  0)
            {
                mStarty = 0;
            }
        }
        else
        {
            mStartx = newStartx;
            mStarty = newStarty;
            mEndx   = newEndx;;
            mEndy   = newEndy;
        }
        mAlignment = align;
        logv("******rendere:align=%x,subDispPos=%d,startx=%d,starty=%d,endx=%d,endy=%d, orgStartx=%d,orgStarty=%d,orgEndx=%d,orgEndy=%d\n",align,sub_info->subDispPos,mStartx,
          mStarty, mEndx, mEndy,sub_info->startx,sub_info->starty,sub_info->endx,sub_info->endy);
        return  NO_ERROR;
    }
 //************************************************************************************************************//
 //*********************************************************************************************************** //
    int CedarXSub::generateBitmap(sub_item_inf *sub_info)
	{
		ssize_t bpr = sub_info->subPicWidth * bytesPerPixel(PIXEL_FORMAT_RGBA_8888);
	    mBitmap.setConfig(convertPixelFormat(PIXEL_FORMAT_RGBA_8888), sub_info->subPicWidth, sub_info->subPicHeight, bpr);
	    mBitmap.setIsOpaque(true);

	    if (sub_info->subPicWidth > 0 && sub_info->subPicHeight > 0)
	    {
            //set R of bitmap(RGBA) to 0
            for (int i = 0 ; i < sub_info->subPicWidth * sub_info->subPicHeight; i++ )
            {
                sub_info->subBitmapBuf[4*i] = 0;
            }
	        mBitmap.setPixels((void *)sub_info->subBitmapBuf);
	    }
	    else
	    {
	        // be safe with an empty bitmap.
	        mBitmap.setPixels(NULL);
	    }

		return NO_ERROR;
	}


    //***************************************************************************************//
    //**************************************************************************************//

     void CedarXSubTextBox::drawText(SkCanvas* canvas, const char *text, size_t len, const SkPaint& mPaint, SkScalar textHeight, int specialEffectFlag)
	{
		size_t		drawCount;
        SkScalar    lineWidth;

	    SkASSERT(canvas && &mPaint && (text || len == 0));

	    SkScalar mMarginWidth = mFBox.width();

		logv("*************&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&CedarXSubTextBox::drawText len = %d,mMarginWidth = %f\n",len,mMarginWidth);
	    if (mMarginWidth <= 0 || len == 0)
	    {
	        return;
	    }

	    const char* textStop = text + len;


	    SkScalar                mSkScalarX=0, mSkScalarY=0, mScaledSpacing, height, mFontHeight;
	    SkPaint::FontMetrics    mMetrics;

	    switch (mPaint.getTextAlign())
	    {
		    case SkPaint::kLeft_Align:
		        mSkScalarX = 0;
		        break;
		    case SkPaint::kCenter_Align:
		        mSkScalarX = SkScalarHalf(mMarginWidth);
		        break;
		    default:
		        mSkScalarX = mMarginWidth;
		        break;
	    }
	    mSkScalarX += mFBox.fLeft;
	    mFontHeight = mPaint.getFontMetrics(&mMetrics);
	    mScaledSpacing = SkScalarMul(mFontHeight, mFSpacingMul) + mFSpacingAdd;
	    height = mFBox.height();

	    //  compute mSkScalarY position for first line
	    {
	        switch (fSpacingAlign)
	        {
		        case CedarXSubTextBoxStart_SpacingAlign:
		            mSkScalarY = 0;
		            break;
		        case CedarXSubTextBoxCenter_SpacingAlign:
		            mSkScalarY = SkScalarHalf(height - textHeight);
                    break;
		        default:
		            mSkScalarY = height - textHeight;
		            break;
	        }

	        mSkScalarY += mFBox.fTop - mMetrics.fAscent;
	        //logd("CedarXSubTextBox::drawText mSkScalarY = %f,mFBox.fTop=%f,mMetrics.fAscent = %f,textHeight = %f,height = %f\n",mSkScalarY,mFBox.fTop,mMetrics.fAscent,textHeight,height);
	    }

        mLastDispXPos = (int)mSkScalarX;
        mLastDispYPos = (int)(mSkScalarY-mScaledSpacing);


	    for (;;)
	    {
	        len = subLineBreak(text, textStop, mPaint, mMarginWidth,&drawCount,specialEffectFlag, &lineWidth);
	        if (mSkScalarY + mMetrics.fDescent + mMetrics.fLeading > 0)
	        {
	            canvas->drawText(text, drawCount, mSkScalarX, mSkScalarY, mPaint);
	            logv("canvas->drawText!text = %s,drawCount = %d\n",text,drawCount);
	        }
	        text += len;
	        if (text >= textStop)
	        {
	            break;
	        }
	        mSkScalarY += mScaledSpacing;
	        if (mSkScalarY + mMetrics.fAscent >= height)
	        {
	            break;
	        }
	    }
	}
 //************************************************************************************************************//
 //*********************************************************************************************************** //
	int CedarXSub::render()
	{
        if(mCanvas == NULL)
		{
			logd("shit!!!!!!!!!");
		}
		mCanvas->drawColor(mBackColor, SkXfermode::kSrc_Mode);
		if(mSubMode & TEXT_SUBTITLE)
		{
            int     len;
		    SkScalar textHeight;
            SkScalar textBoxHeight;
            len = strlen(mText);
            mTextBox->drawText(mCanvas, mText, len, mPaint, mTextHeight, mDispSubInfo->subEffectFlag);
            mStartDispx = mTextBox->getLastXPos();
            mStartDispy = mTextBox->getLastYPos();
		}
		else if(mSubMode & PIC_SUBTITLE)
		{
            int posx    = 0;
            int posy    = 0;
            int width  = mBitmap.width();
            int height  = mBitmap.height();

            if((mDispSubInfo->subScaleWidth==0)||(mDispSubInfo->subScaleHeight==0))
            {
                posx = (mWidth - width)>>1;
                posy = (mHeight - height);
                posx = (posx<0)? 0 : posx;
                posy = (posy<0)? 0 : posy;
                #if SAVE_BITMAP_TO_PNG
                save("/data/local/tmp/subBitmapS011",mBitmap);
                #endif
			    mCanvas->drawBitmap(mBitmap,posx,posy,&mPaint);
                #if SAVE_BITMAP_TO_PNG
                SkBitmap BitmapIncanvas = mCanvas->getDevice()->accessBitmap(false);
                save("/data/local/tmp/subBitmapS011-output",BitmapIncanvas);
                #endif
            }
            else
            {
                SkIRect src;
                SkRect  dst;
                src.set(0,0,width, height);

                posx = (mWidth - mDispSubInfo->subScaleWidth)>>1;
                posy = (mHeight - mDispSubInfo->subScaleHeight);

                posx = (posx<0)? 0 : posx;
                posy = (posy<0)? 0 : posy;

                dst.set(posx,posy,posx+mDispSubInfo->subScaleWidth, posy+mDispSubInfo->subScaleHeight);
                mCanvas->drawBitmapRect(mBitmap, &src, dst,&mPaint);
            }
		}
		return NO_ERROR;
	}

 //************************************************************************************************************//
 //*********************************************************************************************************** //
	CedarXSub::CedarXSub(int index, int userSetFontColor, int userSetFontSize, int userSetFontStyle, int userSetYpercent)
	{
		status_t err;
		sp<Surface> mSurface;
		char prop_value[4];
		int int_val;
        DisplayInfo mDisplayInfo;
		logd("CedarXSub::CedarXSub #####################\n");
		mDisplay = SUB_DISPLAY;
		mMaxTextLine = MAX_TEXTLINE;
		mFontScaleRatio = FONT_SIZE_UNIT;
		mMaxFontHeight	= MAX_FONTHEIGHT;
		mPid			= IPCThreadState::self()->getCallingPid();
		mShow			= false;

        sp<SurfaceComposerClient> mClient = new SurfaceComposerClient;
		mSurfaceClient = mClient;

        sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
        SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);

	mScreenWidth	= mDisplayInfo.w;
	mScreenHeight	= mDisplayInfo.h;

		mMaxWidth		= mScreenWidth;

        if(mScreenHeight >= 1080)
        {
            mFontScaleRatio = FONT_SIZE_UNIT * 3; //X3
			mMaxFontHeight  = mMaxFontHeight * 3;
        }
		else if (mScreenHeight >= 720) {
			mFontScaleRatio = FONT_SIZE_UNIT * 3 / 2; //X1.5
			mMaxFontHeight  = mMaxFontHeight * 3 / 2;
		}
		else if (mScreenHeight >= 600) {
			mFontScaleRatio = FONT_SIZE_UNIT * 5 / 4; //X1.25
			mMaxFontHeight  = mMaxFontHeight * 5 / 4;
		}

		mMaxHeight  = mScreenHeight;

        if(mScreenHeight >= 1080)
        {
            if(mMaxHeight <= 300)
            {
                mMaxHeight = 300;
            }
        }
        else
        {
            if(mMaxHeight <= 300)
            {
                mMaxHeight = 300;
            }
        }

		if(mMaxWidth >= mScreenWidth)
		{
			mPosX		= 0;
		}
		else
		{
			mPosX		= (mScreenWidth - mMaxWidth)>>1;
		}

		if(mMaxHeight >= mScreenHeight)
		{
			mPosY		= 0;
		}
		else
		{
			mPosY   = (mScreenHeight - mMaxHeight)* (100 - userSetYpercent) / 100;
		}
        String8 name;
        const size_t SIZE = 128;
        char buffer[SIZE];
        snprintf(buffer, SIZE, "<pid_%d>", getpid());
        name.append(buffer);
        mSurfaceControl = mClient->createSurface(name, mMaxWidth, mMaxHeight, PIXEL_FORMAT_TRANSPARENT, ISurfaceComposerClient::eFXSurfaceNormal);

		if(mSurfaceControl != NULL)
		{
			SurfaceComposerClient::openGlobalTransaction();
			mTopBaseLayer	= TOPBASELAYER * LAYER_MULTIPLIER + LAYER_OFFSET + 2 + index;
			mBottomBaseLayer= BOTTOMBASELAYER * LAYER_MULTIPLIER + LAYER_OFFSET  - 10 + index;
			mLayer			= mTopBaseLayer;
			logd("3@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ %d %d", mPosX, mPosY);
			mSurfaceControl->setPosition(mPosX,mPosY);
			//mSurfaceControl->setLayer(mLayer);
			mSurfaceControl->setLayer(99999);
			mSurfaceControl->hide();
			SurfaceComposerClient::closeGlobalTransaction();

			mCanvas		= new SkCanvas;

			mWidth	= mMaxWidth;
			mHeight = mMaxHeight;

			mPaint.setAntiAlias(true);
			logd("=**********************8 mFontScaleRatio = %d", mFontScaleRatio);
            if(userSetFontSize == 0)
            {
                mPaint.setTextSize(DEFAULT_TEXT_SIZE * mFontScaleRatio / FONT_SIZE_UNIT);
            }
			else
            {
                mPaint.setTextSize(userSetFontSize * mFontScaleRatio / FONT_SIZE_UNIT);
			}

            if(userSetFontColor == 0)
			{
                mPaint.setColor(0xFFFFFFFF);
            }
            else
            {
                mPaint.setColor(userSetFontColor);
            }
            if(userSetFontStyle == 0)
			{
                mFontStyle = SUB_RENDER_STYLE_NONE;
                setFontStyle(SUB_RENDER_STYLE_NONE);
            }
            else
            {
                setFontStyle(userSetFontStyle);
            }
			mPaint.setTextAlign(SkPaint::kCenter_Align);
			mBackColor = TRANSPARENT_COLOR;
#if(CONFIG_OS_VERSION >= OPTION_OS_VERSION_ANDROID_5_0)
                        mTypeface  = SkTypeface::CreateFromFile("/system/fonts/DroidSansFallbackAndroid44.ttf");
#else
			mTypeface  = SkTypeface::CreateFromFile("/system/fonts/DroidSansFallback.ttf");
#endif
			mPaint.setTypeface(mTypeface);
			mCharset     = SUBTITLE_TEXT_FORMAT_GBK;
			mTextBox     = NULL;
            mSubMode     = 0;
            mDispSubInfo = NULL;
            mSubShowFlag = SUB_SHOW_INVALID;
		}
	}
   //************************************************************************************************************//
  //*********************************************************************************************************** //
	CedarXSub::~CedarXSub()
	{
		if(mTypeface != NULL)
		{
			mTypeface->unref();
		}

		logd("CedarXSub::~CedarXSub1!\n");

		if(mCanvas != NULL)
		{
			mCanvas->unref();
		}

		logd("CedarXSub::~CedarXSub2!\n");

		if(mTextBox != NULL)
		{
			delete mTextBox;
		}

		logd("CedarXSub::~CedarXSub3!\n");

		if (SurfaceControl::isValid(mSurfaceControl))
		{
		mSurfaceControl->clear();
	}

	logd("CedarXSub::~CedarXSub4!\n");
	}
  //************************************************************************************************************//
  //*********************************************************************************************************** //
#if 0
    int CedarXSub::startRenderRegion(int startx, int starty, int endx, int endy)
	{
		ANativeWindow_Buffer nativeWindowBuffer;
		status_t				err;
		SkBitmap				mBitmap;
		sp<Surface>				mSurface;
        Region                 dirtyRegion;
        Rect                   dirty;

        dirty.left   = startx;
        dirty.top    = starty;
        dirty.right  = endx;
        dirty.bottom = endy;

        //dirtyRegion.set(dirty);

		mSurface	= mSurfaceControl->getSurface();

		err = mSurface->lock(&nativeWindowBuffer, &dirty);
		logd("//////////////////////////////////////////////////////1");
	    if (err < 0)
	    {
	        logw("get surface information failed!\n");

	        return  -1;
	    }
	    ssize_t bpr = nativeWindowBuffer.width * bytesPerPixel(nativeWindowBuffer.format);
	    mBitmap.setConfig(convertPixelFormat(nativeWindowBuffer.format), endx-startx, endy-starty, bpr);
	    if (nativeWindowBuffer.format == PIXEL_FORMAT_RGBX_8888)
	    {
	        mBitmap.setIsOpaque(true);
	    }

	    if (nativeWindowBuffer.width > 0 && nativeWindowBuffer.height > 0)
	    {
	        //bitmap.setPixels(info.bits+4*(mStarty*mScreenWidth+mStartx));
	        mBitmap.setPixels(nativeWindowBuffer.bits);
	    }
	    else
	    {
	        // be safe with an empty bitmap.
	        mBitmap.setPixels(NULL);
	    }

		mCanvas->setBitmapDevice(mBitmap);
	    //mCanvas->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
	    //mCanvas->writePixels(bitmap,0,0,SkCanvas::Config8888::kNative_Premul_Config8888);

		mSaveCount = mCanvas->save();

		return  NO_ERROR;
	}
#endif

	int CedarXSub::startRender()
	{
#if(CONFIG_OS_VERSION == OPTION_OS_VERSION_ANDROID_4_2)
        Surface::SurfaceInfo	info;
		status_t				err;
		SkBitmap				mBitmap;
		sp<Surface>				mSurface;

		mSurface	= mSurfaceControl->getSurface();
        err = mSurface->lock(&info, NULL);
	    if (err < 0)
	    {
	        logw("get surface information failed!\n");

	        return  -1;
	    }

	    ssize_t bpr = info.s * bytesPerPixel(info.format);
	    mBitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);
	    if (info.format == PIXEL_FORMAT_RGBX_8888)
	    {
	        mBitmap.setIsOpaque(true);
	    }

	    if (info.w > 0 && info.h > 0)
	    {
	        //bitmap.setPixels(info.bits+4*(mStarty*mScreenWidth+mStartx));
	        mBitmap.setPixels(info.bits);
	    }
	    else
	    {
	        // be safe with an empty bitmap.
	        mBitmap.setPixels(NULL);
	    }

	    mCanvas->setBitmapDevice(mBitmap);

		mSaveCount = mCanvas->save();

		return  NO_ERROR;
#else
        ANativeWindow_Buffer nativeWindowBuffer;
		status_t				err;
		SkBitmap				mBitmap;
		sp<Surface>				mSurface;
		mSurface	= mSurfaceControl->getSurface();
		err = mSurface->lock(&nativeWindowBuffer, NULL/*false*/);
	    if (err < 0)
	    {
	        logw("get surface information failed!\n");

	        return  -1;
	    }
	    ssize_t bpr = nativeWindowBuffer.width * bytesPerPixel(nativeWindowBuffer.format);
	    mBitmap.setConfig(convertPixelFormat(nativeWindowBuffer.format),
                                             nativeWindowBuffer.width,
                                             nativeWindowBuffer.height, bpr);
		/*
		for(int k = 0; k < 1280 * 720; k ++)
		{
			((unsigned int *)outBuffer.bits)[k] = 8334543;
		}
		*/

	    if (nativeWindowBuffer.format == PIXEL_FORMAT_RGBX_8888)
	    {
			mBitmap.setIsOpaque(true);
	    }

	    if (nativeWindowBuffer.width > 0 && nativeWindowBuffer.height > 0)
	    {
	        //bitmap.setPixels(info.bits+4*(mStarty*mScreenWidth+mStartx));
	        mBitmap.setPixels(nativeWindowBuffer.bits);
	    }
	    else
	    {
	        // be safe with an empty bitmap.
	        mBitmap.setPixels(NULL);
	    }
/*
		static int num = 0;
		char fname[128];
		sprintf(fname, "/data/camera/fuqiang%03d.rgba", num);
		num ++;
		FILE *fp = fopen(fname, "w");
		fwrite((void *)outBuffer.bits, outBuffer.width * outBuffer.height * bytesPerPixel(outBuffer.format), 1, fp);
		fflush(fp);
		fclose(fp);
*/
	    mCanvas->setBitmapDevice(mBitmap);
	    //mCanvas->writePixels(bitmap,0,0,SkCanvas::kNative_Premul_Config8888);

		mSaveCount = mCanvas->save();
		return  NO_ERROR;
#endif
	}

	int CedarXSub::endRender()
	{
		status_t				err;
		sp<Surface>				mSurface;

		mSurface	= mSurfaceControl->getSurface();

		// detach the canvas from the surface
	    mCanvas->restoreToCount(mSaveCount);
	    mSaveCount = 0;

	    // unlock surface
	    err = mSurface->unlockAndPost();
	    if (err < 0)
	    {
	        logw("surface unlockAndPost Failed!\n");

	        return -1;
	    }

	    return NO_ERROR;
	}
  //************************************************************************************************************//
  //*********************************************************************************************************** //
    int CedarXSubTextBox::getTextVerInf(const char *text, size_t len, const SkPaint& paint,SkScalar* subTextHeight,SkScalar* subTextWidth,SkScalar* textBoxHeight, int textBoxStartx,
                                         int textBoxEndx, int textBoxStarty, int textBoxEndy, int specialEffectFlag)
    {
        int nCount = 0;
        SkScalar mTextHeight = 0;
        const char* textStop;
	    SkScalar mScaledSpacing, height, mFontHeight;
	    SkPaint::FontMetrics    metrics;
        SkScalar marginWidth;

        marginWidth = textBoxEndx - textBoxStartx + 1;
        mFontHeight = paint.getFontMetrics(&metrics);
	    mScaledSpacing = SkScalarMul(mFontHeight, mFSpacingMul) + mFSpacingAdd;
	    height = textBoxEndy - textBoxStarty + 1;
	    textStop = text + len;
	    mTextHeight = mFontHeight;

	    if(fMode == CedarXSubTextBoxLineBreak_Mode)
	    {
            nCount = countLines(text, textStop - text, paint, marginWidth, subTextWidth, specialEffectFlag);
            SkASSERT(nCount > 0);
	        mTextHeight += mScaledSpacing * (nCount - 1);
	    }
        *subTextHeight = mTextHeight;
        *textBoxHeight = (SkScalar)(textBoxEndy-textBoxStarty);
        return NO_ERROR;
    }
 //************************************************************************************************************//
 //*********************************************************************************************************** //
    int CedarXSub::needModifyBoxInf(SkScalar textBoxHeight)
    {
        int aglignMent= 0;
        int offset = 0;

        if(mTextHeight <= textBoxHeight)
        {
            return NO_ERROR;             // not need modify text box vertical info
        }
        else
        {
            aglignMent = (mAlignment & 0xf0);
            if(aglignMent == SUB_RENDER_VALIGN_TOP)
            {
                if((SkScalar)(mScreenHeight-mStarty) > mTextHeight)
                {
                    mEndy = mStarty + mTextHeight;
                    if(mEndy >= mScreenHeight)
                    {
                        mEndy = mScreenHeight;
                    }
                 }
                else
                {
                    mEndy = mScreenHeight;
                    mStarty = mEndy - mTextHeight;
                    if(mStarty < 0)
                    {
                        mStarty = 0;
                    }
                }
            }
            else if(aglignMent == SUB_RENDER_VALIGN_CENTER)
            {
               offset = (mTextHeight - textBoxHeight)/2;
               mStarty -= offset;
               mEndy += offset;
               if(mStarty < 0)
               {
                    mStarty = 0;
               }
               if(mEndy > mScreenHeight)
               {
                   mEndy = mScreenHeight;
               }
            }
            else if(aglignMent == SUB_RENDER_VALIGN_BOTTOM)
            {
                if((SkScalar)mEndy > mTextHeight)
                {
                    mStarty = mEndy - mTextHeight;
                    if(mStarty < 0)
                    {
                        mStarty = 0;
                    }
                }
                else
                {
                    mStarty = 0;
                    mEndy = mStarty + mTextHeight;
                    if(mEndy > mScreenHeight)
                    {
                        mEndy = mScreenHeight;
                    }
                }
            }
        }
        return NO_ERROR;
    }

  //************************************************************************************************************//
  //*********************************************************************************************************** //
	int CedarXSub::updatePara(sub_item_inf *sub_info, int initSetFontColor, int initSetFontSize, int initSetFontStyle, int Ypercent)
	{
        int	  len = 0;
        int   fontIndex = 0;
        SkScalar textBoxHeight;

		if(sub_info == NULL)
		{
			logw("input para error!\n");

			return	-1;
		}

		mSubMode = 0;

		if(sub_info->subMode == 0)
		{
			mSubMode |= TEXT_SUBTITLE;
			convertUniCode(sub_info);
		}
		else
		{
			mSubMode |= PIC_SUBTITLE;

			generateBitmap(sub_info);
		}

        if(mSubMode & TEXT_SUBTITLE)
        {
            logv("CedarXSub::updatePara mText = %s\n",mText);
            if(mTextBox == NULL)
			{
				mTextBox = new CedarXSubTextBox;
                mTextAlign |= SUB_RENDER_HALIGN_CENTER;
                mTextAlign |= SUB_RENDER_VALIGN_BOTTOM;
			}
            if(sub_info->subHasFontInfFlag == 1)
            {
                if((initSetFontSize==SUB_INIT_SET_FONT_INFO)&&(sub_info->fontSize>0))
                {
                    #if 1
                    fontIndex = (sub_info->fontSize>>2)-2;
                    fontIndex = (fontIndex<0)? 0:fontIndex;
                    fontIndex = (fontIndex>16)? 16:fontIndex;
                    fontIndex += 16;
                    fontIndex = (fontIndex<25)? 25: fontIndex;
                    #else
                    fontIndex = sub_info->fontSize;
                    #endif

                    setFontSize(fontIndex);
                }

                if(mDispSubInfo->subEffectFlag==SUB_RENDER_EFFECT_KARAOKE)
                {
                    if(sub_info->secondaryColor > 0)
                    {
                        setTextColor(sub_info->secondaryColor);
                    }
                }
                else
                {
                    if((initSetFontColor==SUB_INIT_SET_FONT_INFO)&&(sub_info->primaryColor>0))
                    {
                        setTextColor(sub_info->primaryColor);
                    }
                    if((initSetFontStyle==SUB_INIT_SET_FONT_INFO) &&(sub_info->subStyle != SUB_RENDER_STYLE_NONE))
                    {
                        setFontStyle(sub_info->subStyle);
                    }
                }
            }

            len	= strlen((char*)mText);
            #if 0
			char fname[128];
			sprintf(fname, "/data/camera/fuqiang1.txt");
			FILE *fp = fopen(fname, "w");
			fwrite((void *)mText, len, 1, fp);
			fflush(fp);
			fclose(fp);
            #endif
            mTextBox->getTextVerInf(mText,len,mPaint,&mTextHeight,&mTextWidth, &textBoxHeight, mStartx, mEndx, mStarty, mEndy, mDispSubInfo->subEffectFlag);
			needModifyBoxInf(textBoxHeight);
            setPosition(mStartx,mStarty -50);
	        mTextBox->subSetBox(0,0,SkIntToScalar(mEndx-mStartx),SkIntToScalar(mEndy-mStarty));
            setTextAlign(mAlignment);
        }
        else
        {
				mPosY   = (mScreenHeight-mMaxFontHeight)* (Ypercent) / 100;
				logd("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ mPosY = %d, mScreenHeight = %d, mMaxFontHeight = %d", mPosY, mScreenHeight, mMaxFontHeight);
                /*
				if(mPosY + mMaxHeight > mScreenHeight)
				{
					mPosY = mScreenHeight - mMaxHeight;
				}
				*/
				mSurfaceControl->setPosition(mPosX,-mPosY);
        }
        if((mDispSubInfo->subEffectFlag==SUB_RENDER_EFFECT_NONE)||(mDispSubInfo->subEffectFlag==SUB_RENDER_EFFECT_KARAOKE))
		{
			startRender();
		    render();
		    endRender();
        }
		return NO_ERROR;
	}

  //************************************************************************************************************//
  //*********************************************************************************************************** //
	int	CedarXSubRender::updateSubPara(sub_item_inf *sub_info)
	{
		sub_pre = sub_info;
        int				count = 0;
		size_t			size;
		sub_item_inf	*current;
		sp<CedarXSub>	cedarXSub;
        int             dispStartx = 0;
        int             dispStarty = 0;
        int             dispHeight = 0;
        int             align      = 0;
        int             lastPosValidFlag = 0;
        int             startx = 0;
        int             starty = 0;
        int             endx   = 0;
        int             endy   = 0;
        int             lastDispx = 0;
        int             lastDispy = 0;
        int             newShowSubFlag = 0;

		if(sub_info == NULL)
		{
			logw("Invalid sub information!\n");

			return  -1;
		}

		current = sub_info;

		size	= mCedarXSubs.size();
        newShowSubFlag = 1;

		while(current != NULL)
		{
            if(count > 0)
            {
                mCedarXSubs[count-1]->getTextBox(&startx, &starty, &endx, &endy, &lastDispx, &lastDispy);
            }

			if(count >= (int)size)
			{
				cedarXSub = new CedarXSub(0, mUserSetFontColor, mUserSetFontSize, mUserSetFontStyle, mUserSetYPercent);

				/*create main cedarXSub*/
				mCedarXSubs.add(cedarXSub);
			}

            if(mCedarXSubs[count]->getSubShowFlag() == SUB_SHOW_INVALID)
            {
				if(current == NULL)
				{
					logd("***********current is null **********");
				}
				logv("@@startx = %d, starty = %d, endx = %d, endx = %d,lastDispx = %d lastDispy = %d, newShowSubFlag = %d",
                        startx, starty, endx, endy, lastDispx, lastDispy, newShowSubFlag);
                mCedarXSubs[count]->setSubInf(current, startx, starty, endx, endy, lastDispx, lastDispy, newShowSubFlag, mUserSetYPercent);
			    mCedarXSubs[count]->updatePara(current, mInitSetFontColor, mInitSetFontSize, mInitSetFontStyle, mUserSetYPercent);
			    current = (sub_item_inf *)current->nextSubItem;
                newShowSubFlag = 0;
            }
			count++;
		}

		return NO_ERROR;
	}


//************************************************************************************************************//
//************************************************************************************************************//

#ifdef __cplusplus
extern "C"
{
#endif

    CedarXSubRender* gCedarXSubRender = NULL;


	static bool checkCedarXSubRenderUnitialized()
    {
	    if (gCedarXSubRender == NULL)
	    {
	        return true;
	    }

	    return false;
	}

	int SubRenderCreate()
	{
		logd("****************SubRenderCreate!****************\n");

		if(gCedarXSubRender == NULL)
		{
			gCedarXSubRender = new CedarXSubRender();

			logd("****************SubRenderCreate success!****************\n");
		}

		return NO_ERROR;
	}

	int SubRenderDestory()
	{
		logd("****************SubRenderDestory!****************\n");
		if (checkCedarXSubRenderUnitialized())
		{

	        return -1;
	    }
	    logd("****************SubRenderDestory1!****************\n");

	    delete gCedarXSubRender;

	    gCedarXSubRender = NULL;

	    logd("****************SubRenderDestory2!****************\n");

	    return NO_ERROR;
	}

	int SubRenderDraw(sub_item_inf *sub_info)
	{
		if (checkCedarXSubRenderUnitialized())
		{
	        return -1;
	    }
	    logv("****************SubRenderDraw!****************\n");
	    return gCedarXSubRender->updateSubPara(sub_info);
	}

	int SubRenderShow()
	{
		if (checkCedarXSubRenderUnitialized())
		{

	        return -1;
	    }
	    logv("****************SubRenderShow!****************\n");
	    return gCedarXSubRender->cedarxSubShow();
	}

	int SubRenderHide(unsigned int systemTime, unsigned int* hasSubShowFlag)
	{
		if (checkCedarXSubRenderUnitialized())
		{
	        return -1;
	    }
	    logv("****************SubRenderHide!****************\n");
	    return gCedarXSubRender->cedarxSubHide(systemTime, hasSubShowFlag);
	}

	int SubRenderSetZorderTop()
	{
		if (checkCedarXSubRenderUnitialized())
		{
	        return -1;
	    }
	    logv("****************SubRenderSetZorderTop!****************\n");
	    return gCedarXSubRender->cedarxSubSetZorderTop();
	}

	int SubRenderSetZorderBottom()
	{
		if (checkCedarXSubRenderUnitialized())
		{
	        return -1;
	    }
	    logv("****************SubRenderSetZorderBottom!****************\n");
	    return gCedarXSubRender->cedarxSubSetZorderBottom();
	}

#ifdef __cplusplus
}
#endif
} // namespace android