|
|
- /* --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.
- //! @}
- //
- //*****************************************************************************
|