You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

742 lines
24 KiB

/* --COPYRIGHT--,BSD
* Copyright (c) 2013, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* --/COPYRIGHT--*/
#include "grlib.h"
//*****************************************************************************
//
//! \addtogroup string_api
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// The character printed by GrStringDraw in place of any character in the
// string which does not appear in the font. When using a font which does not
// include this character, a space is left instead.
//
//*****************************************************************************
#define ABSENT_CHAR_REPLACEMENT '.'
//*****************************************************************************
//
// Counts the number of zeros at the start of a word. This macro uses
// compiler-specific constructs to perform an inline insertion of the "clz"
// instruction, which counts the leading zeros directly.
//
//*****************************************************************************
int NumLeadingZeros(long x)
{
long y = 0x80, count =0;
long i;
for (i=0; i< 32; i++)
{
if (0x00 != (x & y ))
break;
count++;
y = y >> 1;
}
return count;
}
//*****************************************************************************
//
//! Determines the width of a string.
//!
//! \param pContext is a pointer to the drawing context to use.
//! \param pcString is the string in question.
//! \param lLength is the length of the string.
//!
//! This function determines the width of a string (or portion of the string)
//! when drawn with a particular font. The \e lLength parameter allows a
//! portion of the string to be examined without having to insert a NULL
//! character at the stopping point (would not be possible if the string was
//! located in flash); specifying a length of -1 will cause the width of the
//! entire string to be computed.
//!
//! \return Returns the width of the string in pixels.
//
//*****************************************************************************
long
GrStringWidthGet(const tContext *pContext, const char *pcString, long lLength)
{
const unsigned short *pusOffset;
const unsigned char *pucData;
unsigned char ucFirst, ucLast, ucAbsent;
long lWidth;
//
// Check the arguments.
//
assert(pContext);
assert(pcString);
//
// Get some pointers to relevant information in the font to make things
// easier, and give the compiler a hint about extraneous loads that it can
// avoid.
//
if(pContext->pFont->ucFormat & FONT_EX_MARKER)
{
tFontEx *pFont;
pFont = (tFontEx *)(pContext->pFont);
pucData = pFont->pucData;
pusOffset = pFont->pusOffset;
ucFirst = pFont->ucFirst;
ucLast = pFont->ucLast;
//
// Does the default absent character replacement exist in the font?
//
if((ABSENT_CHAR_REPLACEMENT >= ucFirst) &&
(ABSENT_CHAR_REPLACEMENT <= ucLast))
{
//
// Yes - use the standard character when an absent character is
// found.
//
ucAbsent = ABSENT_CHAR_REPLACEMENT;
}
else
{
//
// The default absent character is not present in the font so use
// the first character (we only use its width here) instead.
//
ucAbsent = pFont->ucFirst;
}
}
else
{
pucData = pContext->pFont->pucData;
pusOffset = pContext->pFont->pusOffset;
ucFirst = 32;
ucLast = 126;
ucAbsent = ABSENT_CHAR_REPLACEMENT;
}
//
// Loop through the characters in the string.
//
for(lWidth = 0; *pcString && lLength; pcString++, lLength--)
{
//
// Get a pointer to the font data for the next character from the
// string. If there is not a glyph for the next character, replace it
// with a ".".
//
if((*pcString >= ucFirst) && (*pcString <= ucLast))
{
//
// Add the width of this character as drawn with the given font.
//
lWidth += pucData[pusOffset[*pcString - ucFirst] + 1];
}
else
{
//
// This character does not exist in the font so replace it with
// a '.' instead. This matches the approach taken in GrStringDraw
// and ensures that the width returned here represents the
// rendered dimension of the string.
//
lWidth += pucData[pusOffset[ucAbsent - ucFirst] + 1];
}
}
//
// Return the width of the string.
//
return(lWidth);
}
//*****************************************************************************
//
//! Draws a string.
//!
//! \param pContext is a pointer to the drawing context to use.
//! \param pcString is a pointer to the string to be drawn.
//! \param lLength is the number of characters from the string that should be
//! drawn on the screen.
//! \param lX is the X coordinate of the upper left corner of the string
//! position on the screen.
//! \param lY is the Y coordinate of the upper left corner of the string
//! position on the screen.
//! \param bOpaque is true of the background of each character should be drawn
//! and false if it should not (leaving the background as is).
//!
//! This function draws a string of test on the screen. The \e lLength
//! parameter allows a portion of the string to be examined without having to
//! insert a NULL character at the stopping point (which would not be possible
//! if the string was located in flash); specifying a length of -1 will cause
//! the entire string to be rendered (subject to clipping).
//!
//! \return None.
//
//*****************************************************************************
void
GrStringDraw(const tContext *pContext, const char *pcString, long lLength,
long lX, long lY, unsigned long bOpaque)
{
long lIdx, lX0, lY0, lCount, lOff, lOn, lBit;
const unsigned char *pucData;
const unsigned char *pucGlyphs;
const unsigned short *pusOffset;
unsigned char ucFirst, ucLast, ucAbsent;
tContext sCon;
long lYSave = lY;
lY = 0;
//
// Check the arguments.
//
assert(pContext);
assert(pcString);
//
// Copy the drawing context into a local structure that can be modified.
//
sCon = *pContext;
//
// Extract various parameters from the font depending upon whether it's
// in the tFont or tFontEx format.
//
if(pContext->pFont->ucFormat & FONT_EX_MARKER)
{
tFontEx *pFont;
pFont = (tFontEx *)(pContext->pFont);
pucGlyphs = pFont->pucData;
pusOffset = pFont->pusOffset;
ucFirst = pFont->ucFirst;
ucLast = pFont->ucLast;
//
// Does the default absent character replacement exist in the font?
//
if((ABSENT_CHAR_REPLACEMENT >= ucFirst) &&
(ABSENT_CHAR_REPLACEMENT <= ucLast))
{
//
// Yes - use the standard character when an absent character is
// found.
//
ucAbsent = ABSENT_CHAR_REPLACEMENT;
}
else
{
//
// The default absent character is not present in the font so use
// the first character instead.
//
ucAbsent = pFont->ucFirst;
}
}
else
{
pucGlyphs = pContext->pFont->pucData;
pusOffset = pContext->pFont->pusOffset;
ucFirst = 32;
ucLast = 126;
ucAbsent = ABSENT_CHAR_REPLACEMENT;
}
//
// Loop through the characters in the string.
//
while(*pcString && lLength--)
{
//
// Stop drawing the string if the right edge of the clipping region has
// been exceeded.
//
if(lX > sCon.sClipRegion.sXMax)
{
break;
}
//
// Get a pointer to the font data for the next character from the
// string. If there is not a glyph for the next character, replace it
// with the "absent" character (usually '.').
//
if((*pcString >= ucFirst) && (*pcString <= ucLast))
{
pucData = (pucGlyphs + pusOffset[*pcString - ucFirst]);
}
else
{
pucData = (pucGlyphs + pusOffset[ucAbsent - ucFirst]);
}
pcString++;
//
// See if the entire character is to the left of the clipping region.
//
if((lX + pucData[1]) < sCon.sClipRegion.sXMin)
{
//
// Increment the X coordinate by the width of the character.
//
lX += pucData[1];
//
// Go to the next character in the string.
//
continue;
}
//
// Loop through the bytes in the encoded data for this glyph.
//
for(lIdx = 2, lX0 = 0, lBit = 0, lY0 = 0; lIdx < pucData[0]; )
{
//
// See if the bottom of the clipping region has been exceeded.
//
if((lY + lY0) > sCon.sClipRegion.sYMax)
{
//
// Stop drawing this character.
//
break;
}
//
// See if the font is uncompressed.
//
if((sCon.pFont->ucFormat & ~FONT_EX_MARKER) ==
FONT_FMT_UNCOMPRESSED)
{
//
// Count the number of off pixels from this position in the
// glyph image.
//
for(lOff = 0; lIdx < pucData[0]; )
{
//
// Get the number of zero pixels at this position.
//
lCount = NumLeadingZeros(pucData[lIdx] << lBit);
//
// If there were more than 8, then it is a "false" result
// since it counted beyond the end of the current byte.
// Therefore, simply limit it to the number of pixels
// remaining in this byte.
//
if(lCount > 8)
{
lCount = 8 - lBit;
}
//
// Increment the number of off pixels.
//
lOff += lCount;
//
// Increment the bit position within the byte.
//
lBit += lCount;
//
// See if the end of the byte has been reached.
//
if(lBit == 8)
{
//
// Advance to the next byte and continue counting off
// pixels.
//
lBit = 0;
lIdx++;
}
else
{
//
// Since the end of the byte was not reached, there
// must be an on pixel. Therefore, stop counting off
// pixels.
//
break;
}
}
//
// Count the number of on pixels from this position in the
// glyph image.
//
for(lOn = 0; lIdx < pucData[0]; )
{
//
// Get the number of one pixels at this location (by
// inverting the data and counting the number of zeros).
//
lCount = NumLeadingZeros(~(pucData[lIdx] << lBit));
//
// If there were more than 8, then it is a "false" result
// since it counted beyond the end of the current byte.
// Therefore, simply limit it to the number of pixels
// remaining in this byte.
//
if(lCount > 8)
{
lCount = 8 - lBit;
}
//
// Increment the number of on pixels.
//
lOn += lCount;
//
// Increment the bit position within the byte.
//
lBit += lCount;
//
// See if the end of the byte has been reached.
//
if(lBit == 8)
{
//
// Advance to the next byte and continue counting on
// pixels.
//
lBit = 0;
lIdx++;
}
else
{
//
// Since the end of the byte was not reached, there
// must be an off pixel. Therefore, stop counting on
// pixels.
//
break;
}
}
}
//
// Otherwise, the font is compressed with a pixel RLE scheme.
//
else
{
//
// See if this is a byte that encodes some on and off pixels.
//
if(pucData[lIdx])
{
//
// Extract the number of off pixels.
//
lOff = (pucData[lIdx] >> 4) & 15;
//
// Extract the number of on pixels.
//
lOn = pucData[lIdx] & 15;
//
// Skip past this encoded byte.
//
lIdx++;
}
//
// Otherwise, see if this is a repeated on pixel byte.
//
else if(pucData[lIdx + 1] & 0x80)
{
//
// There are no off pixels in this encoding.
//
lOff = 0;
//
// Extract the number of on pixels.
//
lOn = (pucData[lIdx + 1] & 0x7f) * 8;
//
// Skip past these two encoded bytes.
//
lIdx += 2;
}
//
// Otherwise, this is a repeated off pixel byte.
//
else
{
//
// Extract the number of off pixels.
//
lOff = pucData[lIdx + 1] * 8;
//
// There are no on pixels in this encoding.
//
lOn = 0;
//
// Skip past these two encoded bytes.
//
lIdx += 2;
}
}
//
// Loop while there are any off pixels.
//
while(lOff)
{
//
// See if the bottom of the clipping region has been exceeded.
//
if((lY + lY0) > sCon.sClipRegion.sYMax)
{
//
// Ignore the remainder of the on pixels.
//
break;
}
//
// See if there is more than one on pixel that will fit onto
// the current row.
//
if((lOff > 1) && ((lX0 + 1) < pucData[1]))
{
//
// Determine the number of on pixels that will fit on this
// row.
//
lCount = (((lX0 + lOff) > pucData[1]) ? pucData[1] - lX0 :
lOff);
//
// If this row is within the clipping region, draw a
// horizontal line that corresponds to the sequence of on
// pixels.
//
if(((lY + lY0) >= sCon.sClipRegion.sYMin) && bOpaque)
{
sCon.ulForeground = pContext->ulBackground;
GrLineDrawH(&sCon, lX + lX0, lX + lX0 + lCount - 1,
lYSave + lY + lY0);
}
//
// Decrement the count of on pixels by the number on this
// row.
//
lOff -= lCount;
//
// Increment the X offset by the number of on pixels.
//
lX0 += lCount;
}
//
// Otherwise, there is only a single on pixel that can be
// drawn.
//
else
{
//
// If this pixel is within the clipping region, then draw
// it.
//
if(((lX + lX0) >= sCon.sClipRegion.sXMin) &&
((lX + lX0) <= sCon.sClipRegion.sXMax) &&
((lY + lY0) >= sCon.sClipRegion.sYMin) && bOpaque)
{
DpyPixelDraw(pContext->pDisplay, lX + lX0, lYSave + lY + lY0,
pContext->ulBackground);
}
//
// Decrement the count of on pixels.
//
lOff--;
//
// Increment the X offset.
//
lX0++;
}
//
// See if the X offset has reached the right side of the
// character glyph.
//
if(lX0 == pucData[1])
{
//
// Increment the Y offset.
//
lY0++;
//
// Reset the X offset to the left side of the character
// glyph.
//
lX0 = 0;
}
}
//
// Loop while there are any on pixels.
//
while(lOn)
{
//
// See if the bottom of the clipping region has been exceeded.
//
if((lY + lY0) > sCon.sClipRegion.sYMax)
{
//
// Ignore the remainder of the on pixels.
//
break;
}
//
// See if there is more than one on pixel that will fit onto
// the current row.
//
if((lOn > 1) && ((lX0 + 1) < pucData[1]))
{
//
// Determine the number of on pixels that will fit on this
// row.
//
lCount = (((lX0 + lOn) > pucData[1]) ? pucData[1] - lX0 :
lOn);
//
// If this row is within the clipping region, draw a
// horizontal line that corresponds to the sequence of on
// pixels.
//
if((lY + lY0) >= sCon.sClipRegion.sYMin)
{
sCon.ulForeground = pContext->ulForeground;
GrLineDrawH(&sCon, lX + lX0, lX + lX0 + lCount - 1,
lYSave + lY + lY0);
}
//
// Decrement the count of on pixels by the number on this
// row.
//
lOn -= lCount;
//
// Increment the X offset by the number of on pixels.
//
lX0 += lCount;
}
//
// Otherwise, there is only a single on pixel that can be
// drawn.
//
else
{
//
// If this pixel is within the clipping region, then draw
// it.
//
if(((lX + lX0) >= sCon.sClipRegion.sXMin) &&
((lX + lX0) <= sCon.sClipRegion.sXMax) &&
((lY + lY0) >= sCon.sClipRegion.sYMin))
DpyPixelDraw(pContext->pDisplay, lX + lX0, lYSave + lY + lY0,
pContext->ulForeground);
//
// Decrement the count of on pixels.
//
lOn--;
//
// Increment the X offset.
//
lX0++;
}
//
// See if the X offset has reached the right side of the
// character glyph.
//
if(lX0 == pucData[1])
{
//
// Increment the Y offset.
//
lY0++;
//
// Reset the X offset to the left side of the character
// glyph.
//
lX0 = 0;
}
}
}
//
// Increment the X coordinate by the width of the character.
//
lX += pucData[1];
}
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************