Exemplo n.º 1
0
//----------------------------------------------------------------//
void MOAITextFrame::Parse () {
	
	float xScaleAdvance = this->mRightToLeft ? -1.0f : 1.0f;
	
	this->mLineBottom = 0;
	this->mLineTop = 0;
	
	this->mLineCount = 0;
	this->mLineXMax = 0.0f;
	this->mTokenXMin = 0.0f;
	this->mTokenXMax = 0.0f;
	
	float points = this->mPoints;
	
	float lineHeight = this->mFont->GetLineSpacing () * this->mPoints * this->mLineSpacing;
	this->mTotalLines = ( u32 )floorf ( this->mFrame.Height () / lineHeight );
	if ( !this->mTotalLines ) return;

	this->mPen.Init ( 0.0f, this->mFrame.mYMin );

	u32 colorSize = 0;
	u8 color [ COLOR_MAX ];

	u32 c = 0;
	this->mGlyph = 0;

	bool inToken = false;
	int resetIdx = 0;
	
	u32 state = META_START;
	while ( state != META_FINISH ) {
		
		switch ( state ) {
			
			//================================================================//
			// META
			//----------------------------------------------------------------//
			
			//----------------------------------------------------------------//
			// check to see if we've encountered a style escape
			case META_START: {
				
				resetIdx = this->mIdx;
				c = this->DecodeChar ();

				if ( c == 0 ) {
					
					this->FlushToken ();
					
					if ( this->mLineCount >= this->mTotalLines ) {
						TRANSITION ( META_FINISH );
					}
					
					// save the cursor just before the EOF
					this->mCursor->mIndex = resetIdx;
					this->mCursor->mRGBA  = this->mRGBA;
					
					this->FlushLine ();
					
					TRANSITION ( META_FINISH );
				}
				
				TRANSITION_ON_MATCH ( '<', STYLE_START );
				TRANSITION ( TEXT_START );
			}
			
			//================================================================//
			// TEXT
			//----------------------------------------------------------------//
			
			//----------------------------------------------------------------//
			// process a single char as text (ignore style escape)
			case TEXT_START: {
				
				if ( c == '\n' ) {
					
					this->FlushToken ();
					inToken = false;
					
					if ( this->mLineCount >= this->mTotalLines ) {
						TRANSITION ( META_FINISH );
					}
					
					this->mCursor->mIndex = resetIdx;
					this->mCursor->mRGBA  = this->mRGBA;
					
					this->FlushLine ();
					
					this->mPen.mX = 0.0f;
					this->mTokenXMax = 0.0f;
					this->mTokenXMin = 0.0f;
					this->mGlyph = 0;
					
					TRANSITION ( META_START );
				}
				
				const MOAIGlyph* prevGlyph = this->mGlyph;
				const MOAIGlyph* glyph = &this->mFont->GetGlyphForChar ( c );
				this->mGlyph = glyph;
				
				assert ( glyph );
				
				bool hasWidth = ( glyph->mWidth > 0.0f );
				
				// apply kerning
				if ( prevGlyph ) {
					MOAIKernVec kernVec = prevGlyph->GetKerning ( glyph->mCode );
					this->mPen.mX += kernVec.mX * points * xScaleAdvance;
				}
				
				if ( hasWidth ) {
	
					if ( inToken == false ) {
						
						// save the cursor just before the new token
						this->mCursor->mIndex = resetIdx;
						this->mCursor->mRGBA  = this->mRGBA;
						
						this->mTokenXMin = this->mPen.mX;
						this->mTokenXMax = this->mPen.mX;
						inToken = true;
					}
					
					// push the glyph
					float penX = this->mPen.mX + (( glyph->mWidth + glyph->mBearingX ) * points * xScaleAdvance );
					float glyphX = this->mRightToLeft ? penX : this->mPen.mX;
					
					this->mLayout->PushGlyph ( glyph, resetIdx, glyphX, 0.0f, points, this->mRGBA );
					this->mTokenXMax = penX;
				}
				else if ( inToken ) {
				
					this->FlushToken ();
					
					// bail if line count overflow
					if ( this->mLineCount >= this->mTotalLines ) {
						TRANSITION ( META_FINISH );
					}
					inToken = false;
				}
				
				// advance the pen
				this->mPen.mX += glyph->mAdvanceX * points * xScaleAdvance;
				
				// back to start
				TRANSITION ( META_START );
			}
			
			//================================================================//
			// STYLE
			//----------------------------------------------------------------//
			
			//----------------------------------------------------------------//
			// see which style we're parsing
			case STYLE_START: {
				
				c = this->DecodeChar ();
				TRANSITION_ON_MATCH ( 'c', COLOR_START );
				TRANSITION ( STYLE_ABORT );
			}
			
			// reset the cursor and go directly to text mode
			case STYLE_ABORT: {
			
				this->mIdx = resetIdx;
				c = this->DecodeChar ();
				TRANSITION ( TEXT_START );
			}
			
			//================================================================//
			// COLOR
			//----------------------------------------------------------------//
			
			//----------------------------------------------------------------//
			case COLOR_START: {
			
				colorSize = 0;
			
				c = this->DecodeChar ();
				if ( IsWhitespace ( c )) continue;
				
				if ( c == ':' ) {
					state = COLOR_BODY;
					break;
				}
				
				TRANSITION_ON_MATCH ( ':', COLOR_BODY );
				TRANSITION_ON_MATCH ( '>', COLOR_FINISH );
				
				TRANSITION ( STYLE_ABORT );
			}
			
			//----------------------------------------------------------------//
			case COLOR_BODY: {
				
				c = this->DecodeChar ();
				if ( IsWhitespace ( c )) continue;
				
				TRANSITION_ON_MATCH ( '>', COLOR_FINISH );
				
				u8 hex = HexToByte ( c );
				if (( hex != 0xff ) && ( colorSize < COLOR_MAX )) {
					color [ colorSize++ ] = hex;
					break;
				}
				
				TRANSITION ( STYLE_ABORT );
			}
			
			//----------------------------------------------------------------//
			case COLOR_FINISH: {
				
				this->mRGBA = this->PackColor ( color, colorSize );
				TRANSITION ( META_START );
			}
		}
	}
	
	// discard overflow
	this->mLayout->SetTop ( this->mLineTop );
}
Exemplo n.º 2
0
//----------------------------------------------------------------//
bool MOAITextStyler::ParseStyle () {

	if ( this->mStr [ this->mIdx ] != '<' ) return false;

	u32 colorSize = 0;
	u8 color [ COLOR_MAX ];

	u32 c = 0;
	
	int startIdx = this->mIdx;
	
	u32 state = STYLE_START;
	while ( state != DONE ) {
		
		switch ( state ) {

			//================================================================//
			// STYLE
			//----------------------------------------------------------------//
			
			//----------------------------------------------------------------//
			// see which style we're parsing
			case STYLE_START: {
				
				c = this->GetChar ();
				
				TRANSITION_ON_MATCH ( '<', STYLE_BODY );
				TRANSITION ( STYLE_ABORT );
			}
			
			//----------------------------------------------------------------//
			case STYLE_BODY: {
				
				c = this->GetChar ();

				if ( c == '<' ) {
					this->mIdx = startIdx + 1;
					this->FinishToken ();
					startIdx = this->mIdx;
					TRANSITION ( DONE );
				}
				
				TRANSITION_ON_MATCH ( '/', STYLE_POP_START );
				TRANSITION_ON_MATCH ( '>', STYLE_POP_FINISH );
				TRANSITION_ON_MATCH ( 'c', COLOR_START );
				TRANSITION ( STYLE_NAME_START );
			}
			
			//----------------------------------------------------------------//
			case STYLE_ABORT: {
				
				this->mIdx = startIdx;
				TRANSITION ( DONE );
			}
			
			//================================================================//
			// COLOR
			//----------------------------------------------------------------//
			
			//----------------------------------------------------------------//
			case COLOR_START: {
				
				colorSize = 0;
				c = this->GetChar ();
				
				TRANSITION_ON_MATCH ( ':', COLOR_BODY );
				
				// reset and try to parse style name instead
				this->mIdx = startIdx;
				TRANSITION ( STYLE_NAME_START );
			}
			
			//----------------------------------------------------------------//
			case COLOR_BODY: {
				
				c = this->GetChar ();

				TRANSITION_ON_MATCH ( '>', COLOR_FINISH );
				
				u8 hex = HexToByte ( c );
				if (( hex != 0xff ) && ( colorSize < COLOR_MAX )) {
					color [ colorSize++ ] = hex;
					TRANSITION ( COLOR_BODY );
				}
				TRANSITION ( STYLE_ABORT );
			}
			
			//----------------------------------------------------------------//
			case COLOR_FINISH: {
				
				this->FinishToken ();
				
				MOAITextStyle* style = this->mTextBox->AddAnonymousStyle ( this->mCurrentStyle );
				style->mColor = this->PackColor ( color, colorSize );
				this->PushStyle ( style );
				
				TRANSITION ( DONE );
			}
			
			//================================================================//
			// STYLE_NAME
			//----------------------------------------------------------------//
			
			//----------------------------------------------------------------//
			case STYLE_NAME_START: {
				
				c = this->GetChar ();
				
				if ( MOAIFont::IsControl ( c ) || MOAIFont::IsWhitespace ( c )) {
					TRANSITION ( STYLE_ABORT );
				}
				
				TRANSITION_ON_MATCH ( '>', STYLE_NAME_FINISH );
				TRANSITION ( STYLE_NAME_START );
			}
			
			//----------------------------------------------------------------//
			case STYLE_NAME_FINISH: {

				this->FinishToken ();

				int namesize = this->mIdx - startIdx - 2;
				assert ( namesize > 0 );

				char* name = ( char* )alloca ( namesize + 1 );
				memcpy ( name, &this->mStr [ startIdx + 1 ], namesize );
				name [ namesize ] = 0;
				
				MOAITextStyle* style = this->mTextBox->GetStyle ( name );
				this->PushStyle ( style );
				
				TRANSITION ( DONE );
			}
			
			//================================================================//
			// STYLE_POP
			//----------------------------------------------------------------//
			
			//----------------------------------------------------------------//
			case STYLE_POP_START: {
				
				c = this->GetChar ();
				
				if ( MOAIFont::IsControl ( c ) || MOAIFont::IsWhitespace ( c )) {
					TRANSITION ( STYLE_ABORT );
				}
				
				TRANSITION_ON_MATCH ( '>', STYLE_POP_FINISH );
				TRANSITION ( STYLE_POP_START );
			}
			
			//----------------------------------------------------------------//
			case STYLE_POP_FINISH: {
				
				this->FinishToken ();
				this->PopStyle ();
				TRANSITION ( DONE );
			}
		}
	}
	
	return ( this->mIdx > startIdx );
}